1
0
Fork 0

Merging upstream version 3.7.1.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-05-02 04:10:43 +02:00
parent 35bddb6fe5
commit 3776ec3c2c
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
26 changed files with 690 additions and 232 deletions

View file

@ -57,22 +57,22 @@ set(CMAKE_MACOSX_RPATH TRUE)
# minor version changes with added functionality (new tool, functionality of the tool or library, ...) and
# micro version is changed with a set of small changes or bugfixes anywhere in the project.
set(LIBNETCONF2_MAJOR_VERSION 3)
set(LIBNETCONF2_MINOR_VERSION 5)
set(LIBNETCONF2_MICRO_VERSION 5)
set(LIBNETCONF2_MINOR_VERSION 7)
set(LIBNETCONF2_MICRO_VERSION 1)
set(LIBNETCONF2_VERSION ${LIBNETCONF2_MAJOR_VERSION}.${LIBNETCONF2_MINOR_VERSION}.${LIBNETCONF2_MICRO_VERSION})
# Version of the library
# Major version is changed with every backward non-compatible API/ABI change in the library, minor version changes
# with backward compatible change and micro version is connected with any internal change of the library.
set(LIBNETCONF2_MAJOR_SOVERSION 4)
set(LIBNETCONF2_MINOR_SOVERSION 4)
set(LIBNETCONF2_MICRO_SOVERSION 5)
set(LIBNETCONF2_MINOR_SOVERSION 6)
set(LIBNETCONF2_MICRO_SOVERSION 1)
set(LIBNETCONF2_SOVERSION_FULL ${LIBNETCONF2_MAJOR_SOVERSION}.${LIBNETCONF2_MINOR_SOVERSION}.${LIBNETCONF2_MICRO_SOVERSION})
set(LIBNETCONF2_SOVERSION ${LIBNETCONF2_MAJOR_SOVERSION})
# Version of libyang library that this project depends on
set(LIBYANG_DEP_VERSION 2.0.0)
set(LIBYANG_DEP_SOVERSION 3.0.0)
set(LIBYANG_DEP_VERSION 3.12.0)
set(LIBYANG_DEP_SOVERSION 3.9.0)
set(LIBYANG_DEP_SOVERSION_MAJOR 3)
# global C flags
@ -388,7 +388,7 @@ endif()
# generate API/ABI report
if ("${BUILD_TYPE_UPPER}" STREQUAL "ABICHECK")
lib_abi_check(netconf2 "${headers}" ${LIBNETCONF2_SOVERSION_FULL} 15fbc59efa5e6f1f7bea19ab561d03f8852caabb)
lib_abi_check(netconf2 "${headers}" ${LIBNETCONF2_SOVERSION_FULL} 5c72504e9a6fc578ed32fcfb15f59f50d2aab234)
endif()
# source files to be covered by the 'format' target and a test with 'format-check' target

View file

@ -47,7 +47,7 @@ help_print()
" get-config [datastore] [xpath-filter]\t\t send a <get-config> RPC with optional XPath filter and datastore, the default datastore is \"running\" \n\n");
}
static enum NC_DATASTORE_TYPE
static NC_DATASTORE
string2datastore(const char *str)
{
if (!str) {
@ -68,7 +68,7 @@ string2datastore(const char *str)
static int
send_rpc(struct nc_session *session, NC_RPC_TYPE rpc_type, const char *param1, const char *param2)
{
enum NC_DATASTORE_TYPE datastore;
NC_DATASTORE datastore;
int r = 0, rc = 0;
uint64_t msg_id = 0;
struct lyd_node *envp = NULL, *op = NULL;

View file

@ -31,6 +31,10 @@ module libnetconf2-netconf-server {
prefix tlss;
}
revision "2025-01-23" {
description "Added a list of YANG modules skipped in the server <hello> message.";
}
revision "2024-07-09" {
description "Second revision.";
}
@ -428,11 +432,11 @@ module libnetconf2-netconf-server {
if-feature "ct:certificate-expiration-notification";
description
"Container for the certificate expiration notification intervals.
Its child nodes describe the ability to set the time intervals for the certificate
expiration notifications. These intervals are given in the form of an anchor and a period.
By default, these notifications are generated 3, 2, and 1 month; 2 weeks; 7, 6, 5, 4, 3, 2 and 1 day before a certificate expires.
Additionally, notifications are generated on the day of expiration and every day thereafter.
"Container for the certificate expiration notification intervals. Its child nodes describe the ability to set
the time intervals for the certificate expiration notifications. These intervals are given in the form of an
anchor and a period. By default, these notifications are generated 3, 2, and 1 month; 2 weeks; 7, 6, 5, 4, 3,
2 and 1 day before a certificate expires. Additionally, notifications are generated on the day of expiration
and every day thereafter.
Simplified example of YANG data that describe the default intervals:
@ -471,5 +475,12 @@ module libnetconf2-netconf-server {
}
}
}
leaf-list ignored-hello-module {
type string;
description
"List of implemented sysrepo YANG modules that will not be reported the NETCONF server in its <hello> messages.";
}
}
}

View file

