config UPDATE add basic SSH call-home
diff --git a/src/server_config.c b/src/server_config.c
index f7f6e93..8e3d3e5 100644
--- a/src/server_config.c
+++ b/src/server_config.c
@@ -108,6 +108,72 @@
return 1;
}
+int
+nc_server_config_get_ch_client(const struct lyd_node *node, struct nc_ch_client **ch_client)
+{
+ uint16_t i;
+ const char *ch_client_name;
+
+ while (node) {
+ if (!strcmp(LYD_NAME(node), "netconf-client")) {
+ break;
+ }
+ node = lyd_parent(node);
+ }
+
+ if (!node) {
+ ERR(NULL, "Node \"%s\" is not contained in a netconf-client subtree.", LYD_NAME(node));
+ return 1;
+ }
+
+ node = lyd_child(node);
+ assert(!strcmp(LYD_NAME(node), "name"));
+ ch_client_name = lyd_get_value(node);
+
+ for (i = 0; i < server_opts.ch_client_count; i++) {
+ if (!strcmp(server_opts.ch_clients[i].name, ch_client_name)) {
+ *ch_client = &server_opts.ch_clients[i];
+ return 0;
+ }
+ }
+
+ ERR(NULL, "Call-home client \"%s\" was not found.", ch_client_name);
+ return 1;
+}
+
+int
+nc_server_config_get_ch_endpt(const struct lyd_node *node, const struct nc_ch_client *ch_client, struct nc_ch_endpt **ch_endpt)
+{
+ uint16_t i;
+ const char *ch_endpt_name;
+
+ while (node) {
+ if (!strcmp(LYD_NAME(node), "endpoint")) {
+ break;
+ }
+ node = lyd_parent(node);
+ }
+
+ if (!node) {
+ ERR(NULL, "Node \"%s\" is not contained in a call-home endpoint subtree.", LYD_NAME(node));
+ return 1;
+ }
+
+ node = lyd_child(node);
+ assert(!strcmp(LYD_NAME(node), "name"));
+ ch_endpt_name = lyd_get_value(node);
+
+ for (i = 0; i < ch_client->ch_endpt_count; i++) {
+ if (!strcmp(ch_client->ch_endpts[i].name, ch_endpt_name)) {
+ *ch_endpt = &ch_client->ch_endpts[i];
+ return 0;
+ }
+ }
+
+ ERR(NULL, "Call-home client's \"%s\" endpoint \"%s\" was not found.", ch_client->name, ch_endpt_name);
+ return 1;
+}
+
#ifdef NC_ENABLED_SSH_TLS
int
@@ -362,8 +428,6 @@
return ret;
}
-#ifdef NC_ENABLED_SSH_TLS
-
static int
is_listen(const struct lyd_node *node)
{
@@ -379,20 +443,22 @@
return node != NULL;
}
-// static int
-// is_ch(const struct lyd_node *node)
-// {
-// assert(node);
+static int
+is_ch(const struct lyd_node *node)
+{
+ assert(node);
-// while (node) {
-// if (!strcmp(LYD_NAME(node), "call-home")) {
-// break;
-// }
-// node = lyd_parent(node);
-// }
+ while (node) {
+ if (!strcmp(LYD_NAME(node), "call-home")) {
+ break;
+ }
+ node = lyd_parent(node);
+ }
-// return node != NULL;
-// }
+ return node != NULL;
+}
+
+#ifdef NC_ENABLED_SSH_TLS
static int
is_ssh(const struct lyd_node *node)
@@ -849,6 +915,13 @@
}
}
+static void
+nc_server_config_del_remote_address(struct nc_ch_endpt *ch_endpt)
+{
+ free(ch_endpt->address);
+ ch_endpt->address = NULL;
+}
+
#endif /* NC_ENABLED_SSH_TLS */
/* presence container */
@@ -887,6 +960,127 @@
return 0;
}
+#ifdef NC_ENABLED_SSH_TLS
+
+static void
+nc_server_config_ch_del_ssh(struct nc_server_ssh_opts *opts)
+{
+ uint16_t i, hostkey_count, client_count;
+
+ /* store in variable because it gets decremented in the function call */
+ hostkey_count = opts->hostkey_count;
+ for (i = 0; i < hostkey_count; i++) {
+ nc_server_config_del_hostkey(opts, &opts->hostkeys[i]);
+ }
+
+ client_count = opts->client_count;
+ for (i = 0; i < client_count; i++) {
+ nc_server_config_del_auth_client(opts, &opts->auth_clients[i]);
+ }
+
+ nc_server_config_del_hostkey_algs(opts);
+ nc_server_config_del_kex_algs(opts);
+ nc_server_config_del_encryption_algs(opts);
+ nc_server_config_del_mac_algs(opts);
+
+ free(opts);
+ opts = NULL;
+}
+
+static void
+nc_server_config_ch_del_endpt_address(struct nc_ch_endpt *ch_endpt)
+{
+ free(ch_endpt->address);
+ ch_endpt->address = NULL;
+}
+
+#endif /* NC_ENABLED_SSH_TLS */
+
+static void
+nc_server_config_ch_del_endpt(struct nc_ch_client *ch_client, struct nc_ch_endpt *ch_endpt)
+{
+ free(ch_endpt->name);
+ ch_endpt->name = NULL;
+
+#ifdef NC_ENABLED_SSH_TLS
+ nc_server_config_ch_del_endpt_address(ch_endpt);
+ if (ch_endpt->sock_pending > -1) {
+ close(ch_endpt->sock_pending);
+ ch_endpt->sock_pending = -1;
+ }
+#endif /* NC_ENABLED_SSH_TLS */
+
+ switch (ch_endpt->ti) {
+#ifdef NC_ENABLED_SSH_TLS
+ case NC_TI_LIBSSH:
+ nc_server_config_ch_del_ssh(ch_endpt->opts.ssh);
+ break;
+#endif /* NC_ENABLED_SSH_TLS */
+ default:
+ ERRINT;
+ break;
+ }
+
+ ch_client->ch_endpt_count--;
+ if (!ch_client->ch_endpt_count) {
+ free(ch_client->ch_endpts);
+ ch_client->ch_endpts = NULL;
+ }
+}
+
+static void
+nc_server_config_ch_del_client(struct nc_ch_client *ch_client)
+{
+ uint16_t i, ch_endpt_count;
+
+ pthread_rwlock_wrlock(&server_opts.ch_client_lock);
+
+ free(ch_client->name);
+ ch_client->name = NULL;
+
+ if (ch_client->session) {
+ pthread_mutex_lock(&ch_client->session->opts.server.ch_lock);
+ pthread_cond_signal(&ch_client->session->opts.server.ch_cond);
+ pthread_mutex_unlock(&ch_client->session->opts.server.ch_lock);
+ }
+
+ ch_client->session = NULL;
+
+ pthread_rwlock_unlock(&server_opts.ch_client_lock);
+
+ pthread_join(ch_client->tid, NULL);
+
+ pthread_rwlock_wrlock(&server_opts.ch_client_lock);
+
+ ch_endpt_count = ch_client->ch_endpt_count;
+ for (i = 0; i < ch_endpt_count; i++) {
+ nc_server_config_ch_del_endpt(ch_client, &ch_client->ch_endpts[i]);
+ }
+
+ server_opts.ch_client_count--;
+ if (!server_opts.ch_client_count) {
+ free(server_opts.ch_clients);
+ server_opts.ch_clients = NULL;
+ }
+
+ pthread_rwlock_unlock(&server_opts.ch_client_lock);
+}
+
+void
+nc_server_config_ch(const struct lyd_node *node, NC_OPERATION op)
+{
+ uint16_t i, ch_client_count;
+
+ (void) node;
+
+ if (op == NC_OP_DELETE) {
+ ch_client_count = server_opts.ch_client_count;
+ for (i = 0; i < ch_client_count; i++) {
+ nc_server_config_ch_del_client(&server_opts.ch_clients[i]);
+ }
+ }
+}
+
/* default leaf */
static int
nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op)
@@ -939,6 +1133,15 @@
return nc_server_config_realloc(lyd_get_value(node), (void **)&server_opts.endpts, sizeof *server_opts.endpts, &server_opts.endpt_count);
}
+static int
+nc_server_config_ch_create_endpoint(const struct lyd_node *node, struct nc_ch_client *ch_client)
+{
+ node = lyd_child(node);
+ assert(!strcmp(LYD_NAME(node), "name"));
+
+ return nc_server_config_realloc(lyd_get_value(node), (void **)&ch_client->ch_endpts, sizeof *ch_client->ch_endpts, &ch_client->ch_endpt_count);
+}
+
/* list */
static int
nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op)
@@ -946,38 +1149,58 @@
int ret = 0;
struct nc_endpt *endpt;
struct nc_bind *bind;
+ struct nc_ch_client *ch_client;
assert(!strcmp(LYD_NAME(node), "endpoint"));
- if (op == NC_OP_CREATE) {
- ret = nc_server_config_create_endpoint(node);
- if (ret) {
- goto cleanup;
+ if (is_listen(node)) {
+ /* listen */
+ if (op == NC_OP_CREATE) {
+ ret = nc_server_config_create_endpoint(node);
+ if (ret) {
+ goto cleanup;
+ }
+ } else if (op == NC_OP_DELETE) {
+ /* free all children */
+ if (nc_server_config_get_endpt(node, &endpt, &bind)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ switch (endpt->ti) {
+#ifdef NC_ENABLED_SSH_TLS
+ case NC_TI_LIBSSH:
+ nc_server_config_del_endpt_ssh(endpt, bind);
+ break;
+ case NC_TI_OPENSSL:
+ nc_server_config_del_endpt_tls(endpt, bind);
+ break;
+#endif /* NC_ENABLED_SSH_TLS */
+ case NC_TI_UNIX:
+ nc_server_config_del_endpt_unix_socket(endpt, bind);
+ break;
+ case NC_TI_NONE:
+ case NC_TI_FD:
+ ERRINT;
+ ret = 1;
+ goto cleanup;
+ }
}
- } else if (op == NC_OP_DELETE) {
- /* free all children */
- if (nc_server_config_get_endpt(node, &endpt, &bind)) {
+ } else if (is_ch(node)) {
+ /* ch */
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
ret = 1;
goto cleanup;
}
- switch (endpt->ti) {
-#ifdef NC_ENABLED_SSH_TLS
- case NC_TI_LIBSSH:
- nc_server_config_del_endpt_ssh(endpt, bind);
- break;
- case NC_TI_OPENSSL:
- nc_server_config_del_endpt_tls(endpt, bind);
- break;
-#endif /* NC_ENABLED_SSH_TLS */
- case NC_TI_UNIX:
- nc_server_config_del_endpt_unix_socket(endpt, bind);
- break;
- case NC_TI_NONE:
- case NC_TI_FD:
- ERRINT;
- ret = 1;
- goto cleanup;
+ if (op == NC_OP_CREATE) {
+ ret = nc_server_config_ch_create_endpoint(node, ch_client);
+ if (ret) {
+ goto cleanup;
+ }
+
+ /* init ch sock */
+ ch_client->ch_endpts[ch_client->ch_endpt_count - 1].sock_pending = -1;
}
}
@@ -1000,28 +1223,62 @@
return 0;
}
+static int
+nc_server_config_ch_create_ssh(struct nc_ch_endpt *ch_endpt)
+{
+ ch_endpt->ti = NC_TI_LIBSSH;
+ ch_endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
+ if (!ch_endpt->opts.ssh) {
+ ERRMEM;
+ return 1;
+ }
+
+ return 0;
+}
+
/* NP container */
static int
nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op)
{
struct nc_endpt *endpt;
struct nc_bind *bind;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
int ret = 0;
assert(!strcmp(LYD_NAME(node), "ssh"));
- if (nc_server_config_get_endpt(node, &endpt, &bind)) {
- ret = 1;
- goto cleanup;
- }
-
- if (op == NC_OP_CREATE) {
- ret = nc_server_config_create_ssh(endpt);
- if (ret) {
+ if (is_listen(node)) {
+ if (nc_server_config_get_endpt(node, &endpt, &bind)) {
+ ret = 1;
goto cleanup;
}
- } else if (op == NC_OP_DELETE) {
- nc_server_config_del_ssh(bind, endpt->opts.ssh);
+
+ if (op == NC_OP_CREATE) {
+ ret = nc_server_config_create_ssh(endpt);
+ if (ret) {
+ goto cleanup;
+ }
+ } else if (op == NC_OP_DELETE) {
+ nc_server_config_del_ssh(bind, endpt->opts.ssh);
+ }
+ } else {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (op == NC_OP_CREATE) {
+ ret = nc_server_config_ch_create_ssh(ch_endpt);
+ if (ret) {
+ goto cleanup;
+ }
+ }
}
cleanup:
@@ -1208,13 +1465,15 @@
static int
nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op)
{
+ int ret = 0;
struct nc_endpt *endpt;
struct nc_bind *bind;
- int ret = 0;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
assert(!strcmp(LYD_NAME(node), "keepalives"));
- if (equal_parent_name(node, 1, "tcp-server-parameters")) {
+ if (is_listen(node) && equal_parent_name(node, 1, "tcp-server-parameters")) {
if (nc_server_config_get_endpt(node, &endpt, &bind)) {
ret = 1;
goto cleanup;
@@ -1229,6 +1488,22 @@
if (ret) {
goto cleanup;
}
+ } else if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (op == NC_OP_CREATE) {
+ ch_endpt->ka.enabled = 1;
+ } else {
+ ch_endpt->ka.enabled = 0;
+ }
}
cleanup:
@@ -1239,13 +1514,15 @@
static int
nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op)
{
+ int ret = 0;
struct nc_endpt *endpt;
struct nc_bind *bind;
- int ret = 0;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
assert(!strcmp(LYD_NAME(node), "idle-time"));
- if (equal_parent_name(node, 4, "listen")) {
+ if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
if (nc_server_config_get_endpt(node, &endpt, &bind)) {
ret = 1;
goto cleanup;
@@ -1260,6 +1537,22 @@
if (ret) {
goto cleanup;
}
+ } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
+ ch_endpt->ka.idle_time = strtoul(lyd_get_value(node), NULL, 10);
+ } else {
+ ch_endpt->ka.idle_time = 0;
+ }
}
cleanup:
@@ -1270,13 +1563,15 @@
static int
nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op)
{
+ int ret = 0;
struct nc_endpt *endpt;
struct nc_bind *bind;
- int ret = 0;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
assert(!strcmp(LYD_NAME(node), "max-probes"));
- if (equal_parent_name(node, 4, "listen")) {
+ if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
if (nc_server_config_get_endpt(node, &endpt, &bind)) {
ret = 1;
goto cleanup;
@@ -1291,6 +1586,22 @@
if (ret) {
goto cleanup;
}
+ } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
+ ch_endpt->ka.max_probes = strtoul(lyd_get_value(node), NULL, 10);
+ } else {
+ ch_endpt->ka.max_probes = 0;
+ }
}
cleanup:
@@ -1301,13 +1612,15 @@
static int
nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op)
{
+ int ret = 0;
struct nc_endpt *endpt;
struct nc_bind *bind;
- int ret = 0;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
assert(!strcmp(LYD_NAME(node), "probe-interval"));
- if (equal_parent_name(node, 4, "listen")) {
+ if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
if (nc_server_config_get_endpt(node, &endpt, &bind)) {
ret = 1;
goto cleanup;
@@ -1322,6 +1635,22 @@
if (ret) {
goto cleanup;
}
+ } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
+ ch_endpt->ka.probe_interval = strtoul(lyd_get_value(node), NULL, 10);
+ } else {
+ ch_endpt->ka.max_probes = 0;
+ }
}
cleanup:
@@ -1341,13 +1670,15 @@
static int
nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op)
{
+ int ret = 0;
struct nc_endpt *endpt;
struct nc_hostkey *hostkey;
- int ret = 0;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
assert(!strcmp(LYD_NAME(node), "host-key"));
- if ((equal_parent_name(node, 1, "server-identity")) && (equal_parent_name(node, 5, "listen"))) {
+ if (is_listen(node) && equal_parent_name(node, 1, "server-identity")) {
if (nc_server_config_get_endpt(node, &endpt, NULL)) {
ret = 1;
goto cleanup;
@@ -1363,16 +1694,31 @@
ret = 1;
goto cleanup;
}
-
nc_server_config_del_hostkey(endpt->opts.ssh, hostkey);
}
- } else if (equal_parent_name(node, 1, "transport-params")) {
- /* just a container with the name host-key, nothing to be done */
- goto cleanup;
- } else {
- ERRINT;
- ret = 1;
- goto cleanup;
+ } else if (is_ch(node) && equal_parent_name(node, 1, "server-identity")) {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (op == NC_OP_CREATE) {
+ ret = nc_server_config_create_host_key(node, ch_endpt->opts.ssh);
+ if (ret) {
+ goto cleanup;
+ }
+ } else if (op == NC_OP_DELETE) {
+ if (nc_server_config_get_hostkey(node, ch_endpt->opts.ssh, &hostkey)) {
+ ret = 1;
+ goto cleanup;
+ }
+ nc_server_config_del_hostkey(ch_endpt->opts.ssh, hostkey);
+ }
}
cleanup:
@@ -1383,13 +1729,15 @@
static int
nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op)
{
- const char *format;
int ret = 0;
+ const char *format;
NC_PUBKEY_FORMAT pubkey_type;
struct nc_endpt *endpt;
struct nc_client_auth *auth_client;
struct nc_public_key *pubkey;
struct nc_hostkey *hostkey;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
assert(!strcmp(LYD_NAME(node), "public-key-format"));
@@ -1404,12 +1752,35 @@
goto cleanup;
}
- if ((equal_parent_name(node, 6, "client-authentication")) && (is_ssh(node)) && (is_listen(node))) {
+ if (is_listen(node)) {
if (nc_server_config_get_endpt(node, &endpt, NULL)) {
ret = 1;
goto cleanup;
}
+ } else if (is_ch(node)) {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+ }
+
+ if (is_listen(node) && is_ssh(node) && equal_parent_name(node, 4, "server-identity")) {
+ /* SSH hostkey public key fmt */
+ if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
+ hostkey->key.pubkey_type = pubkey_type;
+ }
+ } else if (is_listen(node) && is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) {
+ /* SSH client auth public key fmt */
if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
ret = 1;
goto cleanup;
@@ -1423,13 +1794,14 @@
if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
pubkey->type = pubkey_type;
}
- } else if (equal_parent_name(node, 5, "server-identity") && is_ssh(node) && is_listen(node)) {
- if (nc_server_config_get_endpt(node, &endpt, NULL)) {
- ret = 1;
- goto cleanup;
+ } else if (is_listen(node) && is_tls(node) && equal_parent_name(node, 3, "server-identity")) {
+ /* TLS listen server-identity */
+ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
+ endpt->opts.tls->pubkey_type = pubkey_type;
}
-
- if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
+ } else if (is_ch(node) && is_ssh(node) && equal_parent_name(node, 4, "server-identity")) {
+ /* CH SSH server host-key public key fmt */
+ if (nc_server_config_get_hostkey(node, ch_endpt->opts.ssh, &hostkey)) {
ret = 1;
goto cleanup;
}
@@ -1437,193 +1809,20 @@
if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
hostkey->key.pubkey_type = pubkey_type;
}
- } else if (equal_parent_name(node, 3, "server-identity") && is_tls(node) && is_listen(node)) {
- /* TLS listen server-identity */
- if (nc_server_config_get_endpt(node, &endpt, NULL)) {
+ } else if (is_ch(node) && is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) {
+ /* CH SSH client auth public key fmt */
+ if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) {
ret = 1;
goto cleanup;
}
if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
- endpt->opts.tls->pubkey_type = pubkey_type;
- }
- }
-
-cleanup:
- return ret;
-}
-
-/* leaf */
-static int
-nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op)
-{
- int ret = 0;
- const char *format;
- struct nc_endpt *endpt;
- NC_PRIVKEY_FORMAT privkey_type;
- struct nc_hostkey *hostkey;
-
- (void) op;
-
- assert(!strcmp(LYD_NAME(node), "private-key-format"));
-
- if (nc_server_config_get_endpt(node, &endpt, NULL)) {
- ret = 1;
- goto cleanup;
- }
-
- format = ((struct lyd_node_term *)node)->value.ident->name;
- if (!format) {
- ret = 1;
- goto cleanup;
- }
-
- privkey_type = nc_server_config_get_private_key_type(format);
- if (privkey_type == NC_PRIVKEY_FORMAT_UNKNOWN) {
- ret = 1;
- goto cleanup;
- }
-
- if ((is_ssh(node)) && (is_listen(node))) {
- /* listen ssh */
- if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
- ret = 1;
- goto cleanup;
- }
-
- hostkey->key.privkey_type = privkey_type;
- } else if ((is_tls(node)) && (is_listen(node))) {
- /* listen tls */
- endpt->opts.tls->privkey_type = privkey_type;
- }
-
-cleanup:
- return ret;
-}
-
-static int
-nc_server_config_replace_cleartext_private_key(const struct lyd_node *node, struct nc_hostkey *hostkey)
-{
- nc_server_config_del_private_key(hostkey);
- hostkey->key.privkey_data = strdup(lyd_get_value(node));
- if (!hostkey->key.privkey_data) {
- ERRMEM;
- return 1;
- }
-
- return 0;
-}
-
-static int
-nc_server_config_tls_replace_cleartext_private_key(const struct lyd_node *node, struct nc_server_tls_opts *opts)
-{
- nc_server_config_tls_del_cleartext_private_key(opts);
- opts->privkey_data = strdup(lyd_get_value(node));
- if (!opts->privkey_data) {
- ERRMEM;
- return 1;
- }
-
- return 0;
-}
-
-static int
-nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op)
-{
- int ret = 0;
- struct nc_endpt *endpt;
- struct nc_hostkey *hostkey;
-
- assert(!strcmp(LYD_NAME(node), "cleartext-private-key"));
-
- if (nc_server_config_get_endpt(node, &endpt, NULL)) {
- ret = 1;
- goto cleanup;
- }
-
- if ((is_ssh(node)) && (is_listen(node))) {
- if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
- ret = 1;
- goto cleanup;
- }
-
- if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
- ret = nc_server_config_replace_cleartext_private_key(node, hostkey);
- if (ret) {
- goto cleanup;
- }
- } else {
- nc_server_config_del_private_key(hostkey);
- }
- } else if ((is_tls(node)) && (is_listen(node))) {
- /* listen tls */
- if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
- ret = nc_server_config_tls_replace_cleartext_private_key(node, endpt->opts.tls);
- if (ret) {
- goto cleanup;
- }
- } else {
- nc_server_config_tls_del_cleartext_private_key(endpt->opts.tls);
- }
- }
-
-cleanup:
- return ret;
-}
-
-static int
-nc_server_config_create_keystore_reference(const struct lyd_node *node, struct nc_hostkey *hostkey)
-{
- uint16_t i;
- struct nc_keystore *ks = &server_opts.keystore;
-
- /* lookup name */
- for (i = 0; i < ks->asym_key_count; i++) {
- if (!strcmp(lyd_get_value(node), ks->asym_keys[i].name)) {
- break;
- }
- }
-
- if (i == ks->asym_key_count) {
- ERR(NULL, "Keystore \"%s\" not found.", lyd_get_value(node));
- return 1;
- }
-
- hostkey->ks_ref = &ks->asym_keys[i];
-
- return 0;
-}
-
-/* leaf */
-static int
-nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op)
-{
- struct nc_endpt *endpt;
- struct nc_hostkey *hostkey;
- int ret = 0;
-
- assert(!strcmp(LYD_NAME(node), "keystore-reference"));
-
- if ((equal_parent_name(node, 3, "server-identity")) && (is_ssh(node)) && (is_listen(node))) {
- if (nc_server_config_get_endpt(node, &endpt, NULL)) {
- ret = 1;
- goto cleanup;
- }
- if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
- ret = 1;
- goto cleanup;
- }
-
- if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
- /* set to keystore */
- hostkey->store = NC_STORE_KEYSTORE;
-
- ret = nc_server_config_create_keystore_reference(node, hostkey);
- if (ret) {
- goto cleanup;
- }
- } else {
- hostkey->ks_ref = NULL;
+ pubkey->type = pubkey_type;
}
}
@@ -1692,15 +1891,31 @@
struct nc_hostkey *hostkey;
struct nc_client_auth *auth_client;
struct nc_public_key *pubkey;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
assert(!strcmp(LYD_NAME(node), "public-key"));
- if (nc_server_config_get_endpt(node, &endpt, NULL)) {
- ret = 1;
- goto cleanup;
+ if (is_listen(node)) {
+ if (nc_server_config_get_endpt(node, &endpt, NULL)) {
+ ret = 1;
+ goto cleanup;
+ }
}
- if ((equal_parent_name(node, 3, "host-key")) && (is_ssh(node)) && (is_listen(node))) {
+ if (is_ch(node)) {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+ }
+
+ if (is_listen(node) && is_ssh(node) && equal_parent_name(node, 3, "host-key")) {
/* server's public-key, mandatory leaf */
if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
ret = 1;
@@ -1716,7 +1931,7 @@
goto cleanup;
}
}
- } else if ((equal_parent_name(node, 5, "client-authentication")) && (is_ssh(node)) && (is_listen(node))) {
+ } else if (is_listen(node) && is_ssh(node) && equal_parent_name(node, 5, "client-authentication")) {
/* client auth pubkeys, list */
if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
ret = 1;
@@ -1739,7 +1954,7 @@
nc_server_config_del_auth_client_pubkey(auth_client, pubkey);
}
- } else if ((equal_parent_name(node, 6, "client-authentication")) && (is_ssh(node)) && (is_listen(node))) {
+ } else if (is_listen(node) && is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) {
/* client auth pubkey, leaf */
if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
ret = 1;
@@ -1759,7 +1974,7 @@
} else {
nc_server_config_del_auth_client_pubkey_pub_base64(pubkey);
}
- } else if ((equal_parent_name(node, 3, "server-identity")) && (is_tls(node)) && (is_listen(node))) {
+ } else if (is_listen(node) && is_tls(node) && equal_parent_name(node, 3, "server-identity")) {
/* tls listen server-identity */
if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
/* set to local */
@@ -1770,6 +1985,323 @@
goto cleanup;
}
}
+ } else if (is_ch(node) && is_ssh(node) && equal_parent_name(node, 3, "host-key")) {
+ /* CH SSH hostkey's public key */
+ if (nc_server_config_get_hostkey(node, ch_endpt->opts.ssh, &hostkey)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
+ /* set to local */
+ hostkey->store = NC_STORE_LOCAL;
+
+ ret = nc_server_config_replace_host_key_public_key(node, hostkey);
+ if (ret) {
+ goto cleanup;
+ }
+ }
+ } else if (is_ch(node) && is_ssh(node) && equal_parent_name(node, 5, "client-authentication")) {
+ /* CH SSH client auth list */
+ if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (op == NC_OP_CREATE) {
+ /* set to local */
+ auth_client->store = NC_STORE_LOCAL;
+
+ ret = nc_server_config_create_auth_key_public_key_list(node, auth_client);
+ if (ret) {
+ goto cleanup;
+ }
+ } else if (op == NC_OP_DELETE) {
+ if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ nc_server_config_del_auth_client_pubkey(auth_client, pubkey);
+ }
+ } else if (is_ch(node) && is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) {
+ /* CH SSH client auth leaf */
+ if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
+ ret = nc_server_config_replace_auth_key_public_key_leaf(node, pubkey);
+ if (ret) {
+ goto cleanup;
+ }
+ } else {
+ nc_server_config_del_auth_client_pubkey_pub_base64(pubkey);
+ }
+ }
+
+cleanup:
+ return ret;
+}
+
+/* leaf */
+static int
+nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op)
+{
+ int ret = 0;
+ const char *format;
+ NC_PRIVKEY_FORMAT privkey_type;
+ struct nc_endpt *endpt;
+ struct nc_hostkey *hostkey;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
+
+ (void) op;
+
+ assert(!strcmp(LYD_NAME(node), "private-key-format"));
+
+ format = ((struct lyd_node_term *)node)->value.ident->name;
+ if (!format) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ privkey_type = nc_server_config_get_private_key_type(format);
+ if (privkey_type == NC_PRIVKEY_FORMAT_UNKNOWN) {
+ ERR(NULL, "Unknown private key format.");
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (is_listen(node)) {
+ if (nc_server_config_get_endpt(node, &endpt, NULL)) {
+ ret = 1;
+ goto cleanup;
+ }
+ } else if (is_ch(node)) {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+ }
+
+ if (is_listen(node) && is_ssh(node)) {
+ /* listen ssh */
+ if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ hostkey->key.privkey_type = privkey_type;
+ } else if (is_listen(node) && is_tls(node)) {
+ /* listen tls */
+ endpt->opts.tls->privkey_type = privkey_type;
+ } else if (is_ch(node) && is_ssh(node)) {
+ /* ch ssh */
+ if (nc_server_config_get_hostkey(node, ch_endpt->opts.ssh, &hostkey)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ hostkey->key.privkey_type = privkey_type;
+ }
+
+cleanup:
+ return ret;
+}
+
+static int
+nc_server_config_replace_cleartext_private_key(const struct lyd_node *node, struct nc_hostkey *hostkey)
+{
+ nc_server_config_del_private_key(hostkey);
+ hostkey->key.privkey_data = strdup(lyd_get_value(node));
+ if (!hostkey->key.privkey_data) {
+ ERRMEM;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+nc_server_config_tls_replace_cleartext_private_key(const struct lyd_node *node, struct nc_server_tls_opts *opts)
+{
+ nc_server_config_tls_del_cleartext_private_key(opts);
+ opts->privkey_data = strdup(lyd_get_value(node));
+ if (!opts->privkey_data) {
+ ERRMEM;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op)
+{
+ int ret = 0;
+ struct nc_endpt *endpt;
+ struct nc_hostkey *hostkey;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
+
+ assert(!strcmp(LYD_NAME(node), "cleartext-private-key"));
+
+ if (is_listen(node)) {
+ if (nc_server_config_get_endpt(node, &endpt, NULL)) {
+ ret = 1;
+ goto cleanup;
+ }
+ } else if (is_ch(node)) {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+ }
+
+ if (is_listen(node) && is_ssh(node)) {
+ if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
+ ret = nc_server_config_replace_cleartext_private_key(node, hostkey);
+ if (ret) {
+ goto cleanup;
+ }
+ } else {
+ nc_server_config_del_private_key(hostkey);
+ }
+ } else if (is_listen(node) && is_tls(node)) {
+ /* listen tls */
+ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
+ ret = nc_server_config_tls_replace_cleartext_private_key(node, endpt->opts.tls);
+ if (ret) {
+ goto cleanup;
+ }
+ } else {
+ nc_server_config_tls_del_cleartext_private_key(endpt->opts.tls);
+ }
+ } else if (is_ch(node) && is_ssh(node)) {
+ if (nc_server_config_get_hostkey(node, ch_endpt->opts.ssh, &hostkey)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
+ ret = nc_server_config_replace_cleartext_private_key(node, hostkey);
+ if (ret) {
+ goto cleanup;
+ }
+ } else {
+ nc_server_config_del_private_key(hostkey);
+ }
+ }
+
+cleanup:
+ return ret;
+}
+
+static int
+nc_server_config_create_keystore_reference(const struct lyd_node *node, struct nc_hostkey *hostkey)
+{
+ uint16_t i;
+ struct nc_keystore *ks = &server_opts.keystore;
+
+ /* lookup name */
+ for (i = 0; i < ks->asym_key_count; i++) {
+ if (!strcmp(lyd_get_value(node), ks->asym_keys[i].name)) {
+ break;
+ }
+ }
+
+ if (i == ks->asym_key_count) {
+ ERR(NULL, "Keystore \"%s\" not found.", lyd_get_value(node));
+ return 1;
+ }
+
+ hostkey->ks_ref = &ks->asym_keys[i];
+
+ return 0;
+}
+
+/* leaf */
+static int
+nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op)
+{
+ int ret = 0;
+ struct nc_endpt *endpt;
+ struct nc_hostkey *hostkey;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
+
+ assert(!strcmp(LYD_NAME(node), "keystore-reference"));
+
+ if (is_listen(node) && is_ssh(node) && equal_parent_name(node, 3, "server-identity")) {
+ if (nc_server_config_get_endpt(node, &endpt, NULL)) {
+ ret = 1;
+ goto cleanup;
+ }
+ if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
+ /* set to keystore */
+ hostkey->store = NC_STORE_KEYSTORE;
+
+ ret = nc_server_config_create_keystore_reference(node, hostkey);
+ if (ret) {
+ goto cleanup;
+ }
+ } else {
+ hostkey->ks_ref = NULL;
+ }
+ } else if (is_ch(node) && is_ssh(node) && equal_parent_name(node, 3, "server-identity")) {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_hostkey(node, ch_endpt->opts.ssh, &hostkey)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
+ /* set to keystore */
+ hostkey->store = NC_STORE_KEYSTORE;
+
+ ret = nc_server_config_create_keystore_reference(node, hostkey);
+ if (ret) {
+ goto cleanup;
+ }
+ } else {
+ hostkey->ks_ref = NULL;
+ }
}
cleanup:
@@ -1789,13 +2321,15 @@
static int
nc_server_config_user(const struct lyd_node *node, NC_OPERATION op)
{
+ int ret = 0;
struct nc_endpt *endpt;
struct nc_client_auth *auth_client;
- int ret = 0;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
assert(!strcmp(LYD_NAME(node), "user"));
- if (equal_parent_name(node, 6, "listen")) {
+ if (is_listen(node)) {
if (nc_server_config_get_endpt(node, &endpt, NULL)) {
ret = 1;
goto cleanup;
@@ -1814,6 +2348,30 @@
nc_server_config_del_auth_client(endpt->opts.ssh, auth_client);
}
+ } else if (is_ch(node)) {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (op == NC_OP_CREATE) {
+ ret = nc_server_config_create_user(node, ch_endpt->opts.ssh);
+ if (ret) {
+ goto cleanup;
+ }
+ } else if (op == NC_OP_DELETE) {
+ if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ nc_server_config_del_auth_client(ch_endpt->opts.ssh, auth_client);
+ }
}
cleanup:
@@ -1823,12 +2381,14 @@
static int
nc_server_config_auth_attempts(const struct lyd_node *node, NC_OPERATION op)
{
- struct nc_endpt *endpt;
int ret = 0;
+ struct nc_endpt *endpt;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
assert(!strcmp(LYD_NAME(node), "auth-attempts"));
- if (equal_parent_name(node, 5, "listen")) {
+ if (is_listen(node)) {
if (nc_server_config_get_endpt(node, &endpt, NULL)) {
ret = 1;
goto cleanup;
@@ -1837,6 +2397,20 @@
if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
endpt->opts.ssh->auth_attempts = strtoul(lyd_get_value(node), NULL, 10);
}
+ } else if (is_ch(node)) {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
+ ch_endpt->opts.ssh->auth_attempts = strtoul(lyd_get_value(node), NULL, 10);
+ }
}
cleanup:
@@ -1846,12 +2420,14 @@
static int
nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op)
{
- struct nc_endpt *endpt;
int ret = 0;
+ struct nc_endpt *endpt;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
assert(!strcmp(LYD_NAME(node), "auth-timeout"));
- if (equal_parent_name(node, 5, "listen")) {
+ if (is_listen(node)) {
if (nc_server_config_get_endpt(node, &endpt, NULL)) {
ret = 1;
goto cleanup;
@@ -1860,6 +2436,20 @@
if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
endpt->opts.ssh->auth_timeout = strtoul(lyd_get_value(node), NULL, 10);
}
+ } else if (is_ch(node)) {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
+ ch_endpt->opts.ssh->auth_timeout = strtoul(lyd_get_value(node), NULL, 10);
+ }
}
cleanup:
@@ -1919,15 +2509,29 @@
int ret = 0;
struct nc_endpt *endpt;
struct nc_client_auth *auth_client;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
assert(!strcmp(LYD_NAME(node), "truststore-reference"));
- if (nc_server_config_get_endpt(node, &endpt, NULL)) {
- ret = 1;
- goto cleanup;
+ if (is_listen(node)) {
+ if (nc_server_config_get_endpt(node, &endpt, NULL)) {
+ ret = 1;
+ goto cleanup;
+ }
+ } else if (is_ch(node)) {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
}
- if ((equal_parent_name(node, 1, "public-keys")) && (is_ssh(node)) && (is_listen(node))) {
+ if (is_listen(node) && is_ssh(node) && equal_parent_name(node, 1, "public-keys")) {
if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
ret = 1;
goto cleanup;
@@ -1944,7 +2548,7 @@
} else {
auth_client->ts_ref = NULL;
}
- } else if ((equal_parent_name(node, 1, "ca-certs")) && (is_listen(node))) {
+ } else if (is_listen(node) && equal_parent_name(node, 1, "ca-certs")) {
if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
/* set to truststore */
endpt->opts.tls->ca_certs.store = NC_STORE_TRUSTSTORE;
@@ -1956,7 +2560,7 @@
} else {
endpt->opts.tls->ca_certs.ts_ref = NULL;
}
- } else if ((equal_parent_name(node, 1, "ee-certs")) && (is_listen(node))) {
+ } else if (is_listen(node) && equal_parent_name(node, 1, "ee-certs")) {
if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
/* set to truststore */
endpt->opts.tls->ee_certs.store = NC_STORE_TRUSTSTORE;
@@ -1968,6 +2572,23 @@
} else {
endpt->opts.tls->ee_certs.ts_ref = NULL;
}
+ } else if (is_ch(node) && is_ssh(node) && equal_parent_name(node, 1, "public-keys")) {
+ if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
+ /* set to truststore */
+ auth_client->store = NC_STORE_TRUSTSTORE;
+
+ ret = nc_server_config_replace_truststore_reference(node, auth_client);
+ if (ret) {
+ goto cleanup;
+ }
+ } else {
+ auth_client->ts_ref = NULL;
+ }
}
cleanup:
@@ -1992,13 +2613,15 @@
static int
nc_server_config_password(const struct lyd_node *node, NC_OPERATION op)
{
+ int ret = 0;
struct nc_endpt *endpt;
struct nc_client_auth *auth_client;
- int ret = 0;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
assert(!strcmp(LYD_NAME(node), "password"));
- if (equal_parent_name(node, 7, "listen")) {
+ if (is_listen(node)) {
if (nc_server_config_get_endpt(node, &endpt, NULL)) {
ret = 1;
goto cleanup;
@@ -2017,6 +2640,30 @@
} else {
nc_server_config_del_auth_client_password(auth_client);
}
+ } else if (is_ch(node)) {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
+ ret = nc_server_config_replace_password(node, auth_client);
+ if (ret) {
+ goto cleanup;
+ }
+ } else {
+ nc_server_config_del_auth_client_password(auth_client);
+ }
}
cleanup:
@@ -2026,13 +2673,15 @@
static int
nc_server_config_pam_name(const struct lyd_node *node, NC_OPERATION op)
{
+ int ret = 0;
struct nc_endpt *endpt;
struct nc_client_auth *auth_client;
- int ret = 0;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
assert(!strcmp(LYD_NAME(node), "pam-config-file-name"));
- if (equal_parent_name(node, 8, "listen")) {
+ if (is_listen(node)) {
if (nc_server_config_get_endpt(node, &endpt, NULL)) {
ret = 1;
goto cleanup;
@@ -2052,6 +2701,36 @@
ret = 1;
goto cleanup;
}
+ } else {
+ nc_server_config_del_auth_client_pam_name(auth_client);
+ }
+ } else if (is_ch(node)) {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
+ nc_server_config_del_auth_client_pam_name(auth_client);
+
+ auth_client->pam_config_name = strdup(lyd_get_value(node));
+ if (!auth_client->pam_config_name) {
+ ERRMEM;
+ ret = 1;
+ goto cleanup;
+ }
+ } else {
+ nc_server_config_del_auth_client_pam_name(auth_client);
}
}
@@ -2062,13 +2741,15 @@
static int
nc_server_config_pam_dir(const struct lyd_node *node, NC_OPERATION op)
{
+ int ret = 0;
struct nc_endpt *endpt;
struct nc_client_auth *auth_client;
- int ret = 0;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
assert(!strcmp(LYD_NAME(node), "pam-config-file-dir"));
- if (equal_parent_name(node, 8, "listen")) {
+ if (is_listen(node)) {
if (nc_server_config_get_endpt(node, &endpt, NULL)) {
ret = 1;
goto cleanup;
@@ -2087,6 +2768,35 @@
ret = 1;
goto cleanup;
}
+ } else {
+ nc_server_config_del_auth_client_pam_dir(auth_client);
+ }
+ } else if (is_ch(node)) {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
+ nc_server_config_del_auth_client_pam_dir(auth_client);
+ auth_client->pam_config_dir = strdup(lyd_get_value(node));
+ if (!auth_client->pam_config_dir) {
+ ERRMEM;
+ ret = 1;
+ goto cleanup;
+ }
+ } else {
+ nc_server_config_del_auth_client_pam_dir(auth_client);
}
}
@@ -2098,13 +2808,15 @@
static int
nc_server_config_none(const struct lyd_node *node, NC_OPERATION op)
{
+ int ret = 0;
struct nc_endpt *endpt;
struct nc_client_auth *auth_client;
- int ret = 0;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
assert(!strcmp(LYD_NAME(node), "none"));
- if (equal_parent_name(node, 7, "listen")) {
+ if (is_listen(node)) {
if (nc_server_config_get_endpt(node, &endpt, NULL)) {
ret = 1;
goto cleanup;
@@ -2120,6 +2832,27 @@
} else {
auth_client->supports_none = 0;
}
+ } else if (is_ch(node)) {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (op == NC_OP_CREATE) {
+ auth_client->supports_none = 1;
+ } else {
+ auth_client->supports_none = 0;
+ }
}
cleanup:
@@ -2214,30 +2947,46 @@
static int
nc_server_config_host_key_alg(const struct lyd_node *node, NC_OPERATION op)
{
- struct nc_endpt *endpt;
- int ret = 0, listen = 0;
+ int ret = 0;
const char *alg;
uint8_t i;
+ struct nc_endpt *endpt;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
+ struct nc_server_ssh_opts *opts;
- /* get the algorithm name and compare it with algs supported by libssh */
- alg = ((struct lyd_node_term *)node)->value.ident->name;
+ assert(!strcmp(LYD_NAME(node), "host-key-alg"));
+ assert(is_listen(node) || is_ch(node));
- if (equal_parent_name(node, 6, "listen")) {
- listen = 1;
+ if (is_listen(node)) {
if (nc_server_config_get_endpt(node, &endpt, NULL)) {
ret = 1;
goto cleanup;
}
+
+ opts = endpt->opts.ssh;
+ } else {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ opts = ch_endpt->opts.ssh;
}
+ /* get the algorithm name and compare it with algs supported by libssh */
+ alg = ((struct lyd_node_term *)node)->value.ident->name;
i = 0;
while (supported_hostkey_algs[i]) {
if (!strcmp(supported_hostkey_algs[i], alg)) {
- if (listen) {
- if (nc_server_config_transport_params(alg, &endpt->opts.ssh->hostkey_algs, op)) {
- ret = 1;
- goto cleanup;
- }
+ if (nc_server_config_transport_params(alg, &opts->hostkey_algs, op)) {
+ ret = 1;
+ goto cleanup;
}
break;
}
@@ -2257,30 +3006,46 @@
static int
nc_server_config_kex_alg(const struct lyd_node *node, NC_OPERATION op)
{
- struct nc_endpt *endpt;
- int ret = 0, listen = 0;
+ int ret = 0;
const char *alg;
uint8_t i;
+ struct nc_endpt *endpt;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
+ struct nc_server_ssh_opts *opts;
- /* get the algorithm name and compare it with algs supported by libssh */
- alg = ((struct lyd_node_term *)node)->value.ident->name;
+ assert(!strcmp(LYD_NAME(node), "key-exchange-alg"));
+ assert(is_listen(node) || is_ch(node));
- if (equal_parent_name(node, 6, "listen")) {
- listen = 1;
+ if (is_listen(node)) {
if (nc_server_config_get_endpt(node, &endpt, NULL)) {
ret = 1;
goto cleanup;
}
+
+ opts = endpt->opts.ssh;
+ } else {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ opts = ch_endpt->opts.ssh;
}
+ /* get the algorithm name and compare it with algs supported by libssh */
+ alg = ((struct lyd_node_term *)node)->value.ident->name;
i = 0;
while (supported_kex_algs[i]) {
if (!strcmp(supported_kex_algs[i], alg)) {
- if (listen) {
- if (nc_server_config_transport_params(alg, &endpt->opts.ssh->kex_algs, op)) {
- ret = 1;
- goto cleanup;
- }
+ if (nc_server_config_transport_params(alg, &opts->kex_algs, op)) {
+ ret = 1;
+ goto cleanup;
}
break;
}
@@ -2300,30 +3065,46 @@
static int
nc_server_config_encryption_alg(const struct lyd_node *node, NC_OPERATION op)
{
- struct nc_endpt *endpt;
- int ret = 0, listen = 0;
+ int ret = 0;
const char *alg;
uint8_t i;
+ struct nc_endpt *endpt;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
+ struct nc_server_ssh_opts *opts;
- /* get the algorithm name and compare it with algs supported by libssh */
- alg = ((struct lyd_node_term *)node)->value.ident->name;
+ assert(!strcmp(LYD_NAME(node), "encryption-alg"));
+ assert(is_listen(node) || is_ch(node));
- if (equal_parent_name(node, 6, "listen")) {
- listen = 1;
+ if (is_listen(node)) {
if (nc_server_config_get_endpt(node, &endpt, NULL)) {
ret = 1;
goto cleanup;
}
+
+ opts = endpt->opts.ssh;
+ } else {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ opts = ch_endpt->opts.ssh;
}
+ /* get the algorithm name and compare it with algs supported by libssh */
+ alg = ((struct lyd_node_term *)node)->value.ident->name;
i = 0;
while (supported_encryption_algs[i]) {
if (!strcmp(supported_encryption_algs[i], alg)) {
- if (listen) {
- if (nc_server_config_transport_params(alg, &endpt->opts.ssh->encryption_algs, op)) {
- ret = 1;
- goto cleanup;
- }
+ if (nc_server_config_transport_params(alg, &opts->encryption_algs, op)) {
+ ret = 1;
+ goto cleanup;
}
break;
}
@@ -2343,30 +3124,46 @@
static int
nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op)
{
- struct nc_endpt *endpt;
- int ret = 0, listen = 0;
+ int ret = 0;
const char *alg;
uint8_t i;
+ struct nc_endpt *endpt;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
+ struct nc_server_ssh_opts *opts;
- /* get the algorithm name and compare it with algs supported by libssh */
- alg = ((struct lyd_node_term *)node)->value.ident->name;
+ assert(!strcmp(LYD_NAME(node), "mac-alg"));
+ assert(is_listen(node) || is_ch(node));
- if (equal_parent_name(node, 6, "listen")) {
- listen = 1;
+ if (is_listen(node)) {
if (nc_server_config_get_endpt(node, &endpt, NULL)) {
ret = 1;
goto cleanup;
}
+
+ opts = endpt->opts.ssh;
+ } else {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ opts = ch_endpt->opts.ssh;
}
+ /* get the algorithm name and compare it with algs supported by libssh */
+ alg = ((struct lyd_node_term *)node)->value.ident->name;
i = 0;
while (supported_mac_algs[i]) {
if (!strcmp(supported_mac_algs[i], alg)) {
- if (listen) {
- if (nc_server_config_transport_params(alg, &endpt->opts.ssh->mac_algs, op)) {
- ret = 1;
- goto cleanup;
- }
+ if (nc_server_config_transport_params(alg, &opts->mac_algs, op)) {
+ ret = 1;
+ goto cleanup;
}
break;
}
@@ -3304,6 +4101,125 @@
#endif /* NC_ENABLED_SSH_TLS */
static int
+nc_server_config_create_netconf_client(const struct lyd_node *node)
+{
+ int ret = 0;
+
+ node = lyd_child(node);
+ assert(!strcmp(LYD_NAME(node), "name"));
+
+ /* LOCK */
+ pthread_rwlock_wrlock(&server_opts.ch_client_lock);
+
+ ret = nc_server_config_realloc(lyd_get_value(node), (void **)&server_opts.ch_clients, sizeof *server_opts.ch_clients, &server_opts.ch_client_count);
+ if (ret) {
+ goto cleanup;
+ }
+
+ server_opts.ch_clients[server_opts.ch_client_count - 1].id = ATOMIC_INC_RELAXED(server_opts.new_client_id);
+ server_opts.ch_clients[server_opts.ch_client_count - 1].start_with = NC_CH_FIRST_LISTED;
+ server_opts.ch_clients[server_opts.ch_client_count - 1].max_attempts = 3; // TODO
+
+ pthread_mutex_init(&server_opts.ch_clients[server_opts.ch_client_count - 1].lock, NULL);
+
+cleanup:
+ /* UNLOCK */
+ pthread_rwlock_unlock(&server_opts.ch_client_lock);
+ return ret;
+}
+
+static int
+nc_server_config_netconf_client(const struct lyd_node *node, NC_OPERATION op)
+{
+ int ret = 0;
+ struct nc_ch_client *ch_client;
+
+ assert(!strcmp(LYD_NAME(node), "netconf-client"));
+
+ if (op == NC_OP_CREATE) {
+ ret = nc_server_config_create_netconf_client(node);
+ if (ret) {
+ goto cleanup;
+ }
+ } else if (op == NC_OP_DELETE) {
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ nc_server_config_ch_del_client(ch_client);
+ }
+
+cleanup:
+ return ret;
+}
+
+#ifdef NC_ENABLED_SSH_TLS
+
+static int
+nc_server_config_remote_address(const struct lyd_node *node, NC_OPERATION op)
+{
+ int ret = 0;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
+
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
+ nc_server_config_del_remote_address(ch_endpt);
+
+ ch_endpt->address = strdup(lyd_get_value(node));
+ if (!ch_endpt->address) {
+ ERRMEM;
+ ret = 1;
+ goto cleanup;
+ }
+ } else {
+ nc_server_config_del_remote_address(ch_endpt);
+ }
+
+cleanup:
+ return ret;
+}
+
+static int
+nc_server_config_remote_port(const struct lyd_node *node, NC_OPERATION op)
+{
+ int ret = 0;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt;
+
+ if (nc_server_config_get_ch_client(node, &ch_client)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
+ ch_endpt->port = strtoul(lyd_get_value(node), NULL, 10);
+ } else {
+ ch_endpt->port = 0;
+ }
+
+cleanup:
+ return ret;
+}
+
+#endif /* NC_ENABLED_SSH_TLS */
+
+static int
nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION op)
{
const char *name = LYD_NAME(node);
@@ -3476,6 +4392,22 @@
}
}
#endif /* NC_ENABLED_SSH_TLS */
+ else if (!strcmp(name, "netconf-client")) {
+ if (nc_server_config_netconf_client(node, op)) {
+ goto error;
+ }
+ }
+#ifdef NC_ENABLED_SSH_TLS
+ else if (!strcmp(name, "remote-address")) {
+ if (nc_server_config_remote_address(node, op)) {
+ goto error;
+ }
+ } else if (!strcmp(name, "remote-port")) {
+ if (nc_server_config_remote_port(node, op)) {
+ goto error;
+ }
+ }
+#endif /* NC_ENABLED_SSH_TLS */
return 0;