Skip to content

Commit

Permalink
config UPDATE share clients between endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
roman committed May 26, 2023
1 parent 4ca1620 commit 8145975
Show file tree
Hide file tree
Showing 9 changed files with 530 additions and 57 deletions.
126 changes: 79 additions & 47 deletions modules/libnetconf2-netconf-server.yang
Original file line number Diff line number Diff line change
Expand Up @@ -11,53 +11,7 @@ module libnetconf2-netconf-server {
prefix ct;
}

augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" {
leaf auth-attempts {
type uint16;
default 3;
}

leaf auth-timeout {
type uint16;
default 10;
units "seconds";
}
}

augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication/ncs:users/ncs:user" {
container keyboard-interactive {
presence "";
leaf pam-config-file-name {
type string;
mandatory true;
}
leaf pam-config-file-dir {
type string;
}
}
}

augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport" {
case unix-socket {
container unix-socket {
leaf path {
type string;
mandatory true;
}
leaf mode {
type uint16;
}
leaf uid {
type uint16;
}
leaf gid {
type uint16;
}
}
}
}

/*
/*
identity ed25519-private-key-format {
base ct:private-key-format;
description
Expand Down Expand Up @@ -126,4 +80,82 @@ module libnetconf2-netconf-server {
RFC 4253:
The Secure Shell (SSH) Transport Layer Protocol";
}

augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" {
leaf auth-attempts {
type uint16;
default 3;
}

leaf auth-timeout {
type uint16;
default 10;
units "seconds";
}
}

augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication/ncs:users/ncs:user" {
container keyboard-interactive {
presence "";
leaf pam-config-file-name {
type string;
mandatory true;
}
leaf pam-config-file-dir {
type string;
}
}
}

augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport" {
case unix-socket {
container unix-socket {
leaf path {
type string;
mandatory true;
}
leaf mode {
type uint16;
}
leaf uid {
type uint16;
}
leaf gid {
type uint16;
}
}
}
}

augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" {
description
"Reference to another SSH endpoint's client-authentication container.
All the users set in the referencing endpoint will be tried first and if and only if
there is no match, the referenced endpoint's users will be tried. The references can be
multiple, however there must not be a cycle.";

leaf endpoint-client-auth {
type leafref {
path "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:name";
}

must "deref(.)/../*[local-name() = 'ssh']";
}
}

augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:tls/ncs:tls/ncs:tls-server-parameters/ncs:client-authentication" {
description
"Reference to another TLS endpoint's client-authentication container.
All the users set in the referencing endpoint will be tried first and if and only if
there is no match, the referenced endpoint's users will be tried. The references can be
multiple, however there must not be a cycle.";

leaf endpoint-client-auth {
type leafref {
path "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:name";
}

must "deref(.)/../*[local-name() = 'tls']";
}
}
}
156 changes: 151 additions & 5 deletions src/server_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,13 @@ nc_server_config_del_endpt_name(struct nc_endpt *endpt)
endpt->name = NULL;
}

static void
nc_server_config_del_endpt_reference(struct nc_endpt *endpt)
{
free(endpt->referenced_endpt_name);
endpt->referenced_endpt_name = NULL;
}

static void
nc_server_config_del_local_address(struct nc_bind *bind)
{
Expand Down Expand Up @@ -447,6 +454,7 @@ void
nc_server_config_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind)
{
nc_server_config_del_endpt_name(endpt);
nc_server_config_del_endpt_reference(endpt);
nc_server_config_del_ssh(bind, endpt->opts.ssh);

server_opts.endpt_count--;
Expand Down Expand Up @@ -491,14 +499,15 @@ nc_server_config_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *b
int
nc_server_config_listen(struct lyd_node *node, NC_OPERATION op)
{
uint16_t i;
uint16_t i, endpt_count;

(void) node;

assert(op == NC_OP_CREATE || op == NC_OP_DELETE);

if (op == NC_OP_DELETE) {
for (i = 0; i < server_opts.endpt_count; i++) {
endpt_count = server_opts.endpt_count;
for (i = 0; i < endpt_count; i++) {
switch (server_opts.endpts[i].ti) {
#ifdef NC_ENABLED_SSH
case NC_TI_LIBSSH:
Expand Down Expand Up @@ -1912,6 +1921,134 @@ nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op)
return ret;
}

/**
* @brief Set all endpoint client auth references, which couldn't be set beforehand.
*
* The references that could not be set are those, which reference endpoints, which
* lie below the given endpoint in the YANG data (because of DFS tree parsing).
*
* @return 0 on success, 1 on error.
*/
static int
nc_server_config_fill_endpt_client_auth(void)
{
uint16_t i, j;

for (i = 0; i < server_opts.endpt_count; i++) {
/* go through all the endpoint */
if (server_opts.endpts[i].referenced_endpt_name) {
/* endpt has a reference, that hasn't been set yet */
for (j = i + 1; j < server_opts.endpt_count; j++) {
/* go through all the remaining endpts */
if (!strcmp(server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[j].name)) {
/* found the endpoint we were looking for */
if (server_opts.endpts[i].ti == NC_TI_LIBSSH) {
server_opts.endpts[i].opts.ssh->endpt_client_ref = &server_opts.endpts[j];
break;
} else if (server_opts.endpts[i].ti == NC_TI_OPENSSL) {
/* TODO */
} else {
ERRINT;
return 1;
}
}
}

/* didn't find the endpoint */
if (j == server_opts.endpt_count) {
ERR(NULL, "Endpoint \"%s\" referenced by \"%s\" not found.",
server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
return 1;
}
}
}

return 0;
}

static int
nc_server_config_endpoint_client_auth_has_cycle(struct nc_endpt *original, struct nc_endpt *next, NC_TRANSPORT_IMPL transport)
{
if (transport == NC_TI_LIBSSH) {
if (next->opts.ssh->endpt_client_ref) {
if (next->opts.ssh->endpt_client_ref == original) {
return 1;
} else {
return nc_server_config_endpoint_client_auth_has_cycle(original, next->opts.ssh->endpt_client_ref, NC_TI_LIBSSH);
}
} else {
return 0;
}
} else if (transport == NC_TI_OPENSSL) {
/* TODO */
return 0;
} else {
ERRINT;
return 1;
}
}

static int
nc_server_config_endpoint_client_auth(const struct lyd_node *node, NC_OPERATION op)
{
int ret = 0;
uint16_t i;
const char *endpt_name;
struct nc_endpt *endpt;

assert(!strcmp(LYD_NAME(node), "endpoint-client-auth"));

/* get current endpoint */
ret = nc_server_config_get_endpt(node, &endpt, NULL);
if (ret) {
goto cleanup;
}

if (op == NC_OP_DELETE) {
endpt->opts.ssh->endpt_client_ref = NULL;
goto cleanup;
}

/* find the endpoint leafref is referring to */
endpt_name = lyd_get_value(node);
for (i = 0; i < server_opts.endpt_count; i++) {
if (!strcmp(endpt_name, server_opts.endpts[i].name)) {
break;
}
}

if (i == server_opts.endpt_count) {
/* endpt not found, save the name and try to look it up later */
endpt->referenced_endpt_name = strdup(endpt_name);
if (!endpt->referenced_endpt_name) {
ERRMEM;
ret = 1;
goto cleanup;
}
goto cleanup;
}

/* check for self reference */
if (endpt == &server_opts.endpts[i]) {
ERR(NULL, "Self client authentication reference detected.");
ret = 1;
goto cleanup;
}

/* check for cyclic references */
ret = nc_server_config_endpoint_client_auth_has_cycle(endpt, &server_opts.endpts[i], endpt->ti);
if (ret) {
ERR(NULL, "Cyclic client authentication reference detected.");
goto cleanup;
}

/* assign the current endpt the referrenced endpt */
endpt->opts.ssh->endpt_client_ref = &server_opts.endpts[i];

cleanup:
return ret;
}

static int
nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION op)
{
Expand Down Expand Up @@ -2033,6 +2170,10 @@ nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION
if (nc_server_config_unix_socket(node, op)) {
goto error;
}
} else if (!strcmp(name, "endpoint-client-auth")) {
if (nc_server_config_endpoint_client_auth(node, op)) {
goto error;
}
} else if (!strcmp(name, "cert-data")) {} else if (!strcmp(name, "expiration-date")) {} else if (!strcmp(name, "asymmetric-key")) {} else if (!strcmp(name, "certificate")) {} else if (!strcmp(name, "key-format")) {} else if (!strcmp(name,
"cleartext-key")) {} else if (!strcmp(name, "hidden-key")) {} else if (!strcmp(name, "id_hint")) {} else if (!strcmp(name, "external-identity")) {} else if (!strcmp(name, "hash")) {} else if (!strcmp(name, "context")) {} else if (!strcmp(name,
"target-protocol")) {} else if (!strcmp(name, "target-kdf")) {} else if (!strcmp(name, "client-authentication")) {} else if (!strcmp(name, "ca-certs")) {} else if (!strcmp(name, "ee-certs")) {} else if (!strcmp(name,
Expand All @@ -2048,7 +2189,7 @@ nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION
}

int
nc_session_server_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, NC_MODULE module)
nc_server_config_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, NC_MODULE module)
{
struct lyd_node *child;
struct lyd_meta *m;
Expand Down Expand Up @@ -2103,7 +2244,7 @@ nc_session_server_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op

if (current_op != NC_OP_DELETE) {
LY_LIST_FOR(lyd_child(node), child) {
if (nc_session_server_parse_tree(child, current_op, module)) {
if (nc_server_config_parse_tree(child, current_op, module)) {
return 1;
}
}
Expand Down Expand Up @@ -2230,7 +2371,12 @@ nc_server_config_fill_nectonf_server(const struct lyd_node *data, NC_OPERATION o
goto cleanup;
}

if (nc_session_server_parse_tree(tree, op, NC_MODULE_NETCONF_SERVER)) {
if (nc_server_config_parse_tree(tree, op, NC_MODULE_NETCONF_SERVER)) {
ret = 1;
goto cleanup;
}

if (nc_server_config_fill_endpt_client_auth()) {
ret = 1;
goto cleanup;
}
Expand Down
2 changes: 1 addition & 1 deletion src/server_config_ks.c
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ nc_server_config_fill_keystore(const struct lyd_node *data, NC_OPERATION op)
goto cleanup;
}

if (nc_session_server_parse_tree(tree, op, NC_MODULE_KEYSTORE)) {
if (nc_server_config_parse_tree(tree, op, NC_MODULE_KEYSTORE)) {
ret = 1;
goto cleanup;
}
Expand Down
2 changes: 1 addition & 1 deletion src/server_config_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ int nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uin
* @param[in] module Module for which to parse the data - either ietf-netconf-server, ietf-keystore or ietf-truststore
* @return 0 on success, 1 on error.
*/
int nc_session_server_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, NC_MODULE module);
int nc_server_config_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, NC_MODULE module);

/**
* @brief Configures the listen subtree in the ietf-netconf-server module.
Expand Down
2 changes: 1 addition & 1 deletion src/server_config_ts.c
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,7 @@ nc_server_config_fill_truststore(const struct lyd_node *data, NC_OPERATION op)
goto cleanup;
}

if (nc_session_server_parse_tree(tree, op, NC_MODULE_TRUSTSTORE)) {
if (nc_server_config_parse_tree(tree, op, NC_MODULE_TRUSTSTORE)) {
ret = 1;
goto cleanup;
}
Expand Down
Loading

0 comments on commit 8145975

Please sign in to comment.