server config UPDATE dynamic endpt references
Get endpoint references dynamically based on referenced endpt name.
Also some tls fixes.
diff --git a/modules/libnetconf2-netconf-server@2023-09-07.yang b/modules/libnetconf2-netconf-server@2023-09-07.yang
index 6fb4b0f..0ef941f 100644
--- a/modules/libnetconf2-netconf-server@2023-09-07.yang
+++ b/modules/libnetconf2-netconf-server@2023-09-07.yang
@@ -281,7 +281,7 @@
}
}
- grouping endpoint-auth-reference-grouping {
+ grouping endpoint-reference-grouping {
description
"Reference to another endpoint. The purpose is to use the referenced endpoint's authentication mechanisms.
If a connection occurs on an endpoint, the connecting user will be tried to be authenticated
@@ -290,14 +290,9 @@
using the referenced endpoint's mechanisms. The references can be
multiple, however there must not be a cycle.";
- leaf endpoint-client-auth {
- type union {
- type leafref {
- path "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:name";
- }
- type leafref {
- path "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:name";
- }
+ leaf endpoint-reference {
+ type leafref {
+ path "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:name";
}
}
}
@@ -403,19 +398,19 @@
}
augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" {
- uses endpoint-auth-reference-grouping;
+ uses endpoint-reference-grouping;
}
augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" {
- uses endpoint-auth-reference-grouping;
+ uses endpoint-reference-grouping;
}
augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:tls/ncs:tls/ncs:tls-server-parameters/ncs:client-authentication" {
- uses endpoint-auth-reference-grouping;
+ uses endpoint-reference-grouping;
}
augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:transport/ncs:tls/ncs:tls/ncs:tls-server-parameters/ncs:client-authentication" {
- uses endpoint-auth-reference-grouping;
+ uses endpoint-reference-grouping;
}
augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:tls/ncs:tls/ncs:tls-server-parameters/ncs:client-authentication" {
diff --git a/src/server_config.c b/src/server_config.c
index d31c191..47bda15 100644
--- a/src/server_config.c
+++ b/src/server_config.c
@@ -776,10 +776,60 @@
free(opts);
}
+static void
+nc_server_config_del_endpt_references(const char *referenced_endpt_name)
+{
+ uint16_t i, j;
+
+ for (i = 0; i < server_opts.endpt_count; i++) {
+ if (server_opts.endpts[i].referenced_endpt_name) {
+ if (!strcmp(server_opts.endpts[i].referenced_endpt_name, referenced_endpt_name)) {
+ free(server_opts.endpts[i].referenced_endpt_name);
+ server_opts.endpts[i].referenced_endpt_name = NULL;
+
+ if (server_opts.endpts[i].ti == NC_TI_LIBSSH) {
+ server_opts.endpts[i].opts.ssh->referenced_endpt_name = NULL;
+ } else {
+ server_opts.endpts[i].opts.tls->referenced_endpt_name = NULL;
+ }
+ }
+ }
+ }
+
+ /* LOCK */
+ pthread_rwlock_rdlock(&server_opts.ch_client_lock);
+ for (i = 0; i < server_opts.ch_client_count; i++) {
+ /* LOCK */
+ pthread_mutex_lock(&server_opts.ch_clients[i].lock);
+ for (j = 0; j < server_opts.ch_clients[i].ch_endpt_count; j++) {
+ if (server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name) {
+ if (!strcmp(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, referenced_endpt_name)) {
+ free(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name);
+ server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name = NULL;
+
+ if (server_opts.ch_clients[i].ch_endpts[j].ti == NC_TI_LIBSSH) {
+ server_opts.ch_clients[i].ch_endpts[j].opts.ssh->referenced_endpt_name = NULL;
+ } else {
+ server_opts.ch_clients[i].ch_endpts[j].opts.tls->referenced_endpt_name = NULL;
+ }
+ }
+ }
+ }
+ /* UNLOCK */
+ pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
+ }
+
+ /* UNLOCK */
+ pthread_rwlock_unlock(&server_opts.ch_client_lock);
+}
+
void
nc_server_config_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind)
{
+ /* delete any references to this endpoint */
+ nc_server_config_del_endpt_references(endpt->name);
free(endpt->name);
+
free(endpt->referenced_endpt_name);
nc_server_config_del_ssh_opts(bind, endpt->opts.ssh);
@@ -936,7 +986,10 @@
static void
nc_server_config_del_endpt_tls(struct nc_endpt *endpt, struct nc_bind *bind)
{
+ /* delete any references to this endpoint */
+ nc_server_config_del_endpt_references(endpt->name);
free(endpt->name);
+
free(endpt->referenced_endpt_name);
nc_server_config_del_tls_opts(bind, endpt->opts.tls);
@@ -2954,148 +3007,213 @@
#ifdef NC_ENABLED_SSH_TLS
+static int
+nc_server_config_check_endpt_reference_cycle(struct nc_endpt *original, struct nc_endpt *next)
+{
+ if (!next->referenced_endpt_name) {
+ /* no further reference -> no cycle */
+ return 0;
+ }
+
+ if (!strcmp(original->name, next->referenced_endpt_name)) {
+ /* found cycle */
+ return 1;
+ } else {
+ if (nc_server_get_referenced_endpt(next->referenced_endpt_name, &next)) {
+ /* referenced endpoint does not exist */
+ return 1;
+ }
+
+ /* continue further */
+ return nc_server_config_check_endpt_reference_cycle(original, next);
+ }
+}
+
/**
- * @brief Set all endpoint client auth references, which couldn't be set while parsing data.
+ * @brief Set all endpoint references.
*
* @return 0 on success, 1 on error.
*/
static int
-nc_server_config_fill_endpt_client_auth(void)
+nc_server_config_check_endpt_references(void)
{
uint16_t i, j;
+ struct nc_endpt *referenced_endpt = NULL;
+ /* first do listen endpoints */
for (i = 0; i < server_opts.endpt_count; i++) {
/* go through all the endpoints */
if (server_opts.endpts[i].referenced_endpt_name) {
- /* endpt has a reference, that hasn't been set yet */
- for (j = 0; j < server_opts.endpt_count; j++) {
- /* go through all the endpts */
- if (!strcmp(server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[j].name)) {
- /* found the endpoint we were looking for,
- * assign the server opts from the referenced endpt */
- 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) {
- server_opts.endpts[i].opts.tls->endpt_client_ref = &server_opts.endpts[j];
- break;
- } else {
- ERRINT;
- return 1;
- }
- }
- }
-
- /* didn't find the endpoint */
- if (j == server_opts.endpt_count) {
- ERR(NULL, "Endpoint \"%s\" referenced by \"%s\" not found.",
+ /* get referenced endpt */
+ if (nc_server_get_referenced_endpt(server_opts.endpts[i].referenced_endpt_name, &referenced_endpt)) {
+ ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" does not exist.",
server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
return 1;
}
+
+ /* check if the endpoint references itself */
+ if (&server_opts.endpts[i] == referenced_endpt) {
+ ERR(NULL, "Endpoint \"%s\" references itself.", server_opts.endpts[i].name);
+ return 1;
+ }
+
+ /* check transport */
+ if ((server_opts.endpts[i].ti != referenced_endpt->ti)) {
+ ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" has different transport type.",
+ server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
+ return 1;
+ } else if ((referenced_endpt->ti != NC_TI_LIBSSH) && (referenced_endpt->ti != NC_TI_OPENSSL)) {
+ ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" has unsupported transport type.",
+ server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
+ return 1;
+ }
+
+ /* check cyclic reference */
+ if (nc_server_config_check_endpt_reference_cycle(&server_opts.endpts[i], referenced_endpt)) {
+ ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" creates a cycle.",
+ server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
+ return 1;
+ }
+
+ /* all went well, assign the name to the opts, so we can access it for auth */
+ if (server_opts.endpts[i].ti == NC_TI_LIBSSH) {
+ server_opts.endpts[i].opts.ssh->referenced_endpt_name = referenced_endpt->name;
+ } else {
+ server_opts.endpts[i].opts.tls->referenced_endpt_name = referenced_endpt->name;
+ }
}
}
+ /* now check all the call home endpoints */
+ /* LOCK */
+ pthread_rwlock_rdlock(&server_opts.ch_client_lock);
+ for (i = 0; i < server_opts.ch_client_count; i++) {
+ /* LOCK */
+ pthread_mutex_lock(&server_opts.ch_clients[i].lock);
+ for (j = 0; j < server_opts.ch_clients[i].ch_endpt_count; j++) {
+ if (server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name) {
+ /* get referenced endpt */
+ if (nc_server_get_referenced_endpt(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, &referenced_endpt)) {
+ ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" does not exist.",
+ server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
+ goto ch_fail;
+ }
+
+ /* check transport */
+ if (server_opts.ch_clients[i].ch_endpts[j].ti != referenced_endpt->ti) {
+ ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" has different transport type.",
+ server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
+ goto ch_fail;
+ } else if ((referenced_endpt->ti != NC_TI_LIBSSH) && (referenced_endpt->ti != NC_TI_OPENSSL)) {
+ ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" has unsupported transport type.",
+ server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
+ goto ch_fail;
+ }
+
+ /* check cyclic reference */
+ if (nc_server_config_check_endpt_reference_cycle(referenced_endpt, referenced_endpt)) {
+ ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" creates a cycle.",
+ server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
+ goto ch_fail;
+ }
+
+ /* all went well, assign the name to the opts, so we can access it for auth */
+ if (server_opts.ch_clients[i].ch_endpts[j].ti == NC_TI_LIBSSH) {
+ server_opts.ch_clients[i].ch_endpts[j].opts.ssh->referenced_endpt_name = referenced_endpt->name;
+ } else {
+ server_opts.ch_clients[i].ch_endpts[j].opts.tls->referenced_endpt_name = referenced_endpt->name;
+ }
+ }
+ }
+ /* UNLOCK */
+ pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
+ }
+
+ /* UNLOCK */
+ pthread_rwlock_unlock(&server_opts.ch_client_lock);
return 0;
+
+ch_fail:
+ /* UNLOCK */
+ pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
+ /* UNLOCK */
+ pthread_rwlock_unlock(&server_opts.ch_client_lock);
+ return 1;
}
static int
-nc_server_config_endpoint_client_auth_has_cycle(struct nc_endpt *original, struct nc_endpt *next)
-{
- if (original->ti == NC_TI_LIBSSH) {
- if (!next->opts.ssh->endpt_client_ref) {
- /* no further reference -> no cycle */
- return 0;
- }
-
- if (next->opts.ssh->endpt_client_ref == original) {
- /* found cycle */
- return 1;
- } else {
- /* continue further */
- return nc_server_config_endpoint_client_auth_has_cycle(original, next->opts.ssh->endpt_client_ref);
- }
- } else if (original->ti == NC_TI_OPENSSL) {
- if (!next->opts.tls->endpt_client_ref) {
- /* no further reference -> no cycle */
- return 0;
- }
-
- if (next->opts.tls->endpt_client_ref == original) {
- /* found cycle */
- return 1;
- } else {
- /* continue further */
- return nc_server_config_endpoint_client_auth_has_cycle(original, next->opts.tls->endpt_client_ref);
- }
- } else {
- ERRINT;
- return 1;
- }
-}
-
-static int
-nc_server_config_endpoint_client_auth(const struct lyd_node *node, NC_OPERATION op)
+nc_server_config_endpoint_reference(const struct lyd_node *node, NC_OPERATION op)
{
int ret = 0;
- uint16_t i;
- const char *endpt_name;
- struct nc_endpt *endpt;
+ struct nc_endpt *endpt = NULL;
+ struct nc_ch_client *ch_client;
+ struct nc_ch_endpt *ch_endpt = NULL;
+ struct nc_server_ssh_opts *ssh = NULL;
+ struct nc_server_tls_opts *tls = NULL;
- assert(!strcmp(LYD_NAME(node), "endpoint-client-auth"));
+ assert(!strcmp(LYD_NAME(node), "endpoint-reference"));
- /* get current endpoint */
- ret = nc_server_config_get_endpt(node, &endpt, NULL);
+ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
+ /* to avoid unlock on fail */
+ return 1;
+ }
+
+ /* get endpt */
+ if (is_listen(node)) {
+ ret = nc_server_config_get_endpt(node, &endpt, NULL);
+ } else {
+ ret = nc_server_config_get_ch_endpt(node, &ch_endpt);
+ }
if (ret) {
goto cleanup;
}
if (op == NC_OP_DELETE) {
- if (is_ssh(node)) {
- endpt->opts.ssh->endpt_client_ref = NULL;
+ if (endpt) {
+ free(endpt->referenced_endpt_name);
+ endpt->referenced_endpt_name = NULL;
} else {
- endpt->opts.tls->endpt_client_ref = NULL;
+ free(ch_endpt->referenced_endpt_name);
+ ch_endpt->referenced_endpt_name = NULL;
}
- goto cleanup;
- }
+ if (is_ssh(node)) {
+ if (nc_server_config_get_ssh_opts(node, &ssh)) {
+ ret = 1;
+ goto cleanup;
+ }
+
+ ssh->referenced_endpt_name = NULL;
+ } else {
+ if (nc_server_config_get_tls_opts(node, &tls)) {
+ ret = 1;
+ 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;
+ tls->referenced_endpt_name = NULL;
}
- }
- if (i == server_opts.endpt_count) {
- /* endpt not found, save the name and try to look it up later */
- free(endpt->referenced_endpt_name);
- endpt->referenced_endpt_name = strdup(endpt_name);
- NC_CHECK_ERRMEM_GOTO(!endpt->referenced_endpt_name, ret = 1, cleanup);
goto cleanup;
- }
-
- /* check for self reference */
- if (endpt == &server_opts.endpts[i]) {
- ERR(NULL, "Self endpoint reference detected for endpoint \"%s\".", endpt->name);
- ret = 1;
- goto cleanup;
- }
-
- /* check for cyclic references */
- ret = nc_server_config_endpoint_client_auth_has_cycle(endpt, &server_opts.endpts[i]);
- if (ret) {
- ERR(NULL, "Cyclic endpoint reference detected for endpoint \"%s\".", endpt->name);
- goto cleanup;
- }
-
- /* assign the current endpt the referrenced endpt */
- if (is_ssh(node)) {
- endpt->opts.ssh->endpt_client_ref = &server_opts.endpts[i];
} else {
- endpt->opts.tls->endpt_client_ref = &server_opts.endpts[i];
+ /* just set the name, check it once configuring of all nodes is done */
+ if (endpt) {
+ free(endpt->referenced_endpt_name);
+ endpt->referenced_endpt_name = strdup(lyd_get_value(node));
+ NC_CHECK_ERRMEM_GOTO(!endpt->referenced_endpt_name, ret = 1, cleanup);
+ } else {
+ free(ch_endpt->referenced_endpt_name);
+ ch_endpt->referenced_endpt_name = strdup(lyd_get_value(node));
+ NC_CHECK_ERRMEM_GOTO(!ch_endpt->referenced_endpt_name, ret = 1, cleanup);
+ }
+
+ goto cleanup;
}
cleanup:
+ if (is_ch(node)) {
+ /* UNLOCK */
+ nc_ch_client_unlock(ch_client);
+ }
+
return ret;
}
@@ -3154,7 +3272,7 @@
nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op)
{
int ret = 0;
- struct nc_endpt *endpt;
+ struct nc_server_tls_opts *opts;
struct nc_ch_client *ch_client;
assert(!strcmp(LYD_NAME(node), "asymmetric-key"));
@@ -3165,21 +3283,21 @@
return 1;
}
- if (nc_server_config_get_endpt(node, &endpt, NULL)) {
+ if (nc_server_config_get_tls_opts(node, &opts)) {
ret = 1;
goto cleanup;
}
if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
/* set to keystore */
- endpt->opts.tls->store = NC_STORE_KEYSTORE;
+ opts->store = NC_STORE_KEYSTORE;
- free(endpt->opts.tls->key_ref);
- endpt->opts.tls->key_ref = strdup(lyd_get_value(node));
- NC_CHECK_ERRMEM_GOTO(!endpt->opts.tls->key_ref, ret = 1, cleanup);
+ free(opts->key_ref);
+ opts->key_ref = strdup(lyd_get_value(node));
+ NC_CHECK_ERRMEM_GOTO(!opts->key_ref, ret = 1, cleanup);
} else {
- free(endpt->opts.tls->key_ref);
- endpt->opts.tls->key_ref = NULL;
+ free(opts->key_ref);
+ opts->key_ref = NULL;
}
cleanup:
@@ -4134,8 +4252,8 @@
ret = nc_server_config_encryption_alg(node, op);
} else if (!strcmp(name, "mac-alg")) {
ret = nc_server_config_mac_alg(node, op);
- } else if (!strcmp(name, "endpoint-client-auth")) {
- ret = nc_server_config_endpoint_client_auth(node, op);
+ } else if (!strcmp(name, "endpoint-reference")) {
+ ret = nc_server_config_endpoint_reference(node, op);
} else if (!strcmp(name, "tls")) {
ret = nc_server_config_tls(node, op);
} else if (!strcmp(name, "cert-data")) {
@@ -4378,8 +4496,8 @@
}
#ifdef NC_ENABLED_SSH_TLS
- /* backward check of client auth reference */
- if (nc_server_config_fill_endpt_client_auth()) {
+ /* check and set all endpoint references */
+ if (nc_server_config_check_endpt_references()) {
ret = 1;
goto cleanup;
}
diff --git a/src/server_config_util_ssh.c b/src/server_config_util_ssh.c
index f3ca8c0..8b162ee 100644
--- a/src/server_config_util_ssh.c
+++ b/src/server_config_util_ssh.c
@@ -605,7 +605,7 @@
NC_CHECK_ARG_RET(NULL, ctx, endpt_name, referenced_endpt, config, 1);
return nc_server_config_create(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/"
- "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name);
+ "client-authentication/libnetconf2-netconf-server:endpoint-reference", endpt_name);
}
API int
@@ -614,7 +614,7 @@
NC_CHECK_ARG_RET(NULL, endpt_name, config, 1);
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/"
- "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name);
+ "client-authentication/libnetconf2-netconf-server:endpoint-reference", endpt_name);
}
API int
diff --git a/src/server_config_util_tls.c b/src/server_config_util_tls.c
index 66b2559..047a6d5 100644
--- a/src/server_config_util_tls.c
+++ b/src/server_config_util_tls.c
@@ -777,7 +777,7 @@
NC_CHECK_ARG_RET(NULL, ctx, endpt_name, referenced_endpt, config, 1);
return nc_server_config_create(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/"
- "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name);
+ "client-authentication/libnetconf2-netconf-server:endpoint-reference", endpt_name);
}
API int
@@ -786,5 +786,5 @@
NC_CHECK_ARG_RET(NULL, endpt_name, config, 1);
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/"
- "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name);
+ "client-authentication/libnetconf2-netconf-server:endpoint-reference", endpt_name);
}
diff --git a/src/session_p.h b/src/session_p.h
index 5d2ccb1..2b3524d 100644
--- a/src/session_p.h
+++ b/src/session_p.h
@@ -202,7 +202,7 @@
struct nc_auth_client *auth_clients; /**< Server's authorized clients. */
uint16_t client_count; /**< Number of server's authorized clients. */
- struct nc_endpt *endpt_client_ref; /**< Reference to another endpoint (used for client authentication). */
+ char *referenced_endpt_name; /**< Reference to another endpoint (used for client authentication). */
char *hostkey_algs; /**< Hostkey algorithms supported by the server. */
char *encryption_algs; /**< Encryption algorithms supported by the server. */
@@ -275,7 +275,7 @@
int crl_cert_ext; /**< Indicates to use CA's distribution points to obtain CRLs */
X509_STORE *crl_store; /**< Stores all the CRLs */
- struct nc_endpt *endpt_client_ref; /**< Reference to another endpoint (used for client authentication). */
+ char *referenced_endpt_name; /**< Reference to another endpoint (used for client authentication). */
unsigned int tls_versions; /**< TLS versions */
char *ciphers; /**< TLS ciphers */
@@ -476,12 +476,14 @@
* modify CH clients - READ lock ch_client_lock + ch_client_lock */
struct nc_ch_client {
char *name;
-
pthread_t tid; /**< Call Home client's thread ID */
struct nc_ch_client_thread_arg *thread_data; /**< Data of the Call Home client's thread */
struct nc_ch_endpt {
char *name;
+#ifdef NC_ENABLED_SSH_TLS
+ char *referenced_endpt_name;
+#endif /* NC_ENABLED_SSH_TLS */
NC_TRANSPORT_IMPL ti;
char *address;
uint16_t port;
@@ -965,6 +967,15 @@
void nc_server_ch_client_unlock(struct nc_ch_client *client);
/**
+ * @brief Gets an endpoint structure based on its name.
+ *
+ * @param[in] name The name of the endpoint.
+ * @param[out] endpt Pointer to the endpoint structure.
+ * @return 0 on success, 1 on failure.
+ */
+int nc_server_get_referenced_endpt(const char *name, struct nc_endpt **endpt);
+
+/**
* @brief Add a client Call Home bind, listen on it.
*
* @param[in] address Address to bind to.
diff --git a/src/session_server.c b/src/session_server.c
index 1fd84fb..90e02ff 100644
--- a/src/session_server.c
+++ b/src/session_server.c
@@ -151,6 +151,22 @@
pthread_rwlock_unlock(&server_opts.ch_client_lock);
}
+int
+nc_server_get_referenced_endpt(const char *name, struct nc_endpt **endpt)
+{
+ uint16_t i;
+
+ for (i = 0; i < server_opts.endpt_count; i++) {
+ if (!strcmp(name, server_opts.endpts[i].name)) {
+ *endpt = &server_opts.endpts[i];
+ return 0;
+ }
+ }
+
+ ERR(NULL, "Referenced endpoint \"%s\" was not found.", name);
+ return 1;
+}
+
API void
nc_session_set_term_reason(struct nc_session *session, NC_SESSION_TERM_REASON reason)
{
diff --git a/src/session_server_ssh.c b/src/session_server_ssh.c
index c4c3085..cc1f3de 100644
--- a/src/session_server_ssh.c
+++ b/src/session_server_ssh.c
@@ -829,6 +829,7 @@
int subtype, type, libssh_auth_methods = 0, ret = 0;
uint16_t i;
struct nc_auth_client *auth_client = NULL;
+ struct nc_endpt *referenced_endpt;
type = ssh_message_type(msg);
subtype = ssh_message_subtype(msg);
@@ -980,8 +981,14 @@
}
if (!auth_client) {
- if (opts->endpt_client_ref) {
- return nc_session_ssh_msg(session, opts->endpt_client_ref->opts.ssh, msg, state);
+ if (opts->referenced_endpt_name) {
+ /* client not known by the endpt, but it references another one so try it */
+ if (nc_server_get_referenced_endpt(opts->referenced_endpt_name, &referenced_endpt)) {
+ ERRINT;
+ return 1;
+ }
+
+ return nc_session_ssh_msg(session, referenced_endpt->opts.ssh, msg, state);
}
ERR(NULL, "User \"%s\" not known by the server.", username);
diff --git a/src/session_server_tls.c b/src/session_server_tls.c
index de898c8..a11c11b 100644
--- a/src/session_server_tls.c
+++ b/src/session_server_tls.c
@@ -38,12 +38,8 @@
#include "session_p.h"
struct nc_server_tls_opts tls_ch_opts;
-pthread_mutex_t tls_ch_opts_lock = PTHREAD_MUTEX_INITIALIZER;
extern struct nc_server_opts server_opts;
-static pthread_key_t verify_key;
-static pthread_once_t verify_once = PTHREAD_ONCE_INIT;
-
static char *
asn1time_to_str(const ASN1_TIME *t)
{
@@ -312,7 +308,7 @@
/* first make sure the entry is valid */
if (!ctn->map_type || ((ctn->map_type == NC_TLS_CTN_SPECIFIED) && !ctn->name)) {
- VRB(NULL, "Cert verify CTN: entry with id %u not valid, skipping.", ctn->id);
+ VRB(session, "Cert verify CTN: entry with id %u not valid, skipping.", ctn->id);
continue;
}
@@ -324,7 +320,7 @@
} else if (!strncmp(ctn->fingerprint, "01", 2)) {
if (!digest_md5) {
if (X509_digest(cert, EVP_md5(), buf, &buf_len) != 1) {
- ERR(NULL, "Calculating MD5 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
+ ERR(session, "Calculating MD5 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
ret = -1;
goto cleanup;
}
@@ -333,7 +329,7 @@
if (!strcasecmp(ctn->fingerprint + 3, digest_md5)) {
/* we got ourselves a potential winner! */
- VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found.");
+ VRB(session, "Cert verify CTN: entry with a matching fingerprint found.");
map_type = ctn->map_type;
}
free(digest_md5);
@@ -343,7 +339,7 @@
} else if (!strncmp(ctn->fingerprint, "02", 2)) {
if (!digest_sha1) {
if (X509_digest(cert, EVP_sha1(), buf, &buf_len) != 1) {
- ERR(NULL, "Calculating SHA-1 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
+ ERR(session, "Calculating SHA-1 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
ret = -1;
goto cleanup;
}
@@ -352,7 +348,7 @@
if (!strcasecmp(ctn->fingerprint + 3, digest_sha1)) {
/* we got ourselves a potential winner! */
- VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found.");
+ VRB(session, "Cert verify CTN: entry with a matching fingerprint found.");
map_type = ctn->map_type;
}
free(digest_sha1);
@@ -362,7 +358,7 @@
} else if (!strncmp(ctn->fingerprint, "03", 2)) {
if (!digest_sha224) {
if (X509_digest(cert, EVP_sha224(), buf, &buf_len) != 1) {
- ERR(NULL, "Calculating SHA-224 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
+ ERR(session, "Calculating SHA-224 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
ret = -1;
goto cleanup;
}
@@ -371,7 +367,7 @@
if (!strcasecmp(ctn->fingerprint + 3, digest_sha224)) {
/* we got ourselves a potential winner! */
- VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found.");
+ VRB(session, "Cert verify CTN: entry with a matching fingerprint found.");
map_type = ctn->map_type;
}
free(digest_sha224);
@@ -381,7 +377,7 @@
} else if (!strncmp(ctn->fingerprint, "04", 2)) {
if (!digest_sha256) {
if (X509_digest(cert, EVP_sha256(), buf, &buf_len) != 1) {
- ERR(NULL, "Calculating SHA-256 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
+ ERR(session, "Calculating SHA-256 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
ret = -1;
goto cleanup;
}
@@ -390,7 +386,7 @@
if (!strcasecmp(ctn->fingerprint + 3, digest_sha256)) {
/* we got ourselves a potential winner! */
- VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found.");
+ VRB(session, "Cert verify CTN: entry with a matching fingerprint found.");
map_type = ctn->map_type;
}
free(digest_sha256);
@@ -400,7 +396,7 @@
} else if (!strncmp(ctn->fingerprint, "05", 2)) {
if (!digest_sha384) {
if (X509_digest(cert, EVP_sha384(), buf, &buf_len) != 1) {
- ERR(NULL, "Calculating SHA-384 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
+ ERR(session, "Calculating SHA-384 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
ret = -1;
goto cleanup;
}
@@ -409,7 +405,7 @@
if (!strcasecmp(ctn->fingerprint + 3, digest_sha384)) {
/* we got ourselves a potential winner! */
- VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found.");
+ VRB(session, "Cert verify CTN: entry with a matching fingerprint found.");
map_type = ctn->map_type;
}
free(digest_sha384);
@@ -419,7 +415,7 @@
} else if (!strncmp(ctn->fingerprint, "06", 2)) {
if (!digest_sha512) {
if (X509_digest(cert, EVP_sha512(), buf, &buf_len) != 1) {
- ERR(NULL, "Calculating SHA-512 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
+ ERR(session, "Calculating SHA-512 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
ret = -1;
goto cleanup;
}
@@ -428,7 +424,7 @@
if (!strcasecmp(ctn->fingerprint + 3, digest_sha512)) {
/* we got ourselves a potential winner! */
- VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found.");
+ VRB(session, "Cert verify CTN: entry with a matching fingerprint found.");
map_type = ctn->map_type;
}
free(digest_sha512);
@@ -436,7 +432,7 @@
/* unknown */
} else {
- WRN(NULL, "Unknown fingerprint algorithm used (%s), skipping.", ctn->fingerprint);
+ WRN(session, "Unknown fingerprint algorithm used (%s), skipping.", ctn->fingerprint);
continue;
}
@@ -668,16 +664,24 @@
X509_NAME *issuer;
X509 *cert;
char *cp;
+ X509_STORE *store;
STACK_OF(X509) * cert_stack;
struct nc_session *session;
struct nc_server_tls_opts *opts;
+ struct nc_endpt *referenced_endpt;
int rc, depth;
- /* get the thread session */
- session = pthread_getspecific(verify_key);
+ store = X509_STORE_CTX_get0_store(x509_ctx);
+ if (!store) {
+ ERR(NULL, "Error getting store from context (%s).", ERR_reason_error_string(ERR_get_error()));
+ return 0;
+ }
+
+ /* get session from the store */
+ session = X509_STORE_get_ex_data(store, 0);
if (!session) {
- ERRINT;
+ ERR(session, "Error getting session from store (%s).", ERR_reason_error_string(ERR_get_error()));
return 0;
}
@@ -702,7 +706,7 @@
}
/* no match, continue */
- if (opts->endpt_client_ref) {
+ if (opts->referenced_endpt_name) {
/* check referenced endpoint's end-entity certs */
rc = nc_server_tls_do_preverify(session, x509_ctx, 2);
if (rc == -1) {
@@ -751,12 +755,19 @@
/* fatal error */
depth = 0;
goto fail;
- } else if ((rc == 1) && !opts->endpt_client_ref) {
+ } else if ((rc == 1) && !opts->referenced_endpt_name) {
/* no match found and no referenced endpoint */
goto fail;
- } else if ((rc == 1) && opts->endpt_client_ref) {
+ } else if ((rc == 1) && opts->referenced_endpt_name) {
/* no match found, but has a referenced endpoint so try it */
- rc = nc_tls_cert_to_name(session, opts->endpt_client_ref->opts.tls->ctn, cert);
+ if (nc_server_get_referenced_endpt(opts->referenced_endpt_name, &referenced_endpt)) {
+ /* fatal error */
+ ERRINT;
+ depth = 0;
+ goto fail;
+ }
+
+ rc = nc_tls_cert_to_name(session, referenced_endpt->opts.tls->ctn, cert);
if (rc) {
if (rc == -1) {
/* fatal error */
@@ -890,12 +901,6 @@
server_opts.user_verify_clb = verify_clb;
}
-static void
-nc_tls_make_verify_key(void)
-{
- pthread_key_create(&verify_key, NULL);
-}
-
static int
nc_server_tls_ks_ref_get_cert_key(const char *referenced_key_name, const char *referenced_cert_name,
char **privkey_data, NC_PRIVKEY_FORMAT *privkey_type, char **cert_data)
@@ -918,7 +923,7 @@
}
for (j = 0; j < ks->asym_keys[i].cert_count; j++) {
- if (!strcmp(referenced_cert_name, ks->asym_keys[i].certs[i].name)) {
+ if (!strcmp(referenced_cert_name, ks->asym_keys[i].certs[j].name)) {
break;
}
}
@@ -1403,6 +1408,7 @@
SSL_CTX *tls_ctx;
int ret;
struct timespec ts_timeout;
+ struct nc_endpt *referenced_endpt;
/* SSL_CTX */
tls_ctx = SSL_CTX_new(TLS_server_method());
@@ -1424,6 +1430,13 @@
goto error;
}
+ /* store the session, retrieve it when needed */
+ ret = X509_STORE_set_ex_data(cert_store, 0, session);
+ if (!ret) {
+ ERR(session, "Setting certificate store data failed (%s).", ERR_reason_error_string(ERR_get_error()));
+ goto error;
+ }
+
/* set end-entity certs as cert store data, retrieve them if verification fails later */
ret = X509_STORE_set_ex_data(cert_store, 1, &opts->ee_certs);
if (!ret) {
@@ -1432,8 +1445,13 @@
}
/* do the same for referenced endpoint's end entity certs */
- if (opts->endpt_client_ref) {
- ret = X509_STORE_set_ex_data(cert_store, 2, &opts->endpt_client_ref->opts.tls->ee_certs);
+ if (opts->referenced_endpt_name) {
+ if (nc_server_get_referenced_endpt(opts->referenced_endpt_name, &referenced_endpt)) {
+ ERRINT;
+ goto error;
+ }
+
+ ret = X509_STORE_set_ex_data(cert_store, 2, &referenced_endpt->opts.tls->ee_certs);
if (!ret) {
ERR(session, "Setting certificate store data failed (%s).", ERR_reason_error_string(ERR_get_error()));
goto error;
@@ -1449,8 +1467,8 @@
}
/* set referenced endpoint's CA certs if set */
- if (opts->endpt_client_ref) {
- if (nc_tls_store_set_trusted_certs(cert_store, &opts->endpt_client_ref->opts.tls->ca_certs)) {
+ if (opts->referenced_endpt_name) {
+ if (nc_tls_store_set_trusted_certs(cert_store, &referenced_endpt->opts.tls->ca_certs)) {
goto error;
}
}
@@ -1502,10 +1520,6 @@
sock = -1;
SSL_set_mode(session->ti.tls, SSL_MODE_AUTO_RETRY);
- /* store session on per-thread basis */
- pthread_once(&verify_once, nc_tls_make_verify_key);
- pthread_setspecific(verify_key, session);
-
if (timeout > -1) {
nc_timeouttime_get(&ts_timeout, timeout);
}