blob: 781afb4c170d0034356dfa624f0176570402b555 [file] [log] [blame]
romanc1d2b092023-02-02 08:58:27 +01001/**
romane028ef92023-02-24 16:33:08 +01002 * @file server_config.c
romanc1d2b092023-02-02 08:58:27 +01003 * @author Roman Janota <janota@cesnet.cz>
4 * @brief libnetconf2 server configuration functions
5 *
6 * @copyright
romanf02273a2023-05-25 09:44:11 +02007 * Copyright (c) 2022-2023 CESNET, z.s.p.o.
romanc1d2b092023-02-02 08:58:27 +01008 *
9 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * https://opensource.org/licenses/BSD-3-Clause
14 */
roman27215242023-03-10 14:55:00 +010015
16#define _GNU_SOURCE
17
romanc1d2b092023-02-02 08:58:27 +010018#include <assert.h>
roman12644fe2023-06-08 11:06:42 +020019#include <ctype.h>
roman3f9b65c2023-06-05 14:26:58 +020020#include <pthread.h>
21#include <stdint.h>
romanc1d2b092023-02-02 08:58:27 +010022#include <stdlib.h>
23#include <string.h>
roman2eab4742023-06-06 10:00:26 +020024#include <unistd.h>
romanc1d2b092023-02-02 08:58:27 +010025
roman3f9b65c2023-06-05 14:26:58 +020026#include <libyang/libyang.h>
romana3c95c72023-10-26 11:15:53 +020027#include <libyang/tree_data.h>
roman3f9b65c2023-06-05 14:26:58 +020028
romanfaecc582023-06-15 16:13:31 +020029#ifdef NC_ENABLED_SSH_TLS
roman13145912023-08-17 15:36:54 +020030#include <openssl/err.h>
31#include <openssl/evp.h> // EVP_PKEY_free
32#include <openssl/x509.h> // d2i_PUBKEY
romanfaecc582023-06-15 16:13:31 +020033#include <openssl/x509_vfy.h> // X509_STORE_free
34#endif
35
romanc1d2b092023-02-02 08:58:27 +010036#include "compat.h"
roman3f9b65c2023-06-05 14:26:58 +020037#include "config.h"
38#include "log_p.h"
romane028ef92023-02-24 16:33:08 +010039#include "server_config.h"
romanf02273a2023-05-25 09:44:11 +020040#include "server_config_p.h"
roman3f9b65c2023-06-05 14:26:58 +020041#include "session_p.h"
42
roman2eab4742023-06-06 10:00:26 +020043#ifdef NC_ENABLED_SSH_TLS
romanc1d2b092023-02-02 08:58:27 +010044
45/* All libssh supported host-key, key-exchange, encryption and mac algorithms as of version 0.10.90 */
46
47static const char *supported_hostkey_algs[] = {
romana6bf6ab2023-05-26 13:26:02 +020048 "openssh-ssh-ed25519-cert-v01", "openssh-ecdsa-sha2-nistp521-cert-v01",
49 "openssh-ecdsa-sha2-nistp384-cert-v01", "openssh-ecdsa-sha2-nistp256-cert-v01",
50 "openssh-rsa-sha2-512-cert-v01", "openssh-rsa-sha2-256-cert-v01",
51 "openssh-ssh-rsa-cert-v01", "openssh-ssh-dss-cert-v01",
romanc1d2b092023-02-02 08:58:27 +010052 "ssh-ed25519", "ecdsa-sha2-nistp521", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp256",
53 "rsa-sha2-512", "rsa-sha2-256", "ssh-rsa", "ssh-dss", NULL
54};
55
56static const char *supported_kex_algs[] = {
romana6bf6ab2023-05-26 13:26:02 +020057 "diffie-hellman-group-exchange-sha1", "curve25519-sha256", "libssh-curve25519-sha256",
romanc1d2b092023-02-02 08:58:27 +010058 "ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", "diffie-hellman-group18-sha512",
59 "diffie-hellman-group16-sha512", "diffie-hellman-group-exchange-sha256", "diffie-hellman-group14-sha256", NULL
60};
61
62static const char *supported_encryption_algs[] = {
romana6bf6ab2023-05-26 13:26:02 +020063 "openssh-chacha20-poly1305", "openssh-aes256-gcm", "openssh-aes128-gcm",
romanc1d2b092023-02-02 08:58:27 +010064 "aes256-ctr", "aes192-ctr", "aes128-ctr", "aes256-cbc", "aes192-cbc", "aes128-cbc",
roman27215242023-03-10 14:55:00 +010065 "blowfish-cbc", "triple-des-cbc", "none", NULL
romanc1d2b092023-02-02 08:58:27 +010066};
67
68static const char *supported_mac_algs[] = {
romana6bf6ab2023-05-26 13:26:02 +020069 "openssh-hmac-sha2-256-etm", "openssh-hmac-sha2-512-etm", "openssh-hmac-sha1-etm",
romanc1d2b092023-02-02 08:58:27 +010070 "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1", NULL
71};
72
roman2eab4742023-06-06 10:00:26 +020073#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +020074
romanc1d2b092023-02-02 08:58:27 +010075extern struct nc_server_opts server_opts;
76
roman8341e8b2023-11-23 16:12:42 +010077/* returns a parent node of 'node' that matches the name 'name' */
78static const struct lyd_node *
79nc_server_config_get_parent(const struct lyd_node *node, const char *name)
roman4cb8bb12023-06-29 09:16:46 +020080{
roman8341e8b2023-11-23 16:12:42 +010081 NC_CHECK_ARG_RET(NULL, node, name, NULL);
roman4cb8bb12023-06-29 09:16:46 +020082
83 while (node) {
roman8341e8b2023-11-23 16:12:42 +010084 if (!strcmp(LYD_NAME(node), name)) {
85 return node;
roman4cb8bb12023-06-29 09:16:46 +020086 }
87 node = lyd_parent(node);
88 }
89
roman8341e8b2023-11-23 16:12:42 +010090 return NULL;
91}
92
93/* returns a parent list node of 'node' that matches the name 'name' */
94static const struct lyd_node *
95nc_server_config_get_parent_list(const struct lyd_node *node, const char *name)
96{
97 NC_CHECK_ARG_RET(NULL, node, name, NULL);
98
99 while (node) {
100 /* check if the node is a list and its name matches the param */
101 if ((node->schema->nodetype == LYS_LIST) && (!strcmp(LYD_NAME(node), name))) {
102 return node;
103 }
104 node = lyd_parent(node);
105 }
106
107 return NULL;
108}
109
110/* returns the key of a list node with the name 'name' */
111static const char *
112nc_server_config_get_parent_list_key_value(const struct lyd_node *node, const char *name, const char *key_name)
113{
114 const char *original_name;
115
116 NC_CHECK_ARG_RET(NULL, node, name, key_name, NULL);
117 original_name = LYD_NAME(node);
118
119 /* get the supposed parent list */
120 node = nc_server_config_get_parent_list(node, name);
121 if (!node) {
122 ERR(NULL, "Node \"%s\" not contained in \"%s\" subtree.", original_name, name);
123 return NULL;
124 }
125
126 /* child should be the key */
127 node = lyd_child(node);
128 if (!node) {
129 ERR(NULL, "Node \"%s\" has no child nodes.", name);
130 return NULL;
131 }
132 if (strcmp(LYD_NAME(node), key_name)) {
133 ERR(NULL, "Node \"%s\" child names mismatch (found:\"%s\", expected:\"%s\").", original_name, LYD_NAME(node), key_name);
134 return NULL;
135 }
136
137 return lyd_get_value(node);
138}
139
140/* returns true if a node is a part of the listen subtree */
141static int
142is_listen(const struct lyd_node *node)
143{
144 node = nc_server_config_get_parent(node, "listen");
roman4cb8bb12023-06-29 09:16:46 +0200145 return node != NULL;
146}
147
roman6430c152023-10-12 11:28:47 +0200148/* returns true if a node is a part of the Call Home subtree */
roman4cb8bb12023-06-29 09:16:46 +0200149static int
150is_ch(const struct lyd_node *node)
151{
roman8341e8b2023-11-23 16:12:42 +0100152 node = nc_server_config_get_parent(node, "call-home");
roman4cb8bb12023-06-29 09:16:46 +0200153 return node != NULL;
154}
155
156#ifdef NC_ENABLED_SSH_TLS
157
roman6430c152023-10-12 11:28:47 +0200158/* returns true if a node is a part of the ssh subtree */
roman4cb8bb12023-06-29 09:16:46 +0200159static int
160is_ssh(const struct lyd_node *node)
161{
roman8341e8b2023-11-23 16:12:42 +0100162 node = nc_server_config_get_parent(node, "ssh");
roman4cb8bb12023-06-29 09:16:46 +0200163 return node != NULL;
164}
165
roman6430c152023-10-12 11:28:47 +0200166/* returns true if a node is a part of the tls subtree */
roman4cb8bb12023-06-29 09:16:46 +0200167static int
168is_tls(const struct lyd_node *node)
169{
roman8341e8b2023-11-23 16:12:42 +0100170 node = nc_server_config_get_parent(node, "tls");
roman4cb8bb12023-06-29 09:16:46 +0200171 return node != NULL;
172}
173
174#endif /* NC_ENABLED_SSH_TLS */
175
roman6430c152023-10-12 11:28:47 +0200176/* gets the endpoint struct (and optionally bind) based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200177static int
romanf02273a2023-05-25 09:44:11 +0200178nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, struct nc_bind **bind)
romanc1d2b092023-02-02 08:58:27 +0100179{
180 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200181 const char *name;
romanc1d2b092023-02-02 08:58:27 +0100182
roman8341e8b2023-11-23 16:12:42 +0100183 NC_CHECK_ARG_RET(NULL, node, endpt, 1);
romanc1d2b092023-02-02 08:58:27 +0100184
roman8341e8b2023-11-23 16:12:42 +0100185 name = nc_server_config_get_parent_list_key_value(node, "endpoint", "name");
186 if (!name) {
romanc1d2b092023-02-02 08:58:27 +0100187 return 1;
188 }
189
romanc1d2b092023-02-02 08:58:27 +0100190 for (i = 0; i < server_opts.endpt_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200191 if (!strcmp(server_opts.endpts[i].name, name)) {
romanc1d2b092023-02-02 08:58:27 +0100192 *endpt = &server_opts.endpts[i];
193 if (bind) {
194 *bind = &server_opts.binds[i];
195 }
196 return 0;
197 }
198 }
199
romanb9beb112023-07-18 09:06:58 +0200200 ERR(NULL, "Endpoint \"%s\" was not found.", name);
romanc1d2b092023-02-02 08:58:27 +0100201 return 1;
202}
203
roman8341e8b2023-11-23 16:12:42 +0100204/* gets the ch_client struct based on node's location in the YANG data tree
205 * THE ch_client_lock HAS TO BE LOCKED PRIOR TO CALLING THIS
206 */
roman4cb8bb12023-06-29 09:16:46 +0200207static int
roman5cbb6532023-06-22 12:53:17 +0200208nc_server_config_get_ch_client(const struct lyd_node *node, struct nc_ch_client **ch_client)
209{
210 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200211 const char *name;
roman5cbb6532023-06-22 12:53:17 +0200212
roman8341e8b2023-11-23 16:12:42 +0100213 NC_CHECK_ARG_RET(NULL, node, ch_client, 1);
roman4cb8bb12023-06-29 09:16:46 +0200214
roman8341e8b2023-11-23 16:12:42 +0100215 name = nc_server_config_get_parent_list_key_value(node, "netconf-client", "name");
216 if (!name) {
roman5cbb6532023-06-22 12:53:17 +0200217 return 1;
218 }
219
roman5cbb6532023-06-22 12:53:17 +0200220 for (i = 0; i < server_opts.ch_client_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200221 if (!strcmp(server_opts.ch_clients[i].name, name)) {
roman5cbb6532023-06-22 12:53:17 +0200222 *ch_client = &server_opts.ch_clients[i];
223 return 0;
224 }
225 }
226
romanb9beb112023-07-18 09:06:58 +0200227 ERR(NULL, "Call-home client \"%s\" was not found.", name);
roman5cbb6532023-06-22 12:53:17 +0200228 return 1;
229}
230
roman8341e8b2023-11-23 16:12:42 +0100231/* gets the ch_endpt struct based on node's location in the YANG data tree,
232 * ch_client has to be locked
233 */
roman4cb8bb12023-06-29 09:16:46 +0200234static int
roman8341e8b2023-11-23 16:12:42 +0100235nc_server_config_get_ch_endpt(const struct lyd_node *node, const struct nc_ch_client *ch_client,
236 struct nc_ch_endpt **ch_endpt)
roman5cbb6532023-06-22 12:53:17 +0200237{
238 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200239 const char *name;
roman4cb8bb12023-06-29 09:16:46 +0200240
roman8341e8b2023-11-23 16:12:42 +0100241 NC_CHECK_ARG_RET(NULL, node, ch_client, ch_endpt, 1);
roman4cb8bb12023-06-29 09:16:46 +0200242
roman8341e8b2023-11-23 16:12:42 +0100243 name = nc_server_config_get_parent_list_key_value(node, "endpoint", "name");
244 if (!name) {
roman4cb8bb12023-06-29 09:16:46 +0200245 return 1;
246 }
roman5cbb6532023-06-22 12:53:17 +0200247
roman5cbb6532023-06-22 12:53:17 +0200248 for (i = 0; i < ch_client->ch_endpt_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200249 if (!strcmp(ch_client->ch_endpts[i].name, name)) {
roman5cbb6532023-06-22 12:53:17 +0200250 *ch_endpt = &ch_client->ch_endpts[i];
251 return 0;
252 }
253 }
254
romanb9beb112023-07-18 09:06:58 +0200255 ERR(NULL, "Call-home client's \"%s\" endpoint \"%s\" was not found.", ch_client->name, name);
roman5cbb6532023-06-22 12:53:17 +0200256 return 1;
257}
258
roman6430c152023-10-12 11:28:47 +0200259#ifdef NC_ENABLED_SSH_TLS
260
261/* gets the ssh_opts struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200262static int
roman8341e8b2023-11-23 16:12:42 +0100263nc_server_config_get_ssh_opts(const struct lyd_node *node, const struct nc_ch_client *ch_client,
264 struct nc_server_ssh_opts **opts)
roman4cb8bb12023-06-29 09:16:46 +0200265{
266 struct nc_endpt *endpt;
267 struct nc_ch_endpt *ch_endpt;
roman3f9b65c2023-06-05 14:26:58 +0200268
roman8341e8b2023-11-23 16:12:42 +0100269 NC_CHECK_ARG_RET(NULL, node, opts, 1);
roman4cb8bb12023-06-29 09:16:46 +0200270
271 if (is_listen(node)) {
272 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
273 return 1;
274 }
275 *opts = endpt->opts.ssh;
276 } else {
roman8341e8b2023-11-23 16:12:42 +0100277 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman4cb8bb12023-06-29 09:16:46 +0200278 return 1;
279 }
280 *opts = ch_endpt->opts.ssh;
281 }
282
283 return 0;
284}
285
roman6430c152023-10-12 11:28:47 +0200286/* gets the hostkey struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200287static int
roman8341e8b2023-11-23 16:12:42 +0100288nc_server_config_get_hostkey(const struct lyd_node *node, const struct nc_ch_client *ch_client,
289 struct nc_hostkey **hostkey)
romanc1d2b092023-02-02 08:58:27 +0100290{
291 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200292 const char *name;
roman4cb8bb12023-06-29 09:16:46 +0200293 struct nc_server_ssh_opts *opts;
romanc1d2b092023-02-02 08:58:27 +0100294
roman8341e8b2023-11-23 16:12:42 +0100295 NC_CHECK_ARG_RET(NULL, node, hostkey, 1);
romanc1d2b092023-02-02 08:58:27 +0100296
roman8341e8b2023-11-23 16:12:42 +0100297 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
romanc1d2b092023-02-02 08:58:27 +0100298 return 1;
299 }
300
roman8341e8b2023-11-23 16:12:42 +0100301 name = nc_server_config_get_parent_list_key_value(node, "host-key", "name");
302 if (!name) {
romanb9beb112023-07-18 09:06:58 +0200303 return 1;
304 }
roman8341e8b2023-11-23 16:12:42 +0100305
romanc1d2b092023-02-02 08:58:27 +0100306 for (i = 0; i < opts->hostkey_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200307 if (!strcmp(opts->hostkeys[i].name, name)) {
romanc1d2b092023-02-02 08:58:27 +0100308 *hostkey = &opts->hostkeys[i];
309 return 0;
310 }
311 }
312
romanb9beb112023-07-18 09:06:58 +0200313 ERR(NULL, "Host-key \"%s\" was not found.", name);
romanc1d2b092023-02-02 08:58:27 +0100314 return 1;
315}
316
roman6430c152023-10-12 11:28:47 +0200317/* gets the client_auth struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200318static int
roman8341e8b2023-11-23 16:12:42 +0100319nc_server_config_get_auth_client(const struct lyd_node *node, const struct nc_ch_client *ch_client,
320 struct nc_auth_client **auth_client)
romanc1d2b092023-02-02 08:58:27 +0100321{
322 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200323 const char *name;
roman4cb8bb12023-06-29 09:16:46 +0200324 struct nc_server_ssh_opts *opts;
romanc1d2b092023-02-02 08:58:27 +0100325
roman8341e8b2023-11-23 16:12:42 +0100326 NC_CHECK_ARG_RET(NULL, node, auth_client, 1);
romanc1d2b092023-02-02 08:58:27 +0100327
roman8341e8b2023-11-23 16:12:42 +0100328 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
romanc1d2b092023-02-02 08:58:27 +0100329 return 1;
330 }
331
roman8341e8b2023-11-23 16:12:42 +0100332 name = nc_server_config_get_parent_list_key_value(node, "user", "name");
333 if (!name) {
romanb9beb112023-07-18 09:06:58 +0200334 return 1;
335 }
roman8341e8b2023-11-23 16:12:42 +0100336
romanc1d2b092023-02-02 08:58:27 +0100337 for (i = 0; i < opts->client_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200338 if (!strcmp(opts->auth_clients[i].username, name)) {
romanc1d2b092023-02-02 08:58:27 +0100339 *auth_client = &opts->auth_clients[i];
340 return 0;
341 }
342 }
343
romanb9beb112023-07-18 09:06:58 +0200344 ERR(NULL, "Authorized key \"%s\" was not found.", name);
romanc1d2b092023-02-02 08:58:27 +0100345 return 1;
346}
347
roman6430c152023-10-12 11:28:47 +0200348/* gets the pubkey struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200349static int
roman8341e8b2023-11-23 16:12:42 +0100350nc_server_config_get_pubkey(const struct lyd_node *node, const struct nc_ch_client *ch_client,
351 struct nc_public_key **pubkey)
romanc1d2b092023-02-02 08:58:27 +0100352{
353 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200354 const char *name;
roman6430c152023-10-12 11:28:47 +0200355 struct nc_auth_client *auth_client;
romanc1d2b092023-02-02 08:58:27 +0100356
roman8341e8b2023-11-23 16:12:42 +0100357 NC_CHECK_ARG_RET(NULL, node, pubkey, 1);
romanc1d2b092023-02-02 08:58:27 +0100358
roman8341e8b2023-11-23 16:12:42 +0100359 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +0100360 return 1;
361 }
362
roman8341e8b2023-11-23 16:12:42 +0100363 name = nc_server_config_get_parent_list_key_value(node, "public-key", "name");
364 if (!name) {
romanb9beb112023-07-18 09:06:58 +0200365 return 1;
366 }
roman8341e8b2023-11-23 16:12:42 +0100367
romanc1d2b092023-02-02 08:58:27 +0100368 for (i = 0; i < auth_client->pubkey_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200369 if (!strcmp(auth_client->pubkeys[i].name, name)) {
romanc1d2b092023-02-02 08:58:27 +0100370 *pubkey = &auth_client->pubkeys[i];
371 return 0;
372 }
373 }
374
romanb9beb112023-07-18 09:06:58 +0200375 ERR(NULL, "Public key \"%s\" was not found.", name);
romanc1d2b092023-02-02 08:58:27 +0100376 return 1;
377}
378
roman6430c152023-10-12 11:28:47 +0200379/* gets the tls_opts struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200380static int
roman8341e8b2023-11-23 16:12:42 +0100381nc_server_config_get_tls_opts(const struct lyd_node *node, const struct nc_ch_client *ch_client,
382 struct nc_server_tls_opts **opts)
romanb6f44032023-06-30 15:07:56 +0200383{
384 struct nc_endpt *endpt;
385 struct nc_ch_endpt *ch_endpt;
386
roman8341e8b2023-11-23 16:12:42 +0100387 NC_CHECK_ARG_RET(NULL, node, opts, 1);
romanb6f44032023-06-30 15:07:56 +0200388
389 if (is_listen(node)) {
390 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
391 return 1;
392 }
393 *opts = endpt->opts.tls;
394 } else {
roman8341e8b2023-11-23 16:12:42 +0100395 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
romanb6f44032023-06-30 15:07:56 +0200396 return 1;
397 }
398 *opts = ch_endpt->opts.tls;
399 }
400
401 return 0;
402}
403
roman6430c152023-10-12 11:28:47 +0200404/* gets the cert struct based on node's location in the YANG data tree */
romanb6f44032023-06-30 15:07:56 +0200405static int
roman8341e8b2023-11-23 16:12:42 +0100406nc_server_config_get_cert(const struct lyd_node *node, const struct nc_ch_client *ch_client,
407 struct nc_certificate **cert)
roman3f9b65c2023-06-05 14:26:58 +0200408{
409 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200410 const char *name;
roman8341e8b2023-11-23 16:12:42 +0100411 struct nc_cert_grouping *certs;
romanb6f44032023-06-30 15:07:56 +0200412 struct nc_server_tls_opts *opts;
roman6430c152023-10-12 11:28:47 +0200413 int is_cert_end_entity;
roman8341e8b2023-11-23 16:12:42 +0100414 const struct lyd_node *tmp;
roman3f9b65c2023-06-05 14:26:58 +0200415
roman8341e8b2023-11-23 16:12:42 +0100416 NC_CHECK_ARG_RET(NULL, node, cert, 1);
roman3f9b65c2023-06-05 14:26:58 +0200417
roman8341e8b2023-11-23 16:12:42 +0100418 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +0200419 return 1;
420 }
421
roman8341e8b2023-11-23 16:12:42 +0100422 name = nc_server_config_get_parent_list_key_value(node, "certificate", "name");
423 if (!name) {
roman6430c152023-10-12 11:28:47 +0200424 return 1;
425 }
426
roman8341e8b2023-11-23 16:12:42 +0100427 /* it's in certificate subtree, now check if it's end entity or certificate authority */
428 tmp = nc_server_config_get_parent(node, "ee-certs");
429 if (tmp) {
430 is_cert_end_entity = 1;
romanb9beb112023-07-18 09:06:58 +0200431 } else {
roman8341e8b2023-11-23 16:12:42 +0100432 tmp = nc_server_config_get_parent(node, "ca-certs");
433 if (!tmp) {
434 ERR(NULL, "Node \"%s\" is not contained in ee-certs nor ca-certs subtree.", name);
435 return 1;
436 }
437 is_cert_end_entity = 0;
romanb9beb112023-07-18 09:06:58 +0200438 }
roman3f9b65c2023-06-05 14:26:58 +0200439
roman8341e8b2023-11-23 16:12:42 +0100440 /* get the right cert stack, either ee or ca */
441 if (is_cert_end_entity) {
442 certs = &opts->ee_certs;
443 } else {
444 certs = &opts->ca_certs;
445 }
446
447 for (i = 0; i < certs->cert_count; i++) {
448 if (!strcmp(certs->certs[i].name, name)) {
449 *cert = &certs->certs[i];
roman3f9b65c2023-06-05 14:26:58 +0200450 return 0;
451 }
452 }
453
roman8341e8b2023-11-23 16:12:42 +0100454 ERR(NULL, "%s certificate \"%s\" was not found.", is_cert_end_entity ? "End-entity" : "Certificate authority", name);
roman3f9b65c2023-06-05 14:26:58 +0200455 return 1;
456}
457
roman6430c152023-10-12 11:28:47 +0200458/* gets the ctn struct based on node's location in the YANG data tree */
roman3f9b65c2023-06-05 14:26:58 +0200459static int
roman8341e8b2023-11-23 16:12:42 +0100460nc_server_config_get_ctn(const struct lyd_node *node, const struct nc_ch_client *ch_client,
461 struct nc_ctn **ctn)
roman3f9b65c2023-06-05 14:26:58 +0200462{
463 uint32_t id;
464 struct nc_ctn *iter;
romanb6f44032023-06-30 15:07:56 +0200465 struct nc_server_tls_opts *opts;
romanb9beb112023-07-18 09:06:58 +0200466 const char *name;
roman3f9b65c2023-06-05 14:26:58 +0200467
roman8341e8b2023-11-23 16:12:42 +0100468 NC_CHECK_ARG_RET(NULL, node, ctn, 1);
roman3f9b65c2023-06-05 14:26:58 +0200469
roman8341e8b2023-11-23 16:12:42 +0100470 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
471 return 1;
roman3f9b65c2023-06-05 14:26:58 +0200472 }
473
roman8341e8b2023-11-23 16:12:42 +0100474 name = LYD_NAME(node);
475 node = nc_server_config_get_parent_list(node, "cert-to-name");
roman3f9b65c2023-06-05 14:26:58 +0200476 if (!node) {
romanb9beb112023-07-18 09:06:58 +0200477 ERR(NULL, "Node \"%s\" is not contained in a cert-to-name subtree.", name);
roman3f9b65c2023-06-05 14:26:58 +0200478 return 1;
479 }
480
481 node = lyd_child(node);
482 assert(!strcmp(LYD_NAME(node), "id"));
roman91ffeb42023-10-25 13:32:03 +0200483 id = ((struct lyd_node_term *)node)->value.uint32;
roman3f9b65c2023-06-05 14:26:58 +0200484
romanb6f44032023-06-30 15:07:56 +0200485 iter = opts->ctn;
roman3f9b65c2023-06-05 14:26:58 +0200486 while (iter) {
487 if (iter->id == id) {
488 *ctn = iter;
489 return 0;
490 }
491
492 iter = iter->next;
493 }
494
495 ERR(NULL, "Cert-to-name entry with id \"%d\" was not found.", id);
496 return 1;
497}
498
roman2eab4742023-06-06 10:00:26 +0200499NC_PRIVKEY_FORMAT
500nc_server_config_get_private_key_type(const char *format)
501{
502 if (!strcmp(format, "rsa-private-key-format")) {
503 return NC_PRIVKEY_FORMAT_RSA;
504 } else if (!strcmp(format, "ec-private-key-format")) {
505 return NC_PRIVKEY_FORMAT_EC;
roman13145912023-08-17 15:36:54 +0200506 } else if (!strcmp(format, "private-key-info-format")) {
roman2eab4742023-06-06 10:00:26 +0200507 return NC_PRIVKEY_FORMAT_X509;
508 } else if (!strcmp(format, "openssh-private-key-format")) {
509 return NC_PRIVKEY_FORMAT_OPENSSH;
510 } else {
511 ERR(NULL, "Private key format (%s) not supported.", format);
512 return NC_PRIVKEY_FORMAT_UNKNOWN;
513 }
514}
515
516#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200517
roman6430c152023-10-12 11:28:47 +0200518/* gets the ch_client struct based on node's location in the YANG data tree and locks it for reading */
romanba93eac2023-07-18 14:36:48 +0200519static int
520nc_server_config_get_ch_client_with_lock(const struct lyd_node *node, struct nc_ch_client **ch_client)
521{
522 uint16_t i;
523 const char *name;
524
roman8341e8b2023-11-23 16:12:42 +0100525 NC_CHECK_ARG_RET(NULL, node, ch_client, 1);
romanba93eac2023-07-18 14:36:48 +0200526
roman8341e8b2023-11-23 16:12:42 +0100527 name = nc_server_config_get_parent_list_key_value(node, "netconf-client", "name");
528 if (!name) {
romanba93eac2023-07-18 14:36:48 +0200529 return 1;
530 }
531
romanba93eac2023-07-18 14:36:48 +0200532 /* LOCK */
533 pthread_rwlock_rdlock(&server_opts.ch_client_lock);
534 for (i = 0; i < server_opts.ch_client_count; i++) {
535 if (!strcmp(server_opts.ch_clients[i].name, name)) {
536 /* LOCK */
537 pthread_mutex_lock(&server_opts.ch_clients[i].lock);
538 *ch_client = &server_opts.ch_clients[i];
539 return 0;
540 }
541 }
542
roman6430c152023-10-12 11:28:47 +0200543 /* UNLOCK */
544 pthread_rwlock_unlock(&server_opts.ch_client_lock);
romanba93eac2023-07-18 14:36:48 +0200545 ERR(NULL, "Call-home client \"%s\" was not found.", name);
546 return 1;
547}
548
549static void
550nc_ch_client_unlock(struct nc_ch_client *client)
551{
552 assert(client);
553
554 pthread_mutex_unlock(&client->lock);
555 pthread_rwlock_unlock(&server_opts.ch_client_lock);
556}
557
romanf02273a2023-05-25 09:44:11 +0200558int
romanc1d2b092023-02-02 08:58:27 +0100559equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char *parent_name)
560{
561 uint16_t i;
562
roman6430c152023-10-12 11:28:47 +0200563 assert(node && parent_count && parent_name);
romanc1d2b092023-02-02 08:58:27 +0100564
565 node = lyd_parent(node);
566 for (i = 1; i < parent_count; i++) {
567 node = lyd_parent(node);
568 }
569
570 if (!strcmp(LYD_NAME(node), parent_name)) {
571 return 1;
572 }
573
574 return 0;
575}
576
romanf02273a2023-05-25 09:44:11 +0200577int
578nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uint16_t *count)
579{
580 int ret = 0;
581 void *tmp;
582 char **name;
583
584 tmp = realloc(*ptr, (*count + 1) * size);
roman3a95bb22023-10-26 11:07:17 +0200585 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
romanf02273a2023-05-25 09:44:11 +0200586 *ptr = tmp;
587
588 /* set the newly allocated memory to 0 */
589 memset((char *)(*ptr) + (*count * size), 0, size);
590 (*count)++;
591
592 /* access the first member of the supposed structure */
593 name = (char **)((*ptr) + ((*count - 1) * size));
594
595 /* and set it's value */
596 *name = strdup(key_value);
roman3a95bb22023-10-26 11:07:17 +0200597 NC_CHECK_ERRMEM_GOTO(!*name, ret = 1, cleanup);
romanf02273a2023-05-25 09:44:11 +0200598
599cleanup:
600 return ret;
601}
602
roman2eab4742023-06-06 10:00:26 +0200603#ifdef NC_ENABLED_SSH_TLS
604
roman3f9b65c2023-06-05 14:26:58 +0200605static void
roman874fed12023-05-25 10:20:01 +0200606nc_server_config_del_hostkey(struct nc_server_ssh_opts *opts, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100607{
roman874fed12023-05-25 10:20:01 +0200608 assert(hostkey->store == NC_STORE_LOCAL || hostkey->store == NC_STORE_KEYSTORE);
romanc1d2b092023-02-02 08:58:27 +0100609
roman6430c152023-10-12 11:28:47 +0200610 free(hostkey->name);
611
roman874fed12023-05-25 10:20:01 +0200612 if (hostkey->store == NC_STORE_LOCAL) {
roman6430c152023-10-12 11:28:47 +0200613 free(hostkey->key.pubkey_data);
614 free(hostkey->key.privkey_data);
romandd019a92023-09-14 10:17:07 +0200615 } else {
roman6430c152023-10-12 11:28:47 +0200616 free(hostkey->ks_ref);
romanc1d2b092023-02-02 08:58:27 +0100617 }
618
romanc1d2b092023-02-02 08:58:27 +0100619 opts->hostkey_count--;
620 if (!opts->hostkey_count) {
621 free(opts->hostkeys);
622 opts->hostkeys = NULL;
roman6430c152023-10-12 11:28:47 +0200623 } else if (hostkey != &opts->hostkeys[opts->hostkey_count]) {
roman33981232023-07-08 11:55:13 +0200624 memcpy(hostkey, &opts->hostkeys[opts->hostkey_count], sizeof *opts->hostkeys);
romanc1d2b092023-02-02 08:58:27 +0100625 }
626}
627
628static void
roman58f79d02023-10-06 10:20:31 +0200629nc_server_config_del_auth_client_pubkey(struct nc_auth_client *auth_client, struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +0100630{
roman6430c152023-10-12 11:28:47 +0200631 free(pubkey->name);
632 free(pubkey->data);
romanc1d2b092023-02-02 08:58:27 +0100633
634 auth_client->pubkey_count--;
635 if (!auth_client->pubkey_count) {
636 free(auth_client->pubkeys);
637 auth_client->pubkeys = NULL;
roman6430c152023-10-12 11:28:47 +0200638 } else if (pubkey != &auth_client->pubkeys[auth_client->pubkey_count]) {
roman33981232023-07-08 11:55:13 +0200639 memcpy(pubkey, &auth_client->pubkeys[auth_client->pubkey_count], sizeof *auth_client->pubkeys);
romanc1d2b092023-02-02 08:58:27 +0100640 }
641}
642
643static void
roman58f79d02023-10-06 10:20:31 +0200644nc_server_config_del_auth_client(struct nc_server_ssh_opts *opts, struct nc_auth_client *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100645{
646 uint16_t i, pubkey_count;
647
roman4cb8bb12023-06-29 09:16:46 +0200648 free(auth_client->username);
roman4cb8bb12023-06-29 09:16:46 +0200649
roman874fed12023-05-25 10:20:01 +0200650 if (auth_client->store == NC_STORE_LOCAL) {
romanc1d2b092023-02-02 08:58:27 +0100651 pubkey_count = auth_client->pubkey_count;
652 for (i = 0; i < pubkey_count; i++) {
roman874fed12023-05-25 10:20:01 +0200653 nc_server_config_del_auth_client_pubkey(auth_client, &auth_client->pubkeys[i]);
romanc1d2b092023-02-02 08:58:27 +0100654 }
roman6430c152023-10-12 11:28:47 +0200655 } else {
656 free(auth_client->ts_ref);
romanc1d2b092023-02-02 08:58:27 +0100657 }
658
roman6430c152023-10-12 11:28:47 +0200659 free(auth_client->password);
romanc1d2b092023-02-02 08:58:27 +0100660
661 opts->client_count--;
662 if (!opts->client_count) {
663 free(opts->auth_clients);
664 opts->auth_clients = NULL;
roman6430c152023-10-12 11:28:47 +0200665 } else if (auth_client != &opts->auth_clients[opts->client_count]) {
roman33981232023-07-08 11:55:13 +0200666 memcpy(auth_client, &opts->auth_clients[opts->client_count], sizeof *opts->auth_clients);
romanc1d2b092023-02-02 08:58:27 +0100667 }
668}
669
670static void
roman6430c152023-10-12 11:28:47 +0200671nc_server_config_del_ssh_opts(struct nc_bind *bind, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100672{
673 uint16_t i, hostkey_count, client_count;
674
roman5ae78282023-11-02 13:34:34 +0100675 if (bind) {
676 free(bind->address);
677 if (bind->sock > -1) {
678 close(bind->sock);
679 }
romanc1d2b092023-02-02 08:58:27 +0100680 }
681
682 /* store in variable because it gets decremented in the function call */
683 hostkey_count = opts->hostkey_count;
684 for (i = 0; i < hostkey_count; i++) {
roman874fed12023-05-25 10:20:01 +0200685 nc_server_config_del_hostkey(opts, &opts->hostkeys[i]);
romanc1d2b092023-02-02 08:58:27 +0100686 }
687
688 client_count = opts->client_count;
689 for (i = 0; i < client_count; i++) {
roman874fed12023-05-25 10:20:01 +0200690 nc_server_config_del_auth_client(opts, &opts->auth_clients[i]);
romanc1d2b092023-02-02 08:58:27 +0100691 }
692
roman6430c152023-10-12 11:28:47 +0200693 free(opts->hostkey_algs);
694 free(opts->kex_algs);
695 free(opts->encryption_algs);
696 free(opts->mac_algs);
romanc1d2b092023-02-02 08:58:27 +0100697
698 free(opts);
romanc1d2b092023-02-02 08:58:27 +0100699}
700
roman8341e8b2023-11-23 16:12:42 +0100701/* delete references to endpoint with the name 'referenced_endpt_name' from other endpts */
roman78df0fa2023-11-02 10:33:57 +0100702static void
703nc_server_config_del_endpt_references(const char *referenced_endpt_name)
704{
705 uint16_t i, j;
706
roman8341e8b2023-11-23 16:12:42 +0100707 /* first go through listen endpoints */
roman78df0fa2023-11-02 10:33:57 +0100708 for (i = 0; i < server_opts.endpt_count; i++) {
709 if (server_opts.endpts[i].referenced_endpt_name) {
710 if (!strcmp(server_opts.endpts[i].referenced_endpt_name, referenced_endpt_name)) {
711 free(server_opts.endpts[i].referenced_endpt_name);
712 server_opts.endpts[i].referenced_endpt_name = NULL;
713
714 if (server_opts.endpts[i].ti == NC_TI_LIBSSH) {
715 server_opts.endpts[i].opts.ssh->referenced_endpt_name = NULL;
716 } else {
717 server_opts.endpts[i].opts.tls->referenced_endpt_name = NULL;
718 }
719 }
720 }
721 }
722
723 /* LOCK */
724 pthread_rwlock_rdlock(&server_opts.ch_client_lock);
roman8341e8b2023-11-23 16:12:42 +0100725 /* next go through ch endpoints */
roman78df0fa2023-11-02 10:33:57 +0100726 for (i = 0; i < server_opts.ch_client_count; i++) {
727 /* LOCK */
728 pthread_mutex_lock(&server_opts.ch_clients[i].lock);
729 for (j = 0; j < server_opts.ch_clients[i].ch_endpt_count; j++) {
730 if (server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name) {
731 if (!strcmp(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, referenced_endpt_name)) {
732 free(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name);
733 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name = NULL;
734
735 if (server_opts.ch_clients[i].ch_endpts[j].ti == NC_TI_LIBSSH) {
736 server_opts.ch_clients[i].ch_endpts[j].opts.ssh->referenced_endpt_name = NULL;
737 } else {
738 server_opts.ch_clients[i].ch_endpts[j].opts.tls->referenced_endpt_name = NULL;
739 }
740 }
741 }
742 }
743 /* UNLOCK */
744 pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
745 }
746
747 /* UNLOCK */
748 pthread_rwlock_unlock(&server_opts.ch_client_lock);
749}
750
romanc1d2b092023-02-02 08:58:27 +0100751void
roman874fed12023-05-25 10:20:01 +0200752nc_server_config_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind)
romanc1d2b092023-02-02 08:58:27 +0100753{
roman78df0fa2023-11-02 10:33:57 +0100754 /* delete any references to this endpoint */
755 nc_server_config_del_endpt_references(endpt->name);
roman6430c152023-10-12 11:28:47 +0200756 free(endpt->name);
roman78df0fa2023-11-02 10:33:57 +0100757
roman6430c152023-10-12 11:28:47 +0200758 free(endpt->referenced_endpt_name);
759 nc_server_config_del_ssh_opts(bind, endpt->opts.ssh);
romanc1d2b092023-02-02 08:58:27 +0100760
761 server_opts.endpt_count--;
762 if (!server_opts.endpt_count) {
763 free(server_opts.endpts);
764 free(server_opts.binds);
765 server_opts.endpts = NULL;
766 server_opts.binds = NULL;
roman6430c152023-10-12 11:28:47 +0200767 } else if (endpt != &server_opts.endpts[server_opts.endpt_count]) {
roman33981232023-07-08 11:55:13 +0200768 memcpy(endpt, &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts);
769 memcpy(bind, &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds);
romanc1d2b092023-02-02 08:58:27 +0100770 }
771}
772
roman3f9b65c2023-06-05 14:26:58 +0200773static void
roman3f9b65c2023-06-05 14:26:58 +0200774nc_server_config_del_cert(struct nc_cert_grouping *certs, struct nc_certificate *cert)
775{
776 free(cert->name);
roman3f9b65c2023-06-05 14:26:58 +0200777 free(cert->data);
roman3f9b65c2023-06-05 14:26:58 +0200778
779 certs->cert_count--;
780 if (!certs->cert_count) {
781 free(certs->certs);
782 certs->certs = NULL;
roman6430c152023-10-12 11:28:47 +0200783 } else if (cert != &certs->certs[certs->cert_count]) {
roman33981232023-07-08 11:55:13 +0200784 memcpy(cert, &certs->certs[certs->cert_count], sizeof *certs->certs);
roman3f9b65c2023-06-05 14:26:58 +0200785 }
786}
787
788static void
roman6430c152023-10-12 11:28:47 +0200789nc_server_config_del_certs(struct nc_cert_grouping *certs_grp)
roman3f9b65c2023-06-05 14:26:58 +0200790{
roman6430c152023-10-12 11:28:47 +0200791 uint16_t i;
roman3f9b65c2023-06-05 14:26:58 +0200792
roman6430c152023-10-12 11:28:47 +0200793 if (certs_grp->store == NC_STORE_LOCAL) {
794 for (i = 0; i < certs_grp->cert_count; i++) {
795 free(certs_grp->certs[i].name);
796 free(certs_grp->certs[i].data);
roman3f9b65c2023-06-05 14:26:58 +0200797 }
roman6430c152023-10-12 11:28:47 +0200798 free(certs_grp->certs);
799 certs_grp->certs = NULL;
800 } else {
801 free(certs_grp->ts_ref);
roman3f9b65c2023-06-05 14:26:58 +0200802 }
803}
804
805static void
806nc_server_config_del_ctn(struct nc_server_tls_opts *opts, struct nc_ctn *ctn)
807{
808 struct nc_ctn *iter;
809
roman3f9b65c2023-06-05 14:26:58 +0200810 free(ctn->name);
roman6430c152023-10-12 11:28:47 +0200811 free(ctn->fingerprint);
roman3f9b65c2023-06-05 14:26:58 +0200812
813 if (opts->ctn == ctn) {
814 /* it's the first in the list */
815 opts->ctn = ctn->next;
816 free(ctn);
817 return;
818 }
819
roman84fe3252023-10-25 11:28:32 +0200820 for (iter = opts->ctn; iter; iter = iter->next) {
roman3f9b65c2023-06-05 14:26:58 +0200821 if (iter->next == ctn) {
822 /* found the ctn */
823 break;
824 }
roman3f9b65c2023-06-05 14:26:58 +0200825 }
826
romanb7bfa652023-11-09 12:36:35 +0100827 if (!iter) {
828 ERRINT;
829 return;
830 }
831
roman3f9b65c2023-06-05 14:26:58 +0200832 iter->next = ctn->next;
833 free(ctn);
834}
835
836static void
roman6430c152023-10-12 11:28:47 +0200837nc_server_config_del_ctns(struct nc_server_tls_opts *opts)
roman3f9b65c2023-06-05 14:26:58 +0200838{
839 struct nc_ctn *cur, *next;
840
roman84fe3252023-10-25 11:28:32 +0200841 for (cur = opts->ctn; cur; cur = next) {
roman3f9b65c2023-06-05 14:26:58 +0200842 next = cur->next;
roman3f9b65c2023-06-05 14:26:58 +0200843 free(cur->name);
roman6430c152023-10-12 11:28:47 +0200844 free(cur->fingerprint);
roman3f9b65c2023-06-05 14:26:58 +0200845 free(cur);
roman3f9b65c2023-06-05 14:26:58 +0200846 }
roman3a95bb22023-10-26 11:07:17 +0200847
roman3f9b65c2023-06-05 14:26:58 +0200848 opts->ctn = NULL;
849}
850
851static void
roman6430c152023-10-12 11:28:47 +0200852nc_server_config_del_tls_opts(struct nc_bind *bind, struct nc_server_tls_opts *opts)
roman3f9b65c2023-06-05 14:26:58 +0200853{
roman5ae78282023-11-02 13:34:34 +0100854 if (bind) {
855 free(bind->address);
856 if (bind->sock > -1) {
857 close(bind->sock);
858 }
roman3f9b65c2023-06-05 14:26:58 +0200859 }
860
861 if (opts->store == NC_STORE_LOCAL) {
roman6430c152023-10-12 11:28:47 +0200862 free(opts->pubkey_data);
863 free(opts->privkey_data);
864 free(opts->cert_data);
865 } else {
866 free(opts->key_ref);
867 free(opts->cert_ref);
roman3f9b65c2023-06-05 14:26:58 +0200868 }
869
roman6430c152023-10-12 11:28:47 +0200870 nc_server_config_del_certs(&opts->ca_certs);
871 nc_server_config_del_certs(&opts->ee_certs);
roman3f9b65c2023-06-05 14:26:58 +0200872
roman6430c152023-10-12 11:28:47 +0200873 free(opts->crl_path);
874 free(opts->crl_url);
romanfaecc582023-06-15 16:13:31 +0200875 X509_STORE_free(opts->crl_store);
romanfaecc582023-06-15 16:13:31 +0200876
roman6430c152023-10-12 11:28:47 +0200877 nc_server_config_del_ctns(opts);
878 free(opts->ciphers);
roman3f9b65c2023-06-05 14:26:58 +0200879 free(opts);
880}
881
882static void
883nc_server_config_del_endpt_tls(struct nc_endpt *endpt, struct nc_bind *bind)
884{
roman78df0fa2023-11-02 10:33:57 +0100885 /* delete any references to this endpoint */
886 nc_server_config_del_endpt_references(endpt->name);
roman6430c152023-10-12 11:28:47 +0200887 free(endpt->name);
roman78df0fa2023-11-02 10:33:57 +0100888
roman6430c152023-10-12 11:28:47 +0200889 free(endpt->referenced_endpt_name);
890
891 nc_server_config_del_tls_opts(bind, endpt->opts.tls);
roman3f9b65c2023-06-05 14:26:58 +0200892
893 server_opts.endpt_count--;
894 if (!server_opts.endpt_count) {
895 free(server_opts.endpts);
896 free(server_opts.binds);
897 server_opts.endpts = NULL;
898 server_opts.binds = NULL;
roman6430c152023-10-12 11:28:47 +0200899 } else if (endpt != &server_opts.endpts[server_opts.endpt_count]) {
roman33981232023-07-08 11:55:13 +0200900 memcpy(endpt, &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts);
901 memcpy(bind, &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds);
roman3f9b65c2023-06-05 14:26:58 +0200902 }
903}
904
roman2eab4742023-06-06 10:00:26 +0200905#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200906
roman5cbb6532023-06-22 12:53:17 +0200907static void
908nc_server_config_ch_del_endpt(struct nc_ch_client *ch_client, struct nc_ch_endpt *ch_endpt)
909{
910 free(ch_endpt->name);
roman5cbb6532023-06-22 12:53:17 +0200911
912#ifdef NC_ENABLED_SSH_TLS
roman6430c152023-10-12 11:28:47 +0200913 free(ch_endpt->address);
roman5cbb6532023-06-22 12:53:17 +0200914 if (ch_endpt->sock_pending > -1) {
915 close(ch_endpt->sock_pending);
916 ch_endpt->sock_pending = -1;
917 }
roman5ae78282023-11-02 13:34:34 +0100918 free(ch_endpt->referenced_endpt_name);
roman5cbb6532023-06-22 12:53:17 +0200919#endif /* NC_ENABLED_SSH_TLS */
920
921 switch (ch_endpt->ti) {
922#ifdef NC_ENABLED_SSH_TLS
923 case NC_TI_LIBSSH:
roman5ae78282023-11-02 13:34:34 +0100924 nc_server_config_del_ssh_opts(NULL, ch_endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +0200925 break;
romanb6f44032023-06-30 15:07:56 +0200926 case NC_TI_OPENSSL:
roman5ae78282023-11-02 13:34:34 +0100927 nc_server_config_del_tls_opts(NULL, ch_endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +0200928 break;
roman5cbb6532023-06-22 12:53:17 +0200929#endif /* NC_ENABLED_SSH_TLS */
930 default:
931 ERRINT;
932 break;
933 }
934
935 ch_client->ch_endpt_count--;
936 if (!ch_client->ch_endpt_count) {
937 free(ch_client->ch_endpts);
938 ch_client->ch_endpts = NULL;
939 }
940}
941
942static void
roman8341e8b2023-11-23 16:12:42 +0100943nc_server_config_destroy_ch_client(struct nc_ch_client *ch_client)
roman5cbb6532023-06-22 12:53:17 +0200944{
romanba93eac2023-07-18 14:36:48 +0200945 pthread_t tid;
roman8341e8b2023-11-23 16:12:42 +0100946 uint16_t i, ch_endpt_count;
947
948 if (ch_client->thread_data->thread_running) {
949 /* get tid */
950 tid = ch_client->tid;
951 /* CH COND LOCK */
952 pthread_mutex_lock(&ch_client->thread_data->cond_lock);
953 ch_client->thread_data->thread_running = 0;
954 pthread_cond_signal(&ch_client->thread_data->cond);
955 /* CH COND UNLOCK */
956 pthread_mutex_unlock(&ch_client->thread_data->cond_lock);
957
958 /* wait for the thread to terminate */
959 pthread_join(tid, NULL);
960 }
961
962 /* free its members */
963 free(ch_client->name);
964
965 ch_endpt_count = ch_client->ch_endpt_count;
966 for (i = 0; i < ch_endpt_count; i++) {
967 nc_server_config_ch_del_endpt(ch_client, &ch_client->ch_endpts[i]);
968 }
969}
970
971static void
972nc_server_config_ch_del_client(const struct lyd_node *node)
973{
974 struct nc_ch_client client, *ch_client;
roman5cbb6532023-06-22 12:53:17 +0200975
romanba93eac2023-07-18 14:36:48 +0200976 /* WR LOCK */
roman5cbb6532023-06-22 12:53:17 +0200977 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
978
roman8341e8b2023-11-23 16:12:42 +0100979 if (nc_server_config_get_ch_client(node, &ch_client)) {
980 /* WR UNLOCK */
981 pthread_rwlock_unlock(&server_opts.ch_client_lock);
982 ERR(NULL, "Call-home client \"%s\" not found.", lyd_get_value(lyd_child(node)));
983 return;
984 }
985
romanba93eac2023-07-18 14:36:48 +0200986 /* copy the client we want to delete into a local variable */
987 memcpy(&client, ch_client, sizeof *ch_client);
roman5cbb6532023-06-22 12:53:17 +0200988
romanba93eac2023-07-18 14:36:48 +0200989 /* delete the client */
roman5cbb6532023-06-22 12:53:17 +0200990 server_opts.ch_client_count--;
991 if (!server_opts.ch_client_count) {
992 free(server_opts.ch_clients);
993 server_opts.ch_clients = NULL;
romanba93eac2023-07-18 14:36:48 +0200994 } else {
995 memcpy(ch_client, &server_opts.ch_clients[server_opts.ch_client_count], sizeof *server_opts.ch_clients);
roman5cbb6532023-06-22 12:53:17 +0200996 }
997
romanba93eac2023-07-18 14:36:48 +0200998 /* WR UNLOCK */
roman5cbb6532023-06-22 12:53:17 +0200999 pthread_rwlock_unlock(&server_opts.ch_client_lock);
romanba93eac2023-07-18 14:36:48 +02001000
roman8341e8b2023-11-23 16:12:42 +01001001 nc_server_config_destroy_ch_client(&client);
1002}
romanba93eac2023-07-18 14:36:48 +02001003
roman8341e8b2023-11-23 16:12:42 +01001004/* presence container */
1005int
1006nc_server_config_listen(const struct lyd_node *node, NC_OPERATION op)
1007{
1008 uint16_t i, endpt_count;
romanba93eac2023-07-18 14:36:48 +02001009
roman8341e8b2023-11-23 16:12:42 +01001010 (void) node;
romanba93eac2023-07-18 14:36:48 +02001011
roman8341e8b2023-11-23 16:12:42 +01001012 assert(op == NC_OP_CREATE || op == NC_OP_DELETE);
1013
1014 if (op == NC_OP_DELETE) {
1015 endpt_count = server_opts.endpt_count;
1016 for (i = 0; i < endpt_count; i++) {
1017 switch (server_opts.endpts[i].ti) {
1018#ifdef NC_ENABLED_SSH_TLS
1019 case NC_TI_LIBSSH:
1020 nc_server_config_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]);
1021 break;
1022 case NC_TI_OPENSSL:
1023 nc_server_config_del_endpt_tls(&server_opts.endpts[i], &server_opts.binds[i]);
1024 break;
1025#endif /* NC_ENABLED_SSH_TLS */
1026 case NC_TI_UNIX:
romanfb3f7cf2023-11-30 16:10:09 +01001027 _nc_server_del_endpt_unix_socket(&server_opts.endpts[i], &server_opts.binds[i]);
roman8341e8b2023-11-23 16:12:42 +01001028 break;
1029 case NC_TI_NONE:
1030 case NC_TI_FD:
1031 ERRINT;
1032 return 1;
1033 }
1034 }
romanba93eac2023-07-18 14:36:48 +02001035 }
1036
roman8341e8b2023-11-23 16:12:42 +01001037 return 0;
roman5cbb6532023-06-22 12:53:17 +02001038}
1039
roman6430c152023-10-12 11:28:47 +02001040int
roman5cbb6532023-06-22 12:53:17 +02001041nc_server_config_ch(const struct lyd_node *node, NC_OPERATION op)
1042{
1043 uint16_t i, ch_client_count;
roman8341e8b2023-11-23 16:12:42 +01001044 struct nc_ch_client *ch_clients;
roman5cbb6532023-06-22 12:53:17 +02001045
1046 (void) node;
1047
roman8341e8b2023-11-23 16:12:42 +01001048 /* don't do anything if we're not deleting */
1049 if (op != NC_OP_DELETE) {
1050 return 0;
roman5cbb6532023-06-22 12:53:17 +02001051 }
roman6430c152023-10-12 11:28:47 +02001052
roman8341e8b2023-11-23 16:12:42 +01001053 /* WR LOCK */
1054 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
1055
1056 ch_client_count = server_opts.ch_client_count;
1057 ch_clients = server_opts.ch_clients;
1058
1059 /* remove them from the server opts */
1060 server_opts.ch_client_count = 0;
1061 server_opts.ch_clients = NULL;
1062
1063 /* UNLOCK */
1064 pthread_rwlock_unlock(&server_opts.ch_client_lock);
1065
1066 for (i = 0; i < ch_client_count; i++) {
1067 /* now destroy each client */
1068 nc_server_config_destroy_ch_client(&ch_clients[i]);
1069 }
1070
1071 free(ch_clients);
roman6430c152023-10-12 11:28:47 +02001072 return 0;
roman5cbb6532023-06-22 12:53:17 +02001073}
1074
romanc1d2b092023-02-02 08:58:27 +01001075/* default leaf */
1076static int
romaneaf84c72023-10-19 14:38:05 +02001077nc_server_config_hello_timeout(const struct lyd_node *node, NC_OPERATION op)
1078{
1079 assert(!strcmp(LYD_NAME(node), "hello-timeout"));
1080
1081 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001082 server_opts.hello_timeout = ((struct lyd_node_term *)node)->value.uint16;
romaneaf84c72023-10-19 14:38:05 +02001083 } else {
1084 /* default value */
1085 server_opts.hello_timeout = 60;
1086 }
1087
1088 return 0;
1089}
1090
1091/* default leaf */
1092static int
romane028ef92023-02-24 16:33:08 +01001093nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001094{
roman8341e8b2023-11-23 16:12:42 +01001095 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02001096
romanc1d2b092023-02-02 08:58:27 +01001097 assert(!strcmp(LYD_NAME(node), "idle-timeout"));
1098
romaneaf84c72023-10-19 14:38:05 +02001099 if (is_ch(node)) {
romanb6f44032023-06-30 15:07:56 +02001100 /* call-home idle timeout */
roman6430c152023-10-12 11:28:47 +02001101 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
1102 /* to avoid unlock on fail */
romanb6f44032023-06-30 15:07:56 +02001103 return 1;
1104 }
1105
1106 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001107 ch_client->idle_timeout = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02001108 } else if (op == NC_OP_DELETE) {
1109 ch_client->idle_timeout = 180;
1110 }
roman6430c152023-10-12 11:28:47 +02001111
1112 nc_ch_client_unlock(ch_client);
romaneaf84c72023-10-19 14:38:05 +02001113 } else {
1114 /* whole server idle timeout */
1115 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001116 server_opts.idle_timeout = ((struct lyd_node_term *)node)->value.uint16;
romaneaf84c72023-10-19 14:38:05 +02001117 } else {
1118 /* default value */
1119 server_opts.idle_timeout = 0;
1120 }
romanc1d2b092023-02-02 08:58:27 +01001121 }
1122
1123 return 0;
1124}
1125
1126static int
roman874fed12023-05-25 10:20:01 +02001127nc_server_config_create_bind(void)
romanc1d2b092023-02-02 08:58:27 +01001128{
1129 int ret = 0;
1130 void *tmp;
1131
1132 tmp = realloc(server_opts.binds, (server_opts.endpt_count + 1) * sizeof *server_opts.binds);
roman3a95bb22023-10-26 11:07:17 +02001133 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01001134 server_opts.binds = tmp;
1135 memset(&server_opts.binds[server_opts.endpt_count], 0, sizeof *server_opts.binds);
1136
1137 server_opts.binds[server_opts.endpt_count].sock = -1;
1138
1139cleanup:
1140 return ret;
1141}
1142
1143static int
roman874fed12023-05-25 10:20:01 +02001144nc_server_config_create_endpoint(const struct lyd_node *node)
romanc1d2b092023-02-02 08:58:27 +01001145{
roman874fed12023-05-25 10:20:01 +02001146 if (nc_server_config_create_bind()) {
romanf02273a2023-05-25 09:44:11 +02001147 return 1;
romanc1d2b092023-02-02 08:58:27 +01001148 }
romanc1d2b092023-02-02 08:58:27 +01001149
1150 node = lyd_child(node);
1151 assert(!strcmp(LYD_NAME(node), "name"));
1152
romanf02273a2023-05-25 09:44:11 +02001153 return nc_server_config_realloc(lyd_get_value(node), (void **)&server_opts.endpts, sizeof *server_opts.endpts, &server_opts.endpt_count);
romanc1d2b092023-02-02 08:58:27 +01001154}
1155
roman5cbb6532023-06-22 12:53:17 +02001156static int
1157nc_server_config_ch_create_endpoint(const struct lyd_node *node, struct nc_ch_client *ch_client)
1158{
1159 node = lyd_child(node);
1160 assert(!strcmp(LYD_NAME(node), "name"));
1161
1162 return nc_server_config_realloc(lyd_get_value(node), (void **)&ch_client->ch_endpts, sizeof *ch_client->ch_endpts, &ch_client->ch_endpt_count);
1163}
1164
romanc1d2b092023-02-02 08:58:27 +01001165/* list */
1166static int
romane028ef92023-02-24 16:33:08 +01001167nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001168{
1169 int ret = 0;
1170 struct nc_endpt *endpt;
1171 struct nc_bind *bind;
roman6430c152023-10-12 11:28:47 +02001172 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001173 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001174
1175 assert(!strcmp(LYD_NAME(node), "endpoint"));
1176
roman5cbb6532023-06-22 12:53:17 +02001177 if (is_listen(node)) {
1178 /* listen */
1179 if (op == NC_OP_CREATE) {
1180 ret = nc_server_config_create_endpoint(node);
1181 if (ret) {
1182 goto cleanup;
1183 }
1184 } else if (op == NC_OP_DELETE) {
1185 /* free all children */
1186 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1187 ret = 1;
1188 goto cleanup;
1189 }
1190
1191 switch (endpt->ti) {
1192#ifdef NC_ENABLED_SSH_TLS
1193 case NC_TI_LIBSSH:
1194 nc_server_config_del_endpt_ssh(endpt, bind);
1195 break;
1196 case NC_TI_OPENSSL:
1197 nc_server_config_del_endpt_tls(endpt, bind);
1198 break;
1199#endif /* NC_ENABLED_SSH_TLS */
1200 case NC_TI_UNIX:
romanfb3f7cf2023-11-30 16:10:09 +01001201 _nc_server_del_endpt_unix_socket(endpt, bind);
roman5cbb6532023-06-22 12:53:17 +02001202 break;
1203 case NC_TI_NONE:
1204 case NC_TI_FD:
1205 ERRINT;
1206 ret = 1;
1207 goto cleanup;
1208 }
romanc1d2b092023-02-02 08:58:27 +01001209 }
roman5cbb6532023-06-22 12:53:17 +02001210 } else if (is_ch(node)) {
romanba93eac2023-07-18 14:36:48 +02001211 /* LOCK */
1212 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001213 /* to avoid unlock on fail */
1214 return 1;
romanc1d2b092023-02-02 08:58:27 +01001215 }
roman3f9b65c2023-06-05 14:26:58 +02001216
roman5cbb6532023-06-22 12:53:17 +02001217 if (op == NC_OP_CREATE) {
1218 ret = nc_server_config_ch_create_endpoint(node, ch_client);
1219 if (ret) {
1220 goto cleanup;
1221 }
1222
1223 /* init ch sock */
1224 ch_client->ch_endpts[ch_client->ch_endpt_count - 1].sock_pending = -1;
roman6430c152023-10-12 11:28:47 +02001225 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01001226 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman6430c152023-10-12 11:28:47 +02001227 ret = 1;
1228 goto cleanup;
1229 }
1230
1231 nc_server_config_ch_del_endpt(ch_client, ch_endpt);
roman3f9b65c2023-06-05 14:26:58 +02001232 }
romanc1d2b092023-02-02 08:58:27 +01001233 }
1234
1235cleanup:
romanba93eac2023-07-18 14:36:48 +02001236 if (is_ch(node)) {
1237 /* UNLOCK */
1238 nc_ch_client_unlock(ch_client);
1239 }
romanc1d2b092023-02-02 08:58:27 +01001240 return ret;
1241}
1242
roman2eab4742023-06-06 10:00:26 +02001243#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02001244
romanc1d2b092023-02-02 08:58:27 +01001245static int
roman874fed12023-05-25 10:20:01 +02001246nc_server_config_create_ssh(struct nc_endpt *endpt)
romanc1d2b092023-02-02 08:58:27 +01001247{
1248 endpt->ti = NC_TI_LIBSSH;
1249 endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
roman3a95bb22023-10-26 11:07:17 +02001250 NC_CHECK_ERRMEM_RET(!endpt->opts.ssh, 1);
romanc1d2b092023-02-02 08:58:27 +01001251
1252 return 0;
1253}
1254
roman5cbb6532023-06-22 12:53:17 +02001255static int
1256nc_server_config_ch_create_ssh(struct nc_ch_endpt *ch_endpt)
1257{
1258 ch_endpt->ti = NC_TI_LIBSSH;
1259 ch_endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
roman3a95bb22023-10-26 11:07:17 +02001260 NC_CHECK_ERRMEM_RET(!ch_endpt->opts.ssh, 1);
roman5cbb6532023-06-22 12:53:17 +02001261
1262 return 0;
1263}
1264
romanc1d2b092023-02-02 08:58:27 +01001265/* NP container */
1266static int
romane028ef92023-02-24 16:33:08 +01001267nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001268{
1269 struct nc_endpt *endpt;
1270 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001271 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001272 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001273 int ret = 0;
1274
1275 assert(!strcmp(LYD_NAME(node), "ssh"));
1276
roman5cbb6532023-06-22 12:53:17 +02001277 if (is_listen(node)) {
1278 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1279 ret = 1;
romanc1d2b092023-02-02 08:58:27 +01001280 goto cleanup;
1281 }
roman5cbb6532023-06-22 12:53:17 +02001282
1283 if (op == NC_OP_CREATE) {
1284 ret = nc_server_config_create_ssh(endpt);
1285 if (ret) {
1286 goto cleanup;
1287 }
1288 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02001289 nc_server_config_del_ssh_opts(bind, endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +02001290 }
1291 } else {
romanba93eac2023-07-18 14:36:48 +02001292 /* LOCK */
1293 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001294 /* to avoid unlock on fail */
1295 return 1;
romanba93eac2023-07-18 14:36:48 +02001296 }
1297
roman8341e8b2023-11-23 16:12:42 +01001298 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001299 ret = 1;
1300 goto cleanup;
1301 }
1302
1303 if (op == NC_OP_CREATE) {
1304 ret = nc_server_config_ch_create_ssh(ch_endpt);
1305 if (ret) {
1306 goto cleanup;
1307 }
romanb6f44032023-06-30 15:07:56 +02001308 } else if (op == NC_OP_DELETE) {
roman5ae78282023-11-02 13:34:34 +01001309 nc_server_config_del_ssh_opts(NULL, ch_endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +02001310 }
romanc1d2b092023-02-02 08:58:27 +01001311 }
1312
1313cleanup:
romanba93eac2023-07-18 14:36:48 +02001314 if (is_ch(node)) {
1315 /* UNLOCK */
1316 nc_ch_client_unlock(ch_client);
1317 }
romanc1d2b092023-02-02 08:58:27 +01001318 return ret;
1319}
1320
roman3f9b65c2023-06-05 14:26:58 +02001321static int
1322nc_server_config_create_tls(struct nc_endpt *endpt)
1323{
1324 endpt->ti = NC_TI_OPENSSL;
1325 endpt->opts.tls = calloc(1, sizeof *endpt->opts.tls);
roman3a95bb22023-10-26 11:07:17 +02001326 NC_CHECK_ERRMEM_RET(!endpt->opts.tls, 1);
roman3f9b65c2023-06-05 14:26:58 +02001327
1328 return 0;
1329}
1330
1331static int
romanb6f44032023-06-30 15:07:56 +02001332nc_server_config_ch_create_tls(struct nc_ch_endpt *ch_endpt)
1333{
1334 ch_endpt->ti = NC_TI_OPENSSL;
1335 ch_endpt->opts.tls = calloc(1, sizeof(struct nc_server_tls_opts));
roman3a95bb22023-10-26 11:07:17 +02001336 NC_CHECK_ERRMEM_RET(!ch_endpt->opts.tls, 1);
romanb6f44032023-06-30 15:07:56 +02001337
1338 return 0;
1339}
1340
1341static int
roman3f9b65c2023-06-05 14:26:58 +02001342nc_server_config_tls(const struct lyd_node *node, NC_OPERATION op)
1343{
1344 struct nc_endpt *endpt;
1345 struct nc_bind *bind;
romanb6f44032023-06-30 15:07:56 +02001346 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001347 struct nc_ch_client *ch_client = NULL;
roman3f9b65c2023-06-05 14:26:58 +02001348 int ret = 0;
1349
1350 assert(!strcmp(LYD_NAME(node), "tls"));
1351
romanb6f44032023-06-30 15:07:56 +02001352 if (is_listen(node)) {
1353 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1354 ret = 1;
roman3f9b65c2023-06-05 14:26:58 +02001355 goto cleanup;
1356 }
romanb6f44032023-06-30 15:07:56 +02001357
1358 if (op == NC_OP_CREATE) {
1359 ret = nc_server_config_create_tls(endpt);
1360 if (ret) {
1361 goto cleanup;
1362 }
1363 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02001364 nc_server_config_del_tls_opts(bind, endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +02001365 }
1366 } else {
romanba93eac2023-07-18 14:36:48 +02001367 /* LOCK */
1368 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001369 /* to avoid unlock on fail */
1370 return 1;
romanba93eac2023-07-18 14:36:48 +02001371 }
1372
roman8341e8b2023-11-23 16:12:42 +01001373 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
romanb6f44032023-06-30 15:07:56 +02001374 ret = 1;
1375 goto cleanup;
1376 }
1377
1378 if (op == NC_OP_CREATE) {
1379 ret = nc_server_config_ch_create_tls(ch_endpt);
1380 if (ret) {
1381 goto cleanup;
1382 }
roman6430c152023-10-12 11:28:47 +02001383 } else if (op == NC_OP_DELETE) {
roman5ae78282023-11-02 13:34:34 +01001384 nc_server_config_del_tls_opts(NULL, ch_endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +02001385 }
roman3f9b65c2023-06-05 14:26:58 +02001386 }
1387
1388cleanup:
romanba93eac2023-07-18 14:36:48 +02001389 if (is_ch(node)) {
1390 /* UNLOCK */
1391 nc_ch_client_unlock(ch_client);
1392 }
roman3f9b65c2023-06-05 14:26:58 +02001393 return ret;
1394}
1395
romanc1d2b092023-02-02 08:58:27 +01001396/* mandatory leaf */
1397static int
romane028ef92023-02-24 16:33:08 +01001398nc_server_config_local_address(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001399{
1400 struct nc_endpt *endpt;
1401 struct nc_bind *bind;
1402 int ret = 0;
1403
1404 (void) op;
1405
1406 assert(!strcmp(LYD_NAME(node), "local-address"));
1407
1408 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001409 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001410 ret = 1;
1411 goto cleanup;
1412 }
1413
roman6430c152023-10-12 11:28:47 +02001414 free(bind->address);
romanc1d2b092023-02-02 08:58:27 +01001415 bind->address = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001416 NC_CHECK_ERRMEM_GOTO(!bind->address, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01001417
romanfb3f7cf2023-11-30 16:10:09 +01001418 ret = nc_server_set_address_port(endpt, bind, lyd_get_value(node), 0);
romanc1d2b092023-02-02 08:58:27 +01001419 if (ret) {
1420 goto cleanup;
1421 }
1422 }
1423
1424cleanup:
1425 return ret;
1426}
1427
1428/* leaf with default value */
1429static int
romane028ef92023-02-24 16:33:08 +01001430nc_server_config_local_port(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001431{
1432 struct nc_endpt *endpt;
1433 struct nc_bind *bind;
1434 int ret = 0;
1435
1436 assert(!strcmp(LYD_NAME(node), "local-port"));
1437
1438 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001439 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001440 ret = 1;
1441 goto cleanup;
1442 }
1443
1444 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001445 bind->port = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001446 } else {
1447 /* delete -> set to default */
1448 bind->port = 0;
1449 }
1450
romanfb3f7cf2023-11-30 16:10:09 +01001451 ret = nc_server_set_address_port(endpt, bind, NULL, bind->port);
romanc1d2b092023-02-02 08:58:27 +01001452 if (ret) {
1453 goto cleanup;
1454 }
1455 }
1456
1457cleanup:
1458 return ret;
1459}
1460
1461/* P container */
1462static int
romane028ef92023-02-24 16:33:08 +01001463nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001464{
roman5cbb6532023-06-22 12:53:17 +02001465 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001466 struct nc_endpt *endpt;
1467 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001468 struct nc_ch_endpt *ch_endpt;
roman6cb86ea2023-11-08 15:12:05 +01001469 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001470
1471 assert(!strcmp(LYD_NAME(node), "keepalives"));
1472
roman5cbb6532023-06-22 12:53:17 +02001473 if (is_listen(node) && equal_parent_name(node, 1, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001474 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001475 ret = 1;
1476 goto cleanup;
1477 }
1478
1479 if (op == NC_OP_CREATE) {
1480 endpt->ka.enabled = 1;
1481 } else {
1482 endpt->ka.enabled = 0;
1483 }
1484 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1485 if (ret) {
1486 goto cleanup;
1487 }
roman5cbb6532023-06-22 12:53:17 +02001488 } else if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001489 /* LOCK */
1490 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001491 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001492 return 1;
1493 }
1494
roman8341e8b2023-11-23 16:12:42 +01001495 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001496 ret = 1;
1497 goto cleanup;
1498 }
1499
1500 if (op == NC_OP_CREATE) {
1501 ch_endpt->ka.enabled = 1;
1502 } else {
1503 ch_endpt->ka.enabled = 0;
1504 }
romanc1d2b092023-02-02 08:58:27 +01001505 }
1506
1507cleanup:
romanba93eac2023-07-18 14:36:48 +02001508 if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) {
1509 /* UNLOCK */
1510 nc_ch_client_unlock(ch_client);
1511 }
romanc1d2b092023-02-02 08:58:27 +01001512 return ret;
1513}
1514
1515/* mandatory leaf */
1516static int
romane028ef92023-02-24 16:33:08 +01001517nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001518{
roman5cbb6532023-06-22 12:53:17 +02001519 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001520 struct nc_endpt *endpt;
1521 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001522 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001523 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001524
1525 assert(!strcmp(LYD_NAME(node), "idle-time"));
1526
roman5cbb6532023-06-22 12:53:17 +02001527 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001528 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001529 ret = 1;
1530 goto cleanup;
1531 }
1532
1533 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001534 endpt->ka.idle_time = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001535 } else {
1536 endpt->ka.idle_time = 0;
1537 }
1538 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1539 if (ret) {
1540 goto cleanup;
1541 }
roman5cbb6532023-06-22 12:53:17 +02001542 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001543 /* LOCK */
1544 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001545 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001546 return 1;
1547 }
1548
roman8341e8b2023-11-23 16:12:42 +01001549 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001550 ret = 1;
1551 goto cleanup;
1552 }
1553
1554 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001555 ch_endpt->ka.idle_time = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001556 } else {
1557 ch_endpt->ka.idle_time = 0;
1558 }
romanc1d2b092023-02-02 08:58:27 +01001559 }
1560
1561cleanup:
roman6430c152023-10-12 11:28:47 +02001562 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001563 /* UNLOCK */
1564 nc_ch_client_unlock(ch_client);
1565 }
romanc1d2b092023-02-02 08:58:27 +01001566 return ret;
1567}
1568
1569/* mandatory leaf */
1570static int
romane028ef92023-02-24 16:33:08 +01001571nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001572{
roman5cbb6532023-06-22 12:53:17 +02001573 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001574 struct nc_endpt *endpt;
1575 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001576 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001577 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001578
1579 assert(!strcmp(LYD_NAME(node), "max-probes"));
1580
roman5cbb6532023-06-22 12:53:17 +02001581 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001582 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001583 ret = 1;
1584 goto cleanup;
1585 }
1586
1587 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001588 endpt->ka.max_probes = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001589 } else {
1590 endpt->ka.max_probes = 0;
1591 }
1592 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1593 if (ret) {
1594 goto cleanup;
1595 }
roman5cbb6532023-06-22 12:53:17 +02001596 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001597 /* LOCK */
1598 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001599 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001600 return 1;
1601 }
1602
roman8341e8b2023-11-23 16:12:42 +01001603 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001604 ret = 1;
1605 goto cleanup;
1606 }
1607
1608 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001609 ch_endpt->ka.max_probes = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001610 } else {
1611 ch_endpt->ka.max_probes = 0;
1612 }
romanc1d2b092023-02-02 08:58:27 +01001613 }
1614
1615cleanup:
roman6430c152023-10-12 11:28:47 +02001616 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001617 /* UNLOCK */
1618 nc_ch_client_unlock(ch_client);
1619 }
romanc1d2b092023-02-02 08:58:27 +01001620 return ret;
1621}
1622
1623/* mandatory leaf */
1624static int
romane028ef92023-02-24 16:33:08 +01001625nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001626{
roman5cbb6532023-06-22 12:53:17 +02001627 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001628 struct nc_endpt *endpt;
1629 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001630 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001631 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001632
1633 assert(!strcmp(LYD_NAME(node), "probe-interval"));
1634
roman5cbb6532023-06-22 12:53:17 +02001635 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001636 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001637 ret = 1;
1638 goto cleanup;
1639 }
1640
1641 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001642 endpt->ka.probe_interval = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001643 } else {
1644 endpt->ka.probe_interval = 0;
1645 }
1646 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1647 if (ret) {
1648 goto cleanup;
1649 }
roman5cbb6532023-06-22 12:53:17 +02001650 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001651 /* LOCK */
1652 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001653 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001654 return 1;
1655 }
1656
roman8341e8b2023-11-23 16:12:42 +01001657 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001658 ret = 1;
1659 goto cleanup;
1660 }
1661
1662 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001663 ch_endpt->ka.probe_interval = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001664 } else {
1665 ch_endpt->ka.max_probes = 0;
1666 }
romanc1d2b092023-02-02 08:58:27 +01001667 }
1668
1669cleanup:
roman6430c152023-10-12 11:28:47 +02001670 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001671 /* UNLOCK */
1672 nc_ch_client_unlock(ch_client);
1673 }
romanc1d2b092023-02-02 08:58:27 +01001674 return ret;
1675}
1676
1677static int
roman874fed12023-05-25 10:20:01 +02001678nc_server_config_create_host_key(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01001679{
romanf02273a2023-05-25 09:44:11 +02001680 node = lyd_child(node);
1681 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01001682
romanf02273a2023-05-25 09:44:11 +02001683 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->hostkeys, sizeof *opts->hostkeys, &opts->hostkey_count);
romanc1d2b092023-02-02 08:58:27 +01001684}
1685
1686/* list */
1687static int
romane028ef92023-02-24 16:33:08 +01001688nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001689{
roman5cbb6532023-06-22 12:53:17 +02001690 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001691 struct nc_hostkey *hostkey;
roman4cb8bb12023-06-29 09:16:46 +02001692 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01001693 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001694
1695 assert(!strcmp(LYD_NAME(node), "host-key"));
1696
roman4cb8bb12023-06-29 09:16:46 +02001697 if (equal_parent_name(node, 1, "server-identity")) {
romanba93eac2023-07-18 14:36:48 +02001698 /* LOCK */
1699 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001700 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001701 return 1;
1702 }
1703
roman8341e8b2023-11-23 16:12:42 +01001704 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman6cb86ea2023-11-08 15:12:05 +01001705 ret = 1;
1706 goto cleanup;
1707 }
1708
romanc1d2b092023-02-02 08:58:27 +01001709 if (op == NC_OP_CREATE) {
roman4cb8bb12023-06-29 09:16:46 +02001710 ret = nc_server_config_create_host_key(node, opts);
romanc1d2b092023-02-02 08:58:27 +01001711 if (ret) {
1712 goto cleanup;
1713 }
1714 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01001715 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001716 ret = 1;
1717 goto cleanup;
1718 }
roman4cb8bb12023-06-29 09:16:46 +02001719 nc_server_config_del_hostkey(opts, hostkey);
roman5cbb6532023-06-22 12:53:17 +02001720 }
romanc1d2b092023-02-02 08:58:27 +01001721 }
1722
1723cleanup:
romanba93eac2023-07-18 14:36:48 +02001724 if (is_ch(node) && equal_parent_name(node, 1, "server-identity")) {
1725 /* UNLOCK */
1726 nc_ch_client_unlock(ch_client);
1727 }
romanc1d2b092023-02-02 08:58:27 +01001728 return ret;
1729}
1730
1731/* mandatory leaf */
romane028ef92023-02-24 16:33:08 +01001732static int
1733nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001734{
roman3f9b65c2023-06-05 14:26:58 +02001735 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02001736 const char *format;
roman3f9b65c2023-06-05 14:26:58 +02001737 NC_PUBKEY_FORMAT pubkey_type;
roman8edee342023-03-31 13:25:48 +02001738 struct nc_public_key *pubkey;
romanc1d2b092023-02-02 08:58:27 +01001739 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02001740 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01001741 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001742
1743 assert(!strcmp(LYD_NAME(node), "public-key-format"));
1744
roman6cb86ea2023-11-08 15:12:05 +01001745 /* LOCK */
1746 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
1747 /* to avoid unlock on fail */
1748 return 1;
1749 }
1750
romanc1d2b092023-02-02 08:58:27 +01001751 format = ((struct lyd_node_term *)node)->value.ident->name;
roman3f9b65c2023-06-05 14:26:58 +02001752 if (!strcmp(format, "ssh-public-key-format")) {
roman13145912023-08-17 15:36:54 +02001753 pubkey_type = NC_PUBKEY_FORMAT_SSH;
roman3f9b65c2023-06-05 14:26:58 +02001754 } else if (!strcmp(format, "subject-public-key-info-format")) {
1755 pubkey_type = NC_PUBKEY_FORMAT_X509;
1756 } else {
1757 ERR(NULL, "Public key format (%s) not supported.", format);
1758 ret = 1;
1759 goto cleanup;
1760 }
romanc1d2b092023-02-02 08:58:27 +01001761
roman4cb8bb12023-06-29 09:16:46 +02001762 if (is_ssh(node) && equal_parent_name(node, 4, "server-identity")) {
roman5cbb6532023-06-22 12:53:17 +02001763 /* SSH hostkey public key fmt */
roman8341e8b2023-11-23 16:12:42 +01001764 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02001765 ret = 1;
1766 goto cleanup;
1767 }
1768
1769 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1770 hostkey->key.pubkey_type = pubkey_type;
1771 }
roman4cb8bb12023-06-29 09:16:46 +02001772 } else if (is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) {
roman5cbb6532023-06-22 12:53:17 +02001773 /* SSH client auth public key fmt */
roman8341e8b2023-11-23 16:12:42 +01001774 if (nc_server_config_get_pubkey(node, ch_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001775 ret = 1;
1776 goto cleanup;
1777 }
1778
1779 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman3f9b65c2023-06-05 14:26:58 +02001780 pubkey->type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001781 }
romanb6f44032023-06-30 15:07:56 +02001782 } else if (is_tls(node) && equal_parent_name(node, 3, "server-identity")) {
1783 /* TLS server-identity */
roman8341e8b2023-11-23 16:12:42 +01001784 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02001785 ret = 1;
1786 goto cleanup;
1787 }
1788
roman5cbb6532023-06-22 12:53:17 +02001789 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02001790 opts->pubkey_type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001791 }
romanc1d2b092023-02-02 08:58:27 +01001792 }
1793
1794cleanup:
romanba93eac2023-07-18 14:36:48 +02001795 if (is_ch(node)) {
1796 /* UNLOCK */
1797 nc_ch_client_unlock(ch_client);
1798 }
romanc1d2b092023-02-02 08:58:27 +01001799 return ret;
1800}
1801
1802static int
roman58f79d02023-10-06 10:20:31 +02001803nc_server_config_create_auth_key_public_key_list(const struct lyd_node *node, struct nc_auth_client *auth_client)
romanc1d2b092023-02-02 08:58:27 +01001804{
romanc1d2b092023-02-02 08:58:27 +01001805 assert(!strcmp(LYD_NAME(node), "public-key"));
1806
romanc1d2b092023-02-02 08:58:27 +01001807 node = lyd_child(node);
1808 assert(!strcmp(LYD_NAME(node), "name"));
1809
romanf02273a2023-05-25 09:44:11 +02001810 return nc_server_config_realloc(lyd_get_value(node), (void **)&auth_client->pubkeys, sizeof *auth_client->pubkeys, &auth_client->pubkey_count);
romanc1d2b092023-02-02 08:58:27 +01001811}
1812
1813static int
roman874fed12023-05-25 10:20:01 +02001814nc_server_config_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +01001815{
roman6430c152023-10-12 11:28:47 +02001816 free(pubkey->data);
roman3f9b65c2023-06-05 14:26:58 +02001817 pubkey->data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001818 NC_CHECK_ERRMEM_RET(!pubkey->data, 1);
romanc1d2b092023-02-02 08:58:27 +01001819
1820 return 0;
1821}
1822
1823static int
roman874fed12023-05-25 10:20:01 +02001824nc_server_config_replace_host_key_public_key(const struct lyd_node *node, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +01001825{
roman6430c152023-10-12 11:28:47 +02001826 free(hostkey->key.pubkey_data);
roman3f9b65c2023-06-05 14:26:58 +02001827 hostkey->key.pubkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001828 NC_CHECK_ERRMEM_RET(!hostkey->key.pubkey_data, 1);
romanc1d2b092023-02-02 08:58:27 +01001829
1830 return 0;
1831}
1832
roman3f9b65c2023-06-05 14:26:58 +02001833static int
1834nc_server_config_tls_replace_server_public_key(const struct lyd_node *node, struct nc_server_tls_opts *opts)
1835{
roman6430c152023-10-12 11:28:47 +02001836 free(opts->pubkey_data);
roman3f9b65c2023-06-05 14:26:58 +02001837 opts->pubkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001838 NC_CHECK_ERRMEM_RET(!opts->pubkey_data, 1);
roman3f9b65c2023-06-05 14:26:58 +02001839
1840 return 0;
1841}
1842
romanc1d2b092023-02-02 08:58:27 +01001843static int
romane028ef92023-02-24 16:33:08 +01001844nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001845{
roman3f9b65c2023-06-05 14:26:58 +02001846 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001847 struct nc_hostkey *hostkey;
roman58f79d02023-10-06 10:20:31 +02001848 struct nc_auth_client *auth_client;
roman8edee342023-03-31 13:25:48 +02001849 struct nc_public_key *pubkey;
romanb6f44032023-06-30 15:07:56 +02001850 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01001851 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001852
1853 assert(!strcmp(LYD_NAME(node), "public-key"));
1854
romanba93eac2023-07-18 14:36:48 +02001855 /* LOCK */
1856 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02001857 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001858 return 1;
1859 }
1860
roman4cb8bb12023-06-29 09:16:46 +02001861 if (is_ssh(node) && equal_parent_name(node, 3, "host-key")) {
roman3f9b65c2023-06-05 14:26:58 +02001862 /* server's public-key, mandatory leaf */
roman8341e8b2023-11-23 16:12:42 +01001863 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001864 ret = 1;
1865 goto cleanup;
1866 }
1867
roman13145912023-08-17 15:36:54 +02001868 /* the public key must not be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
roman51a1e192023-09-14 10:13:45 +02001869 if (nc_is_pk_subject_public_key_info(lyd_get_value(node))) {
roman13145912023-08-17 15:36:54 +02001870 ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH hostkey is forbidden!");
1871 ret = 1;
1872 goto cleanup;
1873 }
1874
romanc1d2b092023-02-02 08:58:27 +01001875 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02001876 /* set to local */
roman874fed12023-05-25 10:20:01 +02001877 hostkey->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02001878
roman874fed12023-05-25 10:20:01 +02001879 ret = nc_server_config_replace_host_key_public_key(node, hostkey);
romanc1d2b092023-02-02 08:58:27 +01001880 if (ret) {
1881 goto cleanup;
1882 }
1883 }
roman4cb8bb12023-06-29 09:16:46 +02001884 } else if (is_ssh(node) && equal_parent_name(node, 5, "client-authentication")) {
romanc1d2b092023-02-02 08:58:27 +01001885 /* client auth pubkeys, list */
roman8341e8b2023-11-23 16:12:42 +01001886 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001887 ret = 1;
1888 goto cleanup;
1889 }
1890
1891 if (op == NC_OP_CREATE) {
romanf02273a2023-05-25 09:44:11 +02001892 /* set to local */
roman874fed12023-05-25 10:20:01 +02001893 auth_client->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02001894
roman874fed12023-05-25 10:20:01 +02001895 ret = nc_server_config_create_auth_key_public_key_list(node, auth_client);
romanc1d2b092023-02-02 08:58:27 +01001896 if (ret) {
1897 goto cleanup;
1898 }
1899 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01001900 if (nc_server_config_get_pubkey(node, ch_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001901 ret = 1;
1902 goto cleanup;
1903 }
1904
roman874fed12023-05-25 10:20:01 +02001905 nc_server_config_del_auth_client_pubkey(auth_client, pubkey);
romanc1d2b092023-02-02 08:58:27 +01001906 }
roman4cb8bb12023-06-29 09:16:46 +02001907 } else if (is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) {
romanc1d2b092023-02-02 08:58:27 +01001908 /* client auth pubkey, leaf */
roman8341e8b2023-11-23 16:12:42 +01001909 if (nc_server_config_get_pubkey(node, ch_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001910 ret = 1;
1911 goto cleanup;
1912 }
1913
roman13145912023-08-17 15:36:54 +02001914 /* the public key must not be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
roman51a1e192023-09-14 10:13:45 +02001915 if (nc_is_pk_subject_public_key_info(lyd_get_value(node))) {
roman13145912023-08-17 15:36:54 +02001916 ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH user's key is forbidden!");
1917 ret = 1;
1918 goto cleanup;
1919 }
1920
romanc1d2b092023-02-02 08:58:27 +01001921 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02001922 ret = nc_server_config_replace_auth_key_public_key_leaf(node, pubkey);
romanc1d2b092023-02-02 08:58:27 +01001923 if (ret) {
1924 goto cleanup;
1925 }
roman6430c152023-10-12 11:28:47 +02001926 } else if (op == NC_OP_DELETE) {
1927 free(pubkey->data);
1928 pubkey->data = NULL;
romanc1d2b092023-02-02 08:58:27 +01001929 }
romanb6f44032023-06-30 15:07:56 +02001930 } else if (is_tls(node) && equal_parent_name(node, 3, "server-identity")) {
1931 /* TLS server-identity */
roman8341e8b2023-11-23 16:12:42 +01001932 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02001933 ret = 1;
1934 goto cleanup;
1935 }
1936
roman13145912023-08-17 15:36:54 +02001937 /* the public key must be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
roman51a1e192023-09-14 10:13:45 +02001938 if (!nc_is_pk_subject_public_key_info(lyd_get_value(node))) {
roman13145912023-08-17 15:36:54 +02001939 ERR(NULL, "TLS server certificate's Public Key must be in the SubjectPublicKeyInfo format!");
1940 ret = 1;
1941 goto cleanup;
1942 }
1943
roman3f9b65c2023-06-05 14:26:58 +02001944 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1945 /* set to local */
romanb6f44032023-06-30 15:07:56 +02001946 opts->store = NC_STORE_LOCAL;
roman3f9b65c2023-06-05 14:26:58 +02001947
romanb6f44032023-06-30 15:07:56 +02001948 ret = nc_server_config_tls_replace_server_public_key(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02001949 if (ret) {
1950 goto cleanup;
1951 }
1952 }
roman5cbb6532023-06-22 12:53:17 +02001953 }
1954
1955cleanup:
romanba93eac2023-07-18 14:36:48 +02001956 if (is_ch(node)) {
1957 /* UNLOCK */
1958 nc_ch_client_unlock(ch_client);
1959 }
roman5cbb6532023-06-22 12:53:17 +02001960 return ret;
1961}
1962
1963/* leaf */
1964static int
1965nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op)
1966{
1967 int ret = 0;
1968 const char *format;
1969 NC_PRIVKEY_FORMAT privkey_type;
roman5cbb6532023-06-22 12:53:17 +02001970 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02001971 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01001972 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02001973
1974 (void) op;
1975
1976 assert(!strcmp(LYD_NAME(node), "private-key-format"));
1977
roman6cb86ea2023-11-08 15:12:05 +01001978 /* LOCK */
1979 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
1980 /* to avoid unlock on fail */
1981 return 1;
1982 }
1983
roman5cbb6532023-06-22 12:53:17 +02001984 format = ((struct lyd_node_term *)node)->value.ident->name;
1985 if (!format) {
1986 ret = 1;
1987 goto cleanup;
1988 }
1989
1990 privkey_type = nc_server_config_get_private_key_type(format);
1991 if (privkey_type == NC_PRIVKEY_FORMAT_UNKNOWN) {
1992 ERR(NULL, "Unknown private key format.");
1993 ret = 1;
1994 goto cleanup;
1995 }
1996
roman4cb8bb12023-06-29 09:16:46 +02001997 if (is_ssh(node)) {
1998 /* ssh */
roman8341e8b2023-11-23 16:12:42 +01001999 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02002000 ret = 1;
2001 goto cleanup;
2002 }
2003
2004 hostkey->key.privkey_type = privkey_type;
romanb6f44032023-06-30 15:07:56 +02002005 } else if (is_tls(node)) {
2006 /* tls */
roman8341e8b2023-11-23 16:12:42 +01002007 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman5cbb6532023-06-22 12:53:17 +02002008 ret = 1;
2009 goto cleanup;
2010 }
2011
romanb6f44032023-06-30 15:07:56 +02002012 opts->privkey_type = privkey_type;
roman5cbb6532023-06-22 12:53:17 +02002013 }
2014
2015cleanup:
romanba93eac2023-07-18 14:36:48 +02002016 if (is_ch(node)) {
2017 /* UNLOCK */
2018 nc_ch_client_unlock(ch_client);
2019 }
roman5cbb6532023-06-22 12:53:17 +02002020 return ret;
2021}
2022
2023static int
roman5cbb6532023-06-22 12:53:17 +02002024nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op)
2025{
2026 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02002027 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02002028 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002029 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02002030
2031 assert(!strcmp(LYD_NAME(node), "cleartext-private-key"));
2032
romanba93eac2023-07-18 14:36:48 +02002033 /* LOCK */
2034 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002035 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002036 return 1;
2037 }
2038
roman4cb8bb12023-06-29 09:16:46 +02002039 if (is_ssh(node)) {
2040 /* ssh */
roman8341e8b2023-11-23 16:12:42 +01002041 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02002042 ret = 1;
2043 goto cleanup;
2044 }
2045
2046 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002047 free(hostkey->key.privkey_data);
2048 hostkey->key.privkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002049 NC_CHECK_ERRMEM_GOTO(!hostkey->key.privkey_data, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02002050 } else {
roman6430c152023-10-12 11:28:47 +02002051 free(hostkey->key.privkey_data);
2052 hostkey->key.privkey_data = NULL;
roman5cbb6532023-06-22 12:53:17 +02002053 }
romanb6f44032023-06-30 15:07:56 +02002054 } else if (is_tls(node)) {
2055 /* tls */
roman8341e8b2023-11-23 16:12:42 +01002056 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002057 ret = 1;
2058 goto cleanup;
2059 }
2060
roman5cbb6532023-06-22 12:53:17 +02002061 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002062 free(opts->privkey_data);
2063 opts->privkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002064 NC_CHECK_ERRMEM_GOTO(!opts->privkey_data, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02002065 } else {
roman6430c152023-10-12 11:28:47 +02002066 free(opts->privkey_data);
2067 opts->privkey_data = NULL;
roman5cbb6532023-06-22 12:53:17 +02002068 }
roman5cbb6532023-06-22 12:53:17 +02002069 }
2070
2071cleanup:
romanba93eac2023-07-18 14:36:48 +02002072 if (is_ch(node)) {
2073 /* UNLOCK */
2074 nc_ch_client_unlock(ch_client);
2075 }
roman5cbb6532023-06-22 12:53:17 +02002076 return ret;
2077}
2078
roman5cbb6532023-06-22 12:53:17 +02002079/* leaf */
2080static int
2081nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op)
2082{
2083 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02002084 struct nc_hostkey *hostkey;
roman8341e8b2023-11-23 16:12:42 +01002085 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02002086
2087 assert(!strcmp(LYD_NAME(node), "keystore-reference"));
2088
romanba93eac2023-07-18 14:36:48 +02002089 /* LOCK */
2090 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002091 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002092 return 1;
2093 }
2094
roman4cb8bb12023-06-29 09:16:46 +02002095 if (is_ssh(node) && equal_parent_name(node, 3, "server-identity")) {
roman8341e8b2023-11-23 16:12:42 +01002096 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02002097 ret = 1;
2098 goto cleanup;
2099 }
2100
2101 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2102 /* set to keystore */
2103 hostkey->store = NC_STORE_KEYSTORE;
2104
roman6430c152023-10-12 11:28:47 +02002105 free(hostkey->ks_ref);
romandd019a92023-09-14 10:17:07 +02002106 hostkey->ks_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002107 NC_CHECK_ERRMEM_GOTO(!hostkey->ks_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002108 } else if (op == NC_OP_DELETE) {
2109 free(hostkey->ks_ref);
roman5cbb6532023-06-22 12:53:17 +02002110 hostkey->ks_ref = NULL;
2111 }
roman3f9b65c2023-06-05 14:26:58 +02002112 }
romanc1d2b092023-02-02 08:58:27 +01002113
2114cleanup:
romanba93eac2023-07-18 14:36:48 +02002115 if (is_ch(node)) {
2116 /* UNLOCK */
2117 nc_ch_client_unlock(ch_client);
2118 }
romanc1d2b092023-02-02 08:58:27 +01002119 return ret;
2120}
2121
2122static int
roman6430c152023-10-12 11:28:47 +02002123nc_server_config_create_auth_client(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01002124{
romanf02273a2023-05-25 09:44:11 +02002125 node = lyd_child(node);
2126 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01002127
romanf02273a2023-05-25 09:44:11 +02002128 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->auth_clients, sizeof *opts->auth_clients, &opts->client_count);
romanc1d2b092023-02-02 08:58:27 +01002129}
2130
2131/* list */
2132static int
romane028ef92023-02-24 16:33:08 +01002133nc_server_config_user(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002134{
roman5cbb6532023-06-22 12:53:17 +02002135 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002136 struct nc_auth_client *auth_client;
roman4cb8bb12023-06-29 09:16:46 +02002137 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002138 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002139
2140 assert(!strcmp(LYD_NAME(node), "user"));
2141
romanba93eac2023-07-18 14:36:48 +02002142 /* LOCK */
2143 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002144 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002145 return 1;
2146 }
2147
roman8341e8b2023-11-23 16:12:42 +01002148 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002149 ret = 1;
2150 goto cleanup;
2151 }
2152
2153 if (op == NC_OP_CREATE) {
roman6430c152023-10-12 11:28:47 +02002154 ret = nc_server_config_create_auth_client(node, opts);
roman4cb8bb12023-06-29 09:16:46 +02002155 if (ret) {
2156 goto cleanup;
2157 }
2158 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01002159 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002160 ret = 1;
2161 goto cleanup;
2162 }
2163
roman4cb8bb12023-06-29 09:16:46 +02002164 nc_server_config_del_auth_client(opts, auth_client);
romanc1d2b092023-02-02 08:58:27 +01002165 }
2166
2167cleanup:
romanba93eac2023-07-18 14:36:48 +02002168 if (is_ch(node)) {
2169 /* UNLOCK */
2170 nc_ch_client_unlock(ch_client);
2171 }
romanc1d2b092023-02-02 08:58:27 +01002172 return ret;
2173}
2174
2175static int
romane028ef92023-02-24 16:33:08 +01002176nc_server_config_auth_attempts(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002177{
romanc1d2b092023-02-02 08:58:27 +01002178 int ret = 0;
roman4cb8bb12023-06-29 09:16:46 +02002179 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002180 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002181
2182 assert(!strcmp(LYD_NAME(node), "auth-attempts"));
2183
romanba93eac2023-07-18 14:36:48 +02002184 /* LOCK */
2185 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002186 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002187 return 1;
2188 }
2189
roman8341e8b2023-11-23 16:12:42 +01002190 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002191 ret = 1;
2192 goto cleanup;
2193 }
romanc1d2b092023-02-02 08:58:27 +01002194
roman4cb8bb12023-06-29 09:16:46 +02002195 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02002196 opts->auth_attempts = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01002197 }
2198
2199cleanup:
romanba93eac2023-07-18 14:36:48 +02002200 if (is_ch(node)) {
2201 /* UNLOCK */
2202 nc_ch_client_unlock(ch_client);
2203 }
romanc1d2b092023-02-02 08:58:27 +01002204 return ret;
2205}
2206
2207static int
romane028ef92023-02-24 16:33:08 +01002208nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002209{
romanc1d2b092023-02-02 08:58:27 +01002210 int ret = 0;
roman4cb8bb12023-06-29 09:16:46 +02002211 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002212 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002213
2214 assert(!strcmp(LYD_NAME(node), "auth-timeout"));
2215
romanba93eac2023-07-18 14:36:48 +02002216 /* LOCK */
2217 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002218 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002219 return 1;
2220 }
2221
roman8341e8b2023-11-23 16:12:42 +01002222 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002223 ret = 1;
2224 goto cleanup;
2225 }
romanc1d2b092023-02-02 08:58:27 +01002226
roman4cb8bb12023-06-29 09:16:46 +02002227 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02002228 opts->auth_timeout = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01002229 }
2230
2231cleanup:
romanba93eac2023-07-18 14:36:48 +02002232 if (is_ch(node)) {
2233 /* UNLOCK */
2234 nc_ch_client_unlock(ch_client);
2235 }
romanc1d2b092023-02-02 08:58:27 +01002236 return ret;
2237}
2238
romanc1d2b092023-02-02 08:58:27 +01002239/* leaf */
2240static int
romane028ef92023-02-24 16:33:08 +01002241nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002242{
romanc1d2b092023-02-02 08:58:27 +01002243 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002244 struct nc_auth_client *auth_client;
roman8341e8b2023-11-23 16:12:42 +01002245 struct nc_ch_client *ch_client = NULL;
roman6430c152023-10-12 11:28:47 +02002246 struct nc_server_tls_opts *opts;
2247 struct nc_cert_grouping *certs_grp;
romanc1d2b092023-02-02 08:58:27 +01002248
2249 assert(!strcmp(LYD_NAME(node), "truststore-reference"));
2250
romanba93eac2023-07-18 14:36:48 +02002251 /* LOCK */
2252 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002253 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002254 return 1;
2255 }
2256
roman4cb8bb12023-06-29 09:16:46 +02002257 if (is_ssh(node) && equal_parent_name(node, 1, "public-keys")) {
roman8341e8b2023-11-23 16:12:42 +01002258 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002259 ret = 1;
2260 goto cleanup;
2261 }
2262
2263 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02002264 /* set to truststore */
roman874fed12023-05-25 10:20:01 +02002265 auth_client->store = NC_STORE_TRUSTSTORE;
romanf02273a2023-05-25 09:44:11 +02002266
roman6430c152023-10-12 11:28:47 +02002267 free(auth_client->ts_ref);
2268 auth_client->ts_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002269 NC_CHECK_ERRMEM_GOTO(!auth_client->ts_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002270 } else if (op == NC_OP_DELETE) {
2271 free(auth_client->ts_ref);
romand57b3722023-04-05 11:26:25 +02002272 auth_client->ts_ref = NULL;
romanc1d2b092023-02-02 08:58:27 +01002273 }
roman6430c152023-10-12 11:28:47 +02002274 } else if (is_tls(node) && (equal_parent_name(node, 1, "ca-certs") || equal_parent_name(node, 1, "ee-certs"))) {
2275 /* ee-certs or ca-certs */
roman8341e8b2023-11-23 16:12:42 +01002276 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002277 ret = 1;
2278 goto cleanup;
2279 }
2280
roman6430c152023-10-12 11:28:47 +02002281 if (equal_parent_name(node, 1, "ca-certs")) {
2282 certs_grp = &opts->ca_certs;
roman3f9b65c2023-06-05 14:26:58 +02002283 } else {
roman6430c152023-10-12 11:28:47 +02002284 certs_grp = &opts->ee_certs;
roman4cb8bb12023-06-29 09:16:46 +02002285 }
2286
roman3f9b65c2023-06-05 14:26:58 +02002287 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2288 /* set to truststore */
roman6430c152023-10-12 11:28:47 +02002289 certs_grp->store = NC_STORE_TRUSTSTORE;
roman3f9b65c2023-06-05 14:26:58 +02002290
roman6430c152023-10-12 11:28:47 +02002291 free(certs_grp->ts_ref);
2292 certs_grp->ts_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002293 NC_CHECK_ERRMEM_GOTO(!certs_grp->ts_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002294 } else if (op == NC_OP_DELETE) {
2295 free(certs_grp->ts_ref);
2296 certs_grp->ts_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002297 }
2298 }
romanc1d2b092023-02-02 08:58:27 +01002299
2300cleanup:
romanba93eac2023-07-18 14:36:48 +02002301 if (is_ch(node)) {
2302 /* UNLOCK */
2303 nc_ch_client_unlock(ch_client);
2304 }
romanc1d2b092023-02-02 08:58:27 +01002305 return ret;
2306}
2307
romanc1d2b092023-02-02 08:58:27 +01002308/* leaf */
2309static int
romane028ef92023-02-24 16:33:08 +01002310nc_server_config_password(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002311{
roman5cbb6532023-06-22 12:53:17 +02002312 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002313 struct nc_auth_client *auth_client;
roman8341e8b2023-11-23 16:12:42 +01002314 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002315
2316 assert(!strcmp(LYD_NAME(node), "password"));
2317
romanba93eac2023-07-18 14:36:48 +02002318 /* LOCK */
2319 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002320 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002321 return 1;
2322 }
2323
roman8341e8b2023-11-23 16:12:42 +01002324 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
roman4cb8bb12023-06-29 09:16:46 +02002325 ret = 1;
2326 goto cleanup;
2327 }
2328
2329 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002330 free(auth_client->password);
2331 auth_client->password = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002332 NC_CHECK_ERRMEM_GOTO(!auth_client->password, ret = 1, cleanup);
roman4cb8bb12023-06-29 09:16:46 +02002333 } else {
roman6430c152023-10-12 11:28:47 +02002334 free(auth_client->password);
2335 auth_client->password = NULL;
romanc1d2b092023-02-02 08:58:27 +01002336 }
2337
2338cleanup:
romanba93eac2023-07-18 14:36:48 +02002339 if (is_ch(node)) {
2340 /* UNLOCK */
2341 nc_ch_client_unlock(ch_client);
2342 }
romanc1d2b092023-02-02 08:58:27 +01002343 return ret;
2344}
2345
2346static int
roman808f3f62023-11-23 16:01:04 +01002347nc_server_config_kb_int(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002348{
roman5cbb6532023-06-22 12:53:17 +02002349 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002350 struct nc_auth_client *auth_client;
roman808f3f62023-11-23 16:01:04 +01002351 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002352
roman808f3f62023-11-23 16:01:04 +01002353 assert(!strcmp(LYD_NAME(node), "keyboard-interactive"));
romanc1d2b092023-02-02 08:58:27 +01002354
romanba93eac2023-07-18 14:36:48 +02002355 /* LOCK */
2356 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002357 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002358 return 1;
2359 }
2360
roman8341e8b2023-11-23 16:12:42 +01002361 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
roman4cb8bb12023-06-29 09:16:46 +02002362 ret = 1;
2363 goto cleanup;
2364 }
2365
roman808f3f62023-11-23 16:01:04 +01002366 if (op == NC_OP_CREATE) {
2367 auth_client->kb_int_enabled = 1;
roman4cb8bb12023-06-29 09:16:46 +02002368 } else {
roman808f3f62023-11-23 16:01:04 +01002369 auth_client->kb_int_enabled = 0;
romanc1d2b092023-02-02 08:58:27 +01002370 }
2371
2372cleanup:
romanba93eac2023-07-18 14:36:48 +02002373 if (is_ch(node)) {
2374 /* UNLOCK */
2375 nc_ch_client_unlock(ch_client);
2376 }
romanc1d2b092023-02-02 08:58:27 +01002377 return ret;
2378}
2379
2380/* leaf */
2381static int
romane028ef92023-02-24 16:33:08 +01002382nc_server_config_none(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002383{
roman5cbb6532023-06-22 12:53:17 +02002384 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002385 struct nc_auth_client *auth_client;
roman8341e8b2023-11-23 16:12:42 +01002386 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002387
2388 assert(!strcmp(LYD_NAME(node), "none"));
2389
romanba93eac2023-07-18 14:36:48 +02002390 /* LOCK */
2391 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002392 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002393 return 1;
2394 }
2395
roman8341e8b2023-11-23 16:12:42 +01002396 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
roman4cb8bb12023-06-29 09:16:46 +02002397 ret = 1;
2398 goto cleanup;
2399 }
romanc1d2b092023-02-02 08:58:27 +01002400
roman4cb8bb12023-06-29 09:16:46 +02002401 if (op == NC_OP_CREATE) {
roman808f3f62023-11-23 16:01:04 +01002402 auth_client->none_enabled = 1;
roman4cb8bb12023-06-29 09:16:46 +02002403 } else {
roman808f3f62023-11-23 16:01:04 +01002404 auth_client->none_enabled = 0;
romanc1d2b092023-02-02 08:58:27 +01002405 }
2406
2407cleanup:
romanba93eac2023-07-18 14:36:48 +02002408 if (is_ch(node)) {
2409 /* UNLOCK */
2410 nc_ch_client_unlock(ch_client);
2411 }
romanc1d2b092023-02-02 08:58:27 +01002412 return ret;
2413}
2414
2415static int
romanc135c6d2023-10-25 13:32:30 +02002416nc_server_config_delete_substring(const char *haystack, const char *needle, const char delim)
2417{
2418 size_t needle_len = strlen(needle);
2419 char *substr;
2420 int substr_found = 0, ret = 0;
2421
2422 while ((substr = strstr(haystack, needle))) {
2423 /* iterate over all the substrings */
2424 if (((substr == haystack) && (*(substr + needle_len) == delim)) ||
2425 ((substr != haystack) && (*(substr - 1) == delim) && (*(substr + needle_len) == delim))) {
2426 /* either the first element of the string or somewhere in the middle */
2427 memmove(substr, substr + needle_len + 1, strlen(substr + needle_len + 1));
2428 substr_found = 1;
2429 break;
2430 } else if ((*(substr - 1) == delim) && (*(substr + needle_len) == '\0')) {
2431 /* the last element of the string */
2432 *(substr - 1) = '\0';
2433 substr_found = 1;
2434 break;
2435 }
2436 haystack = substr + 1;
2437 }
2438 if (!substr_found) {
2439 ret = 1;
2440 }
2441
2442 return ret;
2443}
2444
2445static int
romana6bf6ab2023-05-26 13:26:02 +02002446nc_server_config_transport_params(const char *algorithm, char **alg_store, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002447{
romanc135c6d2023-10-25 13:32:30 +02002448 int ret = 0;
2449 char *alg = NULL;
romana6bf6ab2023-05-26 13:26:02 +02002450
2451 if (!strncmp(algorithm, "openssh-", 8)) {
2452 /* if the name starts with openssh, convert it to it's original libssh accepted form */
roman3a95bb22023-10-26 11:07:17 +02002453 ret = asprintf(&alg, "%s@openssh.com", algorithm + 8);
2454 NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; alg = NULL, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002455 } else if (!strncmp(algorithm, "libssh-", 7)) {
2456 /* if the name starts with libssh, convert it to it's original libssh accepted form */
roman3a95bb22023-10-26 11:07:17 +02002457 ret = asprintf(&alg, "%s@libssh.org", algorithm + 7);
2458 NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; alg = NULL, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002459 } else {
2460 alg = strdup(algorithm);
roman3a95bb22023-10-26 11:07:17 +02002461 NC_CHECK_ERRMEM_GOTO(!alg, ret = 1, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002462 }
2463
romanc1d2b092023-02-02 08:58:27 +01002464 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2465 if (!*alg_store) {
2466 /* first call */
2467 *alg_store = strdup(alg);
roman3a95bb22023-10-26 11:07:17 +02002468 NC_CHECK_ERRMEM_GOTO(!*alg_store, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01002469 } else {
2470 /* +1 because of ',' between algorithms */
roman3a95bb22023-10-26 11:07:17 +02002471 *alg_store = nc_realloc(*alg_store, strlen(*alg_store) + strlen(alg) + 1 + 1);
2472 NC_CHECK_ERRMEM_GOTO(!*alg_store, ret = 1, cleanup);
roman08f67f42023-06-08 13:51:54 +02002473 strcat(*alg_store, ",");
2474 strcat(*alg_store, alg);
romanc1d2b092023-02-02 08:58:27 +01002475 }
2476 } else {
2477 /* delete */
romanc135c6d2023-10-25 13:32:30 +02002478 ret = nc_server_config_delete_substring(*alg_store, alg, ',');
2479 if (ret) {
romanc1d2b092023-02-02 08:58:27 +01002480 ERR(NULL, "Unable to delete an algorithm (%s), which was not previously added.", alg);
romanc135c6d2023-10-25 13:32:30 +02002481 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002482 }
2483 }
2484
2485cleanup:
romana6bf6ab2023-05-26 13:26:02 +02002486 free(alg);
romanc1d2b092023-02-02 08:58:27 +01002487 return ret;
2488}
2489
2490/* leaf-list */
2491static int
romane028ef92023-02-24 16:33:08 +01002492nc_server_config_host_key_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002493{
roman5cbb6532023-06-22 12:53:17 +02002494 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002495 const char *alg;
2496 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002497 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002498 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002499
roman5cbb6532023-06-22 12:53:17 +02002500 assert(!strcmp(LYD_NAME(node), "host-key-alg"));
romanc1d2b092023-02-02 08:58:27 +01002501
romanba93eac2023-07-18 14:36:48 +02002502 /* LOCK */
2503 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002504 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002505 return 1;
2506 }
2507
roman8341e8b2023-11-23 16:12:42 +01002508 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002509 ret = 1;
2510 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002511 }
2512
roman5cbb6532023-06-22 12:53:17 +02002513 /* get the algorithm name and compare it with algs supported by libssh */
2514 alg = ((struct lyd_node_term *)node)->value.ident->name;
romanc1d2b092023-02-02 08:58:27 +01002515 i = 0;
2516 while (supported_hostkey_algs[i]) {
2517 if (!strcmp(supported_hostkey_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002518 if (nc_server_config_transport_params(alg, &opts->hostkey_algs, op)) {
2519 ret = 1;
2520 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002521 }
2522 break;
2523 }
2524 i++;
2525 }
2526 if (!supported_hostkey_algs[i]) {
2527 /* algorithm not supported */
2528 ERR(NULL, "Public key algorithm (%s) not supported by libssh.", alg);
2529 ret = 1;
2530 }
2531
2532cleanup:
romanba93eac2023-07-18 14:36:48 +02002533 if (is_ch(node)) {
2534 /* UNLOCK */
2535 nc_ch_client_unlock(ch_client);
2536 }
romanc1d2b092023-02-02 08:58:27 +01002537 return ret;
2538}
2539
2540/* leaf-list */
2541static int
romane028ef92023-02-24 16:33:08 +01002542nc_server_config_kex_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002543{
roman5cbb6532023-06-22 12:53:17 +02002544 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002545 const char *alg;
2546 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002547 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002548 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002549
roman5cbb6532023-06-22 12:53:17 +02002550 assert(!strcmp(LYD_NAME(node), "key-exchange-alg"));
romanc1d2b092023-02-02 08:58:27 +01002551
romanba93eac2023-07-18 14:36:48 +02002552 /* LOCK */
2553 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002554 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002555 return 1;
2556 }
2557
roman8341e8b2023-11-23 16:12:42 +01002558 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002559 ret = 1;
2560 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002561 }
2562
roman5cbb6532023-06-22 12:53:17 +02002563 /* get the algorithm name and compare it with algs supported by libssh */
2564 alg = ((struct lyd_node_term *)node)->value.ident->name;
romanc1d2b092023-02-02 08:58:27 +01002565 i = 0;
2566 while (supported_kex_algs[i]) {
2567 if (!strcmp(supported_kex_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002568 if (nc_server_config_transport_params(alg, &opts->kex_algs, op)) {
2569 ret = 1;
2570 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002571 }
2572 break;
2573 }
2574 i++;
2575 }
2576 if (!supported_kex_algs[i]) {
2577 /* algorithm not supported */
2578 ERR(NULL, "Key exchange algorithm (%s) not supported by libssh.", alg);
2579 ret = 1;
2580 }
2581
2582cleanup:
romanba93eac2023-07-18 14:36:48 +02002583 if (is_ch(node)) {
2584 /* UNLOCK */
2585 nc_ch_client_unlock(ch_client);
2586 }
romanc1d2b092023-02-02 08:58:27 +01002587 return ret;
2588}
2589
2590/* leaf-list */
2591static int
romane028ef92023-02-24 16:33:08 +01002592nc_server_config_encryption_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002593{
roman5cbb6532023-06-22 12:53:17 +02002594 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002595 const char *alg;
2596 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002597 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002598 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002599
roman5cbb6532023-06-22 12:53:17 +02002600 assert(!strcmp(LYD_NAME(node), "encryption-alg"));
romanc1d2b092023-02-02 08:58:27 +01002601
romanba93eac2023-07-18 14:36:48 +02002602 /* LOCK */
2603 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002604 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002605 return 1;
2606 }
2607
roman8341e8b2023-11-23 16:12:42 +01002608 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002609 ret = 1;
2610 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002611 }
2612
roman5cbb6532023-06-22 12:53:17 +02002613 /* get the algorithm name and compare it with algs supported by libssh */
2614 alg = ((struct lyd_node_term *)node)->value.ident->name;
romanc1d2b092023-02-02 08:58:27 +01002615 i = 0;
2616 while (supported_encryption_algs[i]) {
2617 if (!strcmp(supported_encryption_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002618 if (nc_server_config_transport_params(alg, &opts->encryption_algs, op)) {
2619 ret = 1;
2620 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002621 }
2622 break;
2623 }
2624 i++;
2625 }
2626 if (!supported_encryption_algs[i]) {
2627 /* algorithm not supported */
2628 ERR(NULL, "Encryption algorithm (%s) not supported by libssh.", alg);
2629 ret = 1;
2630 }
2631
2632cleanup:
romanba93eac2023-07-18 14:36:48 +02002633 if (is_ch(node)) {
2634 /* UNLOCK */
2635 nc_ch_client_unlock(ch_client);
2636 }
romanc1d2b092023-02-02 08:58:27 +01002637 return ret;
2638}
2639
2640/* leaf-list */
2641static int
romane028ef92023-02-24 16:33:08 +01002642nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002643{
roman5cbb6532023-06-22 12:53:17 +02002644 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002645 const char *alg;
2646 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002647 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002648 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002649
roman5cbb6532023-06-22 12:53:17 +02002650 assert(!strcmp(LYD_NAME(node), "mac-alg"));
romanc1d2b092023-02-02 08:58:27 +01002651
romanba93eac2023-07-18 14:36:48 +02002652 /* LOCK */
2653 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002654 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002655 return 1;
2656 }
2657
roman8341e8b2023-11-23 16:12:42 +01002658 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002659 ret = 1;
2660 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002661 }
2662
roman5cbb6532023-06-22 12:53:17 +02002663 /* get the algorithm name and compare it with algs supported by libssh */
2664 alg = ((struct lyd_node_term *)node)->value.ident->name;
romanc1d2b092023-02-02 08:58:27 +01002665 i = 0;
2666 while (supported_mac_algs[i]) {
2667 if (!strcmp(supported_mac_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002668 if (nc_server_config_transport_params(alg, &opts->mac_algs, op)) {
2669 ret = 1;
2670 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002671 }
2672 break;
2673 }
2674 i++;
2675 }
2676 if (!supported_mac_algs[i]) {
2677 /* algorithm not supported */
2678 ERR(NULL, "MAC algorithm (%s) not supported by libssh.", alg);
2679 ret = 1;
2680 }
2681
2682cleanup:
romanba93eac2023-07-18 14:36:48 +02002683 if (is_ch(node)) {
2684 /* UNLOCK */
2685 nc_ch_client_unlock(ch_client);
2686 }
romanc1d2b092023-02-02 08:58:27 +01002687 return ret;
2688}
2689
roman78df0fa2023-11-02 10:33:57 +01002690static int
2691nc_server_config_check_endpt_reference_cycle(struct nc_endpt *original, struct nc_endpt *next)
2692{
2693 if (!next->referenced_endpt_name) {
2694 /* no further reference -> no cycle */
2695 return 0;
2696 }
2697
2698 if (!strcmp(original->name, next->referenced_endpt_name)) {
2699 /* found cycle */
2700 return 1;
2701 } else {
2702 if (nc_server_get_referenced_endpt(next->referenced_endpt_name, &next)) {
2703 /* referenced endpoint does not exist */
2704 return 1;
2705 }
2706
2707 /* continue further */
2708 return nc_server_config_check_endpt_reference_cycle(original, next);
2709 }
2710}
2711
roman0bbc19c2023-05-26 09:59:09 +02002712/**
roman78df0fa2023-11-02 10:33:57 +01002713 * @brief Set all endpoint references.
roman0bbc19c2023-05-26 09:59:09 +02002714 *
2715 * @return 0 on success, 1 on error.
2716 */
2717static int
roman78df0fa2023-11-02 10:33:57 +01002718nc_server_config_check_endpt_references(void)
roman0bbc19c2023-05-26 09:59:09 +02002719{
2720 uint16_t i, j;
roman78df0fa2023-11-02 10:33:57 +01002721 struct nc_endpt *referenced_endpt = NULL;
roman0bbc19c2023-05-26 09:59:09 +02002722
roman78df0fa2023-11-02 10:33:57 +01002723 /* first do listen endpoints */
roman0bbc19c2023-05-26 09:59:09 +02002724 for (i = 0; i < server_opts.endpt_count; i++) {
roman6430c152023-10-12 11:28:47 +02002725 /* go through all the endpoints */
roman0bbc19c2023-05-26 09:59:09 +02002726 if (server_opts.endpts[i].referenced_endpt_name) {
roman78df0fa2023-11-02 10:33:57 +01002727 /* get referenced endpt */
2728 if (nc_server_get_referenced_endpt(server_opts.endpts[i].referenced_endpt_name, &referenced_endpt)) {
2729 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" does not exist.",
roman0bbc19c2023-05-26 09:59:09 +02002730 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2731 return 1;
2732 }
roman78df0fa2023-11-02 10:33:57 +01002733
2734 /* check if the endpoint references itself */
2735 if (&server_opts.endpts[i] == referenced_endpt) {
2736 ERR(NULL, "Endpoint \"%s\" references itself.", server_opts.endpts[i].name);
2737 return 1;
2738 }
2739
2740 /* check transport */
2741 if ((server_opts.endpts[i].ti != referenced_endpt->ti)) {
2742 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" has different transport type.",
2743 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2744 return 1;
2745 } else if ((referenced_endpt->ti != NC_TI_LIBSSH) && (referenced_endpt->ti != NC_TI_OPENSSL)) {
2746 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" has unsupported transport type.",
2747 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2748 return 1;
2749 }
2750
2751 /* check cyclic reference */
2752 if (nc_server_config_check_endpt_reference_cycle(&server_opts.endpts[i], referenced_endpt)) {
2753 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" creates a cycle.",
2754 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2755 return 1;
2756 }
2757
2758 /* all went well, assign the name to the opts, so we can access it for auth */
2759 if (server_opts.endpts[i].ti == NC_TI_LIBSSH) {
2760 server_opts.endpts[i].opts.ssh->referenced_endpt_name = referenced_endpt->name;
2761 } else {
2762 server_opts.endpts[i].opts.tls->referenced_endpt_name = referenced_endpt->name;
2763 }
roman0bbc19c2023-05-26 09:59:09 +02002764 }
2765 }
2766
roman78df0fa2023-11-02 10:33:57 +01002767 /* now check all the call home endpoints */
2768 /* LOCK */
2769 pthread_rwlock_rdlock(&server_opts.ch_client_lock);
2770 for (i = 0; i < server_opts.ch_client_count; i++) {
2771 /* LOCK */
2772 pthread_mutex_lock(&server_opts.ch_clients[i].lock);
2773 for (j = 0; j < server_opts.ch_clients[i].ch_endpt_count; j++) {
2774 if (server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name) {
2775 /* get referenced endpt */
2776 if (nc_server_get_referenced_endpt(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, &referenced_endpt)) {
2777 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" does not exist.",
2778 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
2779 goto ch_fail;
2780 }
2781
2782 /* check transport */
2783 if (server_opts.ch_clients[i].ch_endpts[j].ti != referenced_endpt->ti) {
2784 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" has different transport type.",
2785 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
2786 goto ch_fail;
2787 } else if ((referenced_endpt->ti != NC_TI_LIBSSH) && (referenced_endpt->ti != NC_TI_OPENSSL)) {
2788 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" has unsupported transport type.",
2789 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
2790 goto ch_fail;
2791 }
2792
2793 /* check cyclic reference */
2794 if (nc_server_config_check_endpt_reference_cycle(referenced_endpt, referenced_endpt)) {
2795 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" creates a cycle.",
2796 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
2797 goto ch_fail;
2798 }
2799
2800 /* all went well, assign the name to the opts, so we can access it for auth */
2801 if (server_opts.ch_clients[i].ch_endpts[j].ti == NC_TI_LIBSSH) {
2802 server_opts.ch_clients[i].ch_endpts[j].opts.ssh->referenced_endpt_name = referenced_endpt->name;
2803 } else {
2804 server_opts.ch_clients[i].ch_endpts[j].opts.tls->referenced_endpt_name = referenced_endpt->name;
2805 }
2806 }
2807 }
2808 /* UNLOCK */
2809 pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
2810 }
2811
2812 /* UNLOCK */
2813 pthread_rwlock_unlock(&server_opts.ch_client_lock);
roman0bbc19c2023-05-26 09:59:09 +02002814 return 0;
roman78df0fa2023-11-02 10:33:57 +01002815
2816ch_fail:
2817 /* UNLOCK */
2818 pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
2819 /* UNLOCK */
2820 pthread_rwlock_unlock(&server_opts.ch_client_lock);
roman96c27f92023-11-02 11:09:46 +01002821 return 1;
roman0bbc19c2023-05-26 09:59:09 +02002822}
2823
2824static int
roman78df0fa2023-11-02 10:33:57 +01002825nc_server_config_endpoint_reference(const struct lyd_node *node, NC_OPERATION op)
roman0bbc19c2023-05-26 09:59:09 +02002826{
2827 int ret = 0;
roman78df0fa2023-11-02 10:33:57 +01002828 struct nc_endpt *endpt = NULL;
roman8341e8b2023-11-23 16:12:42 +01002829 struct nc_ch_client *ch_client = NULL;
roman78df0fa2023-11-02 10:33:57 +01002830 struct nc_ch_endpt *ch_endpt = NULL;
2831 struct nc_server_ssh_opts *ssh = NULL;
2832 struct nc_server_tls_opts *tls = NULL;
roman0bbc19c2023-05-26 09:59:09 +02002833
roman78df0fa2023-11-02 10:33:57 +01002834 assert(!strcmp(LYD_NAME(node), "endpoint-reference"));
roman0bbc19c2023-05-26 09:59:09 +02002835
roman78df0fa2023-11-02 10:33:57 +01002836 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
2837 /* to avoid unlock on fail */
2838 return 1;
2839 }
2840
2841 /* get endpt */
2842 if (is_listen(node)) {
2843 ret = nc_server_config_get_endpt(node, &endpt, NULL);
2844 } else {
roman8341e8b2023-11-23 16:12:42 +01002845 ret = nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt);
roman78df0fa2023-11-02 10:33:57 +01002846 }
roman0bbc19c2023-05-26 09:59:09 +02002847 if (ret) {
2848 goto cleanup;
2849 }
2850
2851 if (op == NC_OP_DELETE) {
roman78df0fa2023-11-02 10:33:57 +01002852 if (endpt) {
romanb7bfa652023-11-09 12:36:35 +01002853 /* listen */
roman78df0fa2023-11-02 10:33:57 +01002854 free(endpt->referenced_endpt_name);
2855 endpt->referenced_endpt_name = NULL;
roman2e797ef2023-06-19 10:47:49 +02002856 } else {
romanb7bfa652023-11-09 12:36:35 +01002857 /* call home */
roman78df0fa2023-11-02 10:33:57 +01002858 free(ch_endpt->referenced_endpt_name);
2859 ch_endpt->referenced_endpt_name = NULL;
roman2e797ef2023-06-19 10:47:49 +02002860 }
roman78df0fa2023-11-02 10:33:57 +01002861 if (is_ssh(node)) {
roman8341e8b2023-11-23 16:12:42 +01002862 if (nc_server_config_get_ssh_opts(node, ch_client, &ssh)) {
roman78df0fa2023-11-02 10:33:57 +01002863 ret = 1;
2864 goto cleanup;
2865 }
roman96c27f92023-11-02 11:09:46 +01002866
roman78df0fa2023-11-02 10:33:57 +01002867 ssh->referenced_endpt_name = NULL;
2868 } else {
roman8341e8b2023-11-23 16:12:42 +01002869 if (nc_server_config_get_tls_opts(node, ch_client, &tls)) {
roman78df0fa2023-11-02 10:33:57 +01002870 ret = 1;
2871 goto cleanup;
2872 }
roman0bbc19c2023-05-26 09:59:09 +02002873
roman78df0fa2023-11-02 10:33:57 +01002874 tls->referenced_endpt_name = NULL;
roman0bbc19c2023-05-26 09:59:09 +02002875 }
roman0bbc19c2023-05-26 09:59:09 +02002876
roman0bbc19c2023-05-26 09:59:09 +02002877 goto cleanup;
roman2e797ef2023-06-19 10:47:49 +02002878 } else {
roman78df0fa2023-11-02 10:33:57 +01002879 /* just set the name, check it once configuring of all nodes is done */
2880 if (endpt) {
2881 free(endpt->referenced_endpt_name);
2882 endpt->referenced_endpt_name = strdup(lyd_get_value(node));
2883 NC_CHECK_ERRMEM_GOTO(!endpt->referenced_endpt_name, ret = 1, cleanup);
2884 } else {
2885 free(ch_endpt->referenced_endpt_name);
2886 ch_endpt->referenced_endpt_name = strdup(lyd_get_value(node));
2887 NC_CHECK_ERRMEM_GOTO(!ch_endpt->referenced_endpt_name, ret = 1, cleanup);
2888 }
2889
2890 goto cleanup;
roman2e797ef2023-06-19 10:47:49 +02002891 }
roman0bbc19c2023-05-26 09:59:09 +02002892
2893cleanup:
roman78df0fa2023-11-02 10:33:57 +01002894 if (is_ch(node)) {
2895 /* UNLOCK */
2896 nc_ch_client_unlock(ch_client);
2897 }
2898
roman0bbc19c2023-05-26 09:59:09 +02002899 return ret;
2900}
2901
roman3f9b65c2023-06-05 14:26:58 +02002902static int
roman3f9b65c2023-06-05 14:26:58 +02002903nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op)
2904{
2905 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02002906 struct nc_certificate *cert;
romanb6f44032023-06-30 15:07:56 +02002907 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002908 struct nc_ch_client *ch_client = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002909
2910 assert(!strcmp(LYD_NAME(node), "cert-data"));
2911
romanba93eac2023-07-18 14:36:48 +02002912 /* LOCK */
2913 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002914 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002915 return 1;
2916 }
2917
romanb6f44032023-06-30 15:07:56 +02002918 if (equal_parent_name(node, 3, "server-identity")) {
roman8341e8b2023-11-23 16:12:42 +01002919 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
romanb6f44032023-06-30 15:07:56 +02002920 ret = 1;
2921 goto cleanup;
2922 }
roman3f9b65c2023-06-05 14:26:58 +02002923
roman3f9b65c2023-06-05 14:26:58 +02002924 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002925 free(opts->cert_data);
2926 opts->cert_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002927 NC_CHECK_ERRMEM_GOTO(!opts->cert_data, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02002928 }
roman6430c152023-10-12 11:28:47 +02002929 } else if (equal_parent_name(node, 3, "ca-certs") || equal_parent_name(node, 3, "ee-certs")) {
roman8341e8b2023-11-23 16:12:42 +01002930 if (nc_server_config_get_cert(node, ch_client, &cert)) {
roman3f9b65c2023-06-05 14:26:58 +02002931 ret = 1;
2932 goto cleanup;
2933 }
2934
2935 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002936 free(cert->data);
2937 cert->data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002938 NC_CHECK_ERRMEM_GOTO(!cert->data, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02002939 } else {
roman6430c152023-10-12 11:28:47 +02002940 free(cert->data);
2941 cert->data = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002942 }
2943 }
2944
2945cleanup:
romanba93eac2023-07-18 14:36:48 +02002946 if (is_ch(node)) {
2947 /* UNLOCK */
2948 nc_ch_client_unlock(ch_client);
2949 }
roman3f9b65c2023-06-05 14:26:58 +02002950 return ret;
2951}
2952
2953static int
roman3f9b65c2023-06-05 14:26:58 +02002954nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op)
2955{
2956 int ret = 0;
roman78df0fa2023-11-02 10:33:57 +01002957 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002958 struct nc_ch_client *ch_client = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002959
2960 assert(!strcmp(LYD_NAME(node), "asymmetric-key"));
2961
romanba93eac2023-07-18 14:36:48 +02002962 /* LOCK */
2963 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002964 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002965 return 1;
2966 }
2967
roman8341e8b2023-11-23 16:12:42 +01002968 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02002969 ret = 1;
2970 goto cleanup;
2971 }
2972
2973 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2974 /* set to keystore */
roman78df0fa2023-11-02 10:33:57 +01002975 opts->store = NC_STORE_KEYSTORE;
roman3f9b65c2023-06-05 14:26:58 +02002976
roman78df0fa2023-11-02 10:33:57 +01002977 free(opts->key_ref);
2978 opts->key_ref = strdup(lyd_get_value(node));
2979 NC_CHECK_ERRMEM_GOTO(!opts->key_ref, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02002980 } else {
roman78df0fa2023-11-02 10:33:57 +01002981 free(opts->key_ref);
2982 opts->key_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002983 }
2984
2985cleanup:
romanba93eac2023-07-18 14:36:48 +02002986 if (is_ch(node)) {
2987 /* UNLOCK */
2988 nc_ch_client_unlock(ch_client);
2989 }
roman3f9b65c2023-06-05 14:26:58 +02002990 return ret;
2991}
2992
2993static int
roman3f9b65c2023-06-05 14:26:58 +02002994nc_server_config_create_ca_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
2995{
2996 assert(!strcmp(LYD_NAME(node), "certificate"));
2997
2998 node = lyd_child(node);
2999 assert(!strcmp(LYD_NAME(node), "name"));
3000
3001 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ca_certs.certs, sizeof *opts->ca_certs.certs, &opts->ca_certs.cert_count);
3002}
3003
3004static int
3005nc_server_config_create_ee_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
3006{
3007 assert(!strcmp(LYD_NAME(node), "certificate"));
3008
3009 node = lyd_child(node);
3010 assert(!strcmp(LYD_NAME(node), "name"));
3011
3012 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ee_certs.certs, sizeof *opts->ee_certs.certs, &opts->ee_certs.cert_count);
3013}
3014
3015static int
3016nc_server_config_certificate(const struct lyd_node *node, NC_OPERATION op)
3017{
3018 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003019 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01003020 struct nc_ch_client *ch_client = NULL;
roman6430c152023-10-12 11:28:47 +02003021 struct nc_certificate *cert;
roman3f9b65c2023-06-05 14:26:58 +02003022
3023 assert(!strcmp(LYD_NAME(node), "certificate"));
3024
romanba93eac2023-07-18 14:36:48 +02003025 /* LOCK */
3026 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003027 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003028 return 1;
3029 }
3030
roman8341e8b2023-11-23 16:12:42 +01003031 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02003032 ret = 1;
3033 goto cleanup;
3034 }
3035
romanb6f44032023-06-30 15:07:56 +02003036 if (equal_parent_name(node, 1, "keystore-reference")) {
3037 /* TLS server-identity */
roman3f9b65c2023-06-05 14:26:58 +02003038 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
3039 /* set to keystore */
romanb6f44032023-06-30 15:07:56 +02003040 opts->store = NC_STORE_KEYSTORE;
roman3f9b65c2023-06-05 14:26:58 +02003041
roman6430c152023-10-12 11:28:47 +02003042 free(opts->cert_ref);
3043 opts->cert_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003044 NC_CHECK_ERRMEM_GOTO(!opts->cert_ref, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003045 } else {
roman6430c152023-10-12 11:28:47 +02003046 free(opts->cert_ref);
romanb6f44032023-06-30 15:07:56 +02003047 opts->cert_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003048 }
romanb6f44032023-06-30 15:07:56 +02003049 } else if (equal_parent_name(node, 2, "ca-certs")) {
3050 /* TLS client auth certificate authority */
roman3f9b65c2023-06-05 14:26:58 +02003051 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003052 ret = nc_server_config_create_ca_certs_certificate(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02003053 if (ret) {
3054 goto cleanup;
3055 }
3056 } else {
roman8341e8b2023-11-23 16:12:42 +01003057 if (nc_server_config_get_cert(node, ch_client, &cert)) {
roman6430c152023-10-12 11:28:47 +02003058 ret = 1;
3059 goto cleanup;
3060 }
3061 nc_server_config_del_cert(&opts->ca_certs, cert);
roman3f9b65c2023-06-05 14:26:58 +02003062 }
romanb6f44032023-06-30 15:07:56 +02003063 } else if (equal_parent_name(node, 2, "ee-certs")) {
3064 /* TLS client auth end entity */
roman3f9b65c2023-06-05 14:26:58 +02003065 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003066 ret = nc_server_config_create_ee_certs_certificate(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02003067 if (ret) {
3068 goto cleanup;
3069 }
3070 } else {
roman8341e8b2023-11-23 16:12:42 +01003071 if (nc_server_config_get_cert(node, ch_client, &cert)) {
roman6430c152023-10-12 11:28:47 +02003072 ret = 1;
3073 goto cleanup;
3074 }
3075 nc_server_config_del_cert(&opts->ee_certs, cert);
roman3f9b65c2023-06-05 14:26:58 +02003076 }
3077 }
3078
3079cleanup:
romanba93eac2023-07-18 14:36:48 +02003080 if (is_ch(node)) {
3081 /* UNLOCK */
3082 nc_ch_client_unlock(ch_client);
3083 }
roman3f9b65c2023-06-05 14:26:58 +02003084 return ret;
3085}
3086
3087static int
3088nc_server_config_create_cert_to_name(const struct lyd_node *node, struct nc_server_tls_opts *opts)
3089{
3090 int ret = 0;
3091 struct lyd_node *n;
3092 struct nc_ctn *new, *iter;
3093 const char *map_type, *name;
3094 uint32_t id;
3095 NC_TLS_CTN_MAPTYPE m_type;
3096
3097 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
3098
roman3f9b65c2023-06-05 14:26:58 +02003099 /* get all the data */
3100 /* find the list's key */
3101 lyd_find_path(node, "id", 0, &n);
3102 assert(n);
roman9cdb7b52023-10-25 13:59:55 +02003103 id = ((struct lyd_node_term *)n)->value.uint32;
roman3f9b65c2023-06-05 14:26:58 +02003104
3105 /* find the ctn's name */
3106 lyd_find_path(node, "name", 0, &n);
3107 assert(n);
3108 name = lyd_get_value(n);
3109
3110 /* find the ctn's map-type */
3111 lyd_find_path(node, "map-type", 0, &n);
3112 assert(n);
3113 map_type = ((struct lyd_node_term *)n)->value.ident->name;
3114 if (!strcmp(map_type, "specified")) {
3115 m_type = NC_TLS_CTN_SPECIFIED;
3116 } else if (!strcmp(map_type, "san-rfc822-name")) {
3117 m_type = NC_TLS_CTN_SAN_RFC822_NAME;
3118 } else if (!strcmp(map_type, "san-dns-name")) {
3119 m_type = NC_TLS_CTN_SAN_DNS_NAME;
3120 } else if (!strcmp(map_type, "san-ip-address")) {
3121 m_type = NC_TLS_CTN_SAN_IP_ADDRESS;
3122 } else if (!strcmp(map_type, "san-any")) {
3123 m_type = NC_TLS_CTN_SAN_ANY;
3124 } else if (!strcmp(map_type, "common-name")) {
3125 m_type = NC_TLS_CTN_COMMON_NAME;
3126 } else {
3127 ERR(NULL, "Map-type identity \"%s\" not supported.", map_type);
3128 ret = 1;
3129 goto cleanup;
3130 }
3131
roman6430c152023-10-12 11:28:47 +02003132 /* create new ctn */
3133 new = calloc(1, sizeof *new);
roman3a95bb22023-10-26 11:07:17 +02003134 NC_CHECK_ERRMEM_GOTO(!new, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02003135
roman3f9b65c2023-06-05 14:26:58 +02003136 /* find the right place for insertion */
3137 if (!opts->ctn) {
3138 /* inserting the first one */
3139 opts->ctn = new;
Roytak421eb0c2023-08-01 22:18:27 +02003140 } else if (opts->ctn->id > id) {
roman3f9b65c2023-06-05 14:26:58 +02003141 /* insert at the beginning */
3142 new->next = opts->ctn;
3143 opts->ctn = new;
3144 } else {
3145 /* have to find the right place */
Roytak421eb0c2023-08-01 22:18:27 +02003146 for (iter = opts->ctn; iter->next && iter->next->id <= id; iter = iter->next) {}
3147 if (iter->id == id) {
roman3f9b65c2023-06-05 14:26:58 +02003148 /* collision */
romanb7bfa652023-11-09 12:36:35 +01003149 free(new);
roman3f9b65c2023-06-05 14:26:58 +02003150 new = iter;
3151 } else {
3152 new->next = iter->next;
3153 iter->next = new;
3154 }
3155 }
3156
3157 /* insert the right data */
3158 new->id = id;
roman6430c152023-10-12 11:28:47 +02003159 free(new->name);
roman3f9b65c2023-06-05 14:26:58 +02003160 new->name = strdup(name);
roman3a95bb22023-10-26 11:07:17 +02003161 NC_CHECK_ERRMEM_GOTO(!new->name, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003162 new->map_type = m_type;
3163
3164cleanup:
3165 return ret;
3166}
3167
3168static int
3169nc_server_config_cert_to_name(const struct lyd_node *node, NC_OPERATION op)
3170{
3171 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003172 struct nc_server_tls_opts *opts;
roman3f9b65c2023-06-05 14:26:58 +02003173 struct nc_ctn *ctn;
roman8341e8b2023-11-23 16:12:42 +01003174 struct nc_ch_client *ch_client = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003175
3176 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
3177
romanba93eac2023-07-18 14:36:48 +02003178 /* LOCK */
3179 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003180 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003181 return 1;
3182 }
3183
roman8341e8b2023-11-23 16:12:42 +01003184 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02003185 ret = 1;
3186 goto cleanup;
3187 }
3188
3189 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003190 ret = nc_server_config_create_cert_to_name(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02003191 if (ret) {
3192 goto cleanup;
3193 }
3194 } else {
3195 /* find the given ctn entry */
roman8341e8b2023-11-23 16:12:42 +01003196 if (nc_server_config_get_ctn(node, ch_client, &ctn)) {
roman3f9b65c2023-06-05 14:26:58 +02003197 ret = 1;
3198 goto cleanup;
3199 }
romanb6f44032023-06-30 15:07:56 +02003200 nc_server_config_del_ctn(opts, ctn);
roman3f9b65c2023-06-05 14:26:58 +02003201 }
3202
3203cleanup:
romanba93eac2023-07-18 14:36:48 +02003204 if (is_ch(node)) {
3205 /* UNLOCK */
3206 nc_ch_client_unlock(ch_client);
3207 }
roman3f9b65c2023-06-05 14:26:58 +02003208 return ret;
3209}
3210
3211static int
roman3f9b65c2023-06-05 14:26:58 +02003212nc_server_config_fingerprint(const struct lyd_node *node, NC_OPERATION op)
3213{
3214 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02003215 struct nc_ctn *ctn;
roman8341e8b2023-11-23 16:12:42 +01003216 struct nc_ch_client *ch_client = NULL;
romanba93eac2023-07-18 14:36:48 +02003217
3218 assert(!strcmp(LYD_NAME(node), "fingerprint"));
3219
3220 /* LOCK */
3221 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003222 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003223 return 1;
3224 }
roman3f9b65c2023-06-05 14:26:58 +02003225
roman8341e8b2023-11-23 16:12:42 +01003226 if (nc_server_config_get_ctn(node, ch_client, &ctn)) {
roman3f9b65c2023-06-05 14:26:58 +02003227 ret = 1;
3228 goto cleanup;
3229 }
3230
3231 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003232 free(ctn->fingerprint);
3233 ctn->fingerprint = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003234 NC_CHECK_ERRMEM_GOTO(!ctn->fingerprint, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003235 } else {
roman6430c152023-10-12 11:28:47 +02003236 free(ctn->fingerprint);
3237 ctn->fingerprint = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003238 }
3239
3240cleanup:
romanba93eac2023-07-18 14:36:48 +02003241 if (is_ch(node)) {
3242 /* UNLOCK */
3243 nc_ch_client_unlock(ch_client);
3244 }
roman3f9b65c2023-06-05 14:26:58 +02003245 return ret;
3246}
3247
roman12644fe2023-06-08 11:06:42 +02003248static int
3249nc_server_config_tls_version(const struct lyd_node *node, NC_OPERATION op)
3250{
3251 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003252 struct nc_server_tls_opts *opts;
roman12644fe2023-06-08 11:06:42 +02003253 const char *version = NULL;
roman8341e8b2023-11-23 16:12:42 +01003254 struct nc_ch_client *ch_client = NULL;
roman6430c152023-10-12 11:28:47 +02003255 NC_TLS_VERSION tls_version;
roman12644fe2023-06-08 11:06:42 +02003256
3257 assert(!strcmp(LYD_NAME(node), "tls-version"));
3258
romanba93eac2023-07-18 14:36:48 +02003259 /* LOCK */
3260 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003261 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003262 return 1;
3263 }
3264
roman8341e8b2023-11-23 16:12:42 +01003265 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman12644fe2023-06-08 11:06:42 +02003266 ret = 1;
3267 goto cleanup;
3268 }
3269
roman6430c152023-10-12 11:28:47 +02003270 /* str to tls_version */
roman12644fe2023-06-08 11:06:42 +02003271 version = ((struct lyd_node_term *)node)->value.ident->name;
3272 if (!strcmp(version, "tls10")) {
roman6430c152023-10-12 11:28:47 +02003273 tls_version = NC_TLS_VERSION_10;
roman12644fe2023-06-08 11:06:42 +02003274 } else if (!strcmp(version, "tls11")) {
roman6430c152023-10-12 11:28:47 +02003275 tls_version = NC_TLS_VERSION_11;
roman12644fe2023-06-08 11:06:42 +02003276 } else if (!strcmp(version, "tls12")) {
roman6430c152023-10-12 11:28:47 +02003277 tls_version = NC_TLS_VERSION_12;
roman12644fe2023-06-08 11:06:42 +02003278 } else if (!strcmp(version, "tls13")) {
roman6430c152023-10-12 11:28:47 +02003279 tls_version = NC_TLS_VERSION_13;
roman12644fe2023-06-08 11:06:42 +02003280 } else {
3281 ERR(NULL, "TLS version \"%s\" not supported.", version);
3282 ret = 1;
3283 goto cleanup;
3284 }
3285
roman6430c152023-10-12 11:28:47 +02003286 if (op == NC_OP_CREATE) {
3287 /* add the version if it isn't there already */
3288 opts->tls_versions |= tls_version;
3289 } else if ((op == NC_OP_DELETE) && (opts->tls_versions & tls_version)) {
3290 /* delete the version if it is there */
roman84fe3252023-10-25 11:28:32 +02003291 opts->tls_versions &= ~tls_version;
roman6430c152023-10-12 11:28:47 +02003292 }
3293
roman12644fe2023-06-08 11:06:42 +02003294cleanup:
romanba93eac2023-07-18 14:36:48 +02003295 if (is_ch(node)) {
3296 /* UNLOCK */
3297 nc_ch_client_unlock(ch_client);
3298 }
roman12644fe2023-06-08 11:06:42 +02003299 return ret;
3300}
3301
3302static int
3303nc_server_config_create_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher)
3304{
3305 int ret = 0;
3306 char *ssl_cipher = NULL;
3307 uint16_t i;
roman6430c152023-10-12 11:28:47 +02003308 void *tmp;
roman12644fe2023-06-08 11:06:42 +02003309
3310 ssl_cipher = malloc(strlen(cipher) + 1);
roman3a95bb22023-10-26 11:07:17 +02003311 NC_CHECK_ERRMEM_GOTO(!ssl_cipher, ret = 1, cleanup);
roman12644fe2023-06-08 11:06:42 +02003312
3313 for (i = 0; cipher[i]; i++) {
3314 if (cipher[i] == '-') {
3315 /* OpenSSL requires _ instead of - in cipher names */
3316 ssl_cipher[i] = '_';
3317 } else {
3318 /* and requires uppercase unlike the identities */
3319 ssl_cipher[i] = toupper(cipher[i]);
3320 }
3321 }
3322 ssl_cipher[i] = '\0';
3323
3324 if (!opts->ciphers) {
3325 /* first entry */
3326 opts->ciphers = strdup(ssl_cipher);
roman3a95bb22023-10-26 11:07:17 +02003327 NC_CHECK_ERRMEM_GOTO(!opts->ciphers, ret = 1, cleanup);
roman12644fe2023-06-08 11:06:42 +02003328 } else {
3329 /* + 1 because of : between entries */
roman6430c152023-10-12 11:28:47 +02003330 tmp = nc_realloc(opts->ciphers, strlen(opts->ciphers) + strlen(ssl_cipher) + 1 + 1);
roman3a95bb22023-10-26 11:07:17 +02003331 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02003332 opts->ciphers = tmp;
roman08f67f42023-06-08 13:51:54 +02003333 strcat(opts->ciphers, ":");
3334 strcat(opts->ciphers, ssl_cipher);
roman12644fe2023-06-08 11:06:42 +02003335 }
3336
3337cleanup:
3338 free(ssl_cipher);
3339 return ret;
3340}
3341
3342static int
romanb6f44032023-06-30 15:07:56 +02003343nc_server_config_del_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher)
roman12644fe2023-06-08 11:06:42 +02003344{
romanc135c6d2023-10-25 13:32:30 +02003345 int ret = 0;
roman12644fe2023-06-08 11:06:42 +02003346
romanc135c6d2023-10-25 13:32:30 +02003347 ret = nc_server_config_delete_substring(opts->ciphers, cipher, ':');
3348 if (ret) {
roman12644fe2023-06-08 11:06:42 +02003349 ERR(NULL, "Unable to delete a cipher (%s), which was not previously added.", cipher);
3350 return 1;
3351 }
3352
3353 return 0;
3354}
3355
3356static int
3357nc_server_config_cipher_suite(const struct lyd_node *node, NC_OPERATION op)
3358{
3359 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003360 struct nc_server_tls_opts *opts;
roman12644fe2023-06-08 11:06:42 +02003361 const char *cipher = NULL;
roman8341e8b2023-11-23 16:12:42 +01003362 struct nc_ch_client *ch_client = NULL;
roman12644fe2023-06-08 11:06:42 +02003363
romanfaecc582023-06-15 16:13:31 +02003364 assert(!strcmp(LYD_NAME(node), "cipher-suite"));
3365
romanba93eac2023-07-18 14:36:48 +02003366 /* LOCK */
3367 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003368 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003369 return 1;
3370 }
3371
roman8341e8b2023-11-23 16:12:42 +01003372 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman12644fe2023-06-08 11:06:42 +02003373 ret = 1;
3374 goto cleanup;
3375 }
3376
3377 cipher = ((struct lyd_node_term *)node)->value.ident->name;
3378 if (op == NC_OP_CREATE) {
romanb6f44032023-06-30 15:07:56 +02003379 ret = nc_server_config_create_cipher_suite(opts, cipher);
roman12644fe2023-06-08 11:06:42 +02003380 if (ret) {
3381 goto cleanup;
3382 }
3383 } else if (op == NC_OP_DELETE) {
romanb6f44032023-06-30 15:07:56 +02003384 ret = nc_server_config_del_cipher_suite(opts, cipher);
roman12644fe2023-06-08 11:06:42 +02003385 if (ret) {
3386 goto cleanup;
3387 }
3388 }
3389
3390cleanup:
romanba93eac2023-07-18 14:36:48 +02003391 if (is_ch(node)) {
3392 /* UNLOCK */
3393 nc_ch_client_unlock(ch_client);
3394 }
roman12644fe2023-06-08 11:06:42 +02003395 return ret;
3396}
3397
romanfaecc582023-06-15 16:13:31 +02003398static int
3399nc_server_config_crl_url(const struct lyd_node *node, NC_OPERATION op)
3400{
3401 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003402 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01003403 struct nc_ch_client *ch_client = NULL;
romanfaecc582023-06-15 16:13:31 +02003404
3405 assert(!strcmp(LYD_NAME(node), "crl-url"));
3406
romanba93eac2023-07-18 14:36:48 +02003407 /* LOCK */
3408 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003409 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003410 return 1;
3411 }
3412
roman8341e8b2023-11-23 16:12:42 +01003413 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
romanfaecc582023-06-15 16:13:31 +02003414 ret = 1;
3415 goto cleanup;
3416 }
3417
3418 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003419 free(opts->crl_url);
romanb6f44032023-06-30 15:07:56 +02003420 opts->crl_url = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003421 NC_CHECK_ERRMEM_GOTO(!opts->crl_url, ret = 1, cleanup);
romanfaecc582023-06-15 16:13:31 +02003422 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02003423 free(opts->crl_url);
3424 opts->crl_url = NULL;
romanfaecc582023-06-15 16:13:31 +02003425 }
3426
3427cleanup:
romanba93eac2023-07-18 14:36:48 +02003428 if (is_ch(node)) {
3429 /* UNLOCK */
3430 nc_ch_client_unlock(ch_client);
3431 }
romanfaecc582023-06-15 16:13:31 +02003432 return ret;
3433}
3434
3435static int
3436nc_server_config_crl_path(const struct lyd_node *node, NC_OPERATION op)
3437{
3438 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003439 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01003440 struct nc_ch_client *ch_client = NULL;
romanfaecc582023-06-15 16:13:31 +02003441
3442 assert(!strcmp(LYD_NAME(node), "crl-path"));
3443
romanba93eac2023-07-18 14:36:48 +02003444 /* LOCK */
3445 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003446 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003447 return 1;
3448 }
3449
roman8341e8b2023-11-23 16:12:42 +01003450 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
romanfaecc582023-06-15 16:13:31 +02003451 ret = 1;
3452 goto cleanup;
3453 }
3454
3455 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003456 free(opts->crl_path);
romanb6f44032023-06-30 15:07:56 +02003457 opts->crl_path = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003458 NC_CHECK_ERRMEM_GOTO(!opts->crl_path, ret = 1, cleanup);
romanfaecc582023-06-15 16:13:31 +02003459 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02003460 free(opts->crl_path);
3461 opts->crl_path = NULL;
romanfaecc582023-06-15 16:13:31 +02003462 }
3463
3464cleanup:
romanba93eac2023-07-18 14:36:48 +02003465 if (is_ch(node)) {
3466 /* UNLOCK */
3467 nc_ch_client_unlock(ch_client);
3468 }
romanfaecc582023-06-15 16:13:31 +02003469 return ret;
3470}
3471
3472static int
3473nc_server_config_crl_cert_ext(const struct lyd_node *node, NC_OPERATION op)
3474{
3475 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003476 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01003477 struct nc_ch_client *ch_client = NULL;
romanfaecc582023-06-15 16:13:31 +02003478
3479 assert(!strcmp(LYD_NAME(node), "crl-cert-ext"));
3480
romanba93eac2023-07-18 14:36:48 +02003481 /* LOCK */
3482 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003483 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003484 return 1;
3485 }
3486
roman8341e8b2023-11-23 16:12:42 +01003487 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
romanfaecc582023-06-15 16:13:31 +02003488 ret = 1;
3489 goto cleanup;
3490 }
3491
3492 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003493 opts->crl_cert_ext = 1;
romanfaecc582023-06-15 16:13:31 +02003494 } else if (op == NC_OP_DELETE) {
romanb6f44032023-06-30 15:07:56 +02003495 opts->crl_cert_ext = 0;
romanfaecc582023-06-15 16:13:31 +02003496 }
3497
3498cleanup:
romanba93eac2023-07-18 14:36:48 +02003499 if (is_ch(node)) {
3500 /* UNLOCK */
3501 nc_ch_client_unlock(ch_client);
3502 }
romanfaecc582023-06-15 16:13:31 +02003503 return ret;
3504}
3505
roman2eab4742023-06-06 10:00:26 +02003506#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02003507
roman83683fb2023-02-24 09:15:23 +01003508static int
roman5cbb6532023-06-22 12:53:17 +02003509nc_server_config_create_netconf_client(const struct lyd_node *node)
3510{
3511 int ret = 0;
3512
3513 node = lyd_child(node);
3514 assert(!strcmp(LYD_NAME(node), "name"));
3515
3516 /* LOCK */
3517 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
3518
3519 ret = nc_server_config_realloc(lyd_get_value(node), (void **)&server_opts.ch_clients, sizeof *server_opts.ch_clients, &server_opts.ch_client_count);
3520 if (ret) {
3521 goto cleanup;
3522 }
3523
3524 server_opts.ch_clients[server_opts.ch_client_count - 1].id = ATOMIC_INC_RELAXED(server_opts.new_client_id);
3525 server_opts.ch_clients[server_opts.ch_client_count - 1].start_with = NC_CH_FIRST_LISTED;
roman6430c152023-10-12 11:28:47 +02003526 server_opts.ch_clients[server_opts.ch_client_count - 1].max_attempts = 3;
roman5cbb6532023-06-22 12:53:17 +02003527
3528 pthread_mutex_init(&server_opts.ch_clients[server_opts.ch_client_count - 1].lock, NULL);
3529
3530cleanup:
3531 /* UNLOCK */
3532 pthread_rwlock_unlock(&server_opts.ch_client_lock);
3533 return ret;
3534}
3535
3536static int
3537nc_server_config_netconf_client(const struct lyd_node *node, NC_OPERATION op)
3538{
3539 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02003540
3541 assert(!strcmp(LYD_NAME(node), "netconf-client"));
3542
3543 if (op == NC_OP_CREATE) {
3544 ret = nc_server_config_create_netconf_client(node);
3545 if (ret) {
3546 goto cleanup;
3547 }
roman450c00b2023-11-02 10:31:45 +01003548
roman96c27f92023-11-02 11:09:46 +01003549#ifdef NC_ENABLED_SSH_TLS
roman450c00b2023-11-02 10:31:45 +01003550 if (server_opts.ch_dispatch_data.acquire_ctx_cb && server_opts.ch_dispatch_data.release_ctx_cb &&
roman96c27f92023-11-02 11:09:46 +01003551 server_opts.ch_dispatch_data.new_session_cb) {
roman450c00b2023-11-02 10:31:45 +01003552 /* we have all we need for dispatching a new call home thread */
3553 ret = nc_connect_ch_client_dispatch(lyd_get_value(lyd_child(node)), server_opts.ch_dispatch_data.acquire_ctx_cb,
roman96c27f92023-11-02 11:09:46 +01003554 server_opts.ch_dispatch_data.release_ctx_cb, server_opts.ch_dispatch_data.ctx_cb_data,
3555 server_opts.ch_dispatch_data.new_session_cb, server_opts.ch_dispatch_data.new_session_cb_data);
roman450c00b2023-11-02 10:31:45 +01003556 if (ret) {
3557 ERR(NULL, "Dispatching a new Call Home thread failed for Call Home client \"%s\".", lyd_get_value(lyd_child(node)));
3558 goto cleanup;
3559 }
3560 }
roman96c27f92023-11-02 11:09:46 +01003561#endif /* NC_ENABLED_SSH_TLS */
roman5cbb6532023-06-22 12:53:17 +02003562 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01003563 nc_server_config_ch_del_client(node);
roman5cbb6532023-06-22 12:53:17 +02003564 }
3565
3566cleanup:
3567 return ret;
3568}
3569
3570#ifdef NC_ENABLED_SSH_TLS
3571
3572static int
3573nc_server_config_remote_address(const struct lyd_node *node, NC_OPERATION op)
3574{
3575 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02003576 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01003577 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02003578
romanb6f44032023-06-30 15:07:56 +02003579 assert(!strcmp(LYD_NAME(node), "remote-address"));
3580
romanba93eac2023-07-18 14:36:48 +02003581 /* LOCK */
3582 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003583 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003584 return 1;
3585 }
3586
roman8341e8b2023-11-23 16:12:42 +01003587 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02003588 ret = 1;
3589 goto cleanup;
3590 }
3591
3592 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003593 free(ch_endpt->address);
roman5cbb6532023-06-22 12:53:17 +02003594 ch_endpt->address = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003595 NC_CHECK_ERRMEM_GOTO(!ch_endpt->address, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02003596 } else {
roman6430c152023-10-12 11:28:47 +02003597 free(ch_endpt->address);
3598 ch_endpt->address = NULL;
roman5cbb6532023-06-22 12:53:17 +02003599 }
3600
3601cleanup:
romanba93eac2023-07-18 14:36:48 +02003602 /* UNLOCK */
3603 nc_ch_client_unlock(ch_client);
roman5cbb6532023-06-22 12:53:17 +02003604 return ret;
3605}
3606
3607static int
3608nc_server_config_remote_port(const struct lyd_node *node, NC_OPERATION op)
3609{
3610 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02003611 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01003612 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02003613
romanb6f44032023-06-30 15:07:56 +02003614 assert(!strcmp(LYD_NAME(node), "remote-port"));
3615
romanba93eac2023-07-18 14:36:48 +02003616 /* LOCK */
3617 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003618 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003619 return 1;
3620 }
3621
roman8341e8b2023-11-23 16:12:42 +01003622 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02003623 ret = 1;
3624 goto cleanup;
3625 }
3626
3627 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02003628 ch_endpt->port = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02003629 } else {
3630 ch_endpt->port = 0;
3631 }
3632
3633cleanup:
romanba93eac2023-07-18 14:36:48 +02003634 /* UNLOCK */
3635 nc_ch_client_unlock(ch_client);
roman5cbb6532023-06-22 12:53:17 +02003636 return ret;
3637}
3638
3639#endif /* NC_ENABLED_SSH_TLS */
3640
3641static int
romanb6f44032023-06-30 15:07:56 +02003642nc_server_config_persistent(const struct lyd_node *node, NC_OPERATION op)
3643{
3644 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003645 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003646
3647 assert(!strcmp(LYD_NAME(node), "persistent"));
3648
3649 (void) op;
3650
romanba93eac2023-07-18 14:36:48 +02003651 /* LOCK */
3652 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003653 /* to avoid unlock on fail */
3654 return 1;
romanb6f44032023-06-30 15:07:56 +02003655 }
3656
3657 ch_client->conn_type = NC_CH_PERSIST;
3658
romanba93eac2023-07-18 14:36:48 +02003659 /* UNLOCK */
3660 nc_ch_client_unlock(ch_client);
3661
romanb6f44032023-06-30 15:07:56 +02003662 return ret;
3663}
3664
3665static int
3666nc_server_config_periodic(const struct lyd_node *node, NC_OPERATION op)
3667{
3668 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003669 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003670
3671 assert(!strcmp(LYD_NAME(node), "periodic"));
3672
3673 (void) op;
3674
romanba93eac2023-07-18 14:36:48 +02003675 /* LOCK */
3676 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003677 /* to avoid unlock on fail */
3678 return 1;
romanb6f44032023-06-30 15:07:56 +02003679 }
3680
3681 ch_client->conn_type = NC_CH_PERIOD;
3682 /* set default values */
3683 ch_client->period = 60;
3684 ch_client->anchor_time = 0;
3685 ch_client->idle_timeout = 180;
3686
romanba93eac2023-07-18 14:36:48 +02003687 /* UNLOCK */
3688 nc_ch_client_unlock(ch_client);
3689
romanb6f44032023-06-30 15:07:56 +02003690 return ret;
3691}
3692
3693static int
3694nc_server_config_period(const struct lyd_node *node, NC_OPERATION op)
3695{
3696 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003697 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003698
3699 assert(!strcmp(LYD_NAME(node), "period"));
3700
romanba93eac2023-07-18 14:36:48 +02003701 /* LOCK */
3702 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003703 /* to avoid unlock on fail */
3704 return 1;
romanb6f44032023-06-30 15:07:56 +02003705 }
3706
3707 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02003708 ch_client->period = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02003709 } else if (op == NC_OP_DELETE) {
3710 ch_client->period = 60;
3711 }
3712
romanba93eac2023-07-18 14:36:48 +02003713 /* UNLOCK */
3714 nc_ch_client_unlock(ch_client);
3715
romanb6f44032023-06-30 15:07:56 +02003716 return ret;
3717}
3718
3719static int
3720nc_server_config_anchor_time(const struct lyd_node *node, NC_OPERATION op)
3721{
3722 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003723 struct nc_ch_client *ch_client = NULL;
romana3c95c72023-10-26 11:15:53 +02003724 struct lyd_value_date_and_time *anchor_time;
romanb6f44032023-06-30 15:07:56 +02003725
3726 assert(!strcmp(LYD_NAME(node), "anchor-time"));
3727
romanba93eac2023-07-18 14:36:48 +02003728 /* LOCK */
3729 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003730 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003731 return 1;
romanb6f44032023-06-30 15:07:56 +02003732 }
3733
romana3c95c72023-10-26 11:15:53 +02003734 /* get the value of time from the node directly */
3735 LYD_VALUE_GET(&((struct lyd_node_term *)node)->value, anchor_time);
romanb6f44032023-06-30 15:07:56 +02003736
3737 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romana3c95c72023-10-26 11:15:53 +02003738 ch_client->anchor_time = anchor_time->time;
romanb6f44032023-06-30 15:07:56 +02003739 } else if (op == NC_OP_DELETE) {
3740 ch_client->anchor_time = 0;
3741 }
3742
romanba93eac2023-07-18 14:36:48 +02003743 /* UNLOCK */
3744 nc_ch_client_unlock(ch_client);
romanb6f44032023-06-30 15:07:56 +02003745 return ret;
3746}
3747
3748static int
3749nc_server_config_reconnect_strategy(const struct lyd_node *node, NC_OPERATION op)
3750{
3751 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003752 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003753
3754 assert(!strcmp(LYD_NAME(node), "reconnect-strategy"));
3755
3756 (void) op;
3757
romanba93eac2023-07-18 14:36:48 +02003758 /* LOCK */
3759 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003760 /* to avoid unlock on fail */
3761 return 1;
romanb6f44032023-06-30 15:07:56 +02003762 }
3763
3764 /* set to default values */
3765 ch_client->start_with = NC_CH_FIRST_LISTED;
3766 ch_client->max_wait = 5;
3767 ch_client->max_attempts = 3;
3768
romanba93eac2023-07-18 14:36:48 +02003769 /* UNLOCK */
3770 nc_ch_client_unlock(ch_client);
3771
romanb6f44032023-06-30 15:07:56 +02003772 return ret;
3773}
3774
3775static int
3776nc_server_config_start_with(const struct lyd_node *node, NC_OPERATION op)
3777{
3778 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003779 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003780 const char *value;
3781
3782 assert(!strcmp(LYD_NAME(node), "start-with"));
3783
romanba93eac2023-07-18 14:36:48 +02003784 /* LOCK */
3785 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003786 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003787 return 1;
romanb6f44032023-06-30 15:07:56 +02003788 }
3789
3790 if (op == NC_OP_DELETE) {
3791 ch_client->start_with = NC_CH_FIRST_LISTED;
3792 goto cleanup;
3793 }
3794
3795 value = lyd_get_value(node);
3796 if (!strcmp(value, "first-listed")) {
3797 ch_client->start_with = NC_CH_FIRST_LISTED;
3798 } else if (!strcmp(value, "last-connected")) {
3799 ch_client->start_with = NC_CH_LAST_CONNECTED;
3800 } else if (!strcmp(value, "random-selection")) {
3801 ch_client->start_with = NC_CH_RANDOM;
3802 } else {
3803 ERR(NULL, "Unexpected start-with value \"%s\".", value);
3804 ret = 1;
3805 goto cleanup;
3806 }
3807
3808cleanup:
romanba93eac2023-07-18 14:36:48 +02003809 /* UNLOCK */
3810 nc_ch_client_unlock(ch_client);
romanb6f44032023-06-30 15:07:56 +02003811 return ret;
3812}
3813
3814static int
3815nc_server_config_max_wait(const struct lyd_node *node, NC_OPERATION op)
3816{
3817 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003818 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003819
3820 assert(!strcmp(LYD_NAME(node), "max-wait"));
3821
romanba93eac2023-07-18 14:36:48 +02003822 /* LOCK */
3823 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003824 /* to avoid unlock on fail */
3825 return 1;
romanb6f44032023-06-30 15:07:56 +02003826 }
3827
3828 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02003829 ch_client->max_wait = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02003830 } else {
3831 ch_client->max_wait = 5;
3832 }
3833
romanba93eac2023-07-18 14:36:48 +02003834 /* UNLOCK */
3835 nc_ch_client_unlock(ch_client);
3836
romanb6f44032023-06-30 15:07:56 +02003837 return ret;
3838}
3839
3840static int
3841nc_server_config_max_attempts(const struct lyd_node *node, NC_OPERATION op)
3842{
3843 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003844 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003845
3846 assert(!strcmp(LYD_NAME(node), "max-attempts"));
3847
romanba93eac2023-07-18 14:36:48 +02003848 /* LOCK */
3849 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003850 /* to avoid unlock on fail */
3851 return 1;
romanb6f44032023-06-30 15:07:56 +02003852 }
3853
3854 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02003855 ch_client->max_attempts = ((struct lyd_node_term *)node)->value.uint8;
romanb6f44032023-06-30 15:07:56 +02003856 } else {
3857 ch_client->max_attempts = 3;
3858 }
3859
romanba93eac2023-07-18 14:36:48 +02003860 /* UNLOCK */
3861 nc_ch_client_unlock(ch_client);
3862
romanb6f44032023-06-30 15:07:56 +02003863 return ret;
3864}
3865
3866static int
romanf02273a2023-05-25 09:44:11 +02003867nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01003868{
3869 const char *name = LYD_NAME(node);
roman6430c152023-10-12 11:28:47 +02003870 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01003871
3872 if (!strcmp(name, "listen")) {
roman6430c152023-10-12 11:28:47 +02003873 ret = nc_server_config_listen(node, op);
3874 } else if (!strcmp(name, "call-home")) {
3875 ret = nc_server_config_ch(node, op);
romaneaf84c72023-10-19 14:38:05 +02003876 } else if (!strcmp(name, "hello-timeout")) {
3877 ret = nc_server_config_hello_timeout(node, op);
romanc1d2b092023-02-02 08:58:27 +01003878 } else if (!strcmp(name, "endpoint")) {
roman6430c152023-10-12 11:28:47 +02003879 ret = nc_server_config_endpoint(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003880 }
roman2eab4742023-06-06 10:00:26 +02003881#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02003882 else if (!strcmp(name, "ssh")) {
roman6430c152023-10-12 11:28:47 +02003883 ret = nc_server_config_ssh(node, op);
roman2eab4742023-06-06 10:00:26 +02003884 } else if (!strcmp(name, "local-address")) {
roman6430c152023-10-12 11:28:47 +02003885 ret = nc_server_config_local_address(node, op);
romanc1d2b092023-02-02 08:58:27 +01003886 } else if (!strcmp(name, "local-port")) {
roman6430c152023-10-12 11:28:47 +02003887 ret = nc_server_config_local_port(node, op);
romanc1d2b092023-02-02 08:58:27 +01003888 } else if (!strcmp(name, "keepalives")) {
roman6430c152023-10-12 11:28:47 +02003889 ret = nc_server_config_keepalives(node, op);
romanc1d2b092023-02-02 08:58:27 +01003890 } else if (!strcmp(name, "idle-time")) {
roman6430c152023-10-12 11:28:47 +02003891 ret = nc_server_config_idle_time(node, op);
romanc1d2b092023-02-02 08:58:27 +01003892 } else if (!strcmp(name, "max-probes")) {
roman6430c152023-10-12 11:28:47 +02003893 ret = nc_server_config_max_probes(node, op);
romanc1d2b092023-02-02 08:58:27 +01003894 } else if (!strcmp(name, "probe-interval")) {
roman6430c152023-10-12 11:28:47 +02003895 ret = nc_server_config_probe_interval(node, op);
roman2eab4742023-06-06 10:00:26 +02003896 } else if (!strcmp(name, "host-key")) {
roman6430c152023-10-12 11:28:47 +02003897 ret = nc_server_config_host_key(node, op);
roman2eab4742023-06-06 10:00:26 +02003898 } else if (!strcmp(name, "public-key-format")) {
roman6430c152023-10-12 11:28:47 +02003899 ret = nc_server_config_public_key_format(node, op);
romanc1d2b092023-02-02 08:58:27 +01003900 } else if (!strcmp(name, "public-key")) {
roman6430c152023-10-12 11:28:47 +02003901 ret = nc_server_config_public_key(node, op);
romanc1d2b092023-02-02 08:58:27 +01003902 } else if (!strcmp(name, "private-key-format")) {
roman6430c152023-10-12 11:28:47 +02003903 ret = nc_server_config_private_key_format(node, op);
romanc1d2b092023-02-02 08:58:27 +01003904 } else if (!strcmp(name, "cleartext-private-key")) {
roman6430c152023-10-12 11:28:47 +02003905 ret = nc_server_config_cleartext_private_key(node, op);
roman2eab4742023-06-06 10:00:26 +02003906 } else if (!strcmp(name, "keystore-reference")) {
roman6430c152023-10-12 11:28:47 +02003907 ret = nc_server_config_keystore_reference(node, op);
romanc1d2b092023-02-02 08:58:27 +01003908 } else if (!strcmp(name, "user")) {
roman6430c152023-10-12 11:28:47 +02003909 ret = nc_server_config_user(node, op);
romanc1d2b092023-02-02 08:58:27 +01003910 } else if (!strcmp(name, "auth-attempts")) {
roman6430c152023-10-12 11:28:47 +02003911 ret = nc_server_config_auth_attempts(node, op);
romanc1d2b092023-02-02 08:58:27 +01003912 } else if (!strcmp(name, "auth-timeout")) {
roman6430c152023-10-12 11:28:47 +02003913 ret = nc_server_config_auth_timeout(node, op);
roman2eab4742023-06-06 10:00:26 +02003914 } else if (!strcmp(name, "truststore-reference")) {
roman6430c152023-10-12 11:28:47 +02003915 ret = nc_server_config_truststore_reference(node, op);
roman2eab4742023-06-06 10:00:26 +02003916 } else if (!strcmp(name, "password")) {
roman6430c152023-10-12 11:28:47 +02003917 ret = nc_server_config_password(node, op);
roman808f3f62023-11-23 16:01:04 +01003918 } else if (!strcmp(name, "keyboard-interactive")) {
3919 ret = nc_server_config_kb_int(node, op);
romanc1d2b092023-02-02 08:58:27 +01003920 } else if (!strcmp(name, "none")) {
roman6430c152023-10-12 11:28:47 +02003921 ret = nc_server_config_none(node, op);
romanc1d2b092023-02-02 08:58:27 +01003922 } else if (!strcmp(name, "host-key-alg")) {
roman6430c152023-10-12 11:28:47 +02003923 ret = nc_server_config_host_key_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01003924 } else if (!strcmp(name, "key-exchange-alg")) {
roman6430c152023-10-12 11:28:47 +02003925 ret = nc_server_config_kex_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01003926 } else if (!strcmp(name, "encryption-alg")) {
roman6430c152023-10-12 11:28:47 +02003927 ret = nc_server_config_encryption_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01003928 } else if (!strcmp(name, "mac-alg")) {
roman6430c152023-10-12 11:28:47 +02003929 ret = nc_server_config_mac_alg(node, op);
roman78df0fa2023-11-02 10:33:57 +01003930 } else if (!strcmp(name, "endpoint-reference")) {
3931 ret = nc_server_config_endpoint_reference(node, op);
roman2eab4742023-06-06 10:00:26 +02003932 } else if (!strcmp(name, "tls")) {
roman6430c152023-10-12 11:28:47 +02003933 ret = nc_server_config_tls(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003934 } else if (!strcmp(name, "cert-data")) {
roman6430c152023-10-12 11:28:47 +02003935 ret = nc_server_config_cert_data(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003936 } else if (!strcmp(name, "asymmetric-key")) {
roman6430c152023-10-12 11:28:47 +02003937 ret = nc_server_config_asymmetric_key(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003938 } else if (!strcmp(name, "certificate")) {
roman6430c152023-10-12 11:28:47 +02003939 ret = nc_server_config_certificate(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003940 } else if (!strcmp(name, "cert-to-name")) {
roman6430c152023-10-12 11:28:47 +02003941 ret = nc_server_config_cert_to_name(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003942 } else if (!strcmp(name, "fingerprint")) {
roman6430c152023-10-12 11:28:47 +02003943 ret = nc_server_config_fingerprint(node, op);
roman12644fe2023-06-08 11:06:42 +02003944 } else if (!strcmp(name, "tls-version")) {
roman6430c152023-10-12 11:28:47 +02003945 ret = nc_server_config_tls_version(node, op);
roman12644fe2023-06-08 11:06:42 +02003946 } else if (!strcmp(name, "cipher-suite")) {
roman6430c152023-10-12 11:28:47 +02003947 ret = nc_server_config_cipher_suite(node, op);
romanfaecc582023-06-15 16:13:31 +02003948 } else if (!strcmp(name, "crl-url")) {
roman6430c152023-10-12 11:28:47 +02003949 ret = nc_server_config_crl_url(node, op);
romanfaecc582023-06-15 16:13:31 +02003950 } else if (!strcmp(name, "crl-path")) {
roman6430c152023-10-12 11:28:47 +02003951 ret = nc_server_config_crl_path(node, op);
romanfaecc582023-06-15 16:13:31 +02003952 } else if (!strcmp(name, "crl-cert-ext")) {
roman6430c152023-10-12 11:28:47 +02003953 ret = nc_server_config_crl_cert_ext(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003954 }
roman2eab4742023-06-06 10:00:26 +02003955#endif /* NC_ENABLED_SSH_TLS */
roman5cbb6532023-06-22 12:53:17 +02003956 else if (!strcmp(name, "netconf-client")) {
roman6430c152023-10-12 11:28:47 +02003957 ret = nc_server_config_netconf_client(node, op);
roman5cbb6532023-06-22 12:53:17 +02003958 }
3959#ifdef NC_ENABLED_SSH_TLS
3960 else if (!strcmp(name, "remote-address")) {
roman6430c152023-10-12 11:28:47 +02003961 ret = nc_server_config_remote_address(node, op);
roman5cbb6532023-06-22 12:53:17 +02003962 } else if (!strcmp(name, "remote-port")) {
roman6430c152023-10-12 11:28:47 +02003963 ret = nc_server_config_remote_port(node, op);
roman5cbb6532023-06-22 12:53:17 +02003964 }
3965#endif /* NC_ENABLED_SSH_TLS */
romanb6f44032023-06-30 15:07:56 +02003966 else if (!strcmp(name, "persistent")) {
roman6430c152023-10-12 11:28:47 +02003967 ret = nc_server_config_persistent(node, op);
romanb6f44032023-06-30 15:07:56 +02003968 } else if (!strcmp(name, "periodic")) {
roman6430c152023-10-12 11:28:47 +02003969 ret = nc_server_config_periodic(node, op);
romanb6f44032023-06-30 15:07:56 +02003970 } else if (!strcmp(name, "period")) {
roman6430c152023-10-12 11:28:47 +02003971 ret = nc_server_config_period(node, op);
romanb6f44032023-06-30 15:07:56 +02003972 } else if (!strcmp(name, "anchor-time")) {
roman6430c152023-10-12 11:28:47 +02003973 ret = nc_server_config_anchor_time(node, op);
romaneaf84c72023-10-19 14:38:05 +02003974 } else if (!strcmp(name, "idle-timeout")) {
3975 ret = nc_server_config_idle_timeout(node, op);
romanb6f44032023-06-30 15:07:56 +02003976 } else if (!strcmp(name, "reconnect-strategy")) {
roman6430c152023-10-12 11:28:47 +02003977 ret = nc_server_config_reconnect_strategy(node, op);
romanb6f44032023-06-30 15:07:56 +02003978 } else if (!strcmp(name, "start-with")) {
roman6430c152023-10-12 11:28:47 +02003979 ret = nc_server_config_start_with(node, op);
romanb6f44032023-06-30 15:07:56 +02003980 } else if (!strcmp(name, "max-wait")) {
roman6430c152023-10-12 11:28:47 +02003981 ret = nc_server_config_max_wait(node, op);
romanb6f44032023-06-30 15:07:56 +02003982 } else if (!strcmp(name, "max-attempts")) {
roman6430c152023-10-12 11:28:47 +02003983 ret = nc_server_config_max_attempts(node, op);
3984 }
3985
3986 if (ret) {
3987 ERR(NULL, "Configuring node \"%s\" failed.", LYD_NAME(node));
3988 return 1;
romanb6f44032023-06-30 15:07:56 +02003989 }
romanc1d2b092023-02-02 08:58:27 +01003990
3991 return 0;
romanc1d2b092023-02-02 08:58:27 +01003992}
3993
3994int
roman0bbc19c2023-05-26 09:59:09 +02003995nc_server_config_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, NC_MODULE module)
romanc1d2b092023-02-02 08:58:27 +01003996{
3997 struct lyd_node *child;
3998 struct lyd_meta *m;
romanf9906b42023-05-22 14:04:29 +02003999 NC_OPERATION current_op = NC_OP_UNKNOWN;
romanf02273a2023-05-25 09:44:11 +02004000 int ret;
romanc1d2b092023-02-02 08:58:27 +01004001
4002 assert(node);
4003
romanf9906b42023-05-22 14:04:29 +02004004 /* get current op if there is any */
4005 if ((m = lyd_find_meta(node->meta, NULL, "yang:operation"))) {
4006 if (!strcmp(lyd_get_meta_value(m), "create")) {
4007 current_op = NC_OP_CREATE;
4008 } else if (!strcmp(lyd_get_meta_value(m), "delete")) {
4009 current_op = NC_OP_DELETE;
4010 } else if (!strcmp(lyd_get_meta_value(m), "replace")) {
4011 current_op = NC_OP_REPLACE;
4012 } else if (!strcmp(lyd_get_meta_value(m), "none")) {
4013 current_op = NC_OP_NONE;
romanc1d2b092023-02-02 08:58:27 +01004014 }
4015 }
4016
4017 /* node has no op, inherit from the parent */
romanf9906b42023-05-22 14:04:29 +02004018 if (!current_op) {
4019 if (!parent_op) {
4020 ERR(NULL, "Unknown operation for node \"%s\".", LYD_NAME(node));
4021 return 1;
4022 }
4023
romanc1d2b092023-02-02 08:58:27 +01004024 current_op = parent_op;
4025 }
4026
4027 switch (current_op) {
4028 case NC_OP_NONE:
4029 break;
4030 case NC_OP_CREATE:
4031 case NC_OP_DELETE:
4032 case NC_OP_REPLACE:
roman2eab4742023-06-06 10:00:26 +02004033#ifdef NC_ENABLED_SSH_TLS
4034 if (module == NC_MODULE_KEYSTORE) {
romanf02273a2023-05-25 09:44:11 +02004035 ret = nc_server_config_parse_keystore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02004036 } else if (module == NC_MODULE_TRUSTSTORE) {
romanf02273a2023-05-25 09:44:11 +02004037 ret = nc_server_config_parse_truststore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02004038 } else
4039#endif /* NC_ENABLED_SSH_TLS */
4040 {
4041 ret = nc_server_config_parse_netconf_server(node, current_op);
romanf02273a2023-05-25 09:44:11 +02004042 }
4043 if (ret) {
4044 return ret;
romanc1d2b092023-02-02 08:58:27 +01004045 }
4046 break;
4047 default:
4048 break;
4049 }
4050
4051 if (current_op != NC_OP_DELETE) {
4052 LY_LIST_FOR(lyd_child(node), child) {
roman0bbc19c2023-05-26 09:59:09 +02004053 if (nc_server_config_parse_tree(child, current_op, module)) {
romanc1d2b092023-02-02 08:58:27 +01004054 return 1;
4055 }
4056 }
4057 }
4058 return 0;
4059}
4060
romanc1d2b092023-02-02 08:58:27 +01004061API int
4062nc_server_config_load_modules(struct ly_ctx **ctx)
4063{
4064 int i, new_ctx = 0;
4065
4066 if (!*ctx) {
4067 if (ly_ctx_new(NC_SERVER_SEARCH_DIR, 0, ctx)) {
4068 ERR(NULL, "Couldn't create new libyang context.\n");
4069 goto error;
4070 }
4071 new_ctx = 1;
4072 }
4073
4074 /* all features */
4075 const char *ietf_nectonf_server[] = {"ssh-listen", "tls-listen", "ssh-call-home", "tls-call-home", "central-netconf-server-supported", NULL};
4076 /* all features */
4077 const char *ietf_x509_cert_to_name[] = {NULL};
roman7fdc84d2023-06-06 13:14:53 +02004078 /* no private-key-encryption, csr-generation, p10-csr-format, certificate-expiration-notification,
roman3c6c7e62023-09-14 10:19:19 +02004079 * encrypted-passwords, hidden-symmetric-keys, encrypted-symmetric-keys, hidden-private-keys, encrypted-private-keys,
4080 * one-symmetric-key-format, one-asymmetric-key-format, symmetrically-encrypted-value-format,
4081 * asymmetrically-encrypted-value-format, cms-enveloped-data-format, cms-encrypted-data-format,
Roytakb2794852023-10-18 14:30:22 +02004082 * cleartext-symmetric-keys */
roman3c6c7e62023-09-14 10:19:19 +02004083 const char *ietf_crypto_types[] = {"cleartext-passwords", "cleartext-private-keys", NULL};
romanc1d2b092023-02-02 08:58:27 +01004084 /* all features */
4085 const char *ietf_tcp_common[] = {"keepalives-supported", NULL};
roman7fdc84d2023-06-06 13:14:53 +02004086 /* all features */
4087 const char *ietf_tcp_server[] = {"tcp-server-keepalives", NULL};
Roytakb2794852023-10-18 14:30:22 +02004088 /* no proxy-connect, socks5-gss-api, socks5-username-password, local-binding-supported ? */
4089 const char *ietf_tcp_client[] = {"tcp-client-keepalives", NULL};
roman3c6c7e62023-09-14 10:19:19 +02004090 /* no ssh-x509-certs, public-key-generation */
4091 const char *ietf_ssh_common[] = {"transport-params", NULL};
roman7fdc84d2023-06-06 13:14:53 +02004092 /* no ssh-server-keepalives and local-user-auth-hostbased */
4093 const char *ietf_ssh_server[] = {"local-users-supported", "local-user-auth-publickey", "local-user-auth-password", "local-user-auth-none", NULL};
romanc1d2b092023-02-02 08:58:27 +01004094 /* all features */
4095 const char *iana_ssh_encryption_algs[] = {NULL};
4096 /* all features */
4097 const char *iana_ssh_key_exchange_algs[] = {NULL};
4098 /* all features */
4099 const char *iana_ssh_mac_algs[] = {NULL};
4100 /* all features */
4101 const char *iana_ssh_public_key_algs[] = {NULL};
romanc1d2b092023-02-02 08:58:27 +01004102 /* all features */
roman7fdc84d2023-06-06 13:14:53 +02004103 const char *iana_crypt_hash[] = {"crypt-hash-md5", "crypt-hash-sha-256", "crypt-hash-sha-512", NULL};
4104 /* no symmetric-keys */
4105 const char *ietf_keystore[] = {"central-keystore-supported", "inline-definitions-supported", "asymmetric-keys", NULL};
4106 /* all features */
4107 const char *ietf_truststore[] = {"central-truststore-supported", "inline-definitions-supported", "certificates", "public-keys", NULL};
roman3c6c7e62023-09-14 10:19:19 +02004108 /* no public-key-generation */
4109 const char *ietf_tls_common[] = {"tls10", "tls11", "tls12", "tls13", "hello-params", NULL};
4110 /* no tls-server-keepalives, server-ident-raw-public-key, server-ident-tls12-psk, server-ident-tls13-epsk,
4111 * client-auth-raw-public-key, client-auth-tls12-psk, client-auth-tls13-epsk */
4112 const char *ietf_tls_server[] = {"server-ident-x509-cert", "client-auth-supported", "client-auth-x509-cert", NULL};
roman7fdc84d2023-06-06 13:14:53 +02004113 /* all features */
roman12644fe2023-06-08 11:06:42 +02004114 const char *iana_tls_cipher_suite_algs[] = {NULL};
romanc1d2b092023-02-02 08:58:27 +01004115 /* all features */
4116 const char *libnetconf2_netconf_server[] = {NULL};
4117
4118 const char *module_names[] = {
roman7fdc84d2023-06-06 13:14:53 +02004119 "ietf-netconf-server", "ietf-x509-cert-to-name", "ietf-crypto-types", "ietf-tcp-common", "ietf-tcp-server",
4120 "ietf-tcp-client", "ietf-ssh-common", "ietf-ssh-server", "iana-ssh-encryption-algs",
4121 "iana-ssh-key-exchange-algs", "iana-ssh-mac-algs", "iana-ssh-public-key-algs", "iana-crypt-hash",
roman12644fe2023-06-08 11:06:42 +02004122 "ietf-keystore", "ietf-truststore", "ietf-tls-common", "ietf-tls-server", "iana-tls-cipher-suite-algs",
4123 "libnetconf2-netconf-server", NULL
romanc1d2b092023-02-02 08:58:27 +01004124 };
4125
4126 const char **module_features[] = {
roman7fdc84d2023-06-06 13:14:53 +02004127 ietf_nectonf_server, ietf_x509_cert_to_name, ietf_crypto_types, ietf_tcp_common,
4128 ietf_tcp_server, ietf_tcp_client, ietf_ssh_common, ietf_ssh_server, iana_ssh_encryption_algs,
4129 iana_ssh_key_exchange_algs, iana_ssh_mac_algs, iana_ssh_public_key_algs, iana_crypt_hash,
roman12644fe2023-06-08 11:06:42 +02004130 ietf_keystore, ietf_truststore, ietf_tls_common, ietf_tls_server, iana_tls_cipher_suite_algs,
4131 libnetconf2_netconf_server, NULL
romanc1d2b092023-02-02 08:58:27 +01004132 };
4133
4134 for (i = 0; module_names[i] != NULL; i++) {
4135 if (!ly_ctx_load_module(*ctx, module_names[i], NULL, module_features[i])) {
4136 ERR(NULL, "Loading module \"%s\" failed.\n", module_names[i]);
4137 goto error;
4138 }
4139 }
4140
4141 return 0;
4142
4143error:
4144 if (new_ctx) {
4145 ly_ctx_destroy(*ctx);
4146 *ctx = NULL;
4147 }
4148 return 1;
4149}
4150
romanf9906b42023-05-22 14:04:29 +02004151static int
4152nc_server_config_fill_nectonf_server(const struct lyd_node *data, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01004153{
4154 int ret = 0;
roman84fe3252023-10-25 11:28:32 +02004155 uint32_t log_options = 0;
romanc1d2b092023-02-02 08:58:27 +01004156 struct lyd_node *tree;
romand57b3722023-04-05 11:26:25 +02004157
romanc9b62d62023-09-14 10:19:50 +02004158 /* silently search for ietf-netconf-server, it may not be present */
roman84fe3252023-10-25 11:28:32 +02004159 ly_temp_log_options(&log_options);
romanc9b62d62023-09-14 10:19:50 +02004160
romanc1d2b092023-02-02 08:58:27 +01004161 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &tree);
romanc9b62d62023-09-14 10:19:50 +02004162 if (ret || (tree->flags & LYD_DEFAULT)) {
4163 /* not found */
4164 ret = 0;
romanc1d2b092023-02-02 08:58:27 +01004165 goto cleanup;
4166 }
4167
roman0bbc19c2023-05-26 09:59:09 +02004168 if (nc_server_config_parse_tree(tree, op, NC_MODULE_NETCONF_SERVER)) {
4169 ret = 1;
4170 goto cleanup;
4171 }
4172
roman2eab4742023-06-06 10:00:26 +02004173#ifdef NC_ENABLED_SSH_TLS
roman78df0fa2023-11-02 10:33:57 +01004174 /* check and set all endpoint references */
4175 if (nc_server_config_check_endpt_references()) {
romanf9906b42023-05-22 14:04:29 +02004176 ret = 1;
4177 goto cleanup;
4178 }
roman2eab4742023-06-06 10:00:26 +02004179#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004180
4181cleanup:
romanc9b62d62023-09-14 10:19:50 +02004182 /* reset the logging options back to what they were */
roman84fe3252023-10-25 11:28:32 +02004183 ly_temp_log_options(NULL);
romanf9906b42023-05-22 14:04:29 +02004184 return ret;
4185}
4186
4187API int
romanf6f37a52023-05-25 14:27:51 +02004188nc_server_config_setup_diff(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02004189{
4190 int ret = 0;
4191
romanc9b62d62023-09-14 10:19:50 +02004192 NC_CHECK_ARG_RET(NULL, data, 1);
4193
romanf9906b42023-05-22 14:04:29 +02004194 /* LOCK */
4195 pthread_rwlock_wrlock(&server_opts.config_lock);
4196
roman2eab4742023-06-06 10:00:26 +02004197#ifdef NC_ENABLED_SSH_TLS
romanf9906b42023-05-22 14:04:29 +02004198 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02004199 ret = nc_server_config_fill_keystore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02004200 if (ret) {
4201 ERR(NULL, "Filling keystore failed.");
4202 goto cleanup;
4203 }
4204
4205 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02004206 ret = nc_server_config_fill_truststore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02004207 if (ret) {
4208 ERR(NULL, "Filling truststore failed.");
4209 goto cleanup;
4210 }
roman2eab4742023-06-06 10:00:26 +02004211#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004212
4213 /* configure netconf-server */
4214 ret = nc_server_config_fill_nectonf_server(data, NC_OP_UNKNOWN);
4215 if (ret) {
4216 ERR(NULL, "Filling netconf-server failed.");
4217 goto cleanup;
4218 }
4219
4220cleanup:
4221 /* UNLOCK */
4222 pthread_rwlock_unlock(&server_opts.config_lock);
4223 return ret;
4224}
4225
4226API int
romanf6f37a52023-05-25 14:27:51 +02004227nc_server_config_setup_data(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02004228{
4229 int ret = 0;
4230 struct lyd_node *tree, *iter, *root;
4231
romanc9b62d62023-09-14 10:19:50 +02004232 NC_CHECK_ARG_RET(NULL, data, 1);
4233
romanf9906b42023-05-22 14:04:29 +02004234 /* LOCK */
4235 pthread_rwlock_wrlock(&server_opts.config_lock);
4236
4237 /* find the netconf-server node */
4238 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &root);
4239 if (ret) {
4240 ERR(NULL, "Unable to find the netconf-server container in the YANG data.");
4241 goto cleanup;
4242 }
4243
4244 /* iterate through all the nodes and make sure there is no operation attribute */
4245 LY_LIST_FOR(root, tree) {
4246 LYD_TREE_DFS_BEGIN(tree, iter) {
4247 if (lyd_find_meta(iter->meta, NULL, "yang:operation")) {
4248 ERR(NULL, "Unexpected operation attribute in the YANG data.");
romanc1d2b092023-02-02 08:58:27 +01004249 ret = 1;
4250 goto cleanup;
4251 }
romanf9906b42023-05-22 14:04:29 +02004252 LYD_TREE_DFS_END(tree, iter);
romanc1d2b092023-02-02 08:58:27 +01004253 }
4254 }
4255
romanf9906b42023-05-22 14:04:29 +02004256 /* delete the current configuration */
romanf02273a2023-05-25 09:44:11 +02004257 nc_server_config_listen(NULL, NC_OP_DELETE);
roman4cb8bb12023-06-29 09:16:46 +02004258 nc_server_config_ch(NULL, NC_OP_DELETE);
roman2eab4742023-06-06 10:00:26 +02004259#ifdef NC_ENABLED_SSH_TLS
romanf02273a2023-05-25 09:44:11 +02004260 nc_server_config_ks_keystore(NULL, NC_OP_DELETE);
4261 nc_server_config_ts_truststore(NULL, NC_OP_DELETE);
romanf9906b42023-05-22 14:04:29 +02004262
4263 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02004264 ret = nc_server_config_fill_keystore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02004265 if (ret) {
4266 ERR(NULL, "Filling keystore failed.");
4267 goto cleanup;
4268 }
4269
4270 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02004271 ret = nc_server_config_fill_truststore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02004272 if (ret) {
4273 ERR(NULL, "Filling truststore failed.");
4274 goto cleanup;
4275 }
roman2eab4742023-06-06 10:00:26 +02004276#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004277
4278 /* configure netconf-server */
4279 ret = nc_server_config_fill_nectonf_server(data, NC_OP_CREATE);
4280 if (ret) {
4281 ERR(NULL, "Filling netconf-server failed.");
romanc1d2b092023-02-02 08:58:27 +01004282 goto cleanup;
4283 }
4284
4285cleanup:
4286 /* UNLOCK */
4287 pthread_rwlock_unlock(&server_opts.config_lock);
4288 return ret;
4289}
roman3f9b65c2023-06-05 14:26:58 +02004290
4291API int
4292nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path)
4293{
4294 struct lyd_node *tree = NULL;
4295 int ret = 0;
4296
4297 NC_CHECK_ARG_RET(NULL, path, 1);
4298
4299 ret = lyd_parse_data_path(ctx, path, LYD_UNKNOWN, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree);
4300 if (ret) {
4301 goto cleanup;
4302 }
4303
4304 ret = nc_server_config_setup_data(tree);
4305 if (ret) {
4306 goto cleanup;
4307 }
4308
4309cleanup:
4310 lyd_free_all(tree);
4311 return ret;
4312}