@ -38,8 +38,13 @@
#include "netconf.h"
#include "session.h"
#include "session_p.h"
#ifdef NC_ENABLED_SSH_TLS
#include "session_wrapper.h"
#endif /* NC_ENABLED_SSH_TLS */
const char *nc_msgtype2str[] = {
"error",
"would block",
@ -938,6 +943,7 @@ nc_write_msg_io(struct nc_session *session, int io_timeout, int type, ...)
switch (reply->type) {
case NC_RPL_OK:
assert(rpc_envp != NULL);
if (lyd_new_opaq2(reply_envp, NULL, "ok", NULL, rpc_envp->name.prefix, rpc_envp->name.module_ns, NULL)) {
lyd_free_tree(reply_envp);

View file

@ -96,7 +96,7 @@ nc_libssh_thread_verbosity(int level)
#endif /* NC_ENABLED_SSH_TLS */
static void
void
nc_log_vprintf(const struct nc_session *session, NC_VERB_LEVEL level, const char *format, va_list args)
{
va_list args2;
@ -140,6 +140,7 @@ nc_log_vprintf(const struct nc_session *session, NC_VERB_LEVEL level, const char
cleanup:
free(msg);
va_end(args2);
}
void

View file

@ -35,6 +35,16 @@
*/
void nc_log_printf(const struct nc_session *session, NC_VERB_LEVEL level, const char *format, ...);
/**
* @brief Internal printing function with va_list
*
* @param[in] session Optional NETCONF session that generated the message
* @param[in] level Verbose level
* @param[in] format Formatting string
* @param[in] args va_list with arguments
*/
void nc_log_vprintf(const struct nc_session *session, NC_VERB_LEVEL level, const char *format, va_list args);
/**
* @brief Verbose level variable
*/

View file

@ -1,10 +1,11 @@
/**
* @file messages_p.h
* @author Radek Krejci <rkrejci@cesnet.cz>
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief libnetconf2's private functions and structures of NETCONF messages.
*
* @copyright
* Copyright (c) 2021 CESNET, z.s.p.o.
* Copyright (c) 2021 - 2025 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
@ -34,7 +35,7 @@ struct nc_server_reply {
struct nc_server_reply_data {
NC_RPL type;
struct lyd_node *data;
struct lyd_node *data; /**< always points to the operation, for both RPCs and actions */
int free;
NC_WD_MODE wd;
};

View file

@ -4,7 +4,7 @@
* @brief libnetconf2 - server NETCONF messages functions
*
* @copyright
* Copyright (c) 2015 CESNET, z.s.p.o.
* Copyright (c) 2015 - 2025 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
@ -261,14 +261,21 @@ nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...)
{
va_list ap;
struct lyd_node *err = NULL;
const struct lys_module *nc_mod;
NC_ERR_TYPE type;
const char *arg1, *arg2;
uint32_t sid;
NC_CHECK_ARG_RET(NULL, tag, NULL);
NC_CHECK_ARG_RET(NULL, tag, ctx, NULL);
nc_mod = ly_ctx_get_module_implemented(ctx, "ietf-netconf");
if (!nc_mod) {
ERR(NULL, "Module \"ietf-netconf\" missing in the context.");
return NULL;
}
/* rpc-error */
if (lyd_new_opaq2(NULL, ctx, "rpc-error", NULL, NULL, NC_NS_BASE, &err)) {
if (lyd_new_inner(NULL, nc_mod, "rpc-error", 0, &err)) {
return NULL;
}
@ -337,17 +344,17 @@ nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...)
ERRARG(NULL, "tag");
goto fail;
}
if (lyd_new_opaq2(err, NULL, "error-type", nc_err_type2str(type), NULL, NC_NS_BASE, NULL)) {
if (lyd_new_term(err, NULL, "error-type", nc_err_type2str(type), 0, NULL)) {
goto fail;
}
/* error-tag */
if (lyd_new_opaq2(err, NULL, "error-tag", nc_err_tag2str(tag), NULL, NC_NS_BASE, NULL)) {
if (lyd_new_term(err, NULL, "error-tag", nc_err_tag2str(tag), 0, NULL)) {
goto fail;
}
/* error-severity */
if (lyd_new_opaq2(err, NULL, "error-severity", "error", NULL, NC_NS_BASE, NULL)) {
if (lyd_new_term(err, NULL, "error-severity", "error", 0, NULL)) {
goto fail;
}
@ -474,13 +481,17 @@ fail:
API NC_ERR_TYPE
nc_err_get_type(const struct lyd_node *err)
{
struct lyd_node *match;
const struct lysc_node *schema;
struct lyd_node *match = NULL;
NC_CHECK_ARG_RET(NULL, err, 0);
lyd_find_sibling_opaq_next(lyd_child(err), "error-type", &match);
schema = lys_find_path(NULL, err->schema, "error-type", 0);
if (schema) {
lyd_find_sibling_val(lyd_child(err), schema, NULL, 0, &match);
}
if (match) {
return nc_err_str2type(((struct lyd_node_opaq *)match)->value);
return nc_err_str2type(lyd_get_value(match));
}
return 0;
@ -489,13 +500,17 @@ nc_err_get_type(const struct lyd_node *err)
API NC_ERR
nc_err_get_tag(const struct lyd_node *err)
{
struct lyd_node *match;
const struct lysc_node *schema;
struct lyd_node *match = NULL;
NC_CHECK_ARG_RET(NULL, err, 0);
lyd_find_sibling_opaq_next(lyd_child(err), "error-tag", &match);
schema = lys_find_path(NULL, err->schema, "error-tag", 0);
if (schema) {
lyd_find_sibling_val(lyd_child(err), schema, NULL, 0, &match);
}
if (match) {
return nc_err_str2tag(((struct lyd_node_opaq *)match)->value);
return nc_err_str2tag(lyd_get_value(match));
}
return 0;
@ -504,17 +519,25 @@ nc_err_get_tag(const struct lyd_node *err)
API int
nc_err_set_app_tag(struct lyd_node *err, const char *error_app_tag)
{
const struct lysc_node *schema;
struct lyd_node *match;
NC_CHECK_ARG_RET(NULL, err, error_app_tag, -1);
/* find the schema node */
schema = lys_find_path(NULL, err->schema, "error-app-tag", 0);
if (!schema) {
return -1;
}
/* remove previous node */
lyd_find_sibling_opaq_next(lyd_child(err), "error-app-tag", &match);
lyd_find_sibling_val(lyd_child(err), schema, NULL, 0, &match);
if (match) {
lyd_free_tree(match);
}
if (lyd_new_opaq2(err, NULL, "error-app-tag", error_app_tag, NULL, NC_NS_BASE, NULL)) {
/* create the node */
if (lyd_new_term(err, NULL, "error-app-tag", error_app_tag, 0, &match)) {
return -1;
}
@ -524,13 +547,17 @@ nc_err_set_app_tag(struct lyd_node *err, const char *error_app_tag)
API const char *
nc_err_get_app_tag(const struct lyd_node *err)
{
struct lyd_node *match;
const struct lysc_node *schema;
struct lyd_node *match = NULL;
NC_CHECK_ARG_RET(NULL, err, NULL);
lyd_find_sibling_opaq_next(lyd_child(err), "error-app-tag", &match);
schema = lys_find_path(NULL, err->schema, "error-tag", 0);
if (schema) {
lyd_find_sibling_val(lyd_child(err), schema, NULL, 0, &match);
}
if (match) {
return ((struct lyd_node_opaq *)match)->value;
return lyd_get_value(match);
}
return NULL;
@ -539,17 +566,25 @@ nc_err_get_app_tag(const struct lyd_node *err)
API int
nc_err_set_path(struct lyd_node *err, const char *error_path)
{
const struct lysc_node *schema;
struct lyd_node *match;
NC_CHECK_ARG_RET(NULL, err, error_path, -1);
/* find the schema node */
schema = lys_find_path(NULL, err->schema, "error-path", 0);
if (!schema) {
return -1;
}
/* remove previous node */
lyd_find_sibling_opaq_next(lyd_child(err), "error-path", &match);
lyd_find_sibling_val(lyd_child(err), schema, NULL, 0, &match);
if (match) {
lyd_free_tree(match);
}
if (lyd_new_opaq2(err, NULL, "error-path", error_path, NULL, NC_NS_BASE, NULL)) {
/* create the node */
if (lyd_new_term(err, NULL, "error-path", error_path, 0, &match)) {
return -1;
}
@ -559,13 +594,17 @@ nc_err_set_path(struct lyd_node *err, const char *error_path)
API const char *
nc_err_get_path(const struct lyd_node *err)
{
struct lyd_node *match;
const struct lysc_node *schema;
struct lyd_node *match = NULL;
NC_CHECK_ARG_RET(NULL, err, NULL);
lyd_find_sibling_opaq_next(lyd_child(err), "error-path", &match);
schema = lys_find_path(NULL, err->schema, "error-path", 0);
if (schema) {
lyd_find_sibling_val(lyd_child(err), schema, NULL, 0, &match);
}
if (match) {
return ((struct lyd_node_opaq *)match)->value;
return lyd_get_value(match);
}
return NULL;
@ -574,21 +613,37 @@ nc_err_get_path(const struct lyd_node *err)
API int
nc_err_set_msg(struct lyd_node *err, const char *error_message, const char *lang)
{
struct lyd_node *match;
struct lyd_node *match, *prev_anchor;
struct lyd_attr *attr;
NC_CHECK_ARG_RET(NULL, err, error_message, -1);
/* remove previous node */
lyd_find_sibling_opaq_next(lyd_child(err), "error-message", &match);
if (match) {
/* Change the value of error-message and keep order of elements to comply with appendix-B in RFC 6241. */
lydict_remove(LYD_CTX(err), ((struct lyd_node_opaq *)match)->value);
lydict_insert(LYD_CTX(err), error_message, 0, &(((struct lyd_node_opaq *)match)->value));
return 0;
lyd_free_tree(match);
}
/* find the previous node anchor (last non-opaque node) */
prev_anchor = lyd_child(err);
while (prev_anchor && prev_anchor->next && prev_anchor->next->schema) {
prev_anchor = prev_anchor->next;
}
if (!prev_anchor->schema) {
prev_anchor = NULL;
}
/* create the node at the right place */
if (lyd_new_opaq2(err, NULL, "error-message", error_message, NULL, NC_NS_BASE, &match)) {
return -1;
}
if (prev_anchor) {
lyd_insert_after(prev_anchor, match);
} else if (match->prev != match) {
/* some opaque nodes existed, this must be the first */
lyd_insert_before(lyd_child(err), match);
}
if (lang && lyd_new_attr(match, NULL, "xml:lang", lang, &attr)) {
lyd_free_tree(match);
return -1;
@ -733,6 +788,16 @@ nc_server_rpc_free(struct nc_server_rpc *rpc)
free(rpc);
}
API NC_RPL
nc_server_reply_type(struct nc_server_reply *reply)
{
if (!reply) {
return 0;
}
return reply->type;
}
API void
nc_server_reply_free(struct nc_server_reply *reply)
{
@ -747,7 +812,7 @@ nc_server_reply_free(struct nc_server_reply *reply)
case NC_RPL_DATA:
data_rpl = (struct nc_server_reply_data *)reply;
if (data_rpl->free) {
lyd_free_siblings(data_rpl->data);
lyd_free_all(data_rpl->data);
}
break;
case NC_RPL_OK:
@ -766,7 +831,7 @@ nc_server_reply_free(struct nc_server_reply *reply)
API struct nc_server_notif *
nc_server_notif_new(struct lyd_node *event, char *eventtime, NC_PARAMTYPE paramtype)
{
struct nc_server_notif *ntf;
struct nc_server_notif *ntf = NULL;
struct lyd_node *elem;
int found;
@ -791,9 +856,10 @@ nc_server_notif_new(struct lyd_node *event, char *eventtime, NC_PARAMTYPE paramt
if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
ntf->eventtime = strdup(eventtime);
NC_CHECK_ERRMEM_GOTO(!ntf->eventtime, , error);
if (lyd_dup_single(event, NULL, LYD_DUP_RECURSIVE, &ntf->ntf)) {
free(ntf);
return NULL;
goto error;
}
} else {
ntf->eventtime = eventtime;
@ -802,6 +868,11 @@ nc_server_notif_new(struct lyd_node *event, char *eventtime, NC_PARAMTYPE paramt
ntf->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
return ntf;
error:
free(ntf->eventtime);
free(ntf);
return NULL;
}
API void

View file

@ -210,7 +210,7 @@ const char *nc_err_get_app_tag(const struct lyd_node *err);
* @brief Set the \<error-path\> element of an error. Any previous value will be overwritten.
*
* @param[in] err Error opaque data node tree to modify.
* @param[in] error_path New value of \<error-path\>.
* @param[in] error_path New value of \<error-path\> in JSON format.
* @return 0 on success, -1 on error.
*/
int nc_err_set_path(struct lyd_node *err, const char *error_path);
@ -286,6 +286,14 @@ int nc_err_add_bad_ns(struct lyd_node *err, const char *ns_name);
*/
int nc_err_add_info_other(struct lyd_node *err, struct lyd_node *other);
/**
* @brief Get server reply message type.
*
* @param[in] reply Server rpc-reply object to analyze.
* @return Reply type.
*/
NC_RPL nc_server_reply_type(struct nc_server_reply *reply);
/**
* @brief Free a server rpc-reply object.
*

View file

@ -1,10 +1,11 @@
/**
* @file netconf.h
* @author Radek Krejci <rkrejci@cesnet.cz>
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief libnetconf2's general public functions and structures definitions.
*
* @copyright
* Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
* Copyright (c) 2015 - 2025 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
@ -51,7 +52,7 @@ extern "C" {
/**
* @brief Enumeration of reasons of the NETCONF session termination as defined in RFC 6470.
*/
typedef enum NC_SESSION_TERM_REASON {
typedef enum {
NC_SESSION_TERM_ERR = -1, /**< error return code for function getting the session termination reason */
NC_SESSION_TERM_NONE = 0, /**< session still running */
NC_SESSION_TERM_CLOSED, /**< closed by client in a normal fashion */
@ -65,7 +66,7 @@ typedef enum NC_SESSION_TERM_REASON {
/**
* @brief Enumeration of NETCONF message types.
*/
typedef enum NC_MSG_TYPE {
typedef enum {
NC_MSG_ERROR, /**< error return value */
NC_MSG_WOULDBLOCK, /**< timeout return value */
NC_MSG_NONE, /**< no message at input or message was processed internally */
@ -85,7 +86,7 @@ extern const char *nc_msgtype2str[];
/**
* @brief Enumeration of the supported types of datastores defined by NETCONF
*/
typedef enum NC_DATASTORE_TYPE {
typedef enum {
NC_DATASTORE_ERROR = 0, /**< error state of functions returning the datastore type */
NC_DATASTORE_CONFIG, /**< value describing that the datastore is set as config */
NC_DATASTORE_URL, /**< value describing that the datastore data should be given from the URL */
@ -97,7 +98,7 @@ typedef enum NC_DATASTORE_TYPE {
/**
* @brief Enumeration of NETCONF with-defaults capability modes.
*/
typedef enum NC_WITHDEFAULTS_MODE {
typedef enum {
NC_WD_UNKNOWN = 0, /**< invalid mode */
NC_WD_ALL, /**< report-all mode */
NC_WD_ALL_TAG, /**< report-all-tagged mode */
@ -108,7 +109,7 @@ typedef enum NC_WITHDEFAULTS_MODE {
/**
* @brief Enumeration of NETCONF (both server and client) rpc-reply types.
*/
typedef enum NC_REPLY {
typedef enum {
NC_RPL_OK, /**< OK rpc-reply */
NC_RPL_DATA, /**< DATA rpc-reply */
NC_RPL_ERROR, /**< ERROR rpc-reply */
@ -118,7 +119,7 @@ typedef enum NC_REPLY {
/**
* @brief Enumeration of function parameter treatments.
*/
typedef enum NC_PARAMTYPE {
typedef enum {
NC_PARAMTYPE_CONST, /**< use the parameter directly, do not free */
NC_PARAMTYPE_FREE, /**< use the parameter directly, free afterwards */
NC_PARAMTYPE_DUP_AND_FREE /**< make a copy of the argument, free afterwards */

View file

@ -2617,6 +2617,14 @@ nc_server_config_encryption_alg(const struct lyd_node *node, enum nc_operation o
/* get the algorithm name and append it to supported algs */
alg = ((struct lyd_node_term *)node)->value.ident->name;
/* YANG IDs cannot begin with a number, need to convert them to the correct form */
if (!strcmp(alg, "triple-des-cbc")) {
alg = "3des-cbc";
} else if (!strcmp(alg, "triple-des-ctr")) {
alg = "3des-ctr";
}
if (nc_server_config_transport_params(alg, &opts->encryption_algs, op)) {
ret = 1;
goto cleanup;
@ -3224,7 +3232,7 @@ nc_server_config_create_cert_to_name(const struct lyd_node *node, struct nc_serv
assert(!strcmp(LYD_NAME(node), "cert-to-name"));
/* find the list's key */
/* find the list's key - ignore result using assert of reference argument instead */
lyd_find_path(node, "id", 0, &n);
assert(n);
id = ((struct lyd_node_term *)n)->value.uint32;
@ -4006,13 +4014,20 @@ nc_server_config_parse_netconf_server(const struct lyd_node *node, enum nc_opera
}
int
nc_server_config_ln2_netconf_server(const struct lyd_node *node, enum nc_operation op)
nc_server_config_ln2_netconf_server(const struct lyd_node *UNUSED(node), enum nc_operation op)
{
(void) node;
uint32_t i;
assert((op == NC_OP_CREATE) || (op == NC_OP_DELETE));
if (op == NC_OP_DELETE) {
/* delete ignored modules */
for (i = 0; i < server_opts.ignored_mod_count; ++i) {
free(server_opts.ignored_modules[i]);
}
free(server_opts.ignored_modules);
server_opts.ignored_modules = NULL;
server_opts.ignored_mod_count = 0;
#ifdef NC_ENABLED_SSH_TLS
/* delete the intervals */
@ -4155,6 +4170,45 @@ cleanup:
#endif /* NC_ENABLED_SSH_TLS */
static int
nc_server_config_ignored_module(const struct lyd_node *node, enum nc_operation op)
{
int ret = 0;
const char *mod_name;
uint16_t i;
assert(!strcmp(LYD_NAME(node), "ignored-hello-module"));
mod_name = lyd_get_value(node);
if (op == NC_OP_CREATE) {
/* add the module */
ret = nc_server_config_realloc(mod_name, (void **)&server_opts.ignored_modules,
sizeof *server_opts.ignored_modules, &server_opts.ignored_mod_count);
} else {
/* find the module */
for (i = 0; i < server_opts.ignored_mod_count; ++i) {
if (!strcmp(server_opts.ignored_modules[i], mod_name)) {
break;
}
}
assert(i < server_opts.ignored_mod_count);
/* remove the module by replacing it with the last */
free(server_opts.ignored_modules[i]);
if (i < server_opts.ignored_mod_count - 1) {
server_opts.ignored_modules[i] = server_opts.ignored_modules[server_opts.ignored_mod_count - 1];
}
--server_opts.ignored_mod_count;
if (!server_opts.ignored_mod_count) {
free(server_opts.ignored_modules);
server_opts.ignored_modules = NULL;
}
}
return ret;
}
static int
nc_server_config_parse_libnetconf2_netconf_server(const struct lyd_node *node, enum nc_operation op)
{
@ -4169,6 +4223,9 @@ nc_server_config_parse_libnetconf2_netconf_server(const struct lyd_node *node, e
ret = nc_server_config_interval(node, op);
}
#endif /* NC_ENABLED_SSH_TLS */
else if (!strcmp(name, "ignored-hello-module")) {
ret = nc_server_config_ignored_module(node, op);
}
if (ret) {
ERR(NULL, "Configuring node \"%s\" failed.", LYD_NAME(node));

View file

@ -29,8 +29,13 @@
#include "log_p.h"
#include "session.h"
#include "session_p.h"
#ifdef NC_ENABLED_SSH_TLS
#include "session_wrapper.h"
#endif /* NC_ENABLED_SSH_TLS */
int
nc_server_config_create(const struct ly_ctx *ctx, struct lyd_node **tree, const char *value, const char *path_fmt, ...)
{

View file

@ -498,11 +498,18 @@ _nc_server_config_add_ssh_user_password(const struct ly_ctx *ctx, const char *tr
int ret = 0;
char *hashed_pw = NULL;
const char *salt = "$6$idsizuippipk$";
struct crypt_data cdata = {0};
struct crypt_data *cdata = NULL;
NC_CHECK_ARG_RET(NULL, ctx, tree_path, password, config, 1);
hashed_pw = crypt_r(password, salt, &cdata);
cdata = (struct crypt_data *) calloc(sizeof(struct crypt_data), 1);
if (cdata == NULL) {
ERR(NULL, "Allocation of crypt_data struct failed.");
ret = 1;
goto cleanup;
}
hashed_pw = crypt_r(password, salt, cdata);
if (!hashed_pw) {
ERR(NULL, "Hashing password failed (%s).", strerror(errno));
ret = 1;
@ -515,6 +522,7 @@ _nc_server_config_add_ssh_user_password(const struct ly_ctx *ctx, const char *tr
}
cleanup:
free(cdata);
return ret;
}

View file

@ -37,9 +37,10 @@
#ifdef NC_ENABLED_SSH_TLS
#include "session_wrapper.h"
#include <curl/curl.h>
#include <libssh/libssh.h>
#include "session_wrapper.h"
#endif /* NC_ENABLED_SSH_TLS */
@ -880,8 +881,25 @@ nc_session_free(struct nc_session *session, void (*data_free)(void *))
struct ly_in *msg;
struct timespec ts;
void *p;
NC_STATUS status;
if (!session || (session->status == NC_STATUS_CLOSING)) {
if (!session) {
return;
}
if ((session->side == NC_SERVER) && (session->flags & NC_SESSION_CALLHOME)) {
/* CH LOCK */
pthread_mutex_lock(&session->opts.server.ch_lock);
}
status = session->status;
if ((session->side == NC_SERVER) && (session->flags & NC_SESSION_CALLHOME)) {
/* CH UNLOCK */
pthread_mutex_unlock(&session->opts.server.ch_lock);
}
if (status == NC_STATUS_CLOSING) {
return;
}
@ -948,7 +966,7 @@ nc_session_free(struct nc_session *session, void (*data_free)(void *))
nc_session_client_msgs_unlock(session, __func__);
}
if (session->status == NC_STATUS_RUNNING) {
if ((session->status == NC_STATUS_RUNNING) && nc_session_is_connected(session)) {
/* receive any leftover messages */
while (nc_read_msg_poll_io(session, 0, &msg) == 1) {
ly_in_free(msg, 1);
@ -1117,8 +1135,6 @@ nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version)
cpblts[1] = strdup("urn:ietf:params:netconf:base:1.1");
count = 2;
/* capabilities */
mod = ly_ctx_get_module_implemented(ctx, "ietf-netconf");
if (mod) {
if (lys_feature_value(mod, "writable-running") == LY_SUCCESS) {
@ -1153,11 +1169,15 @@ nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version)
}
}
/* HELLO LOCK */
pthread_rwlock_rdlock(&server_opts.hello_lock);
mod = ly_ctx_get_module_implemented(ctx, "ietf-netconf-with-defaults");
if (mod) {
wd_basic_mode = ATOMIC_LOAD_RELAXED(server_opts.wd_basic_mode);
wd_basic_mode = server_opts.wd_basic_mode;
if (!wd_basic_mode) {
VRB(NULL, "with-defaults capability will not be advertised even though \"ietf-netconf-with-defaults\" model is present, unknown basic-mode.");
VRB(NULL, "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:capability:with-defaults:1.0");
switch (wd_basic_mode) {
@ -1172,10 +1192,10 @@ nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version)
break;
default:
ERRINT;
break;
goto unlock_error;
}
wd_also_supported = ATOMIC_LOAD_RELAXED(server_opts.wd_also_supported);
wd_also_supported = server_opts.wd_also_supported;
if (wd_also_supported) {
strcat(str, "&also-supported=");
if (wd_also_supported & NC_WD_ALL) {
@ -1205,10 +1225,15 @@ nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version)
/* models */
u = 0;
while ((mod = ly_ctx_get_module_iter(ctx, &u))) {
if (nc_server_is_mod_ignored(mod->name)) {
/* ignored, not part of the cababilities */
continue;
}
if (!strcmp(mod->name, "ietf-yang-library")) {
if (!mod->revision || (strcmp(mod->revision, "2016-06-21") && strcmp(mod->revision, "2019-01-04"))) {
ERR(NULL, "Unknown \"ietf-yang-library\" revision, only 2016-06-21 and 2019-01-04 are supported.");
goto error;
goto unlock_error;
}
/* get content-id */
@ -1293,11 +1318,18 @@ nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version)
add_cpblt(str, &cpblts, &size, &count);
}
/* HELLO UNLOCK */
pthread_rwlock_unlock(&server_opts.hello_lock);
/* ending NULL capability */
add_cpblt(NULL, &cpblts, &size, &count);
return cpblts;
unlock_error:
/* HELLO UNLOCK */
pthread_rwlock_unlock(&server_opts.hello_lock);
error:
free(cpblts);
return NULL;

View file

@ -1749,7 +1749,7 @@ nc_sock_connect(const char *src_addr, uint16_t src_port, const char *dst_addr, u
hints.ai_protocol = IPPROTO_TCP;
i = getaddrinfo(dst_addr, dst_port_str, &hints, &res_list);
if (i != 0) {
ERR(NULL, "Unable to translate the host address (%s).", gai_strerror(i));
ERR(NULL, "Unable to translate the host address \"%s\" (%s).", dst_addr, gai_strerror(i));
goto error;
}
@ -2006,6 +2006,10 @@ nc_client_init(void)
}
#ifdef NC_ENABLED_SSH_TLS
if (nc_tls_backend_init_wrap()) {
ERR(NULL, "%s: failed to init the SSL library backend.", __func__);
return -1;
}
if (ssh_init()) {
ERR(NULL, "%s: failed to init libssh.", __func__);
return -1;
@ -2024,6 +2028,7 @@ nc_client_destroy(void)
nc_client_ch_del_bind(NULL, 0, 0);
nc_client_ssh_destroy_opts();
nc_client_tls_destroy_opts();
nc_tls_backend_destroy_wrap();
ssh_finalize();
#endif /* NC_ENABLED_SSH_TLS */
}

View file

@ -52,29 +52,79 @@
#include <mbedtls/x509_crt.h>
/**
* @brief Converts mbedTLS error codes to a string.
* @brief Converts MbedTLS error code to a string and merges it with an arbitrary error message.
*
* Some mbedTLS functions may return 'high' and some 'low' level errors, try to handle both cases this way.
*
* @param[in] err MbedTLS error code.
* @return Error string.
* @param[in] session NETCONF session.
* @param[in] mbedtls_err_code MbedTLS error code.
* @param[in] orig_err_msg_fmt Original error message format string.
* @param[in] ... Additional arguments for the original error message.
*/
static const char *
nc_get_mbedtls_str_err(int err)
static void
nc_mbedtls_strerr(const struct nc_session *session, int mbedtls_err_code, const char *orig_err_msg_fmt, ...)
{
const char *err_str;
va_list args;
char *err_buf = NULL, *err_msg_fmt = NULL;
size_t err_buf_len = 0, err_msg_fmt_len = 0;
const char *high_err_str, *low_err_str;
err_str = mbedtls_high_level_strerr(err);
if (err_str) {
return err_str;
va_start(args, orig_err_msg_fmt);
/* get the length of the error strings */
high_err_str = mbedtls_high_level_strerr(mbedtls_err_code);
low_err_str = mbedtls_low_level_strerr(mbedtls_err_code);
if (high_err_str) {
err_buf_len += strlen(high_err_str);
}
if (low_err_str) {
err_buf_len += strlen(low_err_str);
}
if (!err_buf_len) {
/* just print the original error message */
nc_log_vprintf(session, NC_VERB_ERROR, orig_err_msg_fmt, args);
goto cleanup;
}
err_str = mbedtls_low_level_strerr(err);
if (err_str) {
return err_str;
if (high_err_str && low_err_str) {
/* for a colon and 2 spaces */
err_buf_len += 3;
}
return "unknown error";
/* allocate the mbedtls error buffer */
err_buf = malloc(err_buf_len + 1);
if (!err_buf) {
/* just print the original error message */
nc_log_vprintf(session, NC_VERB_ERROR, orig_err_msg_fmt, args);
goto cleanup;
}
/* fill the error buffer and print it */
if (high_err_str && low_err_str) {
snprintf(err_buf, err_buf_len + 1, "%s : %s", high_err_str, low_err_str);
} else if (high_err_str) {
snprintf(err_buf, err_buf_len + 1, "%s", high_err_str);
} else {
snprintf(err_buf, err_buf_len + 1, "%s", low_err_str);
}
/* allocate the new error format string buffer, err_msg = "orig_err_msg (MbedTLS err)." */
err_msg_fmt_len = strlen(orig_err_msg_fmt) + strlen(" (") + strlen(err_buf) + strlen(").");
err_msg_fmt = malloc(err_msg_fmt_len + 1);
if (!err_msg_fmt) {
/* just print the original error message */
nc_log_vprintf(session, NC_VERB_ERROR, orig_err_msg_fmt, args);
goto cleanup;
}
/* fill the new error format string */
snprintf(err_msg_fmt, err_msg_fmt_len + 1, "%s (%s).", orig_err_msg_fmt, err_buf);
/* print the error message */
nc_log_vprintf(session, NC_VERB_ERROR, err_msg_fmt, args);
cleanup:
va_end(args);
free(err_msg_fmt);
free(err_buf);
}
/**
@ -100,7 +150,7 @@ nc_server_tls_dn2str(const mbedtls_x509_name *dn)
}
if (r < 1) {
free(str);
ERR(NULL, "Failed to convert DN to string (%s).", nc_get_mbedtls_str_err(r));
nc_mbedtls_strerr(NULL, r, "Failed to convert DN to string");
return NULL;
}
@ -132,7 +182,7 @@ nc_tls_rng_new(mbedtls_ctr_drbg_context **ctr_drbg, mbedtls_entropy_context **en
rc = mbedtls_ctr_drbg_seed(*ctr_drbg, mbedtls_entropy_func, *entropy, NULL, 0);
if (rc) {
ERR(NULL, "Seeding ctr_drbg failed (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Seeding ctr_drbg failed");
goto fail;
}
@ -194,6 +244,27 @@ nc_tls_get_verify_err_str(int err)
return err_buf;
}
int
nc_tls_backend_init_wrap(void)
{
int r;
r = psa_crypto_init();
if (r) {
nc_mbedtls_strerr(NULL, r, "Failed to initialize PSA crypto");
return -1;
}
return 0;
}
void
nc_tls_backend_destroy_wrap(void)
{
mbedtls_psa_crypto_free();
}
void *
nc_tls_session_new_wrap(void *tls_cfg)
{
@ -207,7 +278,7 @@ nc_tls_session_new_wrap(void *tls_cfg)
rc = mbedtls_ssl_setup(session, tls_cfg);
if (rc) {
ERR(NULL, "Setting up TLS session failed (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Setting up TLS session failed");
mbedtls_ssl_free(session);
free(session);
return NULL;
@ -335,7 +406,7 @@ nc_tls_pem_to_cert_wrap(const char *cert_data)
rc = mbedtls_x509_crt_parse(cert, (const unsigned char *)cert_data, strlen(cert_data) + 1);
if (rc) {
ERR(NULL, "Parsing certificate data failed (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Parsing certificate data failed");
nc_tls_cert_destroy_wrap(cert);
return NULL;
}
@ -379,7 +450,7 @@ nc_tls_pem_to_privkey_wrap(const char *privkey_data)
rc = mbedtls_pk_parse_key(pkey, (const unsigned char *)privkey_data, strlen(privkey_data) + 1, NULL, 0, mbedtls_ctr_drbg_random, ctr_drbg);
if (rc) {
ERR(NULL, "Parsing private key data failed (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Parsing private key data failed");
goto cleanup;
}
@ -755,7 +826,7 @@ nc_server_tls_md5_wrap(void *cert, unsigned char *buf)
rc = mbedtls_md5(c->raw.p, c->raw.len, buf);
if (rc) {
ERR(NULL, "Calculating MD5 digest failed (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Calculating MD5 digest failed");
return 1;
}
@ -770,7 +841,7 @@ nc_server_tls_sha1_wrap(void *cert, unsigned char *buf)
rc = mbedtls_sha1(c->raw.p, c->raw.len, buf);
if (rc) {
ERR(NULL, "Calculating SHA-1 digest failed (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Calculating SHA-1 digest failed");
return 1;
}
@ -785,7 +856,7 @@ nc_server_tls_sha224_wrap(void *cert, unsigned char *buf)
rc = mbedtls_sha256(c->raw.p, c->raw.len, buf, 1);
if (rc) {
ERR(NULL, "Calculating SHA-224 digest failed (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Calculating SHA-224 digest failed");
return 1;
}
@ -800,7 +871,7 @@ nc_server_tls_sha256_wrap(void *cert, unsigned char *buf)
rc = mbedtls_sha256(c->raw.p, c->raw.len, buf, 0);
if (rc) {
ERR(NULL, "Calculating SHA-256 digest failed (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Calculating SHA-256 digest failed");
return 1;
}
@ -815,7 +886,7 @@ nc_server_tls_sha384_wrap(void *cert, unsigned char *buf)
rc = mbedtls_sha512(c->raw.p, c->raw.len, buf, 1);
if (rc) {
ERR(NULL, "Calculating SHA-384 digest failed (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Calculating SHA-384 digest failed");
return 1;
}
@ -830,7 +901,7 @@ nc_server_tls_sha512_wrap(void *cert, unsigned char *buf)
rc = mbedtls_sha512(c->raw.p, c->raw.len, buf, 0);
if (rc) {
ERR(NULL, "Calculating SHA-512 digest failed (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Calculating SHA-512 digest failed");
return 1;
}
@ -979,7 +1050,7 @@ nc_tls_import_privkey_file_wrap(const char *privkey_path)
rc = mbedtls_pk_parse_keyfile(pkey, privkey_path, NULL, mbedtls_ctr_drbg_random, ctr_drbg);
nc_tls_rng_destroy(ctr_drbg, entropy);
if (rc) {
ERR(NULL, "Parsing private key from file \"%s\" failed (%s).", privkey_path, nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Parsing private key from file \"%s\" failed", privkey_path);
nc_tls_privkey_destroy_wrap(pkey);
return NULL;
}
@ -1002,7 +1073,7 @@ nc_client_tls_load_cert_key_wrap(const char *cert_path, const char *key_path, vo
ret = mbedtls_x509_crt_parse_file(c, cert_path);
if (ret) {
ERR(NULL, "Parsing certificate from file \"%s\" failed (%s).", cert_path, nc_get_mbedtls_str_err(ret));
nc_mbedtls_strerr(NULL, ret, "Parsing certificate from file \"%s\" failed", cert_path);
goto cleanup;
}
@ -1027,12 +1098,12 @@ nc_client_tls_load_trusted_certs_wrap(void *cert_store, const char *file_path, c
int rc;
if (file_path && ((rc = mbedtls_x509_crt_parse_file(cert_store, file_path)) < 0)) {
ERR(NULL, "Loading CA certificate from file \"%s\" failed (%s).", file_path, nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Loading CA certificate from file \"%s\" failed", file_path);
return 1;
}
if (dir_path && ((rc = mbedtls_x509_crt_parse_path(cert_store, dir_path)) < 0)) {
ERR(NULL, "Loading CA certificate from directory \"%s\" failed (%s).", dir_path, nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Loading CA certificate from directory \"%s\" failed", dir_path);
return 1;
}
@ -1046,7 +1117,7 @@ nc_client_tls_set_hostname_wrap(void *tls_session, const char *hostname)
rc = mbedtls_ssl_set_hostname(tls_session, hostname);
if (rc) {
ERR(NULL, "Setting hostname failed (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Setting hostname failed");
return 1;
}
@ -1083,7 +1154,7 @@ nc_tls_setup_config_from_ctx_wrap(struct nc_tls_ctx *tls_ctx, int side, void *tl
rc = mbedtls_ssl_config_defaults(tls_cfg, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
}
if (rc) {
ERR(NULL, "Setting default TLS config failed (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Setting default TLS config failed");
return 1;
}
@ -1111,25 +1182,17 @@ nc_tls_verify_error_string_wrap(uint32_t err_code)
void
nc_client_tls_print_connect_err_wrap(int connect_ret, const char *peername, void *UNUSED(tls_session))
{
const char *err = nc_get_mbedtls_str_err(connect_ret);
if (err) {
ERR(NULL, "TLS connection to \"%s\" failed (%s).", peername, err);
if (peername) {
nc_mbedtls_strerr(NULL, connect_ret, "TLS connect to host \"%s\" failed", peername);
} else {
ERR(NULL, "TLS connection to \"%s\" failed.", peername);
nc_mbedtls_strerr(NULL, connect_ret, "TLS connect to an unknown host failed");
}
}
void
nc_server_tls_print_accept_err_wrap(int accept_ret, void *UNUSED(tls_session))
{
const char *err = nc_get_mbedtls_str_err(accept_ret);
if (err) {
ERR(NULL, "TLS accept failed (%s).", err);
} else {
ERR(NULL, "TLS accept failed.");
}
nc_mbedtls_strerr(NULL, accept_ret, "TLS accept failed");
}
int
@ -1158,7 +1221,7 @@ nc_base64_decode_wrap(const char *base64, unsigned char **bin)
/* get the size of the decoded data */
rc = mbedtls_base64_decode(NULL, 0, &size, (const unsigned char *)base64, strlen(base64));
if (rc != MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) {
ERR(NULL, "Base64 decoding failed (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Base64 decoding failed");
return -1;
}
@ -1168,7 +1231,7 @@ nc_base64_decode_wrap(const char *base64, unsigned char **bin)
/* decode */
rc = mbedtls_base64_decode(*bin, size, &size, (const unsigned char *)base64, strlen(base64));
if (rc) {
ERR(NULL, "Base64 decoding failed (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Base64 decoding failed");
free(*bin);
*bin = NULL;
return -1;
@ -1185,7 +1248,7 @@ nc_base64_encode_wrap(const unsigned char *bin, size_t len, char **base64)
rc = mbedtls_base64_encode(NULL, 0, &size, bin, len);
if (rc != MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) {
ERR(NULL, "Base64 encoding failed (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Base64 encoding failed");
return -1;
}
@ -1194,7 +1257,7 @@ nc_base64_encode_wrap(const unsigned char *bin, size_t len, char **base64)
rc = mbedtls_base64_encode((unsigned char *)*base64, size, &size, bin, len);
if (rc) {
ERR(NULL, "Base64 encoding failed (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Base64 encoding failed");
free(*base64);
*base64 = NULL;
return -1;
@ -1217,13 +1280,13 @@ nc_tls_read_wrap(struct nc_session *session, unsigned char *buf, size_t size)
rc = 0;
break;
case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
ERR(session, "Communication socket unexpectedly closed (MbedTLS).");
nc_mbedtls_strerr(session, rc, "Communication socket unexpectedly closed");
session->status = NC_STATUS_INVALID;
session->term_reason = NC_SESSION_TERM_DROPPED;
rc = -1;
break;
default:
ERR(session, "TLS communication error occurred (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(session, rc, "TLS communication error occurred");
session->status = NC_STATUS_INVALID;
session->term_reason = NC_SESSION_TERM_OTHER;
rc = -1;
@ -1248,11 +1311,11 @@ nc_tls_write_wrap(struct nc_session *session, const unsigned char *buf, size_t s
rc = 0;
break;
case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
ERR(session, "TLS connection was properly closed.");
nc_mbedtls_strerr(session, rc, "TLS connection was properly closed.");
rc = -1;
break;
default:
ERR(session, "TLS communication error occurred (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(session, rc, "TLS communication error occurred");
rc = -1;
break;
}
@ -1281,7 +1344,7 @@ nc_tls_close_notify_wrap(void *tls_session)
while ((rc = mbedtls_ssl_close_notify(tls_session))) {
if ((rc != MBEDTLS_ERR_SSL_WANT_READ) && (rc != MBEDTLS_ERR_SSL_WANT_WRITE)) {
/* some error occurred */
ERR(NULL, "Sending TLS close notify failed (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Sending TLS close notify failed");
return;
}
}
@ -1300,7 +1363,7 @@ nc_tls_import_cert_file_wrap(const char *cert_path)
rc = mbedtls_x509_crt_parse_file(c, cert_path);
if (rc) {
ERR(NULL, "Parsing certificate from file \"%s\" failed (%s).", cert_path, nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Parsing certificate from file \"%s\" failed", cert_path);
nc_tls_cert_destroy_wrap(c);
return NULL;
}
@ -1324,7 +1387,7 @@ nc_tls_export_privkey_pem_wrap(void *pkey)
NC_CHECK_ERRMEM_RET(!pem, NULL);
}
if (rc < 0) {
ERR(NULL, "Exporting private key to PEM format failed (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Exporting private key to PEM format failed");
free(pem);
return NULL;
}
@ -1369,7 +1432,7 @@ nc_tls_export_pubkey_pem_wrap(void *pkey)
NC_CHECK_ERRMEM_RET(!pem, NULL);
}
if (rc < 0) {
ERR(NULL, "Exporting public key to PEM format failed (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Exporting public key to PEM format failed");
free(pem);
return NULL;
}
@ -1399,7 +1462,7 @@ nc_tls_get_rsa_pubkey_params_wrap(void *pkey, void **e, void **n)
mbedtls_mpi_init(mod);
if ((rc = mbedtls_rsa_export(mbedtls_pk_rsa(*(mbedtls_pk_context *)pkey), mod, NULL, NULL, NULL, exp))) {
ERR(NULL, "Failed to export RSA public key parameters (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Failed to export RSA public key parameters");
goto fail;
}
@ -1468,7 +1531,7 @@ nc_tls_get_ec_pubkey_params_wrap(void *pkey, void **q, void **q_grp)
/* get the group and public key */
ret = mbedtls_ecp_export(mbedtls_pk_ec(*(mbedtls_pk_context *)pkey), grp, d, p);
if (ret) {
ERR(NULL, "Failed to export EC public key parameters (%s).", nc_get_mbedtls_str_err(ret));
nc_mbedtls_strerr(NULL, ret, "Failed to export EC private key parameters");
ret = 1;
goto cleanup;
}
@ -1507,7 +1570,7 @@ nc_tls_ec_point_to_bin_wrap(void *q, void *q_grp, unsigned char **bin, int *bin_
NC_CHECK_ERRMEM_RET(!buf, 1);
}
if (rc) {
ERR(NULL, "Failed to write EC public key binary (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Failed to write EC public key binary");
free(buf);
return 1;
}
@ -1544,7 +1607,7 @@ nc_tls_mpi2bin_wrap(void *mpi, unsigned char **bin, int *bin_len)
rc = mbedtls_mpi_write_binary(mpi, buf, buf_len);
if (rc) {
ERR(NULL, "Failed to convert MPI to binary (%s).", nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Failed to convert MPI to binary");
free(buf);
return 1;
}
@ -1567,7 +1630,7 @@ nc_tls_import_pubkey_file_wrap(const char *pubkey_path)
rc = mbedtls_pk_parse_public_keyfile(pk, pubkey_path);
if (rc) {
ERR(NULL, "Parsing public key from file \"%s\" failed (%s).", pubkey_path, nc_get_mbedtls_str_err(rc));
nc_mbedtls_strerr(NULL, rc, "Parsing public key from file \"%s\" failed", pubkey_path);
nc_tls_privkey_destroy_wrap(pk);
return NULL;
}
@ -1608,7 +1671,7 @@ nc_server_tls_parse_crl_dist_points(unsigned char **p, size_t len, char ***uris,
*/
ret = mbedtls_asn1_get_tag(p, end_crl_dist_points, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
if (ret) {
ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
nc_mbedtls_strerr(NULL, ret, "Failed to parse CRL distribution points extension");
goto cleanup;
}
if (!len) {
@ -1631,7 +1694,7 @@ nc_server_tls_parse_crl_dist_points(unsigned char **p, size_t len, char ***uris,
ERR(NULL, "Failed to parse CRL distribution points extension (nameRelativeToCRLIssuer not yet supported).");
goto cleanup;
} else {
ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
nc_mbedtls_strerr(NULL, ret, "Failed to parse CRL distribution points extension");
goto cleanup;
}
}
@ -1640,7 +1703,7 @@ nc_server_tls_parse_crl_dist_points(unsigned char **p, size_t len, char ***uris,
end_general_names = *p + len;
ret = mbedtls_asn1_get_tag(p, end_general_names, &name_len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
if (ret) {
ERR(NULL, "Failed to parse GeneralNames in CRL distribution points extension (%s)", nc_get_mbedtls_str_err(ret));
nc_mbedtls_strerr(NULL, ret, "Failed to parse CRL distribution points extension");
goto cleanup;
}
@ -1665,8 +1728,7 @@ nc_server_tls_parse_crl_dist_points(unsigned char **p, size_t len, char ***uris,
*/
ret = mbedtls_asn1_get_tag(p, end_names, &name_len, MBEDTLS_ASN1_CONTEXT_SPECIFIC | (tag & MBEDTLS_ASN1_CONSTRUCTED) | tag_value);
if (ret) {
ERR(NULL, "Failed to parse GeneralName in CRL distribution points extension (%s).",
nc_get_mbedtls_str_err(ret));
nc_mbedtls_strerr(NULL, ret, "Failed to parse GeneralName in CRL distribution points extension");
goto cleanup;
}
@ -1699,7 +1761,7 @@ nc_server_tls_parse_crl_dist_points(unsigned char **p, size_t len, char ***uris,
} else if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
/* failed to parse it, but not because it's optional */
ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
nc_mbedtls_strerr(NULL, ret, "Failed to parse CRL distribution points extension");
goto cleanup;
}
}
@ -1754,7 +1816,7 @@ nc_server_tls_get_crl_distpoint_uris_wrap(void *leaf_cert, void *cert_store, cha
*/
ret = mbedtls_asn1_get_tag(&p, end_v3_ext, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
if (ret) {
ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
nc_mbedtls_strerr(NULL, ret, "Failed to parse CRL distribution points extension");
goto cleanup;
}
@ -1767,7 +1829,7 @@ nc_server_tls_get_crl_distpoint_uris_wrap(void *leaf_cert, void *cert_store, cha
*/
ret = mbedtls_asn1_get_tag(&p, end_v3_ext, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
if (ret) {
ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
nc_mbedtls_strerr(NULL, ret, "Failed to parse CRL distribution points extension");
goto cleanup;
}
@ -1776,7 +1838,7 @@ nc_server_tls_get_crl_distpoint_uris_wrap(void *leaf_cert, void *cert_store, cha
/* parse extnID */
ret = mbedtls_asn1_get_tag(&p, end_ext, &ext_oid.len, MBEDTLS_ASN1_OID);
if (ret) {
ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
nc_mbedtls_strerr(NULL, ret, "Failed to parse CRL distribution points extension");
goto cleanup;
}
ext_oid.tag = MBEDTLS_ASN1_OID;
@ -1793,14 +1855,14 @@ nc_server_tls_get_crl_distpoint_uris_wrap(void *leaf_cert, void *cert_store, cha
/* parse optional critical */
ret = mbedtls_asn1_get_bool(&p, end_ext, &is_critical);
if (ret && (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)) {
ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
nc_mbedtls_strerr(NULL, ret, "Failed to parse CRL distribution points extension");
goto cleanup;
}
/* parse extnValue */
ret = mbedtls_asn1_get_tag(&p, end_ext, &len, MBEDTLS_ASN1_OCTET_STRING);
if (ret) {
ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
nc_mbedtls_strerr(NULL, ret, "Failed to parse CRL distribution points extension");
goto cleanup;
}
@ -1813,12 +1875,12 @@ nc_server_tls_get_crl_distpoint_uris_wrap(void *leaf_cert, void *cert_store, cha
*/
ret = mbedtls_asn1_get_tag(&p, end_ext_octet, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
if (ret) {
ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
nc_mbedtls_strerr(NULL, ret, "Failed to parse CRL distribution points extension");
goto cleanup;
}
if (p + len != end_ext_octet) {
/* length mismatch */
ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
ERR(NULL, "Failed to parse CRL distribution points extension (length mismatch).");
goto cleanup;
} else if (!len) {
/* empty sequence, but size is 1..max */

View file

@ -44,6 +44,20 @@
#include <openssl/x509.h>
#include <openssl/x509v3.h>
int
nc_tls_backend_init_wrap(void)
{
/* nothing to do */
return 0;
}
void
nc_tls_backend_destroy_wrap(void)
{
/* nothing to do */
return;
}
void *
nc_tls_session_new_wrap(void *tls_cfg)
{

View file

@ -30,8 +30,13 @@
#include "session_client.h"
#include "session_server.h"
#include "session_server_ch.h"
#ifdef NC_ENABLED_SSH_TLS
#include "session_wrapper.h"
#endif /* NC_ENABLED_SSH_TLS */
extern struct nc_server_opts server_opts;
/**
@ -498,19 +503,27 @@ struct nc_ch_client_thread_arg {
};
struct nc_server_opts {
/* ACCESS unlocked */
ATOMIC_T wd_basic_mode;
ATOMIC_T wd_also_supported;
uint32_t capabilities_count;
/* ACCESS locked - hello lock - separate lock to not always hold config_lock */
char **ignored_modules; /**< Names of YANG modules that are not reported in the server <hello> message. */
uint16_t ignored_mod_count;
NC_WD_MODE wd_basic_mode; /**< With-defaults basic mode of the server. */
int wd_also_supported; /**< Bitmap of with-defaults modes that are also supported by the server. */
char **capabilities;
uint32_t capabilities_count;
char *(*content_id_clb)(void *user_data);
char *(*content_id_clb)(void *user_data); /**< Callback for generating content_id for ietf-yang-library data. */
void *content_id_data;
void (*content_id_data_free)(void *data);
pthread_rwlock_t hello_lock; /**< Needs to be held while the server <hello> message is being generated. */
/* ACCESS unlocked */
uint16_t idle_timeout;
/* ACCESS locked - options modified by YANG data/API - WRITE lock
* - options read when accepting sessions - READ lock */
pthread_rwlock_t config_lock;
#ifdef NC_ENABLED_SSH_TLS
char *authkey_path_fmt; /**< Path to users' public keys that may contain tokens with special meaning. */
char *pam_config_name; /**< PAM configuration file name. */
@ -521,13 +534,12 @@ struct nc_server_opts {
int (*user_verify_clb)(const struct nc_session *session);
#endif /* NC_ENABLED_SSH_TLS */
pthread_rwlock_t config_lock;
#ifdef NC_ENABLED_SSH_TLS
struct nc_keystore keystore; /**< store for server's keys/certificates */
struct nc_truststore truststore; /**< store for server client's keys/certificates */
struct nc_keystore keystore; /**< Server's keys/certificates. */
struct nc_truststore truststore; /**< Server client's keys/certificates. */
#endif /* NC_ENABLED_SSH_TLS */
/* ACCESS locked */
struct nc_bind *binds;
pthread_mutex_t bind_lock; /**< To avoid concurrent calls of poll and accept on the bound sockets **/
struct nc_endpt {
@ -607,11 +619,12 @@ struct nc_server_opts {
} ch_dispatch_data;
#endif /* NC_ENABLED_SSH_TLS */
/* Atomic IDs */
/* ACCESS unlocked */
ATOMIC_T new_session_id;
ATOMIC_T new_client_id;
#ifdef NC_ENABLED_SSH_TLS
/* ACCESS locked */
struct {
pthread_t tid; /**< Thread ID of the certificate expiration notification thread. */
int thread_running; /**< Flag representing the runningness of the cert exp notification thread. */
@ -628,7 +641,8 @@ struct nc_server_opts {
int interval_count; /**< Number of intervals. */
} cert_exp_notif;
FILE *tls_keylog_file; /**< File to log TLS secrets to. */
/* ACCESS unlocked */
FILE *tls_keylog_file; /**< File to log TLS secrets to. */
#endif
};
@ -1238,6 +1252,14 @@ int nc_session_tls_crl_from_cert_ext_fetch(void *leaf_cert, void *cert_store, vo
#endif /* NC_ENABLED_SSH_TLS */
/**
* @brief Check whether a module is not ignored by the server.
*
* @param[in] mod_name Module name to check.
* @return Whether the module is ignored.
*/
int nc_server_is_mod_ignored(const char *mod_name);
/**
* Functions
* - io.c

View file

@ -44,14 +44,18 @@
#include "session_p.h"
#include "session_server.h"
#include "session_server_ch.h"
#include "session_wrapper.h"
#ifdef NC_ENABLED_SSH_TLS
#include "session_wrapper.h"
#include <curl/curl.h>
#include <libssh/libssh.h>
#endif
#endif /* NC_ENABLED_SSH_TLS */
struct nc_server_opts server_opts = {
.hello_lock = PTHREAD_RWLOCK_INITIALIZER,
.config_lock = PTHREAD_RWLOCK_INITIALIZER,
.ch_client_lock = PTHREAD_RWLOCK_INITIALIZER,
.idle_timeout = 180, /**< default idle timeout (not in config for UNIX socket) */
@ -818,41 +822,62 @@ nc_server_keylog_file_open(void)
#endif
/**
* @brief Initialize a rwlock.
*
* @param[in] rwlock RW lock to initialize.
* @return errno.
*/
static int
nc_server_init_rwlock(pthread_rwlock_t *rwlock)
{
#ifdef HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP
int rc = 0;
pthread_rwlockattr_t attr;
if ((rc = pthread_rwlockattr_init(&attr))) {
ERR(NULL, "%s: failed to init attribute (%s).", __func__, strerror(rc));
return rc;
}
if ((rc = pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP))) {
ERR(NULL, "%s: failed to set attribute (%s).", __func__, strerror(rc));
goto cleanup;
}
if ((rc = pthread_rwlock_init(rwlock, &attr))) {
ERR(NULL, "%s: failed to init rwlock (%s).", __func__, strerror(rc));
goto cleanup;
}
cleanup:
pthread_rwlockattr_destroy(&attr);
return rc;
#else
int rc = 0;
if ((rc = pthread_rwlock_init(rwlock, NULL))) {
ERR(NULL, "%s: failed to init rwlock (%s).", __func__, strerror(rc));
}
return rc;
#endif
}
API int
nc_server_init(void)
{
pthread_rwlockattr_t *attr_p = NULL;
int r;
ATOMIC_STORE_RELAXED(server_opts.new_session_id, 1);
ATOMIC_STORE_RELAXED(server_opts.new_client_id, 1);
#ifdef HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP
pthread_rwlockattr_t attr;
if ((r = pthread_rwlockattr_init(&attr))) {
ERR(NULL, "%s: failed init attribute (%s).", __func__, strerror(r));
if (nc_server_init_rwlock(&server_opts.config_lock)) {
goto error;
}
attr_p = &attr;
if ((r = pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP))) {
ERR(NULL, "%s: failed set attribute (%s).", __func__, strerror(r));
if (nc_server_init_rwlock(&server_opts.ch_client_lock)) {
goto error;
}
#endif
if ((r = pthread_rwlock_init(&server_opts.config_lock, attr_p))) {
ERR(NULL, "%s: failed to init rwlock(%s).", __func__, strerror(r));
goto error;
}
if ((r = pthread_rwlock_init(&server_opts.ch_client_lock, attr_p))) {
ERR(NULL, "%s: failed to init rwlock(%s).", __func__, strerror(r));
goto error;
}
if (attr_p) {
pthread_rwlockattr_destroy(attr_p);
}
#ifdef NC_ENABLED_SSH_TLS
if (curl_global_init(CURL_GLOBAL_SSL | CURL_GLOBAL_ACK_EINTR)) {
@ -860,6 +885,11 @@ nc_server_init(void)
goto error;
}
if (nc_tls_backend_init_wrap()) {
ERR(NULL, "%s: failed to init the SSL library backend.", __func__);
return -1;
}
/* optional for dynamic library, mandatory for static */
if (ssh_init()) {
ERR(NULL, "%s: failed to init libssh.", __func__);
@ -889,9 +919,6 @@ nc_server_init(void)
return 0;
error:
if (attr_p) {
pthread_rwlockattr_destroy(attr_p);
}
return -1;
}
@ -942,6 +969,7 @@ nc_server_destroy(void)
nc_server_config_ks_keystore(NULL, NC_OP_DELETE);
nc_server_config_ts_truststore(NULL, NC_OP_DELETE);
curl_global_cleanup();
nc_tls_backend_destroy_wrap();
ssh_finalize();
/* close the TLS keylog file */
@ -962,8 +990,15 @@ nc_server_set_capab_withdefaults(NC_WD_MODE basic_mode, int also_supported)
return -1;
}
ATOMIC_STORE_RELAXED(server_opts.wd_basic_mode, basic_mode);
ATOMIC_STORE_RELAXED(server_opts.wd_also_supported, also_supported);
/* HELLO LOCK */
pthread_rwlock_wrlock(&server_opts.hello_lock);
server_opts.wd_basic_mode = basic_mode;
server_opts.wd_also_supported = also_supported;
/* HELLO UNLOCK */
pthread_rwlock_unlock(&server_opts.hello_lock);
return 0;
}
@ -975,12 +1010,18 @@ nc_server_get_capab_withdefaults(NC_WD_MODE *basic_mode, int *also_supported)
return;
}
/* HELLO LOCK */
pthread_rwlock_wrlock(&server_opts.hello_lock);
if (basic_mode) {
*basic_mode = ATOMIC_LOAD_RELAXED(server_opts.wd_basic_mode);
*basic_mode = server_opts.wd_basic_mode;
}
if (also_supported) {
*also_supported = ATOMIC_LOAD_RELAXED(server_opts.wd_also_supported);
*also_supported = server_opts.wd_also_supported;
}
/* HELLO UNLOCK */
pthread_rwlock_unlock(&server_opts.hello_lock);
}
API int
@ -993,6 +1034,9 @@ nc_server_set_capability(const char *value)
return EXIT_FAILURE;
}
/* HELLO LOCK */
pthread_rwlock_wrlock(&server_opts.hello_lock);
mem = realloc(server_opts.capabilities, (server_opts.capabilities_count + 1) * sizeof *server_opts.capabilities);
NC_CHECK_ERRMEM_RET(!mem, EXIT_FAILURE);
server_opts.capabilities = mem;
@ -1000,6 +1044,9 @@ nc_server_set_capability(const char *value)
server_opts.capabilities[server_opts.capabilities_count] = strdup(value);
server_opts.capabilities_count++;
/* HELLO UNLOCK */
pthread_rwlock_unlock(&server_opts.hello_lock);
return EXIT_SUCCESS;
}
@ -1007,9 +1054,15 @@ API void
nc_server_set_content_id_clb(char *(*content_id_clb)(void *user_data), void *user_data,
void (*free_user_data)(void *user_data))
{
/* HELLO LOCK */
pthread_rwlock_wrlock(&server_opts.hello_lock);
server_opts.content_id_clb = content_id_clb;
server_opts.content_id_data = user_data;
server_opts.content_id_data_free = free_user_data;
/* HELLO UNLOCK */
pthread_rwlock_unlock(&server_opts.hello_lock);
}
API NC_MSG_TYPE
@ -2731,7 +2784,7 @@ nc_connect_ch_endpt(struct nc_ch_endpt *endpt, nc_server_ch_session_acquire_ctx_
const struct ly_ctx *ctx = NULL;
int sock, ret;
struct timespec ts_cur;
char *ip_host;
char *ip_host = NULL;
sock = nc_sock_connect(endpt->src_addr, endpt->src_port, endpt->dst_addr, endpt->dst_port,
NC_CH_CONNECT_TIMEOUT, &endpt->ka, &endpt->sock_pending, &ip_host);
@ -4080,3 +4133,17 @@ nc_server_notif_cert_expiration_thread_stop(int wait)
}
#endif /* NC_ENABLED_SSH_TLS */
int
nc_server_is_mod_ignored(const char *mod_name)
{
uint16_t i;
for (i = 0; i < server_opts.ignored_mod_count; ++i) {
if (!strcmp(server_opts.ignored_modules[i], mod_name)) {
return 1;
}
}
return 0;
}

View file

@ -625,7 +625,8 @@ static int
nc_server_ssh_compare_password(const char *stored_pw, const char *received_pw)
{
char *received_pw_hash = NULL;
struct crypt_data cdata = {0};
struct crypt_data *cdata;
int ret;
NC_CHECK_ARG_RET(NULL, stored_pw, received_pw, 1);
@ -645,13 +646,23 @@ nc_server_ssh_compare_password(const char *stored_pw, const char *received_pw)
return strcmp(stored_pw + 3, received_pw);
}
received_pw_hash = crypt_r(received_pw, stored_pw, &cdata);
if (!received_pw_hash) {
ERR(NULL, "Hashing the password failed (%s).", strerror(errno));
cdata = (struct crypt_data *) calloc(sizeof(struct crypt_data), 1);
if (cdata == NULL) {
ERR(NULL, "Allocation of crypt_data struct failed.");
return 1;
}
return strcmp(received_pw_hash, stored_pw);
received_pw_hash = crypt_r(received_pw, stored_pw, cdata);
if (!received_pw_hash) {
ERR(NULL, "Hashing the password failed (%s).", strerror(errno));
free(cdata);
return 1;
}
ret = strcmp(received_pw_hash, stored_pw);
free(cdata);
return ret;
}
API int
@ -1946,17 +1957,29 @@ nc_accept_ssh_session(struct nc_session *session, struct nc_server_ssh_opts *opt
rc = -1;
goto cleanup;
}
if (opts->encryption_algs && ssh_bind_options_set(sbind, SSH_BIND_OPTIONS_CIPHERS_S_C, opts->encryption_algs)) {
rc = -1;
goto cleanup;
if (opts->encryption_algs) {
if (ssh_bind_options_set(sbind, SSH_BIND_OPTIONS_CIPHERS_S_C, opts->encryption_algs)) {
rc = -1;
goto cleanup;
}
if (ssh_bind_options_set(sbind, SSH_BIND_OPTIONS_CIPHERS_C_S, opts->encryption_algs)) {
rc = -1;
goto cleanup;
}
}
if (opts->kex_algs && ssh_bind_options_set(sbind, SSH_BIND_OPTIONS_KEY_EXCHANGE, opts->kex_algs)) {
rc = -1;
goto cleanup;
}
if (opts->mac_algs && ssh_bind_options_set(sbind, SSH_BIND_OPTIONS_HMAC_S_C, opts->mac_algs)) {
rc = -1;
goto cleanup;
if (opts->mac_algs) {
if (ssh_bind_options_set(sbind, SSH_BIND_OPTIONS_HMAC_S_C, opts->mac_algs)) {
rc = -1;
goto cleanup;
}
if (ssh_bind_options_set(sbind, SSH_BIND_OPTIONS_HMAC_C_S, opts->mac_algs)) {
rc = -1;
goto cleanup;
}
}
/* configure the ssh banner */

View file

@ -331,8 +331,8 @@ static int
nc_server_tls_cert_to_name(struct nc_ctn *ctn, void *cert_chain, char **username)
{
int ret = 1, i, cert_count, fingerprint_match;
char *digest_md5 = NULL, *digest_sha1 = NULL, *digest_sha224 = NULL;
char *digest_sha256 = NULL, *digest_sha384 = NULL, *digest_sha512 = NULL;
char *digest_md5, *digest_sha1, *digest_sha224;
char *digest_sha256, *digest_sha384, *digest_sha512;
void *cert;
/* first make sure the entry is valid */
@ -372,7 +372,6 @@ nc_server_tls_cert_to_name(struct nc_ctn *ctn, void *cert_chain, char **username
fingerprint_match = 1;
}
free(digest_md5);
digest_md5 = NULL;
/* SHA-1 */
} else if (!strncmp(ctn->fingerprint, "02", 2)) {
@ -388,7 +387,6 @@ nc_server_tls_cert_to_name(struct nc_ctn *ctn, void *cert_chain, char **username
fingerprint_match = 1;
}
free(digest_sha1);
digest_sha1 = NULL;
/* SHA-224 */
} else if (!strncmp(ctn->fingerprint, "03", 2)) {
@ -404,7 +402,6 @@ nc_server_tls_cert_to_name(struct nc_ctn *ctn, void *cert_chain, char **username
fingerprint_match = 1;
}
free(digest_sha224);
digest_sha224 = NULL;
/* SHA-256 */
} else if (!strncmp(ctn->fingerprint, "04", 2)) {
@ -420,7 +417,6 @@ nc_server_tls_cert_to_name(struct nc_ctn *ctn, void *cert_chain, char **username
fingerprint_match = 1;
}
free(digest_sha256);
digest_sha256 = NULL;
/* SHA-384 */
} else if (!strncmp(ctn->fingerprint, "05", 2)) {
@ -436,7 +432,6 @@ nc_server_tls_cert_to_name(struct nc_ctn *ctn, void *cert_chain, char **username
fingerprint_match = 1;
}
free(digest_sha384);
digest_sha384 = NULL;
/* SHA-512 */
} else if (!strncmp(ctn->fingerprint, "06", 2)) {
@ -452,7 +447,6 @@ nc_server_tls_cert_to_name(struct nc_ctn *ctn, void *cert_chain, char **username
fingerprint_match = 1;
}
free(digest_sha512);
digest_sha512 = NULL;
/* unknown */
} else {
@ -658,7 +652,13 @@ nc_session_get_client_cert(const struct nc_session *session)
API void
nc_server_tls_set_verify_clb(int (*verify_clb)(const struct nc_session *session))
{
/* CONFIG LOCK */
pthread_rwlock_wrlock(&server_opts.config_lock);
server_opts.user_verify_clb = verify_clb;
/* CONFIG UNLOCK */
pthread_rwlock_unlock(&server_opts.config_lock);
}
int

View file

@ -69,6 +69,20 @@ struct nc_tls_verify_cb_data {
void *chain; /**< Certificate chain used to verify the client cert. */
};
/**
* @brief Initializes the TLS backend.
*
* Does nothing for OpenSSL, required for MbedTLS version 3.6.0 and later.
*/
int nc_tls_backend_init_wrap(void);
/**
* @brief Destroys the TLS backend.
*
* Does nothing for OpenSSL, required for MbedTLS version 3.6.0 and later.
*/
void nc_tls_backend_destroy_wrap(void);
/**
* @brief Creates a new TLS session from the given configuration.
*
@ -267,8 +281,6 @@ void nc_tls_sans_destroy_wrap(void *sans);
*/
int nc_tls_get_num_sans_wrap(void *sans);
#ifdef NC_ENABLED_SSH_TLS
/**
* @brief Get the SAN value and type in the context of CTN.
*
@ -280,8 +292,6 @@ int nc_tls_get_num_sans_wrap(void *sans);
*/
int nc_tls_get_san_value_type_wrap(void *sans, int idx, char **san_value, NC_TLS_CTN_MAPTYPE *san_type);
#endif
/**
* @brief Get the number of certificates in a certificate chain.
*

View file

@ -105,7 +105,7 @@ test_nc_rpc_act_generic(void **state)
/* function to check if values of getconfig rpc are set correctly */
void
check_getconfig(struct nc_rpc *rpc, enum NC_DATASTORE_TYPE source, char *filter, NC_WD_MODE wd_mode)
check_getconfig(struct nc_rpc *rpc, NC_DATASTORE source, char *filter, NC_WD_MODE wd_mode)
{
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_GETCONFIG);
struct nc_rpc_getconfig *getconfig_rpc = (struct nc_rpc_getconfig *)rpc;

View file

@ -240,6 +240,7 @@ test_send_recv_error(void)
NC_MSG_TYPE msgtype;
struct nc_rpc *rpc;
struct lyd_node *envp, *op, *node;
const struct lysc_node *schema;
struct nc_pollsession *ps;
/* client RPC */
@ -266,9 +267,10 @@ test_send_recv_error(void)
nc_rpc_free(rpc);
assert_string_equal(LYD_NAME(lyd_child(envp)), "rpc-error");
lyd_find_sibling_opaq_next(lyd_child(lyd_child(envp)), "error-tag", &node);
schema = lys_find_path(LYD_CTX(envp), NULL, "/ietf-netconf:rpc-error/error-tag", 0);
lyd_find_sibling_val(lyd_child(lyd_child(envp)), schema, NULL, 0, &node);
assert_non_null(node);
assert_string_equal(((struct lyd_node_opaq *)node)->value, "operation-not-supported");
assert_string_equal(lyd_get_value(node), "operation-not-supported");
lyd_free_tree(envp);
assert_null(op);
}
@ -508,6 +510,7 @@ test_send_recv_malformed_10(void **state)
struct nc_pollsession *ps;
struct nc_rpc *rpc;
struct lyd_node *envp, *op, *node;
const struct lysc_node *schema;
NC_MSG_TYPE msgtype;
const char *msg;
@ -543,9 +546,10 @@ test_send_recv_malformed_10(void **state)
nc_rpc_free(rpc);
assert_string_equal(LYD_NAME(lyd_child(envp)), "rpc-error");
lyd_find_sibling_opaq_next(lyd_child(lyd_child(envp)), "error-tag", &node);
schema = lys_find_path(LYD_CTX(envp), NULL, "/ietf-netconf:rpc-error/error-tag", 0);
lyd_find_sibling_val(lyd_child(lyd_child(envp)), schema, NULL, 0, &node);
assert_non_null(node);
assert_string_equal(((struct lyd_node_opaq *)node)->value, "missing-attribute");
assert_string_equal(lyd_get_value(node), "missing-attribute");
lyd_free_tree(envp);
assert_null(op);
}

View file

@ -53,6 +53,7 @@ setup_write(void **state)
/* ietf-netconf */
fd = open(TESTS_DIR "/data/modules/ietf-netconf.yin", O_RDONLY);
if (fd == -1) {
free(w->session);
free(w);
return -1;
}

View file

@ -46,8 +46,19 @@ typedef struct arg {
struct nc_server_reply *
rpc_clb(struct lyd_node *rpc, struct nc_session *session)
{
(void)rpc; (void)session;
return nc_server_reply_ok();
struct lyd_node *e;
(void)session;
if (!strcmp(LYD_NAME(rpc), "get") || !strcmp(LYD_NAME(rpc), "delete-config")) {
return nc_server_reply_ok();
} else if (!strcmp(LYD_NAME(rpc), "commit")) {
e = nc_err(LYD_CTX(rpc), NC_ERR_RES_DENIED, NC_ERR_TYPE_APP);
nc_err_set_path(e, "/module-a:top/name");
return nc_server_reply_err(e);
} else {
nc_assert(0);
}
}
static void *
@ -92,10 +103,14 @@ server_thread(void *arg)
nc_server_notif_send(sess, notif, 1000);
/* commit in test */
poll = nc_ps_poll(ps, 1000, &sess);
nc_assert(poll == (NC_PSPOLL_RPC | NC_PSPOLL_REPLY_ERROR));
nc_ps_clear(ps, 1, NULL);
nc_ps_free(ps);
/* Waiting for end of test */
/* waiting for end of test */
pthread_barrier_wait(&barrier);
nc_server_notif_free(notif);
@ -110,7 +125,7 @@ notif_thread(void *arg)
struct lyd_node *op;
NC_MSG_TYPE msgtype;
/* Sync threads for receiving message to increase chance of datarace */
/* sync threads for receiving message to increase chance of datarace */
pthread_barrier_wait(&barrier_msg);
do {
msgtype = nc_recv_notif(sess, 1000, &envp, &op);
@ -131,44 +146,47 @@ main(void)
struct nc_rpc *rpc;
uint64_t msgid;
NC_MSG_TYPE msgtype;
const char *features[] = {"startup", NULL};
const char *features[] = {"startup", "candidate", NULL};
arg_t thread_arg;
pthread_t t[2];
char *str;
pthread_barrier_init(&barrier, NULL, 2);
pthread_barrier_init(&barrier_msg, NULL, 2);
/* Create a two pipes */
/* create a two pipes */
nc_assert(pipe(pipes) != -1);
nc_assert(pipe(pipes + 2) != -1);
thread_arg.in = pipes[0];
thread_arg.out = pipes[3];
/* Create both contexts */
/* create both contexts */
nc_assert(ly_ctx_new(TESTS_DIR "/data/modules", 0, &server_ctx) == LY_SUCCESS);
nc_assert(ly_ctx_load_module(server_ctx, "ietf-netconf", NULL, features));
nc_assert(ly_ctx_load_module(server_ctx, "notif1", NULL, NULL));
nc_assert(ly_ctx_load_module(server_ctx, "module-a", NULL, NULL));
thread_arg.ctx = server_ctx;
nc_set_global_rpc_clb(rpc_clb);
nc_assert(ly_ctx_new(TESTS_DIR "/data/modules", 0, &client_ctx) == LY_SUCCESS);
nc_assert(ly_ctx_load_module(client_ctx, "ietf-netconf", NULL, features));
nc_assert(ly_ctx_load_module(client_ctx, "notif1", NULL, NULL));
nc_assert(ly_ctx_load_module(client_ctx, "module-a", NULL, NULL));
/* Start server thread */
/* start server thread */
pthread_create(&t[0], NULL, server_thread, &thread_arg);
nc_client_init();
/* Listen for notifications */
/* listen for notifications */
sess = nc_connect_inout(pipes[2], pipes[1], client_ctx);
nc_assert(sess);
pthread_create(&t[1], NULL, notif_thread, sess);
/* Send rpc */
/* send delete-config rpc */
rpc = nc_rpc_delete(NC_DATASTORE_STARTUP, NULL, NC_PARAMTYPE_CONST);
nc_assert(nc_send_rpc(sess, rpc, 1000, &msgid) == NC_MSG_RPC);
/* Sync threads for receiving message to increase chance of datarace */
/* sync threads for receiving message to increase chance of datarace */
pthread_barrier_wait(&barrier_msg);
do {
msgtype = nc_recv_reply(sess, rpc, msgid, 1000, &envp, &op);
@ -177,12 +195,33 @@ main(void)
nc_rpc_free(rpc);
lyd_free_tree(envp);
/* Waiting of end of test */
/* send commit rpc */
rpc = nc_rpc_commit(0, 0, NULL, NULL, NC_PARAMTYPE_CONST);
nc_assert(nc_send_rpc(sess, rpc, 1000, &msgid) == NC_MSG_RPC);
do {
msgtype = nc_recv_reply(sess, rpc, msgid, 1000, &envp, &op);
} while (msgtype == NC_MSG_NOTIF);
nc_assert(msgtype == NC_MSG_REPLY);
nc_rpc_free(rpc);
lyd_print_mem(&str, envp, LYD_XML, LYD_PRINT_SHRINK);
nc_assert(!strcmp(str,
"<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\"3\"><rpc-error>"
"<error-type>application</error-type>"
"<error-tag>resource-denied</error-tag>"
"<error-severity>error</error-severity>"
"<error-path xmlns:a=\"urn:jmu:params:xml:ns:yang:module-a\">/a:top/a:name</error-path>"
"<error-message xml:lang=\"en\">Request could not be completed because of insufficient resources.</error-message>"
"</rpc-error></rpc-reply>"));
free(str);
lyd_free_tree(envp);
/* waiting of end of test */
pthread_barrier_wait(&barrier);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
/* Cleanup */
/* cleanup */
nc_session_free(sess, NULL);
ly_ctx_destroy(server_ctx);
ly_ctx_destroy(client_ctx);