session CHANGE api completely rewritten
It was simply wrong before, global settings
for all listening connections is not enough.
diff --git a/src/session.c b/src/session.c
index f53e105..23cf3cf 100644
--- a/src/session.c
+++ b/src/session.c
@@ -488,28 +488,28 @@
mod = ly_ctx_get_module(ctx, "ietf-netconf", NULL);
if (mod) {
if (lys_features_state(mod, "writable-running") == 1) {
- add_cpblt(ctx, "urn:ietf:params:netconf:writable-running:1.0", &cpblts, &size, &count);
+ add_cpblt(ctx, "urn:ietf:params:netconf:capability:writable-running:1.0", &cpblts, &size, &count);
}
if (lys_features_state(mod, "candidate") == 1) {
- add_cpblt(ctx, "urn:ietf:params:netconf:candidate:1.0", &cpblts, &size, &count);
+ add_cpblt(ctx, "urn:ietf:params:netconf:capability:candidate:1.0", &cpblts, &size, &count);
if (lys_features_state(mod, "confirmed-commit") == 1) {
- add_cpblt(ctx, "urn:ietf:params:netconf:confirmed-commit:1.1", &cpblts, &size, &count);
+ add_cpblt(ctx, "urn:ietf:params:netconf:capability:confirmed-commit:1.1", &cpblts, &size, &count);
}
}
if (lys_features_state(mod, "rollback-on-error") == 1) {
- add_cpblt(ctx, "urn:ietf:params:netconf:rollback-on-error:1.0", &cpblts, &size, &count);
+ add_cpblt(ctx, "urn:ietf:params:netconf:capability:rollback-on-error:1.0", &cpblts, &size, &count);
}
if (lys_features_state(mod, "validate") == 1) {
- add_cpblt(ctx, "urn:ietf:params:netconf:validate:1.1", &cpblts, &size, &count);
+ add_cpblt(ctx, "urn:ietf:params:netconf:capability:validate:1.1", &cpblts, &size, &count);
}
if (lys_features_state(mod, "startup") == 1) {
- add_cpblt(ctx, "urn:ietf:params:netconf:startup:1.0", &cpblts, &size, &count);
+ add_cpblt(ctx, "urn:ietf:params:netconf:capability:startup:1.0", &cpblts, &size, &count);
}
if (lys_features_state(mod, "url") == 1) {
- add_cpblt(ctx, "urn:ietf:params:netconf:url:1.0", &cpblts, &size, &count);
+ add_cpblt(ctx, "urn:ietf:params:netconf:capability:url:1.0", &cpblts, &size, &count);
}
if (lys_features_state(mod, "xpath") == 1) {
- add_cpblt(ctx, "urn:ietf:params:netconf:xpath:1.0", &cpblts, &size, &count);
+ add_cpblt(ctx, "urn:ietf:params:netconf:capability:xpath:1.0", &cpblts, &size, &count);
}
}
@@ -518,7 +518,7 @@
if (!server_opts.wd_basic_mode) {
VRB("with-defaults capability will not be advertised even though \"ietf-netconf-with-defaults\" model is present, unknown basic-mode.");
} else {
- strcpy(str, "urn:ietf:params:netconf:with-defaults:1.0");
+ strcpy(str, "urn:ietf:params:netconf:capability:with-defaults:1.0");
switch (server_opts.wd_basic_mode) {
case NC_WD_ALL:
strcat(str, "?basic-mode=report-all");
@@ -557,9 +557,9 @@
mod = ly_ctx_get_module(ctx, "nc-notifications", NULL);
if (mod) {
- add_cpblt(ctx, "urn:ietf:params:netconf:notification:1.0", &cpblts, &size, &count);
+ add_cpblt(ctx, "urn:ietf:params:netconf:capability:notification:1.0", &cpblts, &size, &count);
if (server_opts.interleave_capab) {
- add_cpblt(ctx, "urn:ietf:params:netconf:interleave:1.0", &cpblts, &size, &count);
+ add_cpblt(ctx, "urn:ietf:params:netconf:capability:interleave:1.0", &cpblts, &size, &count);
}
}
diff --git a/src/session_client.c b/src/session_client.c
index f1db4bf..afd5756 100644
--- a/src/session_client.c
+++ b/src/session_client.c
@@ -41,29 +41,29 @@
static const char *ncds2str[] = {NULL, "config", "url", "running", "startup", "candidate"};
-static char *schema_searchpath;
+static struct nc_client_opts client_opts;
API int
-nc_schema_searchpath(const char *path)
+nc_client_schema_searchpath(const char *path)
{
- if (schema_searchpath) {
- free(schema_searchpath);
+ if (client_opts.schema_searchpath) {
+ free(client_opts.schema_searchpath);
}
if (path) {
- schema_searchpath = strdup(path);
- if (!schema_searchpath) {
+ client_opts.schema_searchpath = strdup(path);
+ if (!client_opts.schema_searchpath) {
ERRMEM;
return 1;
}
} else {
- schema_searchpath = NULL;
+ client_opts.schema_searchpath = NULL;
}
return 0;
}
-/* SCHEMAS_DIR not used */
+/* SCHEMAS_DIR not used (implicitly) */
static int
ctx_check_and_load_model(struct nc_session *session, const char *cpblt)
{
@@ -851,6 +851,102 @@
return reply;
}
+int
+nc_client_ch_add_bind_listen(const char *address, uint16_t port, NC_TRANSPORT_IMPL ti)
+{
+ int sock;
+
+ if (!address || !port) {
+ ERRARG;
+ return -1;
+ }
+
+ sock = nc_sock_listen(address, port);
+ if (sock == -1) {
+ return -1;
+ }
+
+ ++client_opts.ch_bind_count;
+ client_opts.ch_binds = realloc(client_opts.ch_binds, client_opts.ch_bind_count * sizeof *client_opts.ch_binds);
+
+ client_opts.ch_binds[client_opts.ch_bind_count - 1].address = strdup(address);
+ client_opts.ch_binds[client_opts.ch_bind_count - 1].port = port;
+ client_opts.ch_binds[client_opts.ch_bind_count - 1].sock = sock;
+ client_opts.ch_binds[client_opts.ch_bind_count - 1].ti = ti;
+
+ return 0;
+}
+
+int
+nc_client_ch_del_bind(const char *address, uint16_t port, NC_TRANSPORT_IMPL ti)
+{
+ uint32_t i;
+ int ret = -1;
+
+ if (!address && !port && !ti) {
+ for (i = 0; i < client_opts.ch_bind_count; ++i) {
+ close(client_opts.ch_binds[i].sock);
+ free((char *)client_opts.ch_binds[i].address);
+
+ ret = 0;
+ }
+ free(client_opts.ch_binds);
+ client_opts.ch_binds = NULL;
+ client_opts.ch_bind_count = 0;
+ } else {
+ for (i = 0; i < client_opts.ch_bind_count; ++i) {
+ if ((!address || !strcmp(client_opts.ch_binds[i].address, address))
+ && (!port || (client_opts.ch_binds[i].port == port))
+ && (!ti || (client_opts.ch_binds[i].ti == ti))) {
+ close(client_opts.ch_binds[i].sock);
+ free((char *)client_opts.ch_binds[i].address);
+
+ --client_opts.ch_bind_count;
+ memcpy(&client_opts.ch_binds[i], &client_opts.ch_binds[client_opts.ch_bind_count], sizeof *client_opts.ch_binds);
+
+ ret = 0;
+ }
+ }
+ }
+
+ return ret;
+}
+
+API int
+nc_accept_callhome(int timeout, struct ly_ctx *ctx, struct nc_session **session)
+{
+ int sock;
+ char *host = NULL;
+ uint16_t port, idx;
+
+ if (!client_opts.ch_binds || !session) {
+ ERRARG;
+ return -1;
+ }
+
+ sock = nc_sock_accept_binds(client_opts.ch_binds, client_opts.ch_bind_count, timeout, &host, &port, &idx);
+
+ if (sock < 1) {
+ return sock;
+ }
+
+ if (client_opts.ch_binds[idx].ti == NC_TI_LIBSSH) {
+ *session = nc_accept_callhome_sock_ssh(sock, host, port, ctx);
+ } else if (client_opts.ch_binds[idx].ti == NC_TI_OPENSSL) {
+ *session = nc_accept_callhome_sock_tls(sock, host, port, ctx);
+ } else {
+ *session = NULL;
+ }
+
+ free(host);
+
+ if (!(*session)) {
+ return -1;
+ }
+
+ return 1;
+}
+
API NC_MSG_TYPE
nc_recv_reply(struct nc_session *session, struct nc_rpc *rpc, uint64_t msgid, int timeout, struct nc_reply **reply)
{
@@ -1431,67 +1527,3 @@
*msgid = cur_msgid;
return NC_MSG_RPC;
}
-
-/* CALL HOME */
-
-int
-nc_sock_accept(int sock, int timeout, char **peer_host, uint16_t *peer_port)
-{
- struct pollfd pfd = {-1, POLLIN, 0};
- struct sockaddr_storage remote;
- socklen_t addr_size = sizeof(remote);
- int ret, status;
-
- pfd.fd = sock;
- pfd.revents = 0;
- while (1) {
- DBG("Waiting %ums for incoming Call Home connections.", timeout);
- status = poll(&pfd, 1, timeout);
-
- if (status == 0) {
- /* timeout */
- ERR("Timeout for Call Home listen expired.");
- return -1;
- } else if ((status == -1) && (errno == EINTR)) {
- /* poll was interrupted - try it again */
- continue;
- } else if (status < 0) {
- /* poll failed - something wrong happened */
- ERR("Call Home poll failed (%s).", strerror(errno));
- return -1;
- } else if (status > 0) {
- if (pfd.revents & (POLLHUP | POLLERR)) {
- /* close pipe/fd - other side already did it */
- ERR("Call Home listening socket was closed.");
- return -1;
- } else if (pfd.revents & POLLIN) {
- /* accept call home */
- ret = accept(pfd.fd, (struct sockaddr *)&remote, &addr_size);
- break;
- }
- }
- }
-
- /* fill some server info, if interested */
- if (remote.ss_family == AF_INET) {
- struct sockaddr_in *remote_in = (struct sockaddr_in *)&remote;
- if (peer_port) {
- *peer_port = ntohs(remote_in->sin_port);
- }
- if (peer_host) {
- *peer_host = malloc(INET6_ADDRSTRLEN);
- inet_ntop(AF_INET, &(remote_in->sin_addr), *peer_host, INET6_ADDRSTRLEN);
- }
- } else if (remote.ss_family == AF_INET6) {
- struct sockaddr_in6 *remote_in = (struct sockaddr_in6 *)&remote;
- if (peer_port) {
- *peer_port = ntohs(remote_in->sin6_port);
- }
- if (peer_host) {
- *peer_host = malloc(INET6_ADDRSTRLEN);
- inet_ntop(AF_INET6, &(remote_in->sin6_addr), *peer_host, INET6_ADDRSTRLEN);
- }
- }
-
- return ret;
-}
diff --git a/src/session_client.h b/src/session_client.h
index ed03d4d..9f493d6 100644
--- a/src/session_client.h
+++ b/src/session_client.h
@@ -52,7 +52,7 @@
* @param[in] path Directory where to search for YANG/YIN schemas.
* @return 0 on success, 1 on (memory allocation) failure.
*/
-int nc_schema_searchpath(const char *path);
+int nc_client_schema_searchpath(const char *path);
/**
* @brief Connect to the NETCONF server via proviaded input/output file descriptors.
@@ -76,14 +76,185 @@
*/
struct nc_session *nc_connect_inout(int fdin, int fdout, struct ly_ctx *ctx);
+#if defined(ENABLE_SSH) || defined(ENABLE_TLS)
+
+/* TODO */
+int nc_accept_callhome(int timeout, struct ly_ctx *ctx, struct nc_session **session);
+
+#endif /* ENABLE_SSH || ENABLE_TLS */
+
#ifdef ENABLE_SSH
/**
- * @brief Destroy any dynamically allocated SSH-specific client context.
+ * @brief Add an SSH public and private key pair to be used for client authentication.
+ *
+ * Private key can be encrypted, the passphrase will be asked for before using it.
+ *
+ * Function is provided only via nc_client.h header file and only when libnetconf2 is compiled with libssh support.
+ *
+ * @param[in] pub_key Path to the public key.
+ * @param[in] priv_key Path to the private key.
+ *
+ * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
+ */
+int nc_client_ssh_add_keypair(const char *pub_key, const char *priv_key);
+
+/**
+ * @brief Remove an SSH public and private key pair that was used for client authentication.
+ *
+ * Function is provided only via nc_client.h header file and only when libnetconf2 is compiled with libssh support.
+ *
+ * @param[in] idx Index of the keypair starting with 0.
+ *
+ * @return 0 on success, -1 on error.
+ */
+int nc_client_ssh_del_keypair(int idx);
+
+/**
+ * @brief Get the number of public an private key pairs set to be used for client authentication.
+ *
+ * @return Keypair count.
+ */
+int nc_client_ssh_get_keypair_count(void);
+
+/**
+ * @brief Get a specific keypair set to be used for client authentication.
+ *
+ * @param[in] idx Index of the specific keypair.
+ * @param[out] pub_key Path to the public key.
+ * @param[out] priv_key Path to the private key.
+ *
+ * @return 0 on success, -1 on error.
+ */
+int nc_client_ssh_get_keypair(int idx, const char **pub_key, const char **priv_key);
+
+/**
+ * @brief Set SSH authentication method preference.
+ *
+ * Function is provided only via nc_client.h header file and only when libnetconf2 is compiled with libssh support.
+ *
+ * @param[in] auth_type Authentication method to modify the prefrence of.
+ * @param[in] pref Preference of \p auth_type. Negative values disable the method.
+ */
+void nc_client_ssh_set_auth_pref(NC_SSH_AUTH_TYPE auth_type, int16_t pref);
+
+/**
+ * @brief Get SSH authentication method preference.
+ *
+ * Function is provided only via nc_client.h header file and only when libnetconf2 is compiled with libssh support.
+ *
+ * @param[in] auth_type Authentication method to retrieve the prefrence of.
+ *
+ * @return Preference of the \p auth_type.
+ */
+int16_t nc_client_ssh_get_auth_pref(NC_SSH_AUTH_TYPE auth_type);
+
+/**
+ * @brief Set client SSH username used for authentication.
+ *
+ * @param[in] username Username to use.
+ * @return 0 on success, -1 on error.
+ */
+int nc_client_ssh_set_username(const char *username);
+
+/* Call Home */
+
+/**
+ * @brief Add a new client bind and start listening on it for SSH Call Home connections.
+ *
+ * @param[in] address IP address to bind to.
+ * @param[in] port Port to bind to.
+ * @return 0 on success, -1 on error.
+ */
+int nc_client_ssh_ch_add_bind_listen(const char *address, uint16_t port);
+
+/**
+ * @brief Remove an SSH listening client bind.
+ *
+ * @param[in] address IP address the socket was bound to. NULL matches all.
+ * @param[in] port Port the socket was bound to. 0 matches all.
+ * @return 0 on success, -1 on not found.
+ */
+int nc_client_ssh_ch_del_bind(const char *address, uint16_t port);
+
+/**
+ * @brief Add an SSH public and private key pair to be used for Call Home client authentication.
+ *
+ * Private key can be encrypted, the passphrase will be asked for before using it.
+ *
+ * Function is provided only via nc_client.h header file and only when libnetconf2 is compiled with libssh support.
+ *
+ * @param[in] pub_key Path to the public key.
+ * @param[in] priv_key Path to the private key.
+ *
+ * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
+ */
+int nc_client_ssh_ch_add_keypair(const char *pub_key, const char *priv_key);
+
+/**
+ * @brief Remove an SSH public and private key pair that was used for Call Home client authentication.
+ *
+ * Function is provided only via nc_client.h header file and only when libnetconf2 is compiled with libssh support.
+ *
+ * @param[in] idx Index of the keypair starting with 0.
+ *
+ * @return 0 on success, -1 on error.
+ */
+int nc_client_ssh_ch_del_keypair(int idx);
+
+/**
+ * @brief Get the number of public an private key pairs set to be used for Call Home client authentication.
+ *
+ * @return Keypair count.
+ */
+int nc_client_ssh_ch_get_keypair_count(void);
+
+/**
+ * @brief Get a specific keypair set to be used for Call Home client authentication.
+ *
+ * @param[in] idx Index of the specific keypair.
+ * @param[out] pub_key Path to the public key.
+ * @param[out] priv_key Path to the private key.
+ *
+ * @return 0 on success, -1 on error.
+ */
+int nc_client_ssh_ch_get_keypair(int idx, const char **pub_key, const char **priv_key);
+
+/**
+ * @brief Set SSH Call Home authentication method preference.
+ *
+ * Function is provided only via nc_client.h header file and only when libnetconf2 is compiled with libssh support.
+ *
+ * @param[in] auth_type Authentication method to modify the prefrence of.
+ * @param[in] pref Preference of \p auth_type. Negative values disable the method.
+ */
+void nc_client_ssh_ch_set_auth_pref(NC_SSH_AUTH_TYPE auth_type, int16_t pref);
+
+/**
+ * @brief Get SSH Call Home authentication method preference.
+ *
+ * Function is provided only via nc_client.h header file and only when libnetconf2 is compiled with libssh support.
+ *
+ * @param[in] auth_type Authentication method to retrieve the prefrence of.
+ *
+ * @return Preference of the \p auth_type.
+ */
+int16_t nc_client_ssh_ch_get_auth_pref(NC_SSH_AUTH_TYPE auth_type);
+
+/**
+ * @brief Set client Call Home SSH username used for authentication.
+ *
+ * @param[in] username Username to use.
+ * @return 0 on success, -1 on error.
+ */
+int nc_client_ssh_ch_set_username(const char *username);
+
+/**
+ * @brief Destroy any dynamically allocated SSH-specific client context (including Call Home).
*
* Function is provided only via nc_client.h header file and only when libnetconf2 is compiled with libssh support.
*/
-void nc_ssh_client_destroy(void);
+void nc_client_ssh_destroy(void);
/**
* @brief Connect to the NETCONF server using SSH transport (via libssh).
@@ -96,8 +267,6 @@
* @param[in] host Hostname or address (both Ipv4 and IPv6 are accepted) of the target server.
* 'localhost' is used by default if NULL is specified.
* @param[in] port Port number of the target server. Default value 830 is used if 0 is specified.
- * @param[in] username Name of the user to login to the server. The user running the application (detected from the
- * effective UID) is used if NULL is specified.
* @param[in] ctx Optional parameter. If set, provides strict YANG context for the session
* (ignoring what is actually supported by the server side). If not set,
* YANG context is created for the session using \<get-schema\> (if supported
@@ -107,7 +276,7 @@
* the session context will not include all the models supported by the server.
* @return Created NETCONF session object or NULL on error.
*/
-struct nc_session *nc_connect_ssh(const char *host, uint16_t port, const char* username, struct ly_ctx *ctx);
+struct nc_session *nc_connect_ssh(const char *host, uint16_t port, struct ly_ctx *ctx);
/**
* @brief Connect to the NETCONF server using the provided SSH (libssh) session.
@@ -150,124 +319,102 @@
*/
struct nc_session *nc_connect_ssh_channel(struct nc_session *session, struct ly_ctx *ctx);
-/**
- * @brief Accept a Call Home SSH connection from a NETCONF server.
- *
- * Function is provided only via nc_client.h header file and only when libnetconf2 is compiled with libssh support.
- *
- * @param[in] host Host the NETCONF client will listen on.
- * @param[in] port Port the NETCONF client will listen on.
- * @param[in] username Name of the user to login to the server. The user running the application (detected from the
- * effective UID) is used if NULL is specified.
- * @param[in] timeout Timeout for reading in milliseconds. Use negative value for infinite
- * waiting and 0 for immediate return if data are not available on wire.
- * @param[in] ctx Optional parameter. If set, provides strict YANG context for the session
- * (ignoring what is actually supported by the server side). If not set,
- * YANG context is created for the session using \<get-schema\> (if supported
- * by the server side) or/and by searching for YANG schemas in the searchpath
- * (see nc_schema_searchpath()). In every case except not providing context
- * to connect to a server supporting \<get-schema\> it is possible that
- * the session context will not include all the models supported by the server.
- * @return Created NETCONF session object or NULL on error.
- */
-struct nc_session *nc_callhome_accept_ssh(const char *host, uint16_t port, const char *username, int timeout, struct ly_ctx *ctx);
-
-/**
- * @brief Add an SSH public and private key pair to be used for client authentication.
- *
- * Private key can be encrypted, the passphrase will be asked for before using it.
- *
- * Function is provided only via nc_client.h header file and only when libnetconf2 is compiled with libssh support.
- *
- * @param[in] pub_key Path to the public key.
- * @param[in] priv_key Path to the private key.
- *
- * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
- */
-int nc_ssh_client_add_keypair(const char *pub_key, const char *priv_key);
-
-/**
- * @brief Remove an SSH public and private key pair that was used for client authentication.
- *
- * Function is provided only via nc_client.h header file and only when libnetconf2 is compiled with libssh support.
- *
- * @param[in] idx Index of the keypair starting with 0.
- *
- * @return 0 on success, -1 on error.
- */
-int nc_ssh_client_del_keypair(int idx);
-
-/**
- * @brief Get the number of public an private key pairs set to be used for client authentication.
- *
- * @return Keypair count.
- */
-int nc_ssh_client_get_keypair_count(void);
-
-/**
- * @brief Get a specific keypair set to be used for client authentication.
- *
- * @param[in] idx Index of the specific keypair.
- * @param[out] pub_key Path to the public key.
- * @param[out] priv_key Path to the private key.
- *
- * @return 0 on success, -1 on error.
- */
-int nc_ssh_client_get_keypair(int idx, const char **pub_key, const char **priv_key);
-
-/**
- * @brief Set SSH authentication method preference.
- *
- * Function is provided only via nc_client.h header file and only when libnetconf2 is compiled with libssh support.
- *
- * @param[in] auth_type Authentication method to modify the prefrence of.
- * @param[in] pref Preference of \p auth_type. Negative values disable the method.
- */
-void nc_ssh_client_set_auth_pref(NC_SSH_AUTH_TYPE auth_type, short int pref);
-
-/**
- * @brief Get SSH authentication method preference.
- *
- * Function is provided only via nc_client.h header file and only when libnetconf2 is compiled with libssh support.
- *
- * @param[in] auth_type Authentication method to retrieve the prefrence of.
- *
- * @return Preference of the \p auth_type.
- */
-short int nc_ssh_client_get_auth_pref(NC_SSH_AUTH_TYPE auth_type);
-
#endif /* ENABLE_SSH */
#ifdef ENABLE_TLS
/**
- * @brief Initialize libssl context with certificates.
- *
- * Must be called before calling nc_connect_tls() or nc_connect_libssl()!
+ * @brief Set client authentication identity - a certificate and a private key.
*
* Function is provided only via nc_client.h header file and only when libnetconf2 is compiled with TLS support.
*
* @param[in] client_cert Path to the file containing the client certificate. If NULL, only initializes libssl/libcrypto.
* @param[in] client_key Path to the file containing the private key for the \p client_cert.
* If NULL, key is expected to be stored with \p client_cert.
+ *
+ * @return 0 on success, -1 on error.
+ */
+int nc_client_tls_set_cert_key(const char *client_cert, const char *client_key);
+
+/**
+ * @brief Set client trusted CA certificates.
+ *
* @param[in] ca_file Location of the CA certificate file used to verify server certificates.
* For more info, see the documentation for SSL_CTX_load_verify_locations() from OpenSSL.
* @param[in] ca_dir Location of the CA certificates directory used to verify the server certificates.
* For more info, see the documentation for SSL_CTX_load_verify_locations() from OpenSSL.
+ * @return 0 on success, -1 on error.
+ */
+int nc_client_tls_set_trusted_ca_certs(const char *ca_file, const char *ca_dir);
+
+/**
+ * @brief Set client Certificate Revocation Lists.
+ *
* @param[in] crl_file Location of the CRL certificate file used to check for revocated certificates.
* @param[in] crl_dir Location of the CRL certificate directory used to check for revocated certificates.
+ * @return 0 on success, -1 on error.
+ */
+int nc_client_tls_set_crl(const char *crl_file, const char *crl_dir);
+
+/* Call Home */
+
+/**
+ * @brief Add a new client bind and start listening on it for TLS Call Home connections.
+ *
+ * @param[in] address IP address to bind to.
+ * @param[in] port Port to bind to.
+ * @return 0 on success, -1 on error.
+ */
+int nc_client_tls_ch_add_bind_listen(const char *address, uint16_t port);
+
+/**
+ * @brief Remove a TLS listening client bind.
+ *
+ * @param[in] address IP address the socket was bound to. NULL matches all.
+ * @param[in] port Port the socket was bound to. 0 matches all.
+ * @return 0 on success, -1 on not found.
+ */
+int nc_client_tls_ch_del_bind(const char *address, uint16_t port);
+
+/**
+ * @brief Set client Call Home authentication identity - a certificate and a private key.
+ *
+ * Function is provided only via nc_client.h header file and only when libnetconf2 is compiled with TLS support.
+ *
+ * @param[in] client_cert Path to the file containing the client certificate. If NULL, only initializes libssl/libcrypto.
+ * @param[in] client_key Path to the file containing the private key for the \p client_cert.
+ * If NULL, key is expected to be stored with \p client_cert.
*
* @return 0 on success, -1 on error.
*/
-int nc_tls_client_init(const char *client_cert, const char *client_key, const char *ca_file, const char *ca_dir,
- const char *crl_file, const char *crl_dir);
+int nc_client_tls_ch_set_cert_key(const char *client_cert, const char *client_key);
/**
- * @brief Destroy any dynamically allocated TLS-specific client data.
+ * @brief Set client Call Home trusted CA certificates.
+ *
+ * @param[in] ca_file Location of the CA certificate file used to verify server certificates.
+ * For more info, see the documentation for SSL_CTX_load_verify_locations() from OpenSSL.
+ * @param[in] ca_dir Location of the CA certificates directory used to verify the server certificates.
+ * For more info, see the documentation for SSL_CTX_load_verify_locations() from OpenSSL.
+ * @return 0 on success, -1 on error.
+ */
+int nc_client_tls_ch_set_trusted_ca_certs(const char *ca_file, const char *ca_dir);
+
+/**
+ * @brief Set client Call Home Certificate Revocation Lists.
+ *
+ * @param[in] crl_file Location of the CRL certificate file used to check for revocated certificates.
+ * @param[in] crl_dir Location of the CRL certificate directory used to check for revocated certificates.
+ * @return 0 on success, -1 on error.
+ */
+int nc_client_tls_ch_set_crl(const char *crl_file, const char *crl_dir);
+
+/**
+ * @brief Destroy any dynamically allocated TLS-specific client data (including Call Home).
*
* Function is provided only via nc_client.h header file and only when libnetconf2 is compiled with TLS support.
*/
-void nc_tls_client_destroy(void);
+void nc_client_tls_destroy(void);
/**
* @brief Connect to the NETCONF server using TLS transport (via libssl)
@@ -310,26 +457,6 @@
*/
struct nc_session *nc_connect_libssl(SSL *tls, struct ly_ctx *ctx);
-/**
- * @brief Accept a Call Home TLS connection from a NETCONF server.
- *
- * Function is provided only via nc_client.h header file and only when libnetconf2 is compiled with TLS support.
- *
- * @param[in] host Host the NETCONF client will listen on.
- * @param[in] port Port the NETCONF client will listen on.
- * @param[in] timeout Timeout for reading in milliseconds. Use negative value for infinite
- * waiting and 0 for immediate return if data are not available on wire.
- * @param[in] ctx Optional parameter. If set, provides strict YANG context for the session
- * (ignoring what is actually supported by the server side). If not set,
- * YANG context is created for the session using \<get-schema\> (if supported
- * by the server side) or/and by searching for YANG schemas in the searchpath
- * (see nc_schema_searchpath()). In every case except not providing context
- * to connect to a server supporting \<get-schema\> it is possible that
- * the session context will not include all the models supported by the server.
- * @return Created NETCONF session object or NULL on error.
- */
-struct nc_session *nc_callhome_accept_tls(const char *host, uint16_t port, int timeout, struct ly_ctx *ctx);
-
#endif /* ENABLE_TLS */
/**
diff --git a/src/session_client_ssh.c b/src/session_client_ssh.c
index cfa0f55..4e4a36f 100644
--- a/src/session_client_ssh.c
+++ b/src/session_client_ssh.c
@@ -48,12 +48,16 @@
#include "libnetconf.h"
-static struct nc_ssh_client_opts ssh_opts = {
+static struct nc_client_ssh_opts ssh_opts = {
.auth_pref = {{NC_SSH_AUTH_INTERACTIVE, 3}, {NC_SSH_AUTH_PASSWORD, 2}, {NC_SSH_AUTH_PUBLICKEY, 1}}
};
+static struct nc_client_ssh_opts ssh_ch_opts = {
+ .auth_pref = {{NC_SSH_AUTH_INTERACTIVE, 1}, {NC_SSH_AUTH_PASSWORD, 2}, {NC_SSH_AUTH_PUBLICKEY, 3}}
+};
+
API void
-nc_ssh_client_destroy(void)
+nc_client_ssh_destroy(void)
{
int i;
@@ -544,8 +548,8 @@
return -1;
}
-API int
-nc_ssh_client_add_keypair(const char *pub_key, const char *priv_key)
+static int
+_nc_client_ssh_add_keypair(const char *pub_key, const char *priv_key, struct nc_client_ssh_opts *opts)
{
int i;
FILE *key;
@@ -556,15 +560,15 @@
return -1;
}
- for (i = 0; i < ssh_opts.key_count; ++i) {
- if (!strcmp(ssh_opts.keys[i].pubkey_path, pub_key) || !strcmp(ssh_opts.keys[i].privkey_path, priv_key)) {
- if (strcmp(ssh_opts.keys[i].pubkey_path, pub_key)) {
+ for (i = 0; i < opts->key_count; ++i) {
+ if (!strcmp(opts->keys[i].pubkey_path, pub_key) || !strcmp(opts->keys[i].privkey_path, priv_key)) {
+ if (strcmp(opts->keys[i].pubkey_path, pub_key)) {
WRN("Private key \"%s\" found with another public key \"%s\".",
- priv_key, ssh_opts.keys[i].pubkey_path);
+ priv_key, opts->keys[i].pubkey_path);
continue;
- } else if (strcmp(ssh_opts.keys[i].privkey_path, priv_key)) {
+ } else if (strcmp(opts->keys[i].privkey_path, priv_key)) {
WRN("Public key \"%s\" found with another private key \"%s\".",
- pub_key, ssh_opts.keys[i].privkey_path);
+ pub_key, opts->keys[i].privkey_path);
continue;
}
@@ -573,12 +577,12 @@
}
}
- /* add the keys safely */
- ++ssh_opts.key_count;
- ssh_opts.keys = realloc(ssh_opts.keys, ssh_opts.key_count * sizeof *ssh_opts.keys);
- ssh_opts.keys[ssh_opts.key_count - 1].pubkey_path = strdup(pub_key);
- ssh_opts.keys[ssh_opts.key_count - 1].privkey_path = strdup(priv_key);
- ssh_opts.keys[ssh_opts.key_count - 1].privkey_crypt = 0;
+ /* add the keys */
+ ++opts->key_count;
+ opts->keys = realloc(opts->keys, opts->key_count * sizeof *opts->keys);
+ opts->keys[opts->key_count - 1].pubkey_path = strdup(pub_key);
+ opts->keys[opts->key_count - 1].privkey_path = strdup(priv_key);
+ opts->keys[opts->key_count - 1].privkey_crypt = 0;
/* check encryption */
if ((key = fopen(priv_key, "r"))) {
@@ -596,7 +600,7 @@
}
fclose(key);
if (strcasestr(line, "encrypted")) {
- ssh_opts.keys[ssh_opts.key_count - 1].privkey_crypt = 1;
+ opts->keys[opts->key_count - 1].privkey_crypt = 1;
}
}
@@ -604,80 +608,195 @@
}
API int
-nc_ssh_client_del_keypair(int idx)
+nc_client_ssh_add_keypair(const char *pub_key, const char *priv_key)
{
- if (idx >= ssh_opts.key_count) {
+ return _nc_client_ssh_add_keypair(pub_key, priv_key, &ssh_opts);
+}
+
+API int
+nc_client_ssh_ch_add_keypair(const char *pub_key, const char *priv_key)
+{
+ return _nc_client_ssh_add_keypair(pub_key, priv_key, &ssh_ch_opts);
+}
+
+static int
+_nc_client_ssh_del_keypair(int idx, struct nc_client_ssh_opts *opts)
+{
+ if (idx >= opts->key_count) {
ERRARG;
return -1;
}
- free(ssh_opts.keys[idx].pubkey_path);
- free(ssh_opts.keys[idx].privkey_path);
+ free(opts->keys[idx].pubkey_path);
+ free(opts->keys[idx].privkey_path);
- --ssh_opts.key_count;
+ --opts->key_count;
- memcpy(ssh_opts.keys + idx, ssh_opts.keys + ssh_opts.key_count, sizeof *ssh_opts.keys);
- ssh_opts.keys = realloc(ssh_opts.keys, ssh_opts.key_count * sizeof *ssh_opts.keys);
+ memcpy(opts->keys + idx, opts->keys + opts->key_count, sizeof *opts->keys);
+ opts->keys = realloc(opts->keys, opts->key_count * sizeof *opts->keys);
return 0;
}
API int
-nc_ssh_client_get_keypair_count(void)
+nc_client_ssh_del_keypair(int idx)
{
- return ssh_opts.key_count;
+ return _nc_client_ssh_del_keypair(idx, &ssh_opts);
}
API int
-nc_ssh_client_get_keypair(int idx, const char **pub_key, const char **priv_key)
+nc_client_ssh_ch_del_keypair(int idx)
{
- if ((idx >= ssh_opts.key_count) || (!pub_key && !priv_key)) {
+ return _nc_client_ssh_del_keypair(idx, &ssh_ch_opts);
+}
+
+static int
+_nc_client_ssh_get_keypair_count(struct nc_client_ssh_opts *opts)
+{
+ return opts->key_count;
+}
+
+API int
+nc_client_ssh_get_keypair_count(void)
+{
+ return _nc_client_ssh_get_keypair_count(&ssh_opts);
+}
+
+API int
+nc_client_ssh_ch_get_keypair_count(void)
+{
+ return _nc_client_ssh_get_keypair_count(&ssh_ch_opts);
+}
+
+static int
+_nc_client_ssh_get_keypair(int idx, const char **pub_key, const char **priv_key, struct nc_client_ssh_opts *opts)
+{
+ if ((idx >= opts->key_count) || (!pub_key && !priv_key)) {
ERRARG;
return -1;
}
if (pub_key) {
- *pub_key = ssh_opts.keys[idx].pubkey_path;
+ *pub_key = opts->keys[idx].pubkey_path;
}
if (priv_key) {
- *priv_key = ssh_opts.keys[idx].privkey_path;
+ *priv_key = opts->keys[idx].privkey_path;
}
return 0;
}
-API void
-nc_ssh_client_set_auth_pref(NC_SSH_AUTH_TYPE auth_type, short int pref)
+API int
+nc_client_ssh_get_keypair(int idx, const char **pub_key, const char **priv_key)
+{
+ return _nc_client_ssh_get_keypair(idx, pub_key, priv_key, &ssh_opts);
+}
+
+API int
+nc_client_ssh_ch_get_keypair(int idx, const char **pub_key, const char **priv_key)
+{
+ return _nc_client_ssh_get_keypair(idx, pub_key, priv_key, &ssh_ch_opts);
+}
+
+static void
+_nc_client_ssh_set_auth_pref(NC_SSH_AUTH_TYPE auth_type, int16_t pref, struct nc_client_ssh_opts *opts)
{
if (pref < 0) {
pref = -1;
}
if (auth_type == NC_SSH_AUTH_INTERACTIVE) {
- ssh_opts.auth_pref[0].value = pref;
+ opts->auth_pref[0].value = pref;
} else if (auth_type == NC_SSH_AUTH_PASSWORD) {
- ssh_opts.auth_pref[1].value = pref;
+ opts->auth_pref[1].value = pref;
} else if (auth_type == NC_SSH_AUTH_PUBLICKEY) {
- ssh_opts.auth_pref[2].value = pref;
+ opts->auth_pref[2].value = pref;
}
}
-API short int
-nc_ssh_client_get_auth_pref(NC_SSH_AUTH_TYPE auth_type)
+API void
+nc_client_ssh_set_auth_pref(NC_SSH_AUTH_TYPE auth_type, int16_t pref)
{
- short int pref = 0;
+ _nc_client_ssh_set_auth_pref(auth_type, pref, &ssh_opts);
+}
+
+API void
+nc_client_ssh_ch_set_auth_pref(NC_SSH_AUTH_TYPE auth_type, int16_t pref)
+{
+ _nc_client_ssh_set_auth_pref(auth_type, pref, &ssh_ch_opts);
+}
+
+static int16_t
+_nc_client_ssh_get_auth_pref(NC_SSH_AUTH_TYPE auth_type, struct nc_client_ssh_opts *opts)
+{
+ int16_t pref = 0;
if (auth_type == NC_SSH_AUTH_INTERACTIVE) {
- pref = ssh_opts.auth_pref[0].value;
+ pref = opts->auth_pref[0].value;
} else if (auth_type == NC_SSH_AUTH_PASSWORD) {
- pref = ssh_opts.auth_pref[1].value;
+ pref = opts->auth_pref[1].value;
} else if (auth_type == NC_SSH_AUTH_PUBLICKEY) {
- pref = ssh_opts.auth_pref[2].value;
+ pref = opts->auth_pref[2].value;
}
return pref;
}
+API int16_t
+nc_client_ssh_get_auth_pref(NC_SSH_AUTH_TYPE auth_type)
+{
+ return _nc_client_ssh_get_auth_pref(auth_type, &ssh_opts);
+}
+
+API int16_t
+nc_client_ssh_ch_get_auth_pref(NC_SSH_AUTH_TYPE auth_type)
+{
+ return _nc_client_ssh_get_auth_pref(auth_type, &ssh_ch_opts);
+}
+
+static int
+_nc_client_ssh_set_username(const char *username, struct nc_client_ssh_opts *opts)
+{
+ if (opts->username) {
+ free(opts->username);
+ }
+ if (username) {
+ opts->username = strdup(username);
+ if (!opts->username) {
+ ERRMEM;
+ return -1;
+ }
+ } else {
+ opts->username = NULL;
+ }
+
+ return 0;
+}
+
+API int
+nc_client_ssh_set_username(const char *username)
+{
+ return _nc_client_ssh_set_username(username, &ssh_opts);
+}
+
+API int
+nc_client_ssh_ch_set_username(const char *username)
+{
+ return _nc_client_ssh_set_username(username, &ssh_ch_opts);
+}
+
+API int
+nc_client_ssh_ch_add_bind_listen(const char *address, uint16_t port)
+{
+ return nc_client_ch_add_bind_listen(address, port, NC_TI_LIBSSH);
+}
+
+API int
+nc_client_ssh_ch_del_bind(const char *address, uint16_t port)
+{
+ return nc_client_ch_del_bind(address, port, NC_TI_LIBSSH);
+}
+
/* Establish a secure SSH connection, authenticate, and create a channel with the 'netconf' subsystem.
* Host, port, username, and a connected socket is expected to be set.
*/
@@ -879,10 +998,11 @@
}
API struct nc_session *
-nc_connect_ssh(const char *host, uint16_t port, const char *username, struct ly_ctx *ctx)
+nc_connect_ssh(const char *host, uint16_t port, struct ly_ctx *ctx)
{
const int timeout = NC_SSH_TIMEOUT;
int sock;
+ char *username;
struct passwd *pw;
struct nc_session *session = NULL;
@@ -895,7 +1015,7 @@
port = NC_PORT_SSH;
}
- if (!username) {
+ if (!ssh_opts.username) {
pw = getpwuid(getuid());
if (!pw) {
ERR("Unknown username for the SSH connection (%s).", strerror(errno));
@@ -903,6 +1023,8 @@
} else {
username = pw->pw_name;
}
+ } else {
+ username = ssh_opts.username;
}
/* prepare session structure */
@@ -1051,13 +1173,16 @@
/* remember username */
if (!username) {
- pw = getpwuid(getuid());
- if (!pw) {
- ERR("Unknown username for the SSH connection (%s).", strerror(errno));
- goto fail;
+ if (!ssh_opts.username) {
+ pw = getpwuid(getuid());
+ if (!pw) {
+ ERR("Unknown username for the SSH connection (%s).", strerror(errno));
+ goto fail;
+ }
+ username = strdup(pw->pw_name);
+ } else {
+ username = strdup(ssh_opts.username);
}
-
- username = strdup(pw->pw_name);
ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_USER, username);
}
@@ -1190,30 +1315,13 @@
return NULL;
}
-API struct nc_session *
-nc_callhome_accept_ssh(const char *host, uint16_t port, const char *username, int timeout, struct ly_ctx *ctx)
+struct nc_session *
+nc_accept_callhome_sock_ssh(int sock, const char *host, uint16_t port, struct ly_ctx *ctx)
{
const int ssh_timeout = NC_SSH_TIMEOUT;
- int sock, listen_sock;
- char *server_host;
+ struct passwd *pw;
ssh_session sess;
- if (!port) {
- port = NC_PORT_CH_SSH;
- }
-
- listen_sock = nc_sock_listen(host, port);
- if (listen_sock < 0) {
- return NULL;
- }
-
- sock = nc_sock_accept(listen_sock, timeout, &server_host, NULL);
- close(listen_sock);
-
- if (sock == -1) {
- return NULL;
- }
-
sess = ssh_new();
if (!sess) {
ERR("Unable to initialize an SSH session.");
@@ -1222,11 +1330,18 @@
}
ssh_options_set(sess, SSH_OPTIONS_FD, &sock);
- ssh_options_set(sess, SSH_OPTIONS_HOST, server_host);
+ ssh_options_set(sess, SSH_OPTIONS_HOST, host);
ssh_options_set(sess, SSH_OPTIONS_PORT, &port);
ssh_options_set(sess, SSH_OPTIONS_TIMEOUT, &ssh_timeout);
- if (username) {
- ssh_options_set(sess, SSH_OPTIONS_USER, username);
+ if (!ssh_ch_opts.username) {
+ pw = getpwuid(getuid());
+ if (!pw) {
+ ERR("Unknown username for the SSH connection (%s).", strerror(errno));
+ return NULL;
+ }
+ ssh_options_set(sess, SSH_OPTIONS_USER, pw->pw_name);
+ } else {
+ ssh_options_set(sess, SSH_OPTIONS_USER, ssh_ch_opts.username);
}
if (ssh_options_set(sess, SSH_OPTIONS_HOSTKEYS,
"ssh-ed25519,ecdsa-sha2-nistp521,ecdsa-sha2-nistp384,"
@@ -1235,7 +1350,5 @@
ssh_options_set(sess, SSH_OPTIONS_HOSTKEYS, "ssh-ed25519,ssh-rsa,ssh-dss,ssh-rsa1");
}
- free(server_host);
-
return nc_connect_libssh(sess, ctx);
}
diff --git a/src/session_client_tls.c b/src/session_client_tls.c
index cb1bc9b..f999c21 100644
--- a/src/session_client_tls.c
+++ b/src/session_client_tls.c
@@ -33,7 +33,10 @@
#include "libnetconf.h"
-static struct nc_tls_client_opts tls_opts;
+static struct nc_client_tls_opts tls_opts;
+static struct nc_client_tls_opts tls_ch_opts;
+
+static int tlsauth_ch;
static int
tlsauth_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
@@ -47,11 +50,19 @@
EVP_PKEY *pubkey;
int i, n, rc;
ASN1_TIME *next_update = NULL;
+ struct nc_client_tls_opts *opts;
if (!preverify_ok) {
return 0;
}
+ opts = (tlsauth_ch ? &tls_ch_opts : &tls_opts);
+
+ if (!opts->crl_store) {
+ /* nothing to check */
+ return 1;
+ }
+
cert = X509_STORE_CTX_get_current_cert(x509_ctx);
subject = X509_get_subject_name(cert);
issuer = X509_get_issuer_name(cert);
@@ -59,7 +70,7 @@
/* try to retrieve a CRL corresponding to the _subject_ of
* the current certificate in order to verify it's integrity */
memset((char *)&obj, 0, sizeof obj);
- X509_STORE_CTX_init(&store_ctx, tls_opts.tls_store, NULL, NULL);
+ X509_STORE_CTX_init(&store_ctx, opts->crl_store, NULL, NULL);
rc = X509_STORE_get_by_subject(&store_ctx, X509_LU_CRL, subject, &obj);
X509_STORE_CTX_cleanup(&store_ctx);
crl = obj.data.crl;
@@ -97,7 +108,7 @@
/* try to retrieve a CRL corresponding to the _issuer_ of
* the current certificate in order to check for revocation */
memset((char *)&obj, 0, sizeof obj);
- X509_STORE_CTX_init(&store_ctx, tls_opts.tls_store, NULL, NULL);
+ X509_STORE_CTX_init(&store_ctx, opts->crl_store, NULL, NULL);
rc = X509_STORE_get_by_subject(&store_ctx, X509_LU_CRL, issuer, &obj);
X509_STORE_CTX_cleanup(&store_ctx);
crl = obj.data.crl;
@@ -119,94 +130,280 @@
return 1; /* success */
}
-API int
-nc_tls_client_init(const char *client_cert, const char *client_key, const char *ca_file, const char *ca_dir,
- const char *crl_file, const char *crl_dir)
+static int
+_nc_client_tls_set_cert_key(const char *client_cert, const char *client_key, int ch)
{
- const char *key_ = client_key;
- X509_LOOKUP *lookup;
-
- if (tls_opts.tls_ctx) {
- VRB("TLS context reinitialization.");
- SSL_CTX_free(tls_opts.tls_ctx);
- tls_opts.tls_ctx = NULL;
- }
+ struct nc_client_tls_opts *opts;
if (!client_cert) {
ERRARG;
return -1;
}
- /* prepare global SSL context, allow only mandatory TLS 1.2 */
- if (!(tls_opts.tls_ctx = SSL_CTX_new(TLSv1_2_client_method()))) {
- ERR("Unable to create OpenSSL context (%s).", ERR_reason_error_string(ERR_get_error()));
- return -1;
- }
+ opts = (ch ? &tls_ch_opts : &tls_opts);
- if (crl_file || crl_dir) {
- /* set the revocation store with the correct paths for the callback */
- tls_opts.tls_store = X509_STORE_new();
- tls_opts.tls_store->cache = 0;
+ free(opts->cert_path);
+ free(opts->key_path);
- if (crl_file) {
- if (!(lookup = X509_STORE_add_lookup(tls_opts.tls_store, X509_LOOKUP_file()))) {
- ERR("Failed to add lookup method to CRL checking.");
- return -1;
- }
- if (X509_LOOKUP_add_dir(lookup, crl_file, X509_FILETYPE_PEM) != 1) {
- ERR("Failed to add the revocation lookup file \"%s\".", crl_file);
- return -1;
- }
+ if (client_cert) {
+ opts->cert_path = strdup(client_cert);
+ if (!opts->cert_path) {
+ ERRMEM;
+ return -1;
}
-
- if (crl_dir) {
- if (!(lookup = X509_STORE_add_lookup(tls_opts.tls_store, X509_LOOKUP_hash_dir()))) {
- ERR("Failed to add lookup method to CRL checking.");
- return -1;
- }
- if (X509_LOOKUP_add_dir(lookup, crl_dir, X509_FILETYPE_PEM) != 1) {
- ERR("Failed to add the revocation lookup directory \"%s\".", crl_dir);
- return -1;
- }
- }
-
- SSL_CTX_set_verify(tls_opts.tls_ctx, SSL_VERIFY_PEER, tlsauth_verify_callback);
} else {
- /* CRL checking will be skipped */
- SSL_CTX_set_verify(tls_opts.tls_ctx, SSL_VERIFY_PEER, NULL);
+ opts->cert_path = NULL;
}
- /* get peer certificate */
- if (SSL_CTX_use_certificate_file(tls_opts.tls_ctx, client_cert, SSL_FILETYPE_PEM) != 1) {
- ERR("Loading a peer certificate from \'%s\' failed (%s).", client_cert, ERR_reason_error_string(ERR_get_error()));
- return -1;
+ if (client_key) {
+ opts->key_path = strdup(client_key);
+ if (!opts->cert_path) {
+ ERRMEM;
+ return -1;
+ }
+ } else {
+ opts->key_path = NULL;
}
- if (!key_) {
- /*
- * if the file with private key not specified, expect that the private
- * key is stored altogether with the certificate
- */
- key_ = client_cert;
- }
- if (SSL_CTX_use_PrivateKey_file(tls_opts.tls_ctx, key_, SSL_FILETYPE_PEM) != 1) {
- ERR("Loading the client certificate from \'%s\' failed (%s).", key_, ERR_reason_error_string(ERR_get_error()));
- return -1;
- }
-
- if (!SSL_CTX_load_verify_locations(tls_opts.tls_ctx, ca_file, ca_dir)) {
- ERR("Failed to load the locations of trusted CA certificates (%s).", ERR_reason_error_string(ERR_get_error()));
- return -1;
- }
+ opts->tls_ctx_change = 1;
return 0;
}
-API void
-nc_tls_client_destroy(void)
+API int
+nc_client_tls_set_cert_key(const char *client_cert, const char *client_key)
{
- SSL_CTX_free(tls_opts.tls_ctx);
- tls_opts.tls_ctx = NULL;
+ return _nc_client_tls_set_cert_key(client_cert, client_key, 0);
+}
+
+API int
+nc_client_tls_ch_set_cert_key(const char *client_cert, const char *client_key)
+{
+ return _nc_client_tls_set_cert_key(client_cert, client_key, 1);
+}
+
+static int
+_nc_client_tls_set_trusted_ca_certs(const char *ca_file, const char *ca_dir, int ch)
+{
+ struct nc_client_tls_opts *opts;
+
+ if (!ca_file && !ca_dir) {
+ ERRARG;
+ return -1;
+ }
+
+ opts = (ch ? &tls_ch_opts : &tls_opts);
+
+ free(opts->ca_file);
+ free(opts->ca_dir);
+
+ if (ca_file) {
+ opts->ca_file = strdup(ca_file);
+ if (!opts->ca_file) {
+ ERRMEM;
+ return -1;
+ }
+ } else {
+ opts->ca_file = NULL;
+ }
+
+ if (ca_dir) {
+ opts->ca_dir = strdup(ca_dir);
+ if (!opts->ca_dir) {
+ ERRMEM;
+ return -1;
+ }
+ } else {
+ opts->ca_dir = NULL;
+ }
+
+ opts->tls_ctx_change = 1;
+
+ return 0;
+}
+
+API int
+nc_client_tls_set_trusted_ca_certs(const char *ca_file, const char *ca_dir)
+{
+ return _nc_client_tls_set_trusted_ca_certs(ca_file, ca_dir, 0);
+}
+
+API int
+nc_client_tls_ch_set_trusted_ca_certs(const char *ca_file, const char *ca_dir)
+{
+ return _nc_client_tls_set_trusted_ca_certs(ca_file, ca_dir, 1);
+}
+
+static int
+_nc_client_tls_set_crl(const char *crl_file, const char *crl_dir, int ch)
+{
+ struct nc_client_tls_opts *opts;
+
+ if (!crl_file && !crl_dir) {
+ ERRARG;
+ return -1;
+ }
+
+ opts = (ch ? &tls_ch_opts : &tls_opts);
+
+ free(opts->crl_file);
+ free(opts->crl_dir);
+
+ if (crl_file) {
+ opts->crl_file = strdup(crl_file);
+ if (!opts->crl_file) {
+ ERRMEM;
+ return -1;
+ }
+ } else {
+ opts->crl_file = NULL;
+ }
+
+ if (crl_dir) {
+ opts->crl_dir = strdup(crl_dir);
+ if (!opts->crl_dir) {
+ ERRMEM;
+ return -1;
+ }
+ } else {
+ opts->crl_dir = NULL;
+ }
+
+ opts->crl_store_change = 1;
+
+ return 0;
+}
+
+API int
+nc_client_tls_set_crl(const char *crl_file, const char *crl_dir)
+{
+ return _nc_client_tls_set_crl(crl_file, crl_dir, 0);
+}
+
+API int
+nc_client_tls_ch_set_crl(const char *crl_file, const char *crl_dir)
+{
+ return _nc_client_tls_set_crl(crl_file, crl_dir, 1);
+}
+
+API int
+nc_client_tls_ch_add_bind_listen(const char *address, uint16_t port)
+{
+ return nc_client_ch_add_bind_listen(address, port, NC_TI_OPENSSL);
+}
+
+API int
+nc_client_tls_ch_del_bind(const char *address, uint16_t port)
+{
+ return nc_client_ch_del_bind(address, port, NC_TI_OPENSSL);
+}
+
+API void
+nc_client_tls_destroy(void)
+{
+ int count = 0;
+ struct nc_client_tls_opts *opts;
+
+repeat:
+ if (count == 0) {
+ opts = &tls_ch_opts;
+ } else if (count == 1) {
+ opts = &tls_opts;
+ } else {
+ return;
+ }
+
+ free(opts->cert_path);
+ free(opts->key_path);
+ free(opts->ca_file);
+ free(opts->ca_dir);
+ SSL_CTX_free(opts->tls_ctx);
+
+ free(opts->crl_file);
+ free(opts->crl_dir);
+ X509_STORE_free(opts->crl_store);
+
+ ++count;
+ goto repeat;
+}
+
+static int
+nc_client_tls_opts_update(int ch)
+{
+ char *key;
+ X509_LOOKUP *lookup;
+ struct nc_client_tls_opts *opts;
+
+ opts = (ch ? &tls_ch_opts : &tls_opts);
+
+ if (!opts->tls_ctx || opts->tls_ctx_change) {
+ SSL_CTX_free(tls_opts.tls_ctx);
+
+ /* prepare global SSL context, allow only mandatory TLS 1.2 */
+ if (!(opts->tls_ctx = SSL_CTX_new(TLSv1_2_client_method()))) {
+ ERR("Unable to create OpenSSL context (%s).", ERR_reason_error_string(ERR_get_error()));
+ return -1;
+ }
+ SSL_CTX_set_verify(opts->tls_ctx, SSL_VERIFY_PEER, tlsauth_verify_callback);
+
+ /* get peer certificate */
+ if (SSL_CTX_use_certificate_file(opts->tls_ctx, opts->cert_path, SSL_FILETYPE_PEM) != 1) {
+ ERR("Loading the client certificate from \'%s\' failed (%s).", opts->cert_path, ERR_reason_error_string(ERR_get_error()));
+ return -1;
+ }
+
+ /* if the file with private key not specified, expect that the private key is stored with the certificate */
+ if (!opts->key_path) {
+ key = opts->cert_path;
+ } else {
+ key = opts->key_path;
+ }
+ if (SSL_CTX_use_PrivateKey_file(opts->tls_ctx, key, SSL_FILETYPE_PEM) != 1) {
+ ERR("Loading the client priavte key from \'%s\' failed (%s).", key, ERR_reason_error_string(ERR_get_error()));
+ return -1;
+ }
+
+ if (!SSL_CTX_load_verify_locations(opts->tls_ctx, opts->ca_file, opts->ca_dir)) {
+ ERR("Failed to load the locations of trusted CA certificates (%s).", ERR_reason_error_string(ERR_get_error()));
+ return -1;
+ }
+ }
+
+ if (opts->crl_store_change || (!opts->crl_store && (opts->crl_file || opts->crl_dir))) {
+ /* set the revocation store with the correct paths for the callback */
+ X509_STORE_free(opts->crl_store);
+
+ opts->crl_store = X509_STORE_new();
+ if (!opts->crl_store) {
+ ERR("Unable to create a certificate store (%s).", ERR_reason_error_string(ERR_get_error()));
+ return -1;
+ }
+ opts->crl_store->cache = 0;
+
+ if (opts->crl_file) {
+ if (!(lookup = X509_STORE_add_lookup(opts->crl_store, X509_LOOKUP_file()))) {
+ ERR("Failed to add lookup method to CRL checking.");
+ return -1;
+ }
+ if (X509_LOOKUP_add_dir(lookup, opts->crl_file, X509_FILETYPE_PEM) != 1) {
+ ERR("Failed to add the revocation lookup file \"%s\".", opts->crl_file);
+ return -1;
+ }
+ }
+
+ if (opts->crl_dir) {
+ if (!(lookup = X509_STORE_add_lookup(opts->crl_store, X509_LOOKUP_hash_dir()))) {
+ ERR("Failed to add lookup method to CRL checking.");
+ return -1;
+ }
+ if (X509_LOOKUP_add_dir(lookup, opts->crl_dir, X509_FILETYPE_PEM) != 1) {
+ ERR("Failed to add the revocation lookup directory \"%s\".", opts->crl_dir);
+ return -1;
+ }
+ }
+ }
+
+ return 0;
}
API struct nc_session *
@@ -215,8 +412,7 @@
struct nc_session *session = NULL;
int sock, verify;
- /* was init called? */
- if (!tls_opts.tls_ctx) {
+ if (!tls_opts.cert_path || (!tls_opts.ca_file && !tls_opts.ca_dir)) {
ERRARG;
return NULL;
}
@@ -230,6 +426,11 @@
port = NC_PORT_TLS;
}
+ /* create/update TLS structures */
+ if (nc_client_tls_opts_update(0)) {
+ return NULL;
+ }
+
/* prepare session structure */
session = calloc(1, sizeof *session);
if (!session) {
@@ -265,6 +466,7 @@
SSL_set_mode(session->ti.tls, SSL_MODE_AUTO_RETRY);
/* connect and perform the handshake */
+ tlsauth_ch = 0;
if (SSL_connect(session->ti.tls) != 1) {
ERR("Connecting over TLS failed (%s).", ERR_reason_error_string(ERR_get_error()));
goto fail;
@@ -366,31 +568,19 @@
return NULL;
}
-API struct nc_session *
-nc_callhome_accept_tls(const char *host, uint16_t port, int timeout, struct ly_ctx *ctx)
+struct nc_session *
+nc_accept_callhome_sock_tls(int sock, const char *host, uint16_t port, struct ly_ctx *ctx)
{
- int listen_sock, sock, verify;
- char *server_host;
+ int verify;
SSL *tls;
struct nc_session *session;
- if (!port) {
- port = NC_PORT_CH_TLS;
- }
-
- listen_sock = nc_sock_listen(host, port);
- if (listen_sock < 0) {
+ if (nc_client_tls_opts_update(1)) {
+ close(sock);
return NULL;
}
- sock = nc_sock_accept(listen_sock, timeout, &server_host, NULL);
- close(listen_sock);
-
- if (sock < 0) {
- return NULL;
- }
-
- if (!(tls = SSL_new(tls_opts.tls_ctx))) {
+ if (!(tls = SSL_new(tls_ch_opts.tls_ctx))) {
ERR("Failed to create new TLS session structure (%s).", ERR_reason_error_string(ERR_get_error()));
close(sock);
return NULL;
@@ -402,6 +592,7 @@
SSL_set_mode(tls, SSL_MODE_AUTO_RETRY);
/* connect and perform the handshake */
+ tlsauth_ch = 1;
if (SSL_connect(tls) != 1) {
ERR("Connecting over TLS failed (%s).", ERR_reason_error_string(ERR_get_error()));
SSL_free(tls);
@@ -421,7 +612,7 @@
session = nc_connect_libssl(tls, ctx);
if (session) {
/* store information into session and the dictionary */
- session->host = lydict_insert_zc(session->ctx, server_host);
+ session->host = lydict_insert(session->ctx, host, 0);
session->port = port;
session->username = lydict_insert(session->ctx, "certificate-based", 0);
}
diff --git a/src/session_p.h b/src/session_p.h
index 93e2844..1e89216 100644
--- a/src/session_p.h
+++ b/src/session_p.h
@@ -44,32 +44,32 @@
/* number of all supported authentication methods */
# define NC_SSH_AUTH_COUNT 3
-struct nc_ssh_client_opts {
+struct nc_client_ssh_opts {
/* SSH authentication method preferences */
struct {
NC_SSH_AUTH_TYPE type;
- short int value;
+ int16_t value;
} auth_pref[NC_SSH_AUTH_COUNT];
/* SSH key pairs */
struct {
char *pubkey_path;
char *privkey_path;
- int privkey_crypt;
+ int8_t privkey_crypt;
} *keys;
- int key_count;
+ uint16_t key_count;
+
+ char *username;
};
-struct nc_ssh_server_opts {
+struct nc_server_ssh_opts {
ssh_bind sshbind;
- pthread_mutex_t sshbind_lock;
struct {
const char *path;
const char *username;
} *authkeys;
uint16_t authkey_count;
- pthread_mutex_t authkey_lock;
int auth_methods;
uint16_t auth_attempts;
@@ -83,17 +83,23 @@
# include <openssl/bio.h>
# include <openssl/ssl.h>
-struct nc_tls_client_opts {
+struct nc_client_tls_opts {
+ char *cert_path;
+ char *key_path;
+ char *ca_file;
+ char *ca_dir;
+ int8_t tls_ctx_change;
SSL_CTX *tls_ctx;
- X509_STORE *tls_store;
+
+ char *crl_file;
+ char *crl_dir;
+ int8_t crl_store_change;
+ X509_STORE *crl_store;
};
-struct nc_tls_server_opts {
+struct nc_server_tls_opts {
SSL_CTX *tls_ctx;
- pthread_mutex_t tls_ctx_lock;
-
X509_STORE *crl_store;
- pthread_mutex_t crl_lock;
struct nc_ctn {
uint32_t id;
@@ -102,11 +108,22 @@
const char *name;
struct nc_ctn *next;
} *ctn;
- pthread_mutex_t ctn_lock;
};
#endif /* ENABLE_TLS */
+struct nc_client_opts {
+ char *schema_searchpath;
+
+ struct nc_bind {
+ const char *address;
+ uint16_t port;
+ int sock;
+ NC_TRANSPORT_IMPL ti;
+ } *ch_binds;
+ uint16_t ch_bind_count;
+};
+
struct nc_server_opts {
struct ly_ctx *ctx;
pthread_mutex_t ctx_lock;
@@ -118,14 +135,15 @@
uint16_t hello_timeout;
uint16_t idle_timeout;
- struct nc_bind {
- const char *address;
- uint16_t port;
- int sock;
- NC_TRANSPORT_IMPL ti;
- } *binds;
- uint16_t bind_count;
- pthread_mutex_t bind_lock;
+ struct nc_bind *binds;
+ struct nc_endpt {
+ const char *name;
+ void *ti_opts;
+ pthread_mutex_t endpt_lock;
+ } *endpts;
+ uint16_t endpt_count;
+ /* WRITE - working with binds/endpoints, READ - modifying a specific bind/endpoint, holding that endpt_lock too */
+ pthread_rwlock_t endpt_array_lock;
uint32_t new_session_id;
pthread_spinlock_t sid_lock;
@@ -220,6 +238,7 @@
struct nc_msg_cont *notifs; /**< queue for notifications received instead of RPC reply */
/* server side only data */
+ void *ti_opts;
time_t last_rpc; /**< time the last RPC was received on this session */
#ifdef ENABLE_SSH
/* SSH session authenticated */
@@ -303,15 +322,58 @@
* @param[in] binds Structure with the listening sockets.
* @param[in] bind_count Number of \p binds.
* @param[in] timeout Timeout for accepting.
- * @param[out] ti Type of transport of the accepted connection. Can be NULL.
* @param[out] host Host of the remote peer. Can be NULL.
* @param[out] port Port of the new connection. Can be NULL.
+ * @param[out] idx Index of the bind that was accepted. Can be NULL.
* @return Accepted socket of the new connection, -1 on error.
*/
-int nc_sock_accept_binds(struct nc_bind *binds, uint16_t bind_count, int timeout, NC_TRANSPORT_IMPL *ti, char **host, uint16_t *port);
+int nc_sock_accept_binds(struct nc_bind *binds, uint16_t bind_count, int timeout, char **host, uint16_t *port, uint16_t *idx);
+
+/**
+ * @brief Add a new endpoint and start listening on it.
+ *
+ * @param[in] name Unique arbitrary name.
+ * @param[in] address IP address to bind to.
+ * @param[in] port Port to bind to.
+ * @param[in] ti Expected transport protocol of incoming connections.
+ * @return 0 on success, -1 on error.
+ */
+int nc_server_add_endpt_listen(const char *name, const char *address, uint16_t port, NC_TRANSPORT_IMPL ti);
+
+/**
+ * @brief Stop listening on and remove an endpoint.
+ *
+ * @param[in] address Name of the endpoint. NULL matches all the names.
+ * @param[in] ti Expected transport. 0 matches all.
+ * @return 0 on success, -1 on not finding any match.
+ */
+int nc_server_del_endpt(const char *name, NC_TRANSPORT_IMPL ti);
+
+/**
+ * @brief Find an endpoint.
+ *
+ * Caller must hold endpt_array_lock for reading.
+ *
+ * @param[in] name Endpoint name.
+ * @param[in] ti Endpoind transport.
+ * @return Endpoint, NULL on error.
+ */
+struct nc_endpt *nc_server_get_endpt(const char *name, NC_TRANSPORT_IMPL ti);
+
+/* TODO */
+int nc_client_ch_add_bind_listen(const char *address, uint16_t port, NC_TRANSPORT_IMPL ti);
+
+/* TODO */
+int nc_client_ch_del_bind(const char *address, uint16_t port, NC_TRANSPORT_IMPL ti);
+
+/* TODO */
+int nc_connect_callhome(const char *host, uint16_t port, NC_TRANSPORT_IMPL ti, int timeout, struct nc_session **session);
#ifdef ENABLE_SSH
+/* TODO */
+struct nc_session *nc_accept_callhome_sock_ssh(int sock, const char *host, uint16_t port, struct ly_ctx *ctx);
+
/**
* @brief Establish SSH transport on a socket.
*
@@ -321,7 +383,7 @@
* @param[in] ch Whether to accept a Call Home session or a standard one.
* @return 1 on success, 0 on timeout, -1 on error.
*/
-int nc_accept_ssh_session(struct nc_session *session, int sock, int timeout, int ch);
+int nc_accept_ssh_session(struct nc_session *session, int sock, int timeout);
/**
* @brief Callback called when a new SSH message is received.
@@ -349,10 +411,16 @@
*/
int nc_ssh_pollin(struct nc_session *session, int *timeout);
-#endif
+/* TODO */
+void nc_server_ssh_opts_clear(struct nc_server_ssh_opts *opts);
+
+#endif /* ENABLE_SSH */
#ifdef ENABLE_TLS
+/* TODO */
+struct nc_session *nc_accept_callhome_sock_tls(int sock, const char *host, uint16_t port, struct ly_ctx *ctx);
+
/**
* @brief Establish TLS transport on a socket.
*
@@ -362,9 +430,12 @@
* @param[in] ch Whether to accept a Call Home session or a standard one.
* @return 1 on success, 0 on timeout, -1 on error.
*/
-int nc_accept_tls_session(struct nc_session *session, int sock, int timeout, int ch);
+int nc_accept_tls_session(struct nc_session *session, int sock, int timeout);
-#endif
+/* TODO */
+void nc_server_tls_opts_clear(struct nc_server_tls_opts *opts);
+
+#endif /* ENABLE_TLS */
/**
* Functions
diff --git a/src/session_server.c b/src/session_server.c
index 74097e9..d1d643f 100644
--- a/src/session_server.c
+++ b/src/session_server.c
@@ -37,9 +37,24 @@
#include "session_server.h"
struct nc_server_opts server_opts = {
- .ctx_lock = PTHREAD_MUTEX_INITIALIZER,
- .bind_lock = PTHREAD_MUTEX_INITIALIZER
+ .endpt_array_lock = PTHREAD_RWLOCK_INITIALIZER
};
+extern struct nc_server_ssh_opts ssh_ch_opts;
+extern struct nc_server_tls_opts tls_ch_opts;
+
+struct nc_endpt *
+nc_server_get_endpt(const char *name, NC_TRANSPORT_IMPL ti)
+{
+ uint16_t i;
+
+ for (i = 0; i < server_opts.endpt_count; ++i) {
+ if ((server_opts.binds[i].ti == ti) && !strcmp(server_opts.endpts[i].name, name)) {
+ return &server_opts.endpts[i];
+ }
+ }
+
+ return NULL;
+}
API void
nc_session_set_term_reason(struct nc_session *session, NC_SESSION_TERM_REASON reason)
@@ -131,7 +146,7 @@
}
int
-nc_sock_accept_binds(struct nc_bind *binds, uint16_t bind_count, int timeout, NC_TRANSPORT_IMPL *ti, char **host, uint16_t *port)
+nc_sock_accept_binds(struct nc_bind *binds, uint16_t bind_count, int timeout, char **host, uint16_t *port, uint16_t *idx)
{
uint16_t i;
struct pollfd *pfd;
@@ -178,8 +193,8 @@
return -1;
}
- if (ti) {
- *ti = binds[i].ti;
+ if (idx) {
+ *idx = i;
}
/* host was requested */
@@ -330,7 +345,7 @@
pthread_spin_destroy(&server_opts.sid_lock);
#if defined(ENABLE_SSH) || defined(ENABLE_TLS)
- nc_server_del_bind(NULL, 0, 0);
+ nc_server_del_endpt(NULL, 0);
#endif
}
@@ -776,81 +791,160 @@
#if defined(ENABLE_SSH) || defined(ENABLE_TLS)
-API int
-nc_server_add_bind_listen(const char *address, uint16_t port, NC_TRANSPORT_IMPL ti)
+int
+nc_server_add_endpt_listen(const char *name, const char *address, uint16_t port, NC_TRANSPORT_IMPL ti)
{
int sock;
+ uint16_t i;
- if (!address || !port || ((ti != NC_TI_LIBSSH) && (ti != NC_TI_OPENSSL))) {
+ if (!name || !address || !port) {
ERRARG;
return -1;
}
+ /* READ LOCK */
+ pthread_rwlock_rdlock(&server_opts.endpt_array_lock);
+
+ /* check name uniqueness */
+ for (i = 0; i < server_opts.endpt_count; ++i) {
+ if (!strcmp(server_opts.endpts[i].name, name)) {
+ ERR("Endpoint \"%s\" already exists.", name);
+ return -1;
+ }
+ }
+
+ /* READ UNLOCK */
+ pthread_rwlock_unlock(&server_opts.endpt_array_lock);
+
sock = nc_sock_listen(address, port);
if (sock == -1) {
return -1;
}
- /* LOCK */
- pthread_mutex_lock(&server_opts.bind_lock);
+ /* WRITE LOCK */
+ pthread_rwlock_wrlock(&server_opts.endpt_array_lock);
- ++server_opts.bind_count;
- server_opts.binds = realloc(server_opts.binds, server_opts.bind_count * sizeof *server_opts.binds);
+ ++server_opts.endpt_count;
+ server_opts.binds = realloc(server_opts.binds, server_opts.endpt_count * sizeof *server_opts.binds);
+ server_opts.endpts = realloc(server_opts.endpts, server_opts.endpt_count * sizeof *server_opts.endpts);
nc_ctx_lock(-1, NULL);
- server_opts.binds[server_opts.bind_count - 1].address = lydict_insert(server_opts.ctx, address, 0);
+ server_opts.endpts[server_opts.endpt_count - 1].name = lydict_insert(server_opts.ctx, name, 0);
+ server_opts.binds[server_opts.endpt_count - 1].address = lydict_insert(server_opts.ctx, address, 0);
nc_ctx_unlock();
- server_opts.binds[server_opts.bind_count - 1].port = port;
- server_opts.binds[server_opts.bind_count - 1].sock = sock;
- server_opts.binds[server_opts.bind_count - 1].ti = ti;
+ server_opts.binds[server_opts.endpt_count - 1].port = port;
+ server_opts.binds[server_opts.endpt_count - 1].sock = sock;
+ server_opts.binds[server_opts.endpt_count - 1].ti = ti;
+ switch (ti) {
+#ifdef ENABLE_SSH
+ case NC_TI_LIBSSH:
+ server_opts.endpts[server_opts.endpt_count - 1].ti_opts = calloc(1, sizeof(struct nc_server_ssh_opts));
+ break;
+#endif
+#ifdef ENABLE_TLS
+ case NC_TI_OPENSSL:
+ server_opts.endpts[server_opts.endpt_count - 1].ti_opts = calloc(1, sizeof(struct nc_server_tls_opts));
+ break;
+#endif
+ default:
+ ERRINT;
+ server_opts.endpts[server_opts.endpt_count - 1].ti_opts = NULL;
+ break;
+ }
+ pthread_mutex_init(&server_opts.endpts[server_opts.endpt_count - 1].endpt_lock, NULL);
- /* UNLOCK */
- pthread_mutex_unlock(&server_opts.bind_lock);
+ /* WRITE UNLOCK */
+ pthread_rwlock_unlock(&server_opts.endpt_array_lock);
return 0;
}
-API int
-nc_server_del_bind(const char *address, uint16_t port, NC_TRANSPORT_IMPL ti)
+int
+nc_server_del_endpt(const char *name, NC_TRANSPORT_IMPL ti)
{
uint32_t i;
int ret = -1;
- /* LOCK */
- pthread_mutex_lock(&server_opts.bind_lock);
+ /* WRITE LOCK */
+ pthread_rwlock_wrlock(&server_opts.endpt_array_lock);
- if (!address && !port && !ti) {
+ if (!name && !ti) {
+ /* remove all */
nc_ctx_lock(-1, NULL);
- for (i = 0; i < server_opts.bind_count; ++i) {
- close(server_opts.binds[i].sock);
+ for (i = 0; i < server_opts.endpt_count; ++i) {
+ lydict_remove(server_opts.ctx, server_opts.endpts[i].name);
lydict_remove(server_opts.ctx, server_opts.binds[i].address);
+ close(server_opts.binds[i].sock);
+ pthread_mutex_destroy(&server_opts.endpts[i].endpt_lock);
+ switch (server_opts.binds[i].ti) {
+#ifdef ENABLE_SSH
+ case NC_TI_LIBSSH:
+ nc_server_ssh_opts_clear(server_opts.endpts[i].ti_opts);
+ break;
+#endif
+#ifdef ENABLE_TLS
+ case NC_TI_OPENSSL:
+ nc_server_tls_opts_clear(server_opts.endpts[i].ti_opts);
+ break;
+#endif
+ default:
+ ERRINT;
+ break;
+ }
+ free(server_opts.endpts[i].ti_opts);
ret = 0;
}
nc_ctx_unlock();
- free(server_opts.binds);
- server_opts.binds = NULL;
- server_opts.bind_count = 0;
+ free(server_opts.endpts);
+ server_opts.endpts = NULL;
+ server_opts.endpt_count = 0;
+
} else {
- for (i = 0; i < server_opts.bind_count; ++i) {
- if ((!address || !strcmp(server_opts.binds[i].address, address))
- && (!port || (server_opts.binds[i].port == port))
- && (!ti || (server_opts.binds[i].ti == ti))) {
- close(server_opts.binds[i].sock);
+ /* remove one name endpoint or all ti endpoints */
+ for (i = 0; i < server_opts.endpt_count; ++i) {
+ if ((server_opts.binds[i].ti == ti) &&
+ (!name || !strcmp(server_opts.endpts[i].name, name))) {
+
nc_ctx_lock(-1, NULL);
+ lydict_remove(server_opts.ctx, server_opts.endpts[i].name);
lydict_remove(server_opts.ctx, server_opts.binds[i].address);
nc_ctx_unlock();
+ close(server_opts.binds[i].sock);
+ pthread_mutex_destroy(&server_opts.endpts[i].endpt_lock);
+ switch (server_opts.binds[i].ti) {
+#ifdef ENABLE_SSH
+ case NC_TI_LIBSSH:
+ nc_server_ssh_opts_clear(server_opts.endpts[i].ti_opts);
+ break;
+#endif
+#ifdef ENABLE_TLS
+ case NC_TI_OPENSSL:
+ nc_server_tls_opts_clear(server_opts.endpts[i].ti_opts);
+ break;
+#endif
+ default:
+ ERRINT;
+ break;
+ }
+ free(server_opts.endpts[i].ti_opts);
- --server_opts.bind_count;
- memcpy(&server_opts.binds[i], &server_opts.binds[server_opts.bind_count], sizeof *server_opts.binds);
+ --server_opts.endpt_count;
+ memcpy(&server_opts.binds[i], &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds);
+ memcpy(&server_opts.endpts[i], &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts);
ret = 0;
+
+ if (name) {
+ /* one name endpoint removed, they are unique, we're done */
+ break;
+ }
}
}
}
- /* UNLOCK */
- pthread_mutex_unlock(&server_opts.bind_lock);
+ /* WRITE UNLOCK */
+ pthread_rwlock_unlock(&server_opts.endpt_array_lock);
return ret;
}
@@ -858,25 +952,23 @@
API int
nc_accept(int timeout, struct nc_session **session)
{
- NC_TRANSPORT_IMPL ti;
int sock, ret;
char *host = NULL;
- uint16_t port;
+ uint16_t port, idx;
- if (!server_opts.ctx || !server_opts.binds || !session) {
+ if (!server_opts.ctx || !server_opts.endpt_count || !session) {
ERRARG;
return -1;
}
- /* LOCK */
- pthread_mutex_lock(&server_opts.bind_lock);
+ /* WRITE LOCK */
+ pthread_rwlock_wrlock(&server_opts.endpt_array_lock);
- ret = nc_sock_accept_binds(server_opts.binds, server_opts.bind_count, timeout, &ti, &host, &port);
-
- /* UNLOCK */
- pthread_mutex_unlock(&server_opts.bind_lock);
+ ret = nc_sock_accept_binds(server_opts.binds, server_opts.endpt_count, timeout, &host, &port, &idx);
if (ret < 0) {
+ /* WRITE UNLOCK */
+ pthread_rwlock_unlock(&server_opts.endpt_array_lock);
return ret;
}
sock = ret;
@@ -886,7 +978,8 @@
ERRMEM;
close(sock);
free(host);
- return -1;
+ ret = -1;
+ goto fail;
}
(*session)->status = NC_STATUS_STARTING;
(*session)->side = NC_SERVER;
@@ -907,14 +1000,16 @@
}
pthread_mutex_init((*session)->ti_lock, NULL);
+ (*session)->ti_opts = server_opts.endpts[idx].ti_opts;
+
/* sock gets assigned to session or closed */
- if (ti == NC_TI_LIBSSH) {
- ret = nc_accept_ssh_session(*session, sock, timeout, 0);
+ if (server_opts.binds[idx].ti == NC_TI_LIBSSH) {
+ ret = nc_accept_ssh_session(*session, sock, timeout);
if (ret < 1) {
goto fail;
}
- } else if (ti == NC_TI_OPENSSL) {
- ret = nc_accept_tls_session(*session, sock, timeout, 0);
+ } else if (server_opts.binds[idx].ti == NC_TI_OPENSSL) {
+ ret = nc_accept_tls_session(*session, sock, timeout);
if (ret < 1) {
goto fail;
}
@@ -925,6 +1020,9 @@
goto fail;
}
+ /* WRITE UNLOCK */
+ pthread_rwlock_unlock(&server_opts.endpt_array_lock);
+
/* assign new SID atomically */
/* LOCK */
pthread_spin_lock(&server_opts.sid_lock);
@@ -934,20 +1032,24 @@
/* NETCONF handshake */
if (nc_handshake(*session)) {
- ret = -1;
- goto fail;
+ nc_session_free(*session);
+ *session = NULL;
+ return -1;
}
(*session)->status = NC_STATUS_RUNNING;
return 1;
fail:
+ /* WRITE UNLOCK */
+ pthread_rwlock_unlock(&server_opts.endpt_array_lock);
+
nc_session_free(*session);
*session = NULL;
return ret;
}
-API int
+int
nc_connect_callhome(const char *host, uint16_t port, NC_TRANSPORT_IMPL ti, int timeout, struct nc_session **session)
{
int sock, ret;
@@ -989,12 +1091,14 @@
/* sock gets assigned to session or closed */
if (ti == NC_TI_LIBSSH) {
- ret = nc_accept_ssh_session(*session, sock, timeout, 1);
+ (*session)->ti_opts = &ssh_ch_opts;
+ ret = nc_accept_ssh_session(*session, sock, timeout);
if (ret < 1) {
goto fail;
}
} else if (ti == NC_TI_OPENSSL) {
- ret = nc_accept_tls_session(*session, sock, timeout, 1);
+ (*session)->ti_opts = &tls_ch_opts;
+ ret = nc_accept_tls_session(*session, sock, timeout);
if (ret < 1) {
goto fail;
}
diff --git a/src/session_server.h b/src/session_server.h
index ec38347..14009c2 100644
--- a/src/session_server.h
+++ b/src/session_server.h
@@ -215,27 +215,7 @@
#if defined(ENABLE_SSH) || defined(ENABLE_TLS)
/**
- * @brief Add a new server bind and start listening on it.
- *
- * @param[in] address IP address to bind to.
- * @param[in] port Port to bind to.
- * @param[in] ti Expected transport protocol of incoming connections.
- * @return 0 on success, -1 on error.
- */
-int nc_server_add_bind_listen(const char *address, uint16_t port, NC_TRANSPORT_IMPL ti);
-
-/**
- * @brief Stop listening on and remove a server bind.
- *
- * @param[in] address IP address the bind was bound to. NULL matches all the addresses.
- * @param[in] port Port the bind was bound to. NULL matches all the ports.
- * @param[in] ti Expected transport. 0 matches all.
- * @return 0 on success, -1 on not finding any match.
- */
-int nc_server_del_bind(const char *address, uint16_t port, NC_TRANSPORT_IMPL ti);
-
-/**
- * @brief Accept new sessions on all the listening binds.
+ * @brief Accept new sessions on all the listening endpoints.
*
* @param[in] timeout Timeout for receiving a new connection in milliseconds, 0 for
* non-blocking call, -1 for infinite waiting.
@@ -244,19 +224,6 @@
*/
int nc_accept(int timeout, struct nc_session **session);
-/**
- * @brief Establish a Call Home connection with a listening NETCONF client.
- *
- * @param[in] host Host the client is listening on.
- * @param[in] port Port the client is listening on.
- * @param[in] ti Transport protocol to use.
- * @param[in] timeout Timeout for transport-related operations, 0 for non-blocking
- * call, -1 for infinite waiting.
- * @param[out] session New Call Home session.
- * @return 1 on success, 0 on timeout, -1 on error.
- */
-int nc_connect_callhome(const char *host, uint16_t port, NC_TRANSPORT_IMPL ti, int timeout, struct nc_session **session);
-
#endif /* ENABLE_SSH || ENABLE_TLS */
#ifdef ENABLE_SSH
@@ -272,78 +239,114 @@
int nc_ps_accept_ssh_channel(struct nc_pollsession *ps, struct nc_session **session);
/**
- * @brief Set SSH host keys the server will identify itself with. Each of RSA, DSA, and
+ * @brief Add a new SSH endpoint and start listening on it.
+ *
+ * @param[in] name Arbitrary unique endpoint name. There can be a TLS endpoint with
+ * the same name.
+ * @param[in] address IP address to listen on.
+ * @param[in] port Port to listen on.
+ * @return 0 on success, -1 on error.
+ */
+int nc_server_ssh_add_endpt_listen(const char *name, const char *address, uint16_t port);
+
+/**
+ * @brief Stop listening on and remove an SSH endpoint.
+ *
+ * @param[in] name Endpoint name. NULL matches all (SSH) endpoints.
+ * @return 0 on success, -1 on not finding any match.
+ */
+int nc_server_ssh_del_endpt(const char *name);
+
+/**
+ * @brief Set endpoint SSH host keys the server will identify itself with. Each of RSA, DSA, and
* ECDSA keys can be set. If the particular type was already set, it is replaced.
*
* @param[in] privkey_path Path to a private key.
* @return 0 on success, -1 on error.
*/
-int nc_ssh_server_set_hostkey(const char *privkey_path);
+int nc_server_ssh_endpt_set_hostkey(const char *endpt_name, const char *privkey_path);
/**
- * @brief Set SSH banner the server will send to every client.
+ * @brief Set endpoint SSH banner the server will send to every client.
*
* @param[in] banner SSH banner.
* @return 0 on success, -1 on error.
*/
-int nc_ssh_server_set_banner(const char *banner);
+int nc_server_ssh_endpt_set_banner(const char *endpt_name, const char *banner);
/**
- * @brief Set accepted SSH authentication methods. All (publickey, password, interactive)
+ * @brief Set endpoint accepted SSH authentication methods. All (publickey, password, interactive)
* are supported by default.
*
* @param[in] auth_methods Accepted authentication methods bit field of NC_SSH_AUTH_TYPE.
* @return 0 on success, -1 on error.
*/
-int nc_ssh_server_set_auth_methods(int auth_methods);
+int nc_server_ssh_endpt_set_auth_methods(const char *endpt_name, int auth_methods);
/**
- * @brief Set SSH authentication attempts of every client. 3 by default.
+ * @brief Set endpoint SSH authentication attempts of every client. 3 by default.
*
* @param[in] auth_attempts Failed authentication attempts before a client is dropped.
* @return 0 on success, -1 on error.
*/
-int nc_ssh_server_set_auth_attempts(uint16_t auth_attempts);
+int nc_server_ssh_endpt_set_auth_attempts(const char *endpt_name, uint16_t auth_attempts);
/**
- * @brief Set SSH authentication timeout. 10 seconds by default.
+ * @brief Set endpoint SSH authentication timeout. 10 seconds by default.
*
* @param[in] auth_timeout Number of seconds before an unauthenticated client is dropped.
* @return 0 on success, -1 on error.
*/
-int nc_ssh_server_set_auth_timeout(uint16_t auth_timeout);
+int nc_server_ssh_endpt_set_auth_timeout(const char *endpt_name, uint16_t auth_timeout);
/**
- * @brief Add an authorized client SSH public key. This public key can be used for
+ * @brief Add an endpoint authorized client SSH public key. This public key can be used for
* publickey authentication afterwards.
*
* @param[in] pubkey_path Path to the public key.
* @param[in] username Username that the client with the public key must use.
* @return 0 on success, -1 on error.
*/
-int nc_ssh_server_add_authkey(const char *pubkey_path, const char *username);
+int nc_server_ssh_endpt_add_authkey(const char *endpt_name, const char *pubkey_path, const char *username);
/**
- * @brief Remove an authorized client SSH public key.
+ * @brief Remove an endpoint authorized client SSH public key.
*
* @param[in] pubkey_path Path to an authorized public key. NULL matches all the keys.
* @param[in] username Username for an authorized public key. NULL matches all the usernames.
* @return 0 on success, -1 on not finding any match.
*/
-int nc_ssh_server_del_authkey(const char *pubkey_path, const char *username);
+int nc_server_ssh_endpt_del_authkey(const char *endpt_name, const char *pubkey_path, const char *username);
+
+/**
+ * @brief Free all the various SSH server options (excluding Call Home).
+ */
+void nc_server_ssh_opts_free(void);
/*
* Call Home
*/
/**
+ * @brief Establish an SSH Call Home connection with a listening NETCONF client.
+ *
+ * @param[in] host Host the client is listening on.
+ * @param[in] port Port the client is listening on.
+ * @param[in] timeout Timeout for transport-related operations, 0 for non-blocking
+ * call, -1 for infinite waiting.
+ * @param[out] session New Call Home session.
+ * @return 1 on success, 0 on timeout, -1 on error.
+ */
+int nc_connect_callhome_ssh(const char *host, uint16_t port, int timeout, struct nc_session **session);
+
+/**
* @brief Set Call Home SSH host keys the server will identify itself with. Each of RSA, DSA, and
* ECDSA keys can be set. If the particular type was already set, it is replaced.
*
* @param[in] privkey_path Path to a private key.
* @return 0 on success, -1 on error.
*/
-int nc_ssh_server_ch_set_hostkey(const char *privkey_path);
+int nc_server_ssh_ch_set_hostkey(const char *privkey_path);
/**
* @brief Set Call Home SSH banner the server will send to every client.
@@ -351,7 +354,7 @@
* @param[in] banner SSH banner.
* @return 0 on success, -1 on error.
*/
-int nc_ssh_server_ch_set_banner(const char *banner);
+int nc_server_ssh_ch_set_banner(const char *banner);
/**
* @brief Set accepted Call Home SSH authentication methods. All (publickey, password, interactive)
@@ -360,7 +363,7 @@
* @param[in] auth_methods Accepted authentication methods bit field of NC_SSH_AUTH_TYPE.
* @return 0 on success, -1 on error.
*/
-int nc_ssh_server_ch_set_auth_methods(int auth_methods);
+int nc_server_ssh_ch_set_auth_methods(int auth_methods);
/**
* @brief Set Call Home SSH authentication attempts of every client. 3 by default.
@@ -368,7 +371,7 @@
* @param[in] auth_attempts Failed authentication attempts before a client is dropped.
* @return 0 on success, -1 on error.
*/
-int nc_ssh_server_ch_set_auth_attempts(uint16_t auth_attempts);
+int nc_server_ssh_ch_set_auth_attempts(uint16_t auth_attempts);
/**
* @brief Set Call Home SSH authentication timeout. 10 seconds by default.
@@ -376,7 +379,7 @@
* @param[in] auth_timeout Number of seconds before an unauthenticated client is dropped.
* @return 0 on success, -1 on error.
*/
-int nc_ssh_server_ch_set_auth_timeout(uint16_t auth_timeout);
+int nc_server_ssh_ch_set_auth_timeout(uint16_t auth_timeout);
/**
* @brief Add an authorized Call Home client SSH public key. This public key can be used for
@@ -386,7 +389,7 @@
* @param[in] username Username that the client with the public key must use.
* @return 0 on success, -1 on error.
*/
-int nc_ssh_server_ch_add_authkey(const char *pubkey_path, const char *username);
+int nc_server_ssh_ch_add_authkey(const char *pubkey_path, const char *username);
/**
* @brief Remove an authorized Call Home client SSH public key.
@@ -395,25 +398,42 @@
* @param[in] username Username for an authorized public key. NULL matches all the usernames.
* @return 0 on success, -1 on not finding any match.
*/
-int nc_ssh_server_ch_del_authkey(const char *pubkey_path, const char *username);
+int nc_server_ssh_ch_del_authkey(const char *pubkey_path, const char *username);
-/**
- * @brief Free all the various SSH server options (including Call Home ones).
- */
-void nc_ssh_server_free_opts(void);
+/* TODO */
+void nc_server_ssh_ch_opts_clear(void);
#endif /* ENABLE_SSH */
#ifdef ENABLE_TLS
/**
+ * @brief Add a new TLS endpoint and start listening on it.
+ *
+ * @param[in] name Arbitrary unique endpoint name. There can be an SSH endpoint with
+ * the same name.
+ * @param[in] address IP address to listen on.
+ * @param[in] port Port to listen on.
+ * @return 0 on success, -1 on error.
+ */
+int nc_server_tls_add_endpt_listen(const char *name, const char *address, uint16_t port);
+
+/**
+ * @brief Stop listening on and remove a TLS endpoint.
+ *
+ * @param[in] name Endpoint name. NULL matches all (TLS) endpoints.
+ * @return 0 on success, -1 on not finding any match.
+ */
+int nc_server_tls_del_endpt(const char *name);
+
+/**
* @brief Set server TLS certificate. Alternative to nc_tls_server_set_cert_path().
* There can only be one certificate for each key type, it is replaced if already set.
*
* @param[in] cert Base64-encoded certificate in ASN.1 DER encoding.
* @return 0 on success, -1 on error.
*/
-int nc_tls_server_set_cert(const char *cert);
+int nc_server_tls_endpt_set_cert(const char *endpt_name, const char *cert);
/**
* @brief Set server TLS certificate. Alternative to nc_tls_server_set_cert().
@@ -422,7 +442,7 @@
* @param[in] cert_path Path to a certificate file in PEM format.
* @return 0 on success, -1 on error.
*/
-int nc_tls_server_set_cert_path(const char *cert_path);
+int nc_server_tls_endpt_set_cert_path(const char *endpt_name, const char *cert_path);
/**
* @brief Set server TLS private key matching the certificate.
@@ -433,7 +453,7 @@
* @param[in] is_rsa Whether \p privkey are the data of an RSA (1) or DSA (0) key.
* @return 0 on success, -1 on error.
*/
-int nc_tls_server_set_key(const char *privkey, int is_rsa);
+int nc_server_tls_endpt_set_key(const char *endpt_name, const char *privkey, int is_rsa);
/**
* @brief Set server TLS private key matching the certificate.
@@ -443,7 +463,7 @@
* @param[in] privkey_path Path to a private key file in PEM format.
* @return 0 on success, -1 on error.
*/
-int nc_tls_server_set_key_path(const char *privkey_path);
+int nc_server_tls_endpt_set_key_path(const char *endpt_name, const char *privkey_path);
/**
* @brief Add a trusted certificate. Can be both a CA or a client one.
@@ -451,7 +471,7 @@
* @param[in] cert Base64-enocded certificate in ASN.1DER encoding.
* @return 0 on success, -1 on error.
*/
-int nc_tls_server_add_trusted_cert(const char *cert);
+int nc_server_tls_endpt_add_trusted_cert(const char *endpt_name, const char *cert);
/**
* @brief Add a trusted certificate. Can be both a CA or a client one.
@@ -459,7 +479,7 @@
* @param[in] cert_path Path to a trusted certificate file in PEM format.
* @return 0 on success, -1 on error.
*/
-int nc_tls_server_add_trusted_cert_path(const char *cert_path);
+int nc_server_tls_endpt_add_trusted_cert_path(const char *endpt_name, const char *cert_path);
/**
* @brief Set trusted Certificate Authority certificate locations. There can only be
@@ -471,13 +491,13 @@
* (c_rehash utility can be used to create hashes) with PEM files. Can be NULL.
* @return 0 on success, -1 on error.
*/
-int nc_tls_server_set_trusted_cacert_locations(const char *cacert_file_path, const char *cacert_dir_path);
+int nc_server_tls_endpt_set_trusted_cacert_locations(const char *endpt_name, const char *cacert_file_path, const char *cacert_dir_path);
/**
* @brief Destroy and clean all the set certificates and private keys. CRLs and
* CTN entries are not affected.
*/
-void nc_tls_server_destroy_certs(void);
+void nc_server_tls_endpt_destroy_certs(const char *endpt_name);
/**
* @brief Set Certificate Revocation List locations. There can only be one file
@@ -488,13 +508,13 @@
* can be used to create hashes) with PEM files. Can be NULL.
* @return 0 on success, -1 on error.
*/
-int nc_tls_server_set_crl_locations(const char *crl_file_path, const char *crl_dir_path);
+int nc_server_tls_endpt_set_crl_locations(const char *endpt_name, const char *crl_file_path, const char *crl_dir_path);
/**
* @brief Destroy and clean CRLs. Certificates, priavte keys, and CTN entries are
* not affected.
*/
-void nc_tls_server_destroy_crls(void);
+void nc_server_tls_endpt_destroy_crls(const char *endpt_name);
/**
* @brief Add a Cert-to-name entry.
@@ -505,7 +525,7 @@
* @param[in] name Specific username if \p map_type == NC_TLS_CTN_SPECIFED. Must be NULL otherwise.
* @return 0 on success, -1 on error.
*/
-int nc_tls_server_add_ctn(uint32_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name);
+int nc_server_tls_endpt_add_ctn(const char *endpt_name, uint32_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name);
/**
* @brief Remove a Cert-to-name entry.
@@ -516,20 +536,32 @@
* @param[in] name Specific username for the entry. NULL matches all the usernames.
* @return 0 on success, -1 on not finding any match.
*/
-int nc_tls_server_del_ctn(int64_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name);
+int nc_server_tls_endpt_del_ctn(const char *endpt_name, int64_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name);
/*
* Call Home
*/
/**
+ * @brief Establish a TLS Call Home connection with a listening NETCONF client.
+ *
+ * @param[in] host Host the client is listening on.
+ * @param[in] port Port the client is listening on.
+ * @param[in] timeout Timeout for transport-related operations, 0 for non-blocking
+ * call, -1 for infinite waiting.
+ * @param[out] session New Call Home session.
+ * @return 1 on success, 0 on timeout, -1 on error.
+ */
+int nc_connect_callhome_tls(const char *host, uint16_t port, int timeout, struct nc_session **session);
+
+/**
* @brief Set server Call Home TLS certificate. Alternative to nc_tls_server_set_cert_path().
* There can only be one certificate for each key type, it is replaced if already set.
*
* @param[in] cert Base64-encoded certificate in ASN.1 DER encoding.
* @return 0 on success, -1 on error.
*/
-int nc_tls_server_ch_set_cert(const char *cert);
+int nc_server_tls_ch_set_cert(const char *cert);
/**
* @brief Set server Call Home TLS certificate. Alternative to nc_tls_server_set_cert().
@@ -538,7 +570,7 @@
* @param[in] cert_path Path to a certificate file in PEM format.
* @return 0 on success, -1 on error.
*/
-int nc_tls_server_ch_set_cert_path(const char *cert_path);
+int nc_server_tls_ch_set_cert_path(const char *cert_path);
/**
* @brief Set server Call Home TLS private key matching the certificate.
@@ -549,7 +581,7 @@
* @param[in] is_rsa Whether \p privkey are the data of an RSA (1) or DSA (0) key.
* @return 0 on success, -1 on error.
*/
-int nc_tls_server_ch_set_key(const char *privkey, int is_rsa);
+int nc_server_tls_ch_set_key(const char *privkey, int is_rsa);
/**
* @brief Set server Call Home TLS private key matching the certificate.
@@ -559,7 +591,7 @@
* @param[in] privkey_path Path to a private key file in PEM format.
* @return 0 on success, -1 on error.
*/
-int nc_tls_server_ch_set_key_path(const char *privkey_path);
+int nc_server_tls_ch_set_key_path(const char *privkey_path);
/**
* @brief Add a Call Home trusted certificate. Can be both a CA or a client one.
@@ -567,7 +599,7 @@
* @param[in] cert Base64-enocded certificate in ASN.1DER encoding.
* @return 0 on success, -1 on error.
*/
-int nc_tls_server_ch_add_trusted_cert(const char *cert);
+int nc_server_tls_ch_add_trusted_cert(const char *cert);
/**
* @brief Add a Call Home trusted certificate. Can be both a CA or a client one.
@@ -575,7 +607,7 @@
* @param[in] cert_path Path to a trusted certificate file in PEM format.
* @return 0 on success, -1 on error.
*/
-int nc_tls_server_ch_add_trusted_cert_path(const char *cert_path);
+int nc_server_tls_ch_add_trusted_cert_path(const char *cert_path);
/**
* @brief Set trusted Call Home Certificate Authority certificate locations. There
@@ -587,13 +619,13 @@
* (c_rehash utility can be used to create hashes) with PEM files. Can be NULL.
* @return 0 on success, -1 on error.
*/
-int nc_tls_server_ch_set_trusted_cacert_locations(const char *cacert_file_path, const char *cacert_dir_path);
+int nc_server_tls_ch_set_trusted_cacert_locations(const char *cacert_file_path, const char *cacert_dir_path);
/**
* @brief Destroy and clean all the set Call Home certificates and private keys.
* CRLs and CTN entries are not affected.
*/
-void nc_tls_server_ch_destroy_certs(void);
+void nc_server_tls_ch_destroy_certs(void);
/**
* @brief Set Call Home Certificate Revocation List locations. There can only be
@@ -604,13 +636,13 @@
* can be used to create hashes) with PEM files. Can be NULL.
* @return 0 on success, -1 on error.
*/
-int nc_tls_server_ch_set_crl_locations(const char *crl_file_path, const char *crl_dir_path);
+int nc_server_tls_ch_set_crl_locations(const char *crl_file_path, const char *crl_dir_path);
/**
* @brief Destroy and clean Call Home CRLs. Call Home certificates, private keys,
* and CTN entries are not affected.
*/
-void nc_tls_server_ch_destroy_crls(void);
+void nc_server_tls_ch_destroy_crls(void);
/**
* @brief Add a Call Home Cert-to-name entry.
@@ -621,7 +653,7 @@
* @param[in] name Specific username if \p map_type == NC_TLS_CTN_SPECIFED. Must be NULL otherwise.
* @return 0 on success, -1 on error.
*/
-int nc_tls_server_ch_add_ctn(uint32_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name);
+int nc_server_tls_ch_add_ctn(uint32_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name);
/**
* @brief Remove a Call Home Cert-to-name entry.
@@ -632,12 +664,10 @@
* @param[in] name Specific username for the entry. NULL matches all the usernames.
* @return 0 on success, -1 on not finding any match.
*/
-int nc_tls_server_ch_del_ctn(int64_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name);
+int nc_server_tls_ch_del_ctn(int64_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name);
-/**
- * @brief Free all the various TLS server options (including Call Home ones).
- */
-void nc_tls_server_free_opts(void);
+/* TODO */
+void nc_server_tls_ch_opts_clear(void);
#endif /* ENABLE_TLS */
diff --git a/src/session_server_ssh.c b/src/session_server_ssh.c
index 900adc4..31838e3 100644
--- a/src/session_server_ssh.c
+++ b/src/session_server_ssh.c
@@ -33,39 +33,33 @@
#include "libnetconf.h"
#include "session_server.h"
+struct nc_server_ssh_opts ssh_ch_opts = {
+ .auth_methods = NC_SSH_AUTH_PUBLICKEY | NC_SSH_AUTH_PASSWORD | NC_SSH_AUTH_INTERACTIVE,
+ .auth_attempts = 3,
+ .auth_timeout = 10
+};
extern struct nc_server_opts server_opts;
-struct nc_ssh_server_opts ssh_opts = {
- .sshbind_lock = PTHREAD_MUTEX_INITIALIZER,
- .authkey_lock = PTHREAD_MUTEX_INITIALIZER,
- .auth_methods = NC_SSH_AUTH_PUBLICKEY | NC_SSH_AUTH_PASSWORD | NC_SSH_AUTH_INTERACTIVE,
- .auth_attempts = 3,
- .auth_timeout = 10
-};
+API int
+nc_server_ssh_add_endpt_listen(const char *name, const char *address, uint16_t port)
+{
+ return nc_server_add_endpt_listen(name, address, port, NC_TI_LIBSSH);
+}
-struct nc_ssh_server_opts ssh_ch_opts = {
- .sshbind_lock = PTHREAD_MUTEX_INITIALIZER,
- .authkey_lock = PTHREAD_MUTEX_INITIALIZER,
- .auth_methods = NC_SSH_AUTH_PUBLICKEY | NC_SSH_AUTH_PASSWORD | NC_SSH_AUTH_INTERACTIVE,
- .auth_attempts = 3,
- .auth_timeout = 10
-};
+API int
+nc_server_ssh_del_endpt(const char *name)
+{
+ return nc_server_del_endpt(name, NC_TI_LIBSSH);
+}
static int
-_nc_ssh_server_set_hostkey(const char *privkey_path, int ch)
+nc_server_ssh_set_hostkey(const char *privkey_path, struct nc_server_ssh_opts *opts)
{
- struct nc_ssh_server_opts *opts;
-
if (!privkey_path) {
ERRARG;
return -1;
}
- opts = (ch ? &ssh_ch_opts : &ssh_opts);
-
- /* LOCK */
- pthread_mutex_lock(&opts->sshbind_lock);
-
if (!opts->sshbind) {
opts->sshbind = ssh_bind_new();
if (!opts->sshbind) {
@@ -83,43 +77,38 @@
goto fail;
}
- /* UNLOCK */
- pthread_mutex_unlock(&opts->sshbind_lock);
- return 0;
-
fail:
- /* UNLOCK */
- pthread_mutex_unlock(&opts->sshbind_lock);
return -1;
}
API int
-nc_ssh_server_set_hostkey(const char *privkey_path)
+nc_server_ssh_endpt_set_hostkey(const char *endpt_name, const char *privkey_path)
{
- return _nc_ssh_server_set_hostkey(privkey_path, 0);
+ struct nc_endpt *endpt;
+
+ endpt = nc_server_get_endpt(endpt_name, NC_TI_LIBSSH);
+ if (!endpt) {
+ ERR("Endpoint \"%s\" was not found.", endpt_name);
+ return -1;
+ }
+
+ return nc_server_ssh_set_hostkey(privkey_path, endpt->ti_opts);
}
API int
-nc_ssh_server_ch_set_hostkey(const char *privkey_path)
+nc_server_ssh_ch_set_hostkey(const char *privkey_path)
{
- return _nc_ssh_server_set_hostkey(privkey_path, 1);
+ return nc_server_ssh_set_hostkey(privkey_path, &ssh_ch_opts);
}
static int
-_nc_ssh_server_set_banner(const char *banner, int ch)
+nc_server_ssh_set_banner(const char *banner, struct nc_server_ssh_opts *opts)
{
- struct nc_ssh_server_opts *opts;
-
if (!banner) {
ERRARG;
return -1;
}
- opts = (ch ? &ssh_ch_opts : &ssh_opts);
-
- /* LOCK */
- pthread_mutex_lock(&opts->sshbind_lock);
-
if (!opts->sshbind) {
opts->sshbind = ssh_bind_new();
if (!opts->sshbind) {
@@ -130,128 +119,137 @@
ssh_bind_options_set(opts->sshbind, SSH_BIND_OPTIONS_BANNER, banner);
- /* UNLOCK */
- pthread_mutex_unlock(&opts->sshbind_lock);
return 0;
fail:
- /* UNLOCK */
- pthread_mutex_unlock(&opts->sshbind_lock);
return -1;
}
API int
-nc_ssh_server_set_banner(const char *banner)
+nc_server_ssh_endpt_set_banner(const char *endpt_name, const char *banner)
{
- return _nc_ssh_server_set_banner(banner, 0);
+ struct nc_endpt *endpt;
+
+ endpt = nc_server_get_endpt(endpt_name, NC_TI_LIBSSH);
+ if (!endpt) {
+ ERR("Endpoint \"%s\" was not found.", endpt_name);
+ return -1;
+ }
+
+ return nc_server_ssh_set_banner(banner, endpt->ti_opts);
}
API int
-nc_ssh_server_ch_set_banner(const char *banner)
+nc_server_ssh_ch_set_banner(const char *banner)
{
- return _nc_ssh_server_set_banner(banner, 1);
+ return nc_server_ssh_set_banner(banner, &ssh_ch_opts);
}
static int
-_nc_ssh_server_set_auth_methods(int auth_methods, int ch)
+nc_server_ssh_set_auth_methods(int auth_methods, struct nc_server_ssh_opts *opts)
{
- struct nc_ssh_server_opts *opts;
-
if (!(auth_methods & NC_SSH_AUTH_PUBLICKEY) && !(auth_methods & NC_SSH_AUTH_PASSWORD)
&& !(auth_methods & NC_SSH_AUTH_INTERACTIVE)) {
ERRARG;
return -1;
}
- opts = (ch ? &ssh_ch_opts : &ssh_opts);
-
opts->auth_methods = auth_methods;
return 0;
}
API int
-nc_ssh_server_set_auth_methods(int auth_methods)
+nc_server_ssh_endpt_set_auth_methods(const char *endpt_name, int auth_methods)
{
- return _nc_ssh_server_set_auth_methods(auth_methods, 0);
+ struct nc_endpt *endpt;
+
+ endpt = nc_server_get_endpt(endpt_name, NC_TI_LIBSSH);
+ if (!endpt) {
+ ERR("Endpoint \"%s\" was not found.", endpt_name);
+ return -1;
+ }
+
+ return nc_server_ssh_set_auth_methods(auth_methods, endpt->ti_opts);
}
API int
-nc_ssh_server_ch_set_auth_methods(int auth_methods)
+nc_server_ssh_ch_set_auth_methods(int auth_methods)
{
- return _nc_ssh_server_set_auth_methods(auth_methods, 1);
+ return nc_server_ssh_set_auth_methods(auth_methods, &ssh_ch_opts);
}
static int
-_nc_ssh_server_set_auth_attempts(uint16_t auth_attempts, int ch)
+nc_server_ssh_set_auth_attempts(uint16_t auth_attempts, struct nc_server_ssh_opts *opts)
{
- struct nc_ssh_server_opts *opts;
-
if (!auth_attempts) {
ERRARG;
return -1;
}
- opts = (ch ? &ssh_ch_opts : &ssh_opts);
-
opts->auth_attempts = auth_attempts;
return 0;
}
API int
-nc_ssh_server_set_auth_attempts(uint16_t auth_attempts)
+nc_server_ssh_endpt_set_auth_attempts(const char *endpt_name, uint16_t auth_attempts)
{
- return _nc_ssh_server_set_auth_attempts(auth_attempts, 0);
+ struct nc_endpt *endpt;
+
+ endpt = nc_server_get_endpt(endpt_name, NC_TI_LIBSSH);
+ if (!endpt) {
+ ERR("Endpoint \"%s\" was not found.", endpt_name);
+ return -1;
+ }
+
+ return nc_server_ssh_set_auth_attempts(auth_attempts, endpt->ti_opts);
}
API int
-nc_ssh_server_set_ch_auth_attempts(uint16_t auth_attempts)
+nc_server_ssh_set_ch_auth_attempts(uint16_t auth_attempts)
{
- return _nc_ssh_server_set_auth_attempts(auth_attempts, 1);
+ return nc_server_ssh_set_auth_attempts(auth_attempts, &ssh_ch_opts);
}
static int
-_nc_ssh_server_set_auth_timeout(uint16_t auth_timeout, int ch)
+nc_server_ssh_set_auth_timeout(uint16_t auth_timeout, struct nc_server_ssh_opts *opts)
{
- struct nc_ssh_server_opts *opts;
-
if (!auth_timeout) {
ERRARG;
return -1;
}
- opts = (ch ? &ssh_ch_opts : &ssh_opts);
-
opts->auth_timeout = auth_timeout;
return 0;
}
API int
-nc_ssh_server_set_auth_timeout(uint16_t auth_timeout)
+nc_server_ssh_endpt_set_auth_timeout(const char *endpt_name, uint16_t auth_timeout)
{
- return _nc_ssh_server_set_auth_timeout(auth_timeout, 0);
+ struct nc_endpt *endpt;
+
+ endpt = nc_server_get_endpt(endpt_name, NC_TI_LIBSSH);
+ if (!endpt) {
+ ERR("Endpoint \"%s\" was not found.", endpt_name);
+ return -1;
+ }
+
+ return nc_server_ssh_set_auth_timeout(auth_timeout, endpt->ti_opts);
}
API int
-nc_ssh_server_ch_set_auth_timeout(uint16_t auth_timeout)
+nc_server_ssh_ch_set_auth_timeout(uint16_t auth_timeout)
{
- return _nc_ssh_server_set_auth_timeout(auth_timeout, 1);
+ return nc_server_ssh_set_auth_timeout(auth_timeout, &ssh_ch_opts);
}
static int
-_nc_ssh_server_add_authkey(const char *pubkey_path, const char *username, int ch)
+nc_server_ssh_add_authkey(const char *pubkey_path, const char *username, struct nc_server_ssh_opts *opts)
{
- struct nc_ssh_server_opts *opts;
-
if (!pubkey_path || !username) {
ERRARG;
return -1;
}
- opts = (ch ? &ssh_ch_opts : &ssh_opts);
-
- /* LOCK */
- pthread_mutex_lock(&opts->authkey_lock);
-
++opts->authkey_count;
opts->authkeys = realloc(opts->authkeys, opts->authkey_count * sizeof *opts->authkeys);
@@ -260,36 +258,35 @@
opts->authkeys[opts->authkey_count - 1].username = lydict_insert(server_opts.ctx, username, 0);
nc_ctx_unlock();
- /* UNLOCK */
- pthread_mutex_unlock(&opts->authkey_lock);
-
return 0;
}
API int
-nc_ssh_server_add_authkey(const char *pubkey_path, const char *username)
+nc_server_ssh_endpt_add_authkey(const char *endpt_name, const char *pubkey_path, const char *username)
{
- return _nc_ssh_server_add_authkey(pubkey_path, username, 0);
+ struct nc_endpt *endpt;
+
+ endpt = nc_server_get_endpt(endpt_name, NC_TI_LIBSSH);
+ if (!endpt) {
+ ERR("Endpoint \"%s\" was not found.", endpt_name);
+ return -1;
+ }
+
+ return nc_server_ssh_add_authkey(pubkey_path, username, endpt->ti_opts);
}
API int
-nc_ssh_server_ch_add_authkey(const char *pubkey_path, const char *username)
+nc_server_ssh_ch_add_authkey(const char *pubkey_path, const char *username)
{
- return _nc_ssh_server_add_authkey(pubkey_path, username, 1);
+ return nc_server_ssh_add_authkey(pubkey_path, username, &ssh_ch_opts);
}
static int
-_nc_ssh_server_del_authkey(const char *pubkey_path, const char *username, int ch)
+nc_server_ssh_del_authkey(const char *pubkey_path, const char *username, struct nc_server_ssh_opts *opts)
{
- struct nc_ssh_server_opts *opts;
uint32_t i;
int ret = -1;
- opts = (ch ? &ssh_ch_opts : &ssh_opts);
-
- /* LOCK */
- pthread_mutex_lock(&opts->authkey_lock);
-
if (!pubkey_path && !username) {
nc_ctx_lock(-1, NULL);
for (i = 0; i < opts->authkey_count; ++i) {
@@ -319,54 +316,44 @@
}
}
- /* UNLOCK */
- pthread_mutex_unlock(&opts->authkey_lock);
-
return ret;
}
API int
-nc_ssh_server_del_authkey(const char *pubkey_path, const char *username)
+nc_server_ssh_endpt_del_authkey(const char *endpt_name, const char *pubkey_path, const char *username)
{
- return _nc_ssh_server_del_authkey(pubkey_path, username, 0);
+ struct nc_endpt *endpt;
+
+ endpt = nc_server_get_endpt(endpt_name, NC_TI_LIBSSH);
+ if (!endpt) {
+ ERR("Endpoint \"%s\" was not found.", endpt_name);
+ return -1;
+ }
+
+ return nc_server_ssh_del_authkey(pubkey_path, username, endpt->ti_opts);
}
API int
-nc_ssh_server_ch_del_authkey(const char *pubkey_path, const char *username)
+nc_server_ssh_ch_del_authkey(const char *pubkey_path, const char *username)
{
- return _nc_ssh_server_del_authkey(pubkey_path, username, 1);
+ return nc_server_ssh_del_authkey(pubkey_path, username, &ssh_ch_opts);
+}
+
+void
+nc_server_ssh_opts_clear(struct nc_server_ssh_opts *opts)
+{
+ if (opts->sshbind) {
+ ssh_bind_free(opts->sshbind);
+ opts->sshbind = NULL;
+ }
+
+ nc_server_ssh_del_authkey(NULL, NULL, opts);
}
API void
-nc_ssh_server_free_opts(void)
+nc_server_ssh_ch_opts_clear(void)
{
- /* LOCK */
- pthread_mutex_lock(&ssh_opts.sshbind_lock);
-
- if (ssh_opts.sshbind) {
- ssh_bind_free(ssh_opts.sshbind);
- ssh_opts.sshbind = NULL;
- }
-
- /* UNLOCK */
- pthread_mutex_unlock(&ssh_opts.sshbind_lock);
-
- nc_ssh_server_del_authkey(NULL, NULL);
-
- /* Call Home */
-
- /* LOCK */
- pthread_mutex_lock(&ssh_ch_opts.sshbind_lock);
-
- if (ssh_ch_opts.sshbind) {
- ssh_bind_free(ssh_ch_opts.sshbind);
- ssh_ch_opts.sshbind = NULL;
- }
-
- /* UNLOCK */
- pthread_mutex_unlock(&ssh_ch_opts.sshbind_lock);
-
- nc_ssh_server_ch_del_authkey(NULL, NULL);
+ nc_server_ssh_opts_clear(&ssh_ch_opts);
}
static char *
@@ -487,21 +474,18 @@
}
static const char *
-auth_pubkey_compare_key(ssh_key key)
+auth_pubkey_compare_key(struct nc_server_ssh_opts *opts, ssh_key key)
{
uint32_t i;
ssh_key pub_key;
const char *username = NULL;
- /* LOCK */
- pthread_mutex_lock(&ssh_opts.authkey_lock);
-
- for (i = 0; i < ssh_opts.authkey_count; ++i) {
- if (ssh_pki_import_pubkey_file(ssh_opts.authkeys[i].path, &pub_key) != SSH_OK) {
- if (eaccess(ssh_opts.authkeys[i].path, R_OK)) {
- WRN("Failed to import the public key \"%s\" (%s).", ssh_opts.authkeys[i].path, strerror(errno));
+ for (i = 0; i < opts->authkey_count; ++i) {
+ if (ssh_pki_import_pubkey_file(opts->authkeys[i].path, &pub_key) != SSH_OK) {
+ if (eaccess(opts->authkeys[i].path, R_OK)) {
+ WRN("Failed to import the public key \"%s\" (%s).", opts->authkeys[i].path, strerror(errno));
} else {
- WRN("Failed to import the public key \"%s\" (%s).", __func__, ssh_opts.authkeys[i].path, ssh_get_error(pub_key));
+ WRN("Failed to import the public key \"%s\" (%s).", __func__, opts->authkeys[i].path, ssh_get_error(pub_key));
}
continue;
}
@@ -514,13 +498,10 @@
ssh_key_free(pub_key);
}
- if (i < ssh_opts.authkey_count) {
- username = ssh_opts.authkeys[i].username;
+ if (i < opts->authkey_count) {
+ username = opts->authkeys[i].username;
}
- /* UNLOCK */
- pthread_mutex_unlock(&ssh_opts.authkey_lock);
-
return username;
}
@@ -538,7 +519,7 @@
return;
} else if (signature_state == SSH_PUBLICKEY_STATE_NONE) {
- if ((username = auth_pubkey_compare_key(ssh_message_auth_pubkey(msg))) == NULL) {
+ if ((username = auth_pubkey_compare_key(session->ti_opts, ssh_message_auth_pubkey(msg))) == NULL) {
VRB("User \"%s\" tried to use an unknown (unauthorized) public key.", session->username);
} else if (strcmp(session->username, username)) {
@@ -769,7 +750,7 @@
return 0;
}
- if (session->ssh_auth_attempts >= ssh_opts.auth_attempts) {
+ if (session->ssh_auth_attempts >= ((struct nc_server_ssh_opts *)session->ti_opts)->auth_attempts) {
/* too many failed attempts */
ssh_message_reply_default(msg);
return 0;
@@ -982,13 +963,19 @@
return 1;
}
-int
-nc_accept_ssh_session(struct nc_session *session, int sock, int timeout, int ch)
+API int
+nc_connect_callhome_ssh(const char *host, uint16_t port, int timeout, struct nc_session **session)
{
- struct nc_ssh_server_opts *opts;
+ return nc_connect_callhome(host, port, NC_TI_LIBSSH, timeout, session);
+}
+
+int
+nc_accept_ssh_session(struct nc_session *session, int sock, int timeout)
+{
+ struct nc_server_ssh_opts *opts;
int libssh_auth_methods = 0, elapsed = 0, ret;
- opts = (ch ? &ssh_ch_opts : &ssh_opts);
+ opts = session->ti_opts;
/* other transport-specific data */
session->ti_type = NC_TI_LIBSSH;
@@ -1014,23 +1001,12 @@
/* remember that this session was just set as nc_sshcb_msg() parameter */
session->flags |= NC_SESSION_SSH_MSG_CB;
- /* LOCK */
- ret = nc_timedlock(&opts->sshbind_lock, timeout, &elapsed);
- if (ret < 1) {
- return ret;
- }
-
if (ssh_bind_accept_fd(opts->sshbind, session->ti.libssh.session, sock) == SSH_ERROR) {
- ERR("SSH failed to accept a new connection (%s).", ssh_get_error(ssh_opts.sshbind));
+ ERR("SSH failed to accept a new connection (%s).", ssh_get_error(opts->sshbind));
close(sock);
- /* UNLOCK */
- pthread_mutex_unlock(&opts->sshbind_lock);
return -1;
}
- /* UNLOCK */
- pthread_mutex_unlock(&opts->sshbind_lock);
-
if (ssh_handle_key_exchange(session->ti.libssh.session) != SSH_OK) {
ERR("SSH key exchange error (%s).", ssh_get_error(session->ti.libssh.session));
return -1;
diff --git a/src/session_server_tls.c b/src/session_server_tls.c
index 1dd5cf9..d40fcaa 100644
--- a/src/session_server_tls.c
+++ b/src/session_server_tls.c
@@ -33,20 +33,9 @@
#include "libnetconf.h"
#include "session_server.h"
+struct nc_server_tls_opts tls_ch_opts;
extern struct nc_server_opts server_opts;
-struct nc_tls_server_opts tls_opts = {
- .tls_ctx_lock = PTHREAD_MUTEX_INITIALIZER,
- .crl_lock = PTHREAD_MUTEX_INITIALIZER,
- .ctn_lock = PTHREAD_MUTEX_INITIALIZER
-};
-
-struct nc_tls_server_opts tls_ch_opts = {
- .tls_ctx_lock = PTHREAD_MUTEX_INITIALIZER,
- .crl_lock = PTHREAD_MUTEX_INITIALIZER,
- .ctn_lock = PTHREAD_MUTEX_INITIALIZER
-};
-
static pthread_key_t verify_key;
static pthread_once_t verify_once = PTHREAD_ONCE_INIT;
@@ -466,7 +455,7 @@
STACK_OF(X509) *cert_stack;
EVP_PKEY *pubkey;
struct nc_session* session;
- struct nc_tls_server_opts *opts;
+ struct nc_server_tls_opts *opts;
long serial;
int i, n, rc, depth;
char *cp;
@@ -481,7 +470,7 @@
return 0;
}
- opts = (session->flags & NC_SESSION_CALLHOME ? &tls_ch_opts : &tls_opts);
+ opts = session->ti_opts;
/* get the last certificate, that is the peer (client) certificate */
if (!session->tls_cert) {
@@ -535,9 +524,6 @@
VRB("Cert verify: issuer: %s.", cp);
OPENSSL_free(cp);
- /* LOCK */
- pthread_mutex_lock(&opts->crl_lock);
-
/* check for revocation if set */
if (opts->crl_store) {
/* try to retrieve a CRL corresponding to the _subject_ of
@@ -570,8 +556,6 @@
if (pubkey) {
EVP_PKEY_free(pubkey);
}
- /* UNLOCK */
- pthread_mutex_unlock(&opts->crl_lock);
return 0;
}
if (pubkey) {
@@ -583,16 +567,12 @@
ERR("Cert verify CRL: invalid nextUpdate field.");
X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
X509_OBJECT_free_contents(&obj);
- /* UNLOCK */
- pthread_mutex_unlock(&opts->crl_lock);
return 0;
}
if (X509_cmp_current_time(next_update) < 0) {
ERR("Cert verify CRL: expired - revoking all certificates.");
X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_HAS_EXPIRED);
X509_OBJECT_free_contents(&obj);
- /* UNLOCK */
- pthread_mutex_unlock(&opts->crl_lock);
return 0;
}
X509_OBJECT_free_contents(&obj);
@@ -617,8 +597,6 @@
OPENSSL_free(cp);
X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CERT_REVOKED);
X509_OBJECT_free_contents(&obj);
- /* UNLOCK */
- pthread_mutex_unlock(&opts->crl_lock);
return 0;
}
}
@@ -626,20 +604,13 @@
}
}
- /* UNLOCK */
- pthread_mutex_unlock(&opts->crl_lock);
-
/* cert-to-name already successful */
if (session->username) {
return 1;
}
- /* LOCK */
- pthread_mutex_lock(&opts->ctn_lock);
/* cert-to-name */
rc = nc_tls_cert_to_name(opts->ctn, cert, &map_type, &username);
- /* UNLOCK */
- pthread_mutex_unlock(&opts->ctn_lock);
if (rc) {
if (rc == -1) {
@@ -682,10 +653,21 @@
return 0;
}
-static int
-_nc_tls_server_set_cert(const char *cert, int ch)
+API int
+nc_server_tls_add_endpt_listen(const char *name, const char *address, uint16_t port)
{
- struct nc_tls_server_opts *opts;
+ return nc_server_add_endpt_listen(name, address, port, NC_TI_OPENSSL);
+}
+
+API int
+nc_server_tls_del_endpt(const char *name)
+{
+ return nc_server_del_endpt(name, NC_TI_OPENSSL);
+}
+
+static int
+nc_server_tls_set_cert(const char *cert, struct nc_server_tls_opts *opts)
+{
X509 *x509_cert;
if (!cert) {
@@ -693,11 +675,6 @@
return -1;
}
- opts = (ch ? &tls_ch_opts : &tls_opts);
-
- /* LOCK */
- pthread_mutex_lock(&opts->tls_ctx_lock);
-
if (!opts->tls_ctx) {
opts->tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
if (!opts->tls_ctx) {
@@ -715,43 +692,40 @@
}
X509_free(x509_cert);
- /* UNLOCK */
- pthread_mutex_unlock(&opts->tls_ctx_lock);
return 0;
fail:
- /* UNLOCK */
- pthread_mutex_unlock(&opts->tls_ctx_lock);
return -1;
}
API int
-nc_tls_server_set_cert(const char *cert)
+nc_server_tls_endpt_set_cert(const char *endpt_name, const char *cert)
{
- return _nc_tls_server_set_cert(cert, 0);
+ struct nc_endpt *endpt;
+
+ endpt = nc_server_get_endpt(endpt_name, NC_TI_OPENSSL);
+ if (!endpt) {
+ ERR("Endpoint \"%s\" was not found.", endpt_name);
+ return -1;
+ }
+
+ return nc_server_tls_set_cert(cert, endpt->ti_opts);
}
API int
-nc_tls_server_ch_set_cert(const char *cert)
+nc_server_tls_ch_set_cert(const char *cert)
{
- return _nc_tls_server_set_cert(cert, 1);
+ return nc_server_tls_set_cert(cert, &tls_ch_opts);
}
static int
-_nc_tls_server_set_cert_path(const char *cert_path, int ch)
+nc_server_tls_set_cert_path(const char *cert_path, struct nc_server_tls_opts *opts)
{
- struct nc_tls_server_opts *opts;
-
if (!cert_path) {
ERRARG;
return -1;
}
- opts = (ch ? &tls_ch_opts : &tls_opts);
-
- /* LOCK */
- pthread_mutex_lock(&opts->tls_ctx_lock);
-
if (!opts->tls_ctx) {
opts->tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
if (!opts->tls_ctx) {
@@ -766,32 +740,35 @@
goto fail;
}
- /* UNLOCK */
- pthread_mutex_unlock(&opts->tls_ctx_lock);
return 0;
fail:
- /* UNLOCK */
- pthread_mutex_unlock(&opts->tls_ctx_lock);
return -1;
}
API int
-nc_tls_server_set_cert_path(const char *cert_path)
+nc_server_tls_set_endpt_cert_path(const char *endpt_name, const char *cert_path)
{
- return _nc_tls_server_set_cert_path(cert_path, 0);
+ struct nc_endpt *endpt;
+
+ endpt = nc_server_get_endpt(endpt_name, NC_TI_OPENSSL);
+ if (!endpt) {
+ ERR("Endpoint \"%s\" was not found.", endpt_name);
+ return -1;
+ }
+
+ return nc_server_tls_set_cert_path(cert_path, endpt->ti_opts);
}
API int
-nc_tls_server_ch_set_cert_path(const char *cert_path)
+nc_server_tls_ch_set_cert_path(const char *cert_path)
{
- return _nc_tls_server_set_cert_path(cert_path, 1);
+ return nc_server_tls_set_cert_path(cert_path, &tls_ch_opts);
}
static int
-_nc_tls_server_set_key(const char *privkey, int is_rsa, int ch)
+nc_server_tls_set_key(const char *privkey, int is_rsa, struct nc_server_tls_opts *opts)
{
- struct nc_tls_server_opts *opts;
EVP_PKEY *key;;
if (!privkey) {
@@ -799,11 +776,6 @@
return -1;
}
- opts = (ch ? &tls_ch_opts : &tls_opts);
-
- /* LOCK */
- pthread_mutex_lock(&opts->tls_ctx_lock);
-
if (!opts->tls_ctx) {
opts->tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
if (!opts->tls_ctx) {
@@ -821,43 +793,40 @@
}
EVP_PKEY_free(key);
- /* UNLOCK */
- pthread_mutex_unlock(&opts->tls_ctx_lock);
return 0;
fail:
- /* UNLOCK */
- pthread_mutex_unlock(&opts->tls_ctx_lock);
return -1;
}
API int
-nc_tls_server_set_key(const char *privkey, int is_rsa)
+nc_server_tls_endpt_set_key(const char *endpt_name, const char *privkey, int is_rsa)
{
- return _nc_tls_server_set_key(privkey, is_rsa, 0);
+ struct nc_endpt *endpt;
+
+ endpt = nc_server_get_endpt(endpt_name, NC_TI_OPENSSL);
+ if (!endpt) {
+ ERR("Endpoint \"%s\" was not found.", endpt_name);
+ return -1;
+ }
+
+ return nc_server_tls_set_key(privkey, is_rsa, endpt->ti_opts);
}
API int
-nc_tls_server_ch_set_key(const char *privkey, int is_rsa)
+nc_server_tls_ch_set_key(const char *privkey, int is_rsa)
{
- return _nc_tls_server_set_key(privkey, is_rsa, 1);
+ return nc_server_tls_set_key(privkey, is_rsa, &tls_ch_opts);
}
static int
-_nc_tls_server_set_key_path(const char *privkey_path, int ch)
+nc_server_tls_set_key_path(const char *privkey_path, struct nc_server_tls_opts *opts)
{
- struct nc_tls_server_opts *opts;
-
if (!privkey_path) {
ERRARG;
return -1;
}
- opts = (ch ? &tls_ch_opts : &tls_opts);
-
- /* LOCK */
- pthread_mutex_lock(&opts->tls_ctx_lock);
-
if (!opts->tls_ctx) {
opts->tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
if (!opts->tls_ctx) {
@@ -872,32 +841,35 @@
goto fail;
}
- /* UNLOCK */
- pthread_mutex_unlock(&opts->tls_ctx_lock);
return 0;
fail:
- /* UNLOCK */
- pthread_mutex_unlock(&opts->tls_ctx_lock);
return -1;
}
API int
-nc_tls_server_set_key_path(const char *privkey_path)
+nc_server_tls_endpt_set_key_path(const char *endpt_name, const char *privkey_path)
{
- return _nc_tls_server_set_key_path(privkey_path, 0);
+ struct nc_endpt *endpt;
+
+ endpt = nc_server_get_endpt(endpt_name, NC_TI_OPENSSL);
+ if (!endpt) {
+ ERR("Endpoint \"%s\" was not found.", endpt_name);
+ return -1;
+ }
+
+ return nc_server_tls_set_key_path(privkey_path, endpt->ti_opts);
}
API int
-nc_tls_server_ch_set_key_path(const char *privkey_path)
+nc_server_tls_ch_set_key_path(const char *privkey_path)
{
- return _nc_tls_server_set_key_path(privkey_path, 1);
+ return nc_server_tls_set_key_path(privkey_path, &tls_ch_opts);
}
static int
-_nc_tls_server_add_trusted_cert(const char *cert, int ch)
+nc_server_tls_add_trusted_cert(const char *cert, struct nc_server_tls_opts *opts)
{
- struct nc_tls_server_opts *opts;
X509_STORE *cert_store;
X509 *x509_cert;
@@ -906,11 +878,6 @@
return -1;
}
- opts = (ch ? &tls_ch_opts : &tls_opts);
-
- /* LOCK */
- pthread_mutex_lock(&opts->tls_ctx_lock);
-
if (!opts->tls_ctx) {
opts->tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
if (!opts->tls_ctx) {
@@ -934,32 +901,35 @@
}
X509_free(x509_cert);
- /* UNLOCK */
- pthread_mutex_unlock(&opts->tls_ctx_lock);
return 0;
fail:
- /* UNLOCK */
- pthread_mutex_unlock(&opts->tls_ctx_lock);
return -1;
}
API int
-nc_tls_server_add_trusted_cert(const char *cert)
+nc_server_tls_endpt_add_trusted_cert(const char *endpt_name, const char *cert)
{
- return _nc_tls_server_add_trusted_cert(cert, 0);
+ struct nc_endpt *endpt;
+
+ endpt = nc_server_get_endpt(endpt_name, NC_TI_OPENSSL);
+ if (!endpt) {
+ ERR("Endpoint \"%s\" was not found.", endpt_name);
+ return -1;
+ }
+
+ return nc_server_tls_add_trusted_cert(cert, endpt->ti_opts);
}
API int
-nc_tls_server_ch_add_trusted_cert(const char *cert)
+nc_server_tls_ch_add_trusted_cert(const char *cert)
{
- return _nc_tls_server_add_trusted_cert(cert, 1);
+ return nc_server_tls_add_trusted_cert(cert, &tls_ch_opts);
}
static int
-_nc_tls_server_add_trusted_cert_path(const char *cert_path, int ch)
+nc_server_tls_add_trusted_cert_path(const char *cert_path, struct nc_server_tls_opts *opts)
{
- struct nc_tls_server_opts *opts;
X509_STORE *cert_store;
X509 *x509_cert;
@@ -968,11 +938,6 @@
return -1;
}
- opts = (ch ? &tls_ch_opts : &tls_opts);
-
- /* LOCK */
- pthread_mutex_lock(&opts->tls_ctx_lock);
-
if (!opts->tls_ctx) {
opts->tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
if (!opts->tls_ctx) {
@@ -998,32 +963,35 @@
}
X509_free(x509_cert);
- /* UNLOCK */
- pthread_mutex_unlock(&opts->tls_ctx_lock);
return 0;
fail:
- /* UNLOCK */
- pthread_mutex_unlock(&opts->tls_ctx_lock);
return -1;
}
API int
-nc_tls_server_add_trusted_cert_path(const char *cert_path)
+nc_server_tls_endpt_add_trusted_cert_path(const char *endpt_name, const char *cert_path)
{
- return _nc_tls_server_add_trusted_cert_path(cert_path, 0);
+ struct nc_endpt *endpt;
+
+ endpt = nc_server_get_endpt(endpt_name, NC_TI_OPENSSL);
+ if (!endpt) {
+ ERR("Endpoint \"%s\" was not found.", endpt_name);
+ return -1;
+ }
+
+ return nc_server_tls_add_trusted_cert_path(cert_path, endpt->ti_opts);
}
API int
-nc_tls_server_ch_add_trusted_cert_path(const char *cert_path)
+nc_server_tls_ch_add_trusted_cert_path(const char *cert_path)
{
- return _nc_tls_server_add_trusted_cert_path(cert_path, 1);
+ return nc_server_tls_add_trusted_cert_path(cert_path, &tls_ch_opts);
}
static int
-_nc_tls_server_set_trusted_cacert_locations(const char *cacert_file_path, const char *cacert_dir_path, int ch)
+nc_server_tls_set_trusted_cacert_locations(const char *cacert_file_path, const char *cacert_dir_path, struct nc_server_tls_opts *opts)
{
- struct nc_tls_server_opts *opts;
X509_STORE *cert_store;
X509_LOOKUP *lookup;
@@ -1032,11 +1000,6 @@
return -1;
}
- opts = (ch ? &tls_ch_opts : &tls_opts);
-
- /* LOCK */
- pthread_mutex_lock(&opts->tls_ctx_lock);
-
if (!opts->tls_ctx) {
opts->tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
if (!opts->tls_ctx) {
@@ -1078,67 +1041,66 @@
}
}
- /* UNLOCK */
- pthread_mutex_unlock(&opts->tls_ctx_lock);
return 0;
fail:
- /* UNLOCK */
- pthread_mutex_unlock(&tls_opts.tls_ctx_lock);
return -1;
}
API int
-nc_tls_server_set_trusted_cacert_locations(const char *cacert_file_path, const char *cacert_dir_path)
+nc_server_tls_endpt_set_trusted_cacert_locations(const char *endpt_name, const char *cacert_file_path, const char *cacert_dir_path)
{
- return _nc_tls_server_set_trusted_cacert_locations(cacert_file_path, cacert_dir_path, 0);
+ struct nc_endpt *endpt;
+
+ endpt = nc_server_get_endpt(endpt_name, NC_TI_OPENSSL);
+ if (!endpt) {
+ ERR("Endpoint \"%s\" was not found.", endpt_name);
+ return -1;
+ }
+
+ return nc_server_tls_set_trusted_cacert_locations(cacert_file_path, cacert_dir_path, endpt->ti_opts);
}
API int
-nc_tls_server_ch_set_trusted_cacert_locations(const char *cacert_file_path, const char *cacert_dir_path)
+nc_server_tls_ch_set_trusted_cacert_locations(const char *cacert_file_path, const char *cacert_dir_path)
{
- return _nc_tls_server_set_trusted_cacert_locations(cacert_file_path, cacert_dir_path, 1);
+ return nc_server_tls_set_trusted_cacert_locations(cacert_file_path, cacert_dir_path, &tls_ch_opts);
}
static void
-_nc_tls_server_destroy_certs(int ch)
+nc_server_tls_destroy_certs(struct nc_server_tls_opts *opts)
{
- struct nc_tls_server_opts *opts;
-
- opts = (ch ? &tls_ch_opts : &tls_opts);
-
- /* LOCK */
- pthread_mutex_lock(&opts->tls_ctx_lock);
-
if (!opts->tls_ctx) {
- /* UNLOCK */
- pthread_mutex_unlock(&opts->tls_ctx_lock);
return;
}
SSL_CTX_free(opts->tls_ctx);
opts->tls_ctx = NULL;
-
- /* UNLOCK */
- pthread_mutex_unlock(&opts->tls_ctx_lock);
}
API void
-nc_tls_server_destroy_certs(void)
+nc_server_tls_endpt_destroy_certs(const char *endpt_name)
{
- _nc_tls_server_destroy_certs(0);
+ struct nc_endpt *endpt;
+
+ endpt = nc_server_get_endpt(endpt_name, NC_TI_OPENSSL);
+ if (!endpt) {
+ ERR("Endpoint \"%s\" was not found.", endpt_name);
+ return;
+ }
+
+ nc_server_tls_destroy_certs(endpt->ti_opts);
}
API void
-nc_tls_server_ch_destroy_certs(void)
+nc_server_tls_ch_destroy_certs(void)
{
- _nc_tls_server_destroy_certs(1);
+ nc_server_tls_destroy_certs(&tls_ch_opts);
}
static int
-_nc_tls_server_set_crl_locations(const char *crl_file_path, const char *crl_dir_path, int ch)
+nc_server_tls_set_crl_locations(const char *crl_file_path, const char *crl_dir_path, struct nc_server_tls_opts *opts)
{
- struct nc_tls_server_opts *opts;
X509_LOOKUP *lookup;
if (!crl_file_path && !crl_dir_path) {
@@ -1146,11 +1108,6 @@
return -1;
}
- opts = (ch ? &tls_ch_opts : &tls_opts);
-
- /* LOCK */
- pthread_mutex_lock(&opts->crl_lock);
-
if (!opts->crl_store) {
opts->crl_store = X509_STORE_new();
}
@@ -1181,67 +1138,66 @@
}
}
- /* UNLOCK */
- pthread_mutex_unlock(&opts->crl_lock);
return 0;
fail:
- /* UNLOCK */
- pthread_mutex_unlock(&opts->crl_lock);
return -1;
}
API int
-nc_tls_server_set_crl_locations(const char *crl_file_path, const char *crl_dir_path)
+nc_server_tls_endpt_set_crl_locations(const char *endpt_name, const char *crl_file_path, const char *crl_dir_path)
{
- return _nc_tls_server_set_crl_locations(crl_file_path, crl_dir_path, 0);
+ struct nc_endpt *endpt;
+
+ endpt = nc_server_get_endpt(endpt_name, NC_TI_OPENSSL);
+ if (!endpt) {
+ ERR("Endpoint \"%s\" was not found.", endpt_name);
+ return -1;
+ }
+
+ return nc_server_tls_set_crl_locations(crl_file_path, crl_dir_path, endpt->ti_opts);
}
API int
-nc_tls_server_ch_set_crl_locations(const char *crl_file_path, const char *crl_dir_path)
+nc_server_tls_ch_set_crl_locations(const char *crl_file_path, const char *crl_dir_path)
{
- return _nc_tls_server_set_crl_locations(crl_file_path, crl_dir_path, 1);
+ return nc_server_tls_set_crl_locations(crl_file_path, crl_dir_path, &tls_ch_opts);
}
static void
-_nc_tls_server_destroy_crls(int ch)
+nc_server_tls_destroy_crls(struct nc_server_tls_opts *opts)
{
- struct nc_tls_server_opts *opts;
-
- opts = (ch ? &tls_ch_opts : &tls_opts);
-
- /* LOCK */
- pthread_mutex_lock(&opts->crl_lock);
-
if (!opts->crl_store) {
- /* UNLOCK */
- pthread_mutex_unlock(&opts->crl_lock);
return;
}
X509_STORE_free(opts->crl_store);
opts->crl_store = NULL;
-
- /* UNLOCK */
- pthread_mutex_unlock(&opts->crl_lock);
}
API void
-nc_tls_server_destroy_crls(void)
+nc_server_tls_endpt_destroy_crls(const char *endpt_name)
{
- _nc_tls_server_destroy_crls(0);
+ struct nc_endpt *endpt;
+
+ endpt = nc_server_get_endpt(endpt_name, NC_TI_OPENSSL);
+ if (!endpt) {
+ ERR("Endpoint \"%s\" was not found.", endpt_name);
+ return;
+ }
+
+ nc_server_tls_destroy_crls(endpt->ti_opts);
}
API void
-nc_tls_server_ch_destroy_crls(void)
+nc_server_tls_ch_destroy_crls(void)
{
- _nc_tls_server_destroy_crls(1);
+ nc_server_tls_destroy_crls(&tls_ch_opts);
}
static int
-_nc_tls_server_add_ctn(uint32_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name, int ch)
+nc_server_tls_add_ctn(uint32_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name, struct nc_server_tls_opts *opts)
{
- struct nc_tls_server_opts *opts;
struct nc_ctn *ctn, *new;
if (!fingerprint || !map_type || ((map_type == NC_TLS_CTN_SPECIFIED) && !name)
@@ -1250,8 +1206,6 @@
return -1;
}
- opts = (ch ? &tls_ch_opts : &tls_opts);
-
new = malloc(sizeof *new);
nc_ctx_lock(-1, NULL);
@@ -1262,9 +1216,6 @@
new->map_type = map_type;
new->next = NULL;
- /* LOCK */
- pthread_mutex_lock(&opts->ctn_lock);
-
if (!opts->ctn) {
/* the first item */
opts->ctn = new;
@@ -1279,36 +1230,35 @@
ctn->next = new;
}
- /* UNLOCK */
- pthread_mutex_unlock(&opts->ctn_lock);
-
return 0;
}
API int
-nc_tls_server_add_ctn(uint32_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name)
+nc_server_tls_endpt_add_ctn(const char *endpt_name, uint32_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name)
{
- return _nc_tls_server_add_ctn(id, fingerprint, map_type, name, 0);
+ struct nc_endpt *endpt;
+
+ endpt = nc_server_get_endpt(endpt_name, NC_TI_OPENSSL);
+ if (!endpt) {
+ ERR("Endpoint \"%s\" was not found.", endpt_name);
+ return -1;
+ }
+
+ return nc_server_tls_add_ctn(id, fingerprint, map_type, name, endpt->ti_opts);
}
API int
-nc_tls_server_ch_add_ctn(uint32_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name)
+nc_server_tls_ch_add_ctn(uint32_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name)
{
- return _nc_tls_server_add_ctn(id, fingerprint, map_type, name, 1);
+ return nc_server_tls_add_ctn(id, fingerprint, map_type, name, &tls_ch_opts);
}
static int
-_nc_tls_server_del_ctn(int64_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name, int ch)
+nc_server_tls_del_ctn(int64_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name, struct nc_server_tls_opts *opts)
{
- struct nc_tls_server_opts *opts;
struct nc_ctn *ctn, *next, *prev;
int ret = -1;
- opts = (ch ? &tls_ch_opts : &tls_opts);
-
- /* LOCK */
- pthread_mutex_lock(&opts->ctn_lock);
-
if ((id < 0) && !fingerprint && !map_type && !name) {
ctn = opts->ctn;
nc_ctx_lock(-1, NULL);
@@ -1323,7 +1273,7 @@
ret = 0;
}
nc_ctx_unlock();
- tls_opts.ctn = NULL;
+ opts->ctn = NULL;
} else {
prev = NULL;
ctn = opts->ctn;
@@ -1341,7 +1291,7 @@
prev->next = ctn->next;
next = ctn->next;
} else {
- tls_opts.ctn = ctn->next;
+ opts->ctn = ctn->next;
next = ctn->next;
}
free(ctn);
@@ -1355,34 +1305,41 @@
}
}
- /* UNLOCK */
- pthread_mutex_unlock(&opts->ctn_lock);
-
return ret;
}
API int
-nc_tls_server_del_ctn(int64_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name)
+nc_server_tls_endpt_del_ctn(const char *endpt_name, int64_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name)
{
- return _nc_tls_server_del_ctn(id, fingerprint, map_type, name, 0);
+ struct nc_endpt *endpt;
+
+ endpt = nc_server_get_endpt(endpt_name, NC_TI_OPENSSL);
+ if (!endpt) {
+ ERR("Endpoint \"%s\" was not found.", endpt_name);
+ return -1;
+ }
+
+ return nc_server_tls_del_ctn(id, fingerprint, map_type, name, endpt->ti_opts);
}
API int
-nc_tls_server_ch_del_ctn(int64_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name)
+nc_server_tls_ch_del_ctn(int64_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name)
{
- return _nc_tls_server_del_ctn(id, fingerprint, map_type, name, 1);
+ return nc_server_tls_del_ctn(id, fingerprint, map_type, name, &tls_ch_opts);
}
API void
-nc_tls_server_free_opts(void)
+nc_server_tls_ch_opts_clear(void)
{
- nc_tls_server_destroy_certs();
- nc_tls_server_destroy_crls();
- nc_tls_server_del_ctn(-1, NULL, 0, NULL);
+ nc_server_tls_opts_clear(&tls_ch_opts);
+}
- nc_tls_server_ch_destroy_certs();
- nc_tls_server_ch_destroy_crls();
- nc_tls_server_ch_del_ctn(-1, NULL, 0, NULL);
+void
+nc_server_tls_opts_clear(struct nc_server_tls_opts *opts)
+{
+ nc_server_tls_destroy_certs(opts);
+ nc_server_tls_destroy_crls(opts);
+ nc_server_tls_del_ctn(-1, NULL, 0, NULL, opts);
}
static void
@@ -1391,15 +1348,21 @@
pthread_key_create(&verify_key, NULL);
}
-int
-nc_accept_tls_session(struct nc_session *session, int sock, int timeout, int ch)
+API int
+nc_connect_callhome_tls(const char *host, uint16_t port, int timeout, struct nc_session **session)
{
- struct nc_tls_server_opts *opts;
+ return nc_connect_callhome(host, port, NC_TI_OPENSSL, timeout, session);
+}
+
+int
+nc_accept_tls_session(struct nc_session *session, int sock, int timeout)
+{
+ struct nc_server_tls_opts *opts;
struct pollfd pfd;
struct timespec old_ts, new_ts;
int ret, elapsed = 0;
- opts = (ch ? &tls_ch_opts : &tls_opts);
+ opts = session->ti_opts;
pfd.fd = sock;
pfd.events = POLLIN;
@@ -1433,17 +1396,8 @@
/* data waiting, prepare session */
session->ti_type = NC_TI_OPENSSL;
- /* LOCK */
- ret = nc_timedlock(&opts->tls_ctx_lock, timeout, &elapsed);
- if (ret < 1) {
- return ret;
- }
-
session->ti.tls = SSL_new(opts->tls_ctx);
- /* UNLOCK */
- pthread_mutex_unlock(&opts->tls_ctx_lock);
-
if (!session->ti.tls) {
ERR("Failed to create TLS structure from context.");
close(sock);