blob: 04281ae8eb820659fb8266dc9f6d9d1e971773c8 [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
roman2eab4742023-06-06 10:00:26 +0200773#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200774
roman45cec4e2023-02-17 10:21:39 +0100775void
roman6430c152023-10-12 11:28:47 +0200776nc_server_config_del_unix_socket_opts(struct nc_bind *bind, struct nc_server_unix_opts *opts)
roman83683fb2023-02-24 09:15:23 +0100777{
778 if (bind->sock > -1) {
779 close(bind->sock);
780 }
781
romand0b78372023-09-14 10:06:03 +0200782 unlink(bind->address);
roman83683fb2023-02-24 09:15:23 +0100783 free(bind->address);
784 free(opts->address);
785
786 free(opts);
roman83683fb2023-02-24 09:15:23 +0100787}
788
789void
roman874fed12023-05-25 10:20:01 +0200790nc_server_config_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *bind)
roman83683fb2023-02-24 09:15:23 +0100791{
roman6430c152023-10-12 11:28:47 +0200792 free(endpt->name);
793 nc_server_config_del_unix_socket_opts(bind, endpt->opts.unixsock);
roman83683fb2023-02-24 09:15:23 +0100794
795 server_opts.endpt_count--;
796 if (!server_opts.endpt_count) {
797 free(server_opts.endpts);
798 free(server_opts.binds);
799 server_opts.endpts = NULL;
800 server_opts.binds = NULL;
roman6430c152023-10-12 11:28:47 +0200801 } else if (endpt != &server_opts.endpts[server_opts.endpt_count]) {
roman33981232023-07-08 11:55:13 +0200802 memcpy(endpt, &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts);
803 memcpy(bind, &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds);
roman83683fb2023-02-24 09:15:23 +0100804 }
805}
806
roman2eab4742023-06-06 10:00:26 +0200807#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +0200808
809static void
roman3f9b65c2023-06-05 14:26:58 +0200810nc_server_config_del_cert(struct nc_cert_grouping *certs, struct nc_certificate *cert)
811{
812 free(cert->name);
roman3f9b65c2023-06-05 14:26:58 +0200813 free(cert->data);
roman3f9b65c2023-06-05 14:26:58 +0200814
815 certs->cert_count--;
816 if (!certs->cert_count) {
817 free(certs->certs);
818 certs->certs = NULL;
roman6430c152023-10-12 11:28:47 +0200819 } else if (cert != &certs->certs[certs->cert_count]) {
roman33981232023-07-08 11:55:13 +0200820 memcpy(cert, &certs->certs[certs->cert_count], sizeof *certs->certs);
roman3f9b65c2023-06-05 14:26:58 +0200821 }
822}
823
824static void
roman6430c152023-10-12 11:28:47 +0200825nc_server_config_del_certs(struct nc_cert_grouping *certs_grp)
roman3f9b65c2023-06-05 14:26:58 +0200826{
roman6430c152023-10-12 11:28:47 +0200827 uint16_t i;
roman3f9b65c2023-06-05 14:26:58 +0200828
roman6430c152023-10-12 11:28:47 +0200829 if (certs_grp->store == NC_STORE_LOCAL) {
830 for (i = 0; i < certs_grp->cert_count; i++) {
831 free(certs_grp->certs[i].name);
832 free(certs_grp->certs[i].data);
roman3f9b65c2023-06-05 14:26:58 +0200833 }
roman6430c152023-10-12 11:28:47 +0200834 free(certs_grp->certs);
835 certs_grp->certs = NULL;
836 } else {
837 free(certs_grp->ts_ref);
roman3f9b65c2023-06-05 14:26:58 +0200838 }
839}
840
841static void
842nc_server_config_del_ctn(struct nc_server_tls_opts *opts, struct nc_ctn *ctn)
843{
844 struct nc_ctn *iter;
845
roman3f9b65c2023-06-05 14:26:58 +0200846 free(ctn->name);
roman6430c152023-10-12 11:28:47 +0200847 free(ctn->fingerprint);
roman3f9b65c2023-06-05 14:26:58 +0200848
849 if (opts->ctn == ctn) {
850 /* it's the first in the list */
851 opts->ctn = ctn->next;
852 free(ctn);
853 return;
854 }
855
roman84fe3252023-10-25 11:28:32 +0200856 for (iter = opts->ctn; iter; iter = iter->next) {
roman3f9b65c2023-06-05 14:26:58 +0200857 if (iter->next == ctn) {
858 /* found the ctn */
859 break;
860 }
roman3f9b65c2023-06-05 14:26:58 +0200861 }
862
romanb7bfa652023-11-09 12:36:35 +0100863 if (!iter) {
864 ERRINT;
865 return;
866 }
867
roman3f9b65c2023-06-05 14:26:58 +0200868 iter->next = ctn->next;
869 free(ctn);
870}
871
872static void
roman6430c152023-10-12 11:28:47 +0200873nc_server_config_del_ctns(struct nc_server_tls_opts *opts)
roman3f9b65c2023-06-05 14:26:58 +0200874{
875 struct nc_ctn *cur, *next;
876
roman84fe3252023-10-25 11:28:32 +0200877 for (cur = opts->ctn; cur; cur = next) {
roman3f9b65c2023-06-05 14:26:58 +0200878 next = cur->next;
roman3f9b65c2023-06-05 14:26:58 +0200879 free(cur->name);
roman6430c152023-10-12 11:28:47 +0200880 free(cur->fingerprint);
roman3f9b65c2023-06-05 14:26:58 +0200881 free(cur);
roman3f9b65c2023-06-05 14:26:58 +0200882 }
roman3a95bb22023-10-26 11:07:17 +0200883
roman3f9b65c2023-06-05 14:26:58 +0200884 opts->ctn = NULL;
885}
886
887static void
roman6430c152023-10-12 11:28:47 +0200888nc_server_config_del_tls_opts(struct nc_bind *bind, struct nc_server_tls_opts *opts)
roman3f9b65c2023-06-05 14:26:58 +0200889{
roman5ae78282023-11-02 13:34:34 +0100890 if (bind) {
891 free(bind->address);
892 if (bind->sock > -1) {
893 close(bind->sock);
894 }
roman3f9b65c2023-06-05 14:26:58 +0200895 }
896
897 if (opts->store == NC_STORE_LOCAL) {
roman6430c152023-10-12 11:28:47 +0200898 free(opts->pubkey_data);
899 free(opts->privkey_data);
900 free(opts->cert_data);
901 } else {
902 free(opts->key_ref);
903 free(opts->cert_ref);
roman3f9b65c2023-06-05 14:26:58 +0200904 }
905
roman6430c152023-10-12 11:28:47 +0200906 nc_server_config_del_certs(&opts->ca_certs);
907 nc_server_config_del_certs(&opts->ee_certs);
roman3f9b65c2023-06-05 14:26:58 +0200908
roman6430c152023-10-12 11:28:47 +0200909 free(opts->crl_path);
910 free(opts->crl_url);
romanfaecc582023-06-15 16:13:31 +0200911 X509_STORE_free(opts->crl_store);
romanfaecc582023-06-15 16:13:31 +0200912
roman6430c152023-10-12 11:28:47 +0200913 nc_server_config_del_ctns(opts);
914 free(opts->ciphers);
roman3f9b65c2023-06-05 14:26:58 +0200915 free(opts);
916}
917
918static void
919nc_server_config_del_endpt_tls(struct nc_endpt *endpt, struct nc_bind *bind)
920{
roman78df0fa2023-11-02 10:33:57 +0100921 /* delete any references to this endpoint */
922 nc_server_config_del_endpt_references(endpt->name);
roman6430c152023-10-12 11:28:47 +0200923 free(endpt->name);
roman78df0fa2023-11-02 10:33:57 +0100924
roman6430c152023-10-12 11:28:47 +0200925 free(endpt->referenced_endpt_name);
926
927 nc_server_config_del_tls_opts(bind, endpt->opts.tls);
roman3f9b65c2023-06-05 14:26:58 +0200928
929 server_opts.endpt_count--;
930 if (!server_opts.endpt_count) {
931 free(server_opts.endpts);
932 free(server_opts.binds);
933 server_opts.endpts = NULL;
934 server_opts.binds = NULL;
roman6430c152023-10-12 11:28:47 +0200935 } else if (endpt != &server_opts.endpts[server_opts.endpt_count]) {
roman33981232023-07-08 11:55:13 +0200936 memcpy(endpt, &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts);
937 memcpy(bind, &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds);
roman3f9b65c2023-06-05 14:26:58 +0200938 }
939}
940
roman2eab4742023-06-06 10:00:26 +0200941#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200942
roman5cbb6532023-06-22 12:53:17 +0200943static void
944nc_server_config_ch_del_endpt(struct nc_ch_client *ch_client, struct nc_ch_endpt *ch_endpt)
945{
946 free(ch_endpt->name);
roman5cbb6532023-06-22 12:53:17 +0200947
948#ifdef NC_ENABLED_SSH_TLS
roman6430c152023-10-12 11:28:47 +0200949 free(ch_endpt->address);
roman5cbb6532023-06-22 12:53:17 +0200950 if (ch_endpt->sock_pending > -1) {
951 close(ch_endpt->sock_pending);
952 ch_endpt->sock_pending = -1;
953 }
roman5ae78282023-11-02 13:34:34 +0100954 free(ch_endpt->referenced_endpt_name);
roman5cbb6532023-06-22 12:53:17 +0200955#endif /* NC_ENABLED_SSH_TLS */
956
957 switch (ch_endpt->ti) {
958#ifdef NC_ENABLED_SSH_TLS
959 case NC_TI_LIBSSH:
roman5ae78282023-11-02 13:34:34 +0100960 nc_server_config_del_ssh_opts(NULL, ch_endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +0200961 break;
romanb6f44032023-06-30 15:07:56 +0200962 case NC_TI_OPENSSL:
roman5ae78282023-11-02 13:34:34 +0100963 nc_server_config_del_tls_opts(NULL, ch_endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +0200964 break;
roman5cbb6532023-06-22 12:53:17 +0200965#endif /* NC_ENABLED_SSH_TLS */
966 default:
967 ERRINT;
968 break;
969 }
970
971 ch_client->ch_endpt_count--;
972 if (!ch_client->ch_endpt_count) {
973 free(ch_client->ch_endpts);
974 ch_client->ch_endpts = NULL;
975 }
976}
977
978static void
roman8341e8b2023-11-23 16:12:42 +0100979nc_server_config_destroy_ch_client(struct nc_ch_client *ch_client)
roman5cbb6532023-06-22 12:53:17 +0200980{
romanba93eac2023-07-18 14:36:48 +0200981 pthread_t tid;
roman8341e8b2023-11-23 16:12:42 +0100982 uint16_t i, ch_endpt_count;
983
984 if (ch_client->thread_data->thread_running) {
985 /* get tid */
986 tid = ch_client->tid;
987 /* CH COND LOCK */
988 pthread_mutex_lock(&ch_client->thread_data->cond_lock);
989 ch_client->thread_data->thread_running = 0;
990 pthread_cond_signal(&ch_client->thread_data->cond);
991 /* CH COND UNLOCK */
992 pthread_mutex_unlock(&ch_client->thread_data->cond_lock);
993
994 /* wait for the thread to terminate */
995 pthread_join(tid, NULL);
996 }
997
998 /* free its members */
999 free(ch_client->name);
1000
1001 ch_endpt_count = ch_client->ch_endpt_count;
1002 for (i = 0; i < ch_endpt_count; i++) {
1003 nc_server_config_ch_del_endpt(ch_client, &ch_client->ch_endpts[i]);
1004 }
1005}
1006
1007static void
1008nc_server_config_ch_del_client(const struct lyd_node *node)
1009{
1010 struct nc_ch_client client, *ch_client;
roman5cbb6532023-06-22 12:53:17 +02001011
romanba93eac2023-07-18 14:36:48 +02001012 /* WR LOCK */
roman5cbb6532023-06-22 12:53:17 +02001013 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
1014
roman8341e8b2023-11-23 16:12:42 +01001015 if (nc_server_config_get_ch_client(node, &ch_client)) {
1016 /* WR UNLOCK */
1017 pthread_rwlock_unlock(&server_opts.ch_client_lock);
1018 ERR(NULL, "Call-home client \"%s\" not found.", lyd_get_value(lyd_child(node)));
1019 return;
1020 }
1021
romanba93eac2023-07-18 14:36:48 +02001022 /* copy the client we want to delete into a local variable */
1023 memcpy(&client, ch_client, sizeof *ch_client);
roman5cbb6532023-06-22 12:53:17 +02001024
romanba93eac2023-07-18 14:36:48 +02001025 /* delete the client */
roman5cbb6532023-06-22 12:53:17 +02001026 server_opts.ch_client_count--;
1027 if (!server_opts.ch_client_count) {
1028 free(server_opts.ch_clients);
1029 server_opts.ch_clients = NULL;
romanba93eac2023-07-18 14:36:48 +02001030 } else {
1031 memcpy(ch_client, &server_opts.ch_clients[server_opts.ch_client_count], sizeof *server_opts.ch_clients);
roman5cbb6532023-06-22 12:53:17 +02001032 }
1033
romanba93eac2023-07-18 14:36:48 +02001034 /* WR UNLOCK */
roman5cbb6532023-06-22 12:53:17 +02001035 pthread_rwlock_unlock(&server_opts.ch_client_lock);
romanba93eac2023-07-18 14:36:48 +02001036
roman8341e8b2023-11-23 16:12:42 +01001037 nc_server_config_destroy_ch_client(&client);
1038}
romanba93eac2023-07-18 14:36:48 +02001039
roman8341e8b2023-11-23 16:12:42 +01001040/* presence container */
1041int
1042nc_server_config_listen(const struct lyd_node *node, NC_OPERATION op)
1043{
1044 uint16_t i, endpt_count;
romanba93eac2023-07-18 14:36:48 +02001045
roman8341e8b2023-11-23 16:12:42 +01001046 (void) node;
romanba93eac2023-07-18 14:36:48 +02001047
roman8341e8b2023-11-23 16:12:42 +01001048 assert(op == NC_OP_CREATE || op == NC_OP_DELETE);
1049
1050 if (op == NC_OP_DELETE) {
1051 endpt_count = server_opts.endpt_count;
1052 for (i = 0; i < endpt_count; i++) {
1053 switch (server_opts.endpts[i].ti) {
1054#ifdef NC_ENABLED_SSH_TLS
1055 case NC_TI_LIBSSH:
1056 nc_server_config_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]);
1057 break;
1058 case NC_TI_OPENSSL:
1059 nc_server_config_del_endpt_tls(&server_opts.endpts[i], &server_opts.binds[i]);
1060 break;
1061#endif /* NC_ENABLED_SSH_TLS */
1062 case NC_TI_UNIX:
1063 nc_server_config_del_endpt_unix_socket(&server_opts.endpts[i], &server_opts.binds[i]);
1064 break;
1065 case NC_TI_NONE:
1066 case NC_TI_FD:
1067 ERRINT;
1068 return 1;
1069 }
1070 }
romanba93eac2023-07-18 14:36:48 +02001071 }
1072
roman8341e8b2023-11-23 16:12:42 +01001073 return 0;
roman5cbb6532023-06-22 12:53:17 +02001074}
1075
roman6430c152023-10-12 11:28:47 +02001076int
roman5cbb6532023-06-22 12:53:17 +02001077nc_server_config_ch(const struct lyd_node *node, NC_OPERATION op)
1078{
1079 uint16_t i, ch_client_count;
roman8341e8b2023-11-23 16:12:42 +01001080 struct nc_ch_client *ch_clients;
roman5cbb6532023-06-22 12:53:17 +02001081
1082 (void) node;
1083
roman8341e8b2023-11-23 16:12:42 +01001084 /* don't do anything if we're not deleting */
1085 if (op != NC_OP_DELETE) {
1086 return 0;
roman5cbb6532023-06-22 12:53:17 +02001087 }
roman6430c152023-10-12 11:28:47 +02001088
roman8341e8b2023-11-23 16:12:42 +01001089 /* WR LOCK */
1090 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
1091
1092 ch_client_count = server_opts.ch_client_count;
1093 ch_clients = server_opts.ch_clients;
1094
1095 /* remove them from the server opts */
1096 server_opts.ch_client_count = 0;
1097 server_opts.ch_clients = NULL;
1098
1099 /* UNLOCK */
1100 pthread_rwlock_unlock(&server_opts.ch_client_lock);
1101
1102 for (i = 0; i < ch_client_count; i++) {
1103 /* now destroy each client */
1104 nc_server_config_destroy_ch_client(&ch_clients[i]);
1105 }
1106
1107 free(ch_clients);
roman6430c152023-10-12 11:28:47 +02001108 return 0;
roman5cbb6532023-06-22 12:53:17 +02001109}
1110
romanc1d2b092023-02-02 08:58:27 +01001111/* default leaf */
1112static int
romaneaf84c72023-10-19 14:38:05 +02001113nc_server_config_hello_timeout(const struct lyd_node *node, NC_OPERATION op)
1114{
1115 assert(!strcmp(LYD_NAME(node), "hello-timeout"));
1116
1117 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001118 server_opts.hello_timeout = ((struct lyd_node_term *)node)->value.uint16;
romaneaf84c72023-10-19 14:38:05 +02001119 } else {
1120 /* default value */
1121 server_opts.hello_timeout = 60;
1122 }
1123
1124 return 0;
1125}
1126
1127/* default leaf */
1128static int
romane028ef92023-02-24 16:33:08 +01001129nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001130{
roman8341e8b2023-11-23 16:12:42 +01001131 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02001132
romanc1d2b092023-02-02 08:58:27 +01001133 assert(!strcmp(LYD_NAME(node), "idle-timeout"));
1134
romaneaf84c72023-10-19 14:38:05 +02001135 if (is_ch(node)) {
romanb6f44032023-06-30 15:07:56 +02001136 /* call-home idle timeout */
roman6430c152023-10-12 11:28:47 +02001137 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
1138 /* to avoid unlock on fail */
romanb6f44032023-06-30 15:07:56 +02001139 return 1;
1140 }
1141
1142 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001143 ch_client->idle_timeout = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02001144 } else if (op == NC_OP_DELETE) {
1145 ch_client->idle_timeout = 180;
1146 }
roman6430c152023-10-12 11:28:47 +02001147
1148 nc_ch_client_unlock(ch_client);
romaneaf84c72023-10-19 14:38:05 +02001149 } else {
1150 /* whole server idle timeout */
1151 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001152 server_opts.idle_timeout = ((struct lyd_node_term *)node)->value.uint16;
romaneaf84c72023-10-19 14:38:05 +02001153 } else {
1154 /* default value */
1155 server_opts.idle_timeout = 0;
1156 }
romanc1d2b092023-02-02 08:58:27 +01001157 }
1158
1159 return 0;
1160}
1161
1162static int
roman874fed12023-05-25 10:20:01 +02001163nc_server_config_create_bind(void)
romanc1d2b092023-02-02 08:58:27 +01001164{
1165 int ret = 0;
1166 void *tmp;
1167
1168 tmp = realloc(server_opts.binds, (server_opts.endpt_count + 1) * sizeof *server_opts.binds);
roman3a95bb22023-10-26 11:07:17 +02001169 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01001170 server_opts.binds = tmp;
1171 memset(&server_opts.binds[server_opts.endpt_count], 0, sizeof *server_opts.binds);
1172
1173 server_opts.binds[server_opts.endpt_count].sock = -1;
1174
1175cleanup:
1176 return ret;
1177}
1178
1179static int
roman874fed12023-05-25 10:20:01 +02001180nc_server_config_create_endpoint(const struct lyd_node *node)
romanc1d2b092023-02-02 08:58:27 +01001181{
roman874fed12023-05-25 10:20:01 +02001182 if (nc_server_config_create_bind()) {
romanf02273a2023-05-25 09:44:11 +02001183 return 1;
romanc1d2b092023-02-02 08:58:27 +01001184 }
romanc1d2b092023-02-02 08:58:27 +01001185
1186 node = lyd_child(node);
1187 assert(!strcmp(LYD_NAME(node), "name"));
1188
romanf02273a2023-05-25 09:44:11 +02001189 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 +01001190}
1191
roman5cbb6532023-06-22 12:53:17 +02001192static int
1193nc_server_config_ch_create_endpoint(const struct lyd_node *node, struct nc_ch_client *ch_client)
1194{
1195 node = lyd_child(node);
1196 assert(!strcmp(LYD_NAME(node), "name"));
1197
1198 return nc_server_config_realloc(lyd_get_value(node), (void **)&ch_client->ch_endpts, sizeof *ch_client->ch_endpts, &ch_client->ch_endpt_count);
1199}
1200
romanc1d2b092023-02-02 08:58:27 +01001201/* list */
1202static int
romane028ef92023-02-24 16:33:08 +01001203nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001204{
1205 int ret = 0;
1206 struct nc_endpt *endpt;
1207 struct nc_bind *bind;
roman6430c152023-10-12 11:28:47 +02001208 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001209 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001210
1211 assert(!strcmp(LYD_NAME(node), "endpoint"));
1212
roman5cbb6532023-06-22 12:53:17 +02001213 if (is_listen(node)) {
1214 /* listen */
1215 if (op == NC_OP_CREATE) {
1216 ret = nc_server_config_create_endpoint(node);
1217 if (ret) {
1218 goto cleanup;
1219 }
1220 } else if (op == NC_OP_DELETE) {
1221 /* free all children */
1222 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1223 ret = 1;
1224 goto cleanup;
1225 }
1226
1227 switch (endpt->ti) {
1228#ifdef NC_ENABLED_SSH_TLS
1229 case NC_TI_LIBSSH:
1230 nc_server_config_del_endpt_ssh(endpt, bind);
1231 break;
1232 case NC_TI_OPENSSL:
1233 nc_server_config_del_endpt_tls(endpt, bind);
1234 break;
1235#endif /* NC_ENABLED_SSH_TLS */
1236 case NC_TI_UNIX:
1237 nc_server_config_del_endpt_unix_socket(endpt, bind);
1238 break;
1239 case NC_TI_NONE:
1240 case NC_TI_FD:
1241 ERRINT;
1242 ret = 1;
1243 goto cleanup;
1244 }
romanc1d2b092023-02-02 08:58:27 +01001245 }
roman5cbb6532023-06-22 12:53:17 +02001246 } else if (is_ch(node)) {
romanba93eac2023-07-18 14:36:48 +02001247 /* LOCK */
1248 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001249 /* to avoid unlock on fail */
1250 return 1;
romanc1d2b092023-02-02 08:58:27 +01001251 }
roman3f9b65c2023-06-05 14:26:58 +02001252
roman5cbb6532023-06-22 12:53:17 +02001253 if (op == NC_OP_CREATE) {
1254 ret = nc_server_config_ch_create_endpoint(node, ch_client);
1255 if (ret) {
1256 goto cleanup;
1257 }
1258
1259 /* init ch sock */
1260 ch_client->ch_endpts[ch_client->ch_endpt_count - 1].sock_pending = -1;
roman6430c152023-10-12 11:28:47 +02001261 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01001262 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman6430c152023-10-12 11:28:47 +02001263 ret = 1;
1264 goto cleanup;
1265 }
1266
1267 nc_server_config_ch_del_endpt(ch_client, ch_endpt);
roman3f9b65c2023-06-05 14:26:58 +02001268 }
romanc1d2b092023-02-02 08:58:27 +01001269 }
1270
1271cleanup:
romanba93eac2023-07-18 14:36:48 +02001272 if (is_ch(node)) {
1273 /* UNLOCK */
1274 nc_ch_client_unlock(ch_client);
1275 }
romanc1d2b092023-02-02 08:58:27 +01001276 return ret;
1277}
1278
roman2eab4742023-06-06 10:00:26 +02001279#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02001280
romanc1d2b092023-02-02 08:58:27 +01001281static int
roman874fed12023-05-25 10:20:01 +02001282nc_server_config_create_ssh(struct nc_endpt *endpt)
romanc1d2b092023-02-02 08:58:27 +01001283{
1284 endpt->ti = NC_TI_LIBSSH;
1285 endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
roman3a95bb22023-10-26 11:07:17 +02001286 NC_CHECK_ERRMEM_RET(!endpt->opts.ssh, 1);
romanc1d2b092023-02-02 08:58:27 +01001287
1288 return 0;
1289}
1290
roman5cbb6532023-06-22 12:53:17 +02001291static int
1292nc_server_config_ch_create_ssh(struct nc_ch_endpt *ch_endpt)
1293{
1294 ch_endpt->ti = NC_TI_LIBSSH;
1295 ch_endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
roman3a95bb22023-10-26 11:07:17 +02001296 NC_CHECK_ERRMEM_RET(!ch_endpt->opts.ssh, 1);
roman5cbb6532023-06-22 12:53:17 +02001297
1298 return 0;
1299}
1300
romanc1d2b092023-02-02 08:58:27 +01001301/* NP container */
1302static int
romane028ef92023-02-24 16:33:08 +01001303nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001304{
1305 struct nc_endpt *endpt;
1306 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001307 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001308 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001309 int ret = 0;
1310
1311 assert(!strcmp(LYD_NAME(node), "ssh"));
1312
roman5cbb6532023-06-22 12:53:17 +02001313 if (is_listen(node)) {
1314 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1315 ret = 1;
romanc1d2b092023-02-02 08:58:27 +01001316 goto cleanup;
1317 }
roman5cbb6532023-06-22 12:53:17 +02001318
1319 if (op == NC_OP_CREATE) {
1320 ret = nc_server_config_create_ssh(endpt);
1321 if (ret) {
1322 goto cleanup;
1323 }
1324 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02001325 nc_server_config_del_ssh_opts(bind, endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +02001326 }
1327 } else {
romanba93eac2023-07-18 14:36:48 +02001328 /* LOCK */
1329 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001330 /* to avoid unlock on fail */
1331 return 1;
romanba93eac2023-07-18 14:36:48 +02001332 }
1333
roman8341e8b2023-11-23 16:12:42 +01001334 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001335 ret = 1;
1336 goto cleanup;
1337 }
1338
1339 if (op == NC_OP_CREATE) {
1340 ret = nc_server_config_ch_create_ssh(ch_endpt);
1341 if (ret) {
1342 goto cleanup;
1343 }
romanb6f44032023-06-30 15:07:56 +02001344 } else if (op == NC_OP_DELETE) {
roman5ae78282023-11-02 13:34:34 +01001345 nc_server_config_del_ssh_opts(NULL, ch_endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +02001346 }
romanc1d2b092023-02-02 08:58:27 +01001347 }
1348
1349cleanup:
romanba93eac2023-07-18 14:36:48 +02001350 if (is_ch(node)) {
1351 /* UNLOCK */
1352 nc_ch_client_unlock(ch_client);
1353 }
romanc1d2b092023-02-02 08:58:27 +01001354 return ret;
1355}
1356
roman3f9b65c2023-06-05 14:26:58 +02001357static int
1358nc_server_config_create_tls(struct nc_endpt *endpt)
1359{
1360 endpt->ti = NC_TI_OPENSSL;
1361 endpt->opts.tls = calloc(1, sizeof *endpt->opts.tls);
roman3a95bb22023-10-26 11:07:17 +02001362 NC_CHECK_ERRMEM_RET(!endpt->opts.tls, 1);
roman3f9b65c2023-06-05 14:26:58 +02001363
1364 return 0;
1365}
1366
1367static int
romanb6f44032023-06-30 15:07:56 +02001368nc_server_config_ch_create_tls(struct nc_ch_endpt *ch_endpt)
1369{
1370 ch_endpt->ti = NC_TI_OPENSSL;
1371 ch_endpt->opts.tls = calloc(1, sizeof(struct nc_server_tls_opts));
roman3a95bb22023-10-26 11:07:17 +02001372 NC_CHECK_ERRMEM_RET(!ch_endpt->opts.tls, 1);
romanb6f44032023-06-30 15:07:56 +02001373
1374 return 0;
1375}
1376
1377static int
roman3f9b65c2023-06-05 14:26:58 +02001378nc_server_config_tls(const struct lyd_node *node, NC_OPERATION op)
1379{
1380 struct nc_endpt *endpt;
1381 struct nc_bind *bind;
romanb6f44032023-06-30 15:07:56 +02001382 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001383 struct nc_ch_client *ch_client = NULL;
roman3f9b65c2023-06-05 14:26:58 +02001384 int ret = 0;
1385
1386 assert(!strcmp(LYD_NAME(node), "tls"));
1387
romanb6f44032023-06-30 15:07:56 +02001388 if (is_listen(node)) {
1389 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1390 ret = 1;
roman3f9b65c2023-06-05 14:26:58 +02001391 goto cleanup;
1392 }
romanb6f44032023-06-30 15:07:56 +02001393
1394 if (op == NC_OP_CREATE) {
1395 ret = nc_server_config_create_tls(endpt);
1396 if (ret) {
1397 goto cleanup;
1398 }
1399 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02001400 nc_server_config_del_tls_opts(bind, endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +02001401 }
1402 } else {
romanba93eac2023-07-18 14:36:48 +02001403 /* LOCK */
1404 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001405 /* to avoid unlock on fail */
1406 return 1;
romanba93eac2023-07-18 14:36:48 +02001407 }
1408
roman8341e8b2023-11-23 16:12:42 +01001409 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
romanb6f44032023-06-30 15:07:56 +02001410 ret = 1;
1411 goto cleanup;
1412 }
1413
1414 if (op == NC_OP_CREATE) {
1415 ret = nc_server_config_ch_create_tls(ch_endpt);
1416 if (ret) {
1417 goto cleanup;
1418 }
roman6430c152023-10-12 11:28:47 +02001419 } else if (op == NC_OP_DELETE) {
roman5ae78282023-11-02 13:34:34 +01001420 nc_server_config_del_tls_opts(NULL, ch_endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +02001421 }
roman3f9b65c2023-06-05 14:26:58 +02001422 }
1423
1424cleanup:
romanba93eac2023-07-18 14:36:48 +02001425 if (is_ch(node)) {
1426 /* UNLOCK */
1427 nc_ch_client_unlock(ch_client);
1428 }
roman3f9b65c2023-06-05 14:26:58 +02001429 return ret;
1430}
1431
roman2eab4742023-06-06 10:00:26 +02001432#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02001433
romanc1d2b092023-02-02 08:58:27 +01001434static int
1435nc_server_config_set_address_port(struct nc_endpt *endpt, struct nc_bind *bind, const char *address, uint16_t port)
1436{
1437 int sock = -1, set_addr, ret = 0;
1438
roman83683fb2023-02-24 09:15:23 +01001439 assert((address && !port) || (!address && port) || (endpt->ti == NC_TI_UNIX));
romanc1d2b092023-02-02 08:58:27 +01001440
1441 if (address) {
1442 set_addr = 1;
1443 } else {
1444 set_addr = 0;
1445 }
1446
1447 if (set_addr) {
1448 port = bind->port;
1449 } else {
1450 address = bind->address;
1451 }
1452
romanc1d2b092023-02-02 08:58:27 +01001453 /* we have all the information we need to create a listening socket */
roman83683fb2023-02-24 09:15:23 +01001454 if ((address && port) || (endpt->ti == NC_TI_UNIX)) {
romanc1d2b092023-02-02 08:58:27 +01001455 /* create new socket, close the old one */
roman83683fb2023-02-24 09:15:23 +01001456 if (endpt->ti == NC_TI_UNIX) {
1457 sock = nc_sock_listen_unix(endpt->opts.unixsock);
1458 } else {
1459 sock = nc_sock_listen_inet(address, port, &endpt->ka);
1460 }
1461
romanc1d2b092023-02-02 08:58:27 +01001462 if (sock == -1) {
1463 ret = 1;
1464 goto cleanup;
1465 }
1466
1467 if (bind->sock > -1) {
1468 close(bind->sock);
1469 }
1470 bind->sock = sock;
1471 }
1472
1473 if (sock > -1) {
1474 switch (endpt->ti) {
roman83683fb2023-02-24 09:15:23 +01001475 case NC_TI_UNIX:
1476 VRB(NULL, "Listening on %s for UNIX connections.", endpt->opts.unixsock->address);
1477 break;
roman2eab4742023-06-06 10:00:26 +02001478#ifdef NC_ENABLED_SSH_TLS
romanc1d2b092023-02-02 08:58:27 +01001479 case NC_TI_LIBSSH:
1480 VRB(NULL, "Listening on %s:%u for SSH connections.", address, port);
1481 break;
romanc1d2b092023-02-02 08:58:27 +01001482 case NC_TI_OPENSSL:
1483 VRB(NULL, "Listening on %s:%u for TLS connections.", address, port);
1484 break;
roman2eab4742023-06-06 10:00:26 +02001485#endif /* NC_ENABLED_SSH_TLS */
romanc1d2b092023-02-02 08:58:27 +01001486 default:
1487 ERRINT;
1488 ret = 1;
1489 break;
1490 }
1491 }
1492
1493cleanup:
1494 return ret;
1495}
1496
roman2eab4742023-06-06 10:00:26 +02001497#ifdef NC_ENABLED_SSH_TLS
1498
romanc1d2b092023-02-02 08:58:27 +01001499/* mandatory leaf */
1500static int
romane028ef92023-02-24 16:33:08 +01001501nc_server_config_local_address(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001502{
1503 struct nc_endpt *endpt;
1504 struct nc_bind *bind;
1505 int ret = 0;
1506
1507 (void) op;
1508
1509 assert(!strcmp(LYD_NAME(node), "local-address"));
1510
1511 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001512 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001513 ret = 1;
1514 goto cleanup;
1515 }
1516
roman6430c152023-10-12 11:28:47 +02001517 free(bind->address);
romanc1d2b092023-02-02 08:58:27 +01001518 bind->address = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001519 NC_CHECK_ERRMEM_GOTO(!bind->address, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01001520
1521 ret = nc_server_config_set_address_port(endpt, bind, lyd_get_value(node), 0);
1522 if (ret) {
1523 goto cleanup;
1524 }
1525 }
1526
1527cleanup:
1528 return ret;
1529}
1530
1531/* leaf with default value */
1532static int
romane028ef92023-02-24 16:33:08 +01001533nc_server_config_local_port(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001534{
1535 struct nc_endpt *endpt;
1536 struct nc_bind *bind;
1537 int ret = 0;
1538
1539 assert(!strcmp(LYD_NAME(node), "local-port"));
1540
1541 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001542 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001543 ret = 1;
1544 goto cleanup;
1545 }
1546
1547 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001548 bind->port = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001549 } else {
1550 /* delete -> set to default */
1551 bind->port = 0;
1552 }
1553
1554 ret = nc_server_config_set_address_port(endpt, bind, NULL, bind->port);
1555 if (ret) {
1556 goto cleanup;
1557 }
1558 }
1559
1560cleanup:
1561 return ret;
1562}
1563
1564/* P container */
1565static int
romane028ef92023-02-24 16:33:08 +01001566nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001567{
roman5cbb6532023-06-22 12:53:17 +02001568 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001569 struct nc_endpt *endpt;
1570 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001571 struct nc_ch_endpt *ch_endpt;
roman6cb86ea2023-11-08 15:12:05 +01001572 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001573
1574 assert(!strcmp(LYD_NAME(node), "keepalives"));
1575
roman5cbb6532023-06-22 12:53:17 +02001576 if (is_listen(node) && equal_parent_name(node, 1, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001577 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001578 ret = 1;
1579 goto cleanup;
1580 }
1581
1582 if (op == NC_OP_CREATE) {
1583 endpt->ka.enabled = 1;
1584 } else {
1585 endpt->ka.enabled = 0;
1586 }
1587 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1588 if (ret) {
1589 goto cleanup;
1590 }
roman5cbb6532023-06-22 12:53:17 +02001591 } else if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001592 /* LOCK */
1593 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001594 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001595 return 1;
1596 }
1597
roman8341e8b2023-11-23 16:12:42 +01001598 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001599 ret = 1;
1600 goto cleanup;
1601 }
1602
1603 if (op == NC_OP_CREATE) {
1604 ch_endpt->ka.enabled = 1;
1605 } else {
1606 ch_endpt->ka.enabled = 0;
1607 }
romanc1d2b092023-02-02 08:58:27 +01001608 }
1609
1610cleanup:
romanba93eac2023-07-18 14:36:48 +02001611 if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) {
1612 /* UNLOCK */
1613 nc_ch_client_unlock(ch_client);
1614 }
romanc1d2b092023-02-02 08:58:27 +01001615 return ret;
1616}
1617
1618/* mandatory leaf */
1619static int
romane028ef92023-02-24 16:33:08 +01001620nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001621{
roman5cbb6532023-06-22 12:53:17 +02001622 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001623 struct nc_endpt *endpt;
1624 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001625 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001626 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001627
1628 assert(!strcmp(LYD_NAME(node), "idle-time"));
1629
roman5cbb6532023-06-22 12:53:17 +02001630 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001631 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001632 ret = 1;
1633 goto cleanup;
1634 }
1635
1636 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001637 endpt->ka.idle_time = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001638 } else {
1639 endpt->ka.idle_time = 0;
1640 }
1641 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1642 if (ret) {
1643 goto cleanup;
1644 }
roman5cbb6532023-06-22 12:53:17 +02001645 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001646 /* LOCK */
1647 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001648 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001649 return 1;
1650 }
1651
roman8341e8b2023-11-23 16:12:42 +01001652 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001653 ret = 1;
1654 goto cleanup;
1655 }
1656
1657 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001658 ch_endpt->ka.idle_time = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001659 } else {
1660 ch_endpt->ka.idle_time = 0;
1661 }
romanc1d2b092023-02-02 08:58:27 +01001662 }
1663
1664cleanup:
roman6430c152023-10-12 11:28:47 +02001665 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001666 /* UNLOCK */
1667 nc_ch_client_unlock(ch_client);
1668 }
romanc1d2b092023-02-02 08:58:27 +01001669 return ret;
1670}
1671
1672/* mandatory leaf */
1673static int
romane028ef92023-02-24 16:33:08 +01001674nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001675{
roman5cbb6532023-06-22 12:53:17 +02001676 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001677 struct nc_endpt *endpt;
1678 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001679 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001680 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001681
1682 assert(!strcmp(LYD_NAME(node), "max-probes"));
1683
roman5cbb6532023-06-22 12:53:17 +02001684 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001685 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001686 ret = 1;
1687 goto cleanup;
1688 }
1689
1690 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001691 endpt->ka.max_probes = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001692 } else {
1693 endpt->ka.max_probes = 0;
1694 }
1695 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1696 if (ret) {
1697 goto cleanup;
1698 }
roman5cbb6532023-06-22 12:53:17 +02001699 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001700 /* LOCK */
1701 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001702 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001703 return 1;
1704 }
1705
roman8341e8b2023-11-23 16:12:42 +01001706 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001707 ret = 1;
1708 goto cleanup;
1709 }
1710
1711 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001712 ch_endpt->ka.max_probes = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001713 } else {
1714 ch_endpt->ka.max_probes = 0;
1715 }
romanc1d2b092023-02-02 08:58:27 +01001716 }
1717
1718cleanup:
roman6430c152023-10-12 11:28:47 +02001719 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001720 /* UNLOCK */
1721 nc_ch_client_unlock(ch_client);
1722 }
romanc1d2b092023-02-02 08:58:27 +01001723 return ret;
1724}
1725
1726/* mandatory leaf */
1727static int
romane028ef92023-02-24 16:33:08 +01001728nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001729{
roman5cbb6532023-06-22 12:53:17 +02001730 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001731 struct nc_endpt *endpt;
1732 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001733 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001734 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001735
1736 assert(!strcmp(LYD_NAME(node), "probe-interval"));
1737
roman5cbb6532023-06-22 12:53:17 +02001738 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001739 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001740 ret = 1;
1741 goto cleanup;
1742 }
1743
1744 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001745 endpt->ka.probe_interval = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001746 } else {
1747 endpt->ka.probe_interval = 0;
1748 }
1749 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1750 if (ret) {
1751 goto cleanup;
1752 }
roman5cbb6532023-06-22 12:53:17 +02001753 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001754 /* LOCK */
1755 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001756 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001757 return 1;
1758 }
1759
roman8341e8b2023-11-23 16:12:42 +01001760 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001761 ret = 1;
1762 goto cleanup;
1763 }
1764
1765 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001766 ch_endpt->ka.probe_interval = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001767 } else {
1768 ch_endpt->ka.max_probes = 0;
1769 }
romanc1d2b092023-02-02 08:58:27 +01001770 }
1771
1772cleanup:
roman6430c152023-10-12 11:28:47 +02001773 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001774 /* UNLOCK */
1775 nc_ch_client_unlock(ch_client);
1776 }
romanc1d2b092023-02-02 08:58:27 +01001777 return ret;
1778}
1779
1780static int
roman874fed12023-05-25 10:20:01 +02001781nc_server_config_create_host_key(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01001782{
romanf02273a2023-05-25 09:44:11 +02001783 node = lyd_child(node);
1784 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01001785
romanf02273a2023-05-25 09:44:11 +02001786 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->hostkeys, sizeof *opts->hostkeys, &opts->hostkey_count);
romanc1d2b092023-02-02 08:58:27 +01001787}
1788
1789/* list */
1790static int
romane028ef92023-02-24 16:33:08 +01001791nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001792{
roman5cbb6532023-06-22 12:53:17 +02001793 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001794 struct nc_hostkey *hostkey;
roman4cb8bb12023-06-29 09:16:46 +02001795 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01001796 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001797
1798 assert(!strcmp(LYD_NAME(node), "host-key"));
1799
roman4cb8bb12023-06-29 09:16:46 +02001800 if (equal_parent_name(node, 1, "server-identity")) {
romanba93eac2023-07-18 14:36:48 +02001801 /* LOCK */
1802 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001803 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001804 return 1;
1805 }
1806
roman8341e8b2023-11-23 16:12:42 +01001807 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman6cb86ea2023-11-08 15:12:05 +01001808 ret = 1;
1809 goto cleanup;
1810 }
1811
romanc1d2b092023-02-02 08:58:27 +01001812 if (op == NC_OP_CREATE) {
roman4cb8bb12023-06-29 09:16:46 +02001813 ret = nc_server_config_create_host_key(node, opts);
romanc1d2b092023-02-02 08:58:27 +01001814 if (ret) {
1815 goto cleanup;
1816 }
1817 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01001818 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001819 ret = 1;
1820 goto cleanup;
1821 }
roman4cb8bb12023-06-29 09:16:46 +02001822 nc_server_config_del_hostkey(opts, hostkey);
roman5cbb6532023-06-22 12:53:17 +02001823 }
romanc1d2b092023-02-02 08:58:27 +01001824 }
1825
1826cleanup:
romanba93eac2023-07-18 14:36:48 +02001827 if (is_ch(node) && equal_parent_name(node, 1, "server-identity")) {
1828 /* UNLOCK */
1829 nc_ch_client_unlock(ch_client);
1830 }
romanc1d2b092023-02-02 08:58:27 +01001831 return ret;
1832}
1833
1834/* mandatory leaf */
romane028ef92023-02-24 16:33:08 +01001835static int
1836nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001837{
roman3f9b65c2023-06-05 14:26:58 +02001838 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02001839 const char *format;
roman3f9b65c2023-06-05 14:26:58 +02001840 NC_PUBKEY_FORMAT pubkey_type;
roman8edee342023-03-31 13:25:48 +02001841 struct nc_public_key *pubkey;
romanc1d2b092023-02-02 08:58:27 +01001842 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02001843 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01001844 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001845
1846 assert(!strcmp(LYD_NAME(node), "public-key-format"));
1847
roman6cb86ea2023-11-08 15:12:05 +01001848 /* LOCK */
1849 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
1850 /* to avoid unlock on fail */
1851 return 1;
1852 }
1853
romanc1d2b092023-02-02 08:58:27 +01001854 format = ((struct lyd_node_term *)node)->value.ident->name;
roman3f9b65c2023-06-05 14:26:58 +02001855 if (!strcmp(format, "ssh-public-key-format")) {
roman13145912023-08-17 15:36:54 +02001856 pubkey_type = NC_PUBKEY_FORMAT_SSH;
roman3f9b65c2023-06-05 14:26:58 +02001857 } else if (!strcmp(format, "subject-public-key-info-format")) {
1858 pubkey_type = NC_PUBKEY_FORMAT_X509;
1859 } else {
1860 ERR(NULL, "Public key format (%s) not supported.", format);
1861 ret = 1;
1862 goto cleanup;
1863 }
romanc1d2b092023-02-02 08:58:27 +01001864
roman4cb8bb12023-06-29 09:16:46 +02001865 if (is_ssh(node) && equal_parent_name(node, 4, "server-identity")) {
roman5cbb6532023-06-22 12:53:17 +02001866 /* SSH hostkey public key fmt */
roman8341e8b2023-11-23 16:12:42 +01001867 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02001868 ret = 1;
1869 goto cleanup;
1870 }
1871
1872 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1873 hostkey->key.pubkey_type = pubkey_type;
1874 }
roman4cb8bb12023-06-29 09:16:46 +02001875 } else if (is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) {
roman5cbb6532023-06-22 12:53:17 +02001876 /* SSH client auth public key fmt */
roman8341e8b2023-11-23 16:12:42 +01001877 if (nc_server_config_get_pubkey(node, ch_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001878 ret = 1;
1879 goto cleanup;
1880 }
1881
1882 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman3f9b65c2023-06-05 14:26:58 +02001883 pubkey->type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001884 }
romanb6f44032023-06-30 15:07:56 +02001885 } else if (is_tls(node) && equal_parent_name(node, 3, "server-identity")) {
1886 /* TLS server-identity */
roman8341e8b2023-11-23 16:12:42 +01001887 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02001888 ret = 1;
1889 goto cleanup;
1890 }
1891
roman5cbb6532023-06-22 12:53:17 +02001892 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02001893 opts->pubkey_type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001894 }
romanc1d2b092023-02-02 08:58:27 +01001895 }
1896
1897cleanup:
romanba93eac2023-07-18 14:36:48 +02001898 if (is_ch(node)) {
1899 /* UNLOCK */
1900 nc_ch_client_unlock(ch_client);
1901 }
romanc1d2b092023-02-02 08:58:27 +01001902 return ret;
1903}
1904
1905static int
roman58f79d02023-10-06 10:20:31 +02001906nc_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 +01001907{
romanc1d2b092023-02-02 08:58:27 +01001908 assert(!strcmp(LYD_NAME(node), "public-key"));
1909
romanc1d2b092023-02-02 08:58:27 +01001910 node = lyd_child(node);
1911 assert(!strcmp(LYD_NAME(node), "name"));
1912
romanf02273a2023-05-25 09:44:11 +02001913 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 +01001914}
1915
1916static int
roman874fed12023-05-25 10:20:01 +02001917nc_server_config_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +01001918{
roman6430c152023-10-12 11:28:47 +02001919 free(pubkey->data);
roman3f9b65c2023-06-05 14:26:58 +02001920 pubkey->data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001921 NC_CHECK_ERRMEM_RET(!pubkey->data, 1);
romanc1d2b092023-02-02 08:58:27 +01001922
1923 return 0;
1924}
1925
1926static int
roman874fed12023-05-25 10:20:01 +02001927nc_server_config_replace_host_key_public_key(const struct lyd_node *node, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +01001928{
roman6430c152023-10-12 11:28:47 +02001929 free(hostkey->key.pubkey_data);
roman3f9b65c2023-06-05 14:26:58 +02001930 hostkey->key.pubkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001931 NC_CHECK_ERRMEM_RET(!hostkey->key.pubkey_data, 1);
romanc1d2b092023-02-02 08:58:27 +01001932
1933 return 0;
1934}
1935
roman3f9b65c2023-06-05 14:26:58 +02001936static int
1937nc_server_config_tls_replace_server_public_key(const struct lyd_node *node, struct nc_server_tls_opts *opts)
1938{
roman6430c152023-10-12 11:28:47 +02001939 free(opts->pubkey_data);
roman3f9b65c2023-06-05 14:26:58 +02001940 opts->pubkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001941 NC_CHECK_ERRMEM_RET(!opts->pubkey_data, 1);
roman3f9b65c2023-06-05 14:26:58 +02001942
1943 return 0;
1944}
1945
romanc1d2b092023-02-02 08:58:27 +01001946static int
romane028ef92023-02-24 16:33:08 +01001947nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001948{
roman3f9b65c2023-06-05 14:26:58 +02001949 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001950 struct nc_hostkey *hostkey;
roman58f79d02023-10-06 10:20:31 +02001951 struct nc_auth_client *auth_client;
roman8edee342023-03-31 13:25:48 +02001952 struct nc_public_key *pubkey;
romanb6f44032023-06-30 15:07:56 +02001953 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01001954 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001955
1956 assert(!strcmp(LYD_NAME(node), "public-key"));
1957
romanba93eac2023-07-18 14:36:48 +02001958 /* LOCK */
1959 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02001960 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001961 return 1;
1962 }
1963
roman4cb8bb12023-06-29 09:16:46 +02001964 if (is_ssh(node) && equal_parent_name(node, 3, "host-key")) {
roman3f9b65c2023-06-05 14:26:58 +02001965 /* server's public-key, mandatory leaf */
roman8341e8b2023-11-23 16:12:42 +01001966 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001967 ret = 1;
1968 goto cleanup;
1969 }
1970
roman13145912023-08-17 15:36:54 +02001971 /* the public key must not be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
roman51a1e192023-09-14 10:13:45 +02001972 if (nc_is_pk_subject_public_key_info(lyd_get_value(node))) {
roman13145912023-08-17 15:36:54 +02001973 ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH hostkey is forbidden!");
1974 ret = 1;
1975 goto cleanup;
1976 }
1977
romanc1d2b092023-02-02 08:58:27 +01001978 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02001979 /* set to local */
roman874fed12023-05-25 10:20:01 +02001980 hostkey->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02001981
roman874fed12023-05-25 10:20:01 +02001982 ret = nc_server_config_replace_host_key_public_key(node, hostkey);
romanc1d2b092023-02-02 08:58:27 +01001983 if (ret) {
1984 goto cleanup;
1985 }
1986 }
roman4cb8bb12023-06-29 09:16:46 +02001987 } else if (is_ssh(node) && equal_parent_name(node, 5, "client-authentication")) {
romanc1d2b092023-02-02 08:58:27 +01001988 /* client auth pubkeys, list */
roman8341e8b2023-11-23 16:12:42 +01001989 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001990 ret = 1;
1991 goto cleanup;
1992 }
1993
1994 if (op == NC_OP_CREATE) {
romanf02273a2023-05-25 09:44:11 +02001995 /* set to local */
roman874fed12023-05-25 10:20:01 +02001996 auth_client->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02001997
roman874fed12023-05-25 10:20:01 +02001998 ret = nc_server_config_create_auth_key_public_key_list(node, auth_client);
romanc1d2b092023-02-02 08:58:27 +01001999 if (ret) {
2000 goto cleanup;
2001 }
2002 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01002003 if (nc_server_config_get_pubkey(node, ch_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01002004 ret = 1;
2005 goto cleanup;
2006 }
2007
roman874fed12023-05-25 10:20:01 +02002008 nc_server_config_del_auth_client_pubkey(auth_client, pubkey);
romanc1d2b092023-02-02 08:58:27 +01002009 }
roman4cb8bb12023-06-29 09:16:46 +02002010 } else if (is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) {
romanc1d2b092023-02-02 08:58:27 +01002011 /* client auth pubkey, leaf */
roman8341e8b2023-11-23 16:12:42 +01002012 if (nc_server_config_get_pubkey(node, ch_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01002013 ret = 1;
2014 goto cleanup;
2015 }
2016
roman13145912023-08-17 15:36:54 +02002017 /* the public key must not be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
roman51a1e192023-09-14 10:13:45 +02002018 if (nc_is_pk_subject_public_key_info(lyd_get_value(node))) {
roman13145912023-08-17 15:36:54 +02002019 ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH user's key is forbidden!");
2020 ret = 1;
2021 goto cleanup;
2022 }
2023
romanc1d2b092023-02-02 08:58:27 +01002024 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02002025 ret = nc_server_config_replace_auth_key_public_key_leaf(node, pubkey);
romanc1d2b092023-02-02 08:58:27 +01002026 if (ret) {
2027 goto cleanup;
2028 }
roman6430c152023-10-12 11:28:47 +02002029 } else if (op == NC_OP_DELETE) {
2030 free(pubkey->data);
2031 pubkey->data = NULL;
romanc1d2b092023-02-02 08:58:27 +01002032 }
romanb6f44032023-06-30 15:07:56 +02002033 } else if (is_tls(node) && equal_parent_name(node, 3, "server-identity")) {
2034 /* TLS server-identity */
roman8341e8b2023-11-23 16:12:42 +01002035 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002036 ret = 1;
2037 goto cleanup;
2038 }
2039
roman13145912023-08-17 15:36:54 +02002040 /* the public key must be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
roman51a1e192023-09-14 10:13:45 +02002041 if (!nc_is_pk_subject_public_key_info(lyd_get_value(node))) {
roman13145912023-08-17 15:36:54 +02002042 ERR(NULL, "TLS server certificate's Public Key must be in the SubjectPublicKeyInfo format!");
2043 ret = 1;
2044 goto cleanup;
2045 }
2046
roman3f9b65c2023-06-05 14:26:58 +02002047 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2048 /* set to local */
romanb6f44032023-06-30 15:07:56 +02002049 opts->store = NC_STORE_LOCAL;
roman3f9b65c2023-06-05 14:26:58 +02002050
romanb6f44032023-06-30 15:07:56 +02002051 ret = nc_server_config_tls_replace_server_public_key(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02002052 if (ret) {
2053 goto cleanup;
2054 }
2055 }
roman5cbb6532023-06-22 12:53:17 +02002056 }
2057
2058cleanup:
romanba93eac2023-07-18 14:36:48 +02002059 if (is_ch(node)) {
2060 /* UNLOCK */
2061 nc_ch_client_unlock(ch_client);
2062 }
roman5cbb6532023-06-22 12:53:17 +02002063 return ret;
2064}
2065
2066/* leaf */
2067static int
2068nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op)
2069{
2070 int ret = 0;
2071 const char *format;
2072 NC_PRIVKEY_FORMAT privkey_type;
roman5cbb6532023-06-22 12:53:17 +02002073 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02002074 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002075 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02002076
2077 (void) op;
2078
2079 assert(!strcmp(LYD_NAME(node), "private-key-format"));
2080
roman6cb86ea2023-11-08 15:12:05 +01002081 /* LOCK */
2082 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
2083 /* to avoid unlock on fail */
2084 return 1;
2085 }
2086
roman5cbb6532023-06-22 12:53:17 +02002087 format = ((struct lyd_node_term *)node)->value.ident->name;
2088 if (!format) {
2089 ret = 1;
2090 goto cleanup;
2091 }
2092
2093 privkey_type = nc_server_config_get_private_key_type(format);
2094 if (privkey_type == NC_PRIVKEY_FORMAT_UNKNOWN) {
2095 ERR(NULL, "Unknown private key format.");
2096 ret = 1;
2097 goto cleanup;
2098 }
2099
roman4cb8bb12023-06-29 09:16:46 +02002100 if (is_ssh(node)) {
2101 /* ssh */
roman8341e8b2023-11-23 16:12:42 +01002102 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02002103 ret = 1;
2104 goto cleanup;
2105 }
2106
2107 hostkey->key.privkey_type = privkey_type;
romanb6f44032023-06-30 15:07:56 +02002108 } else if (is_tls(node)) {
2109 /* tls */
roman8341e8b2023-11-23 16:12:42 +01002110 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman5cbb6532023-06-22 12:53:17 +02002111 ret = 1;
2112 goto cleanup;
2113 }
2114
romanb6f44032023-06-30 15:07:56 +02002115 opts->privkey_type = privkey_type;
roman5cbb6532023-06-22 12:53:17 +02002116 }
2117
2118cleanup:
romanba93eac2023-07-18 14:36:48 +02002119 if (is_ch(node)) {
2120 /* UNLOCK */
2121 nc_ch_client_unlock(ch_client);
2122 }
roman5cbb6532023-06-22 12:53:17 +02002123 return ret;
2124}
2125
2126static int
roman5cbb6532023-06-22 12:53:17 +02002127nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op)
2128{
2129 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02002130 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02002131 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002132 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02002133
2134 assert(!strcmp(LYD_NAME(node), "cleartext-private-key"));
2135
romanba93eac2023-07-18 14:36:48 +02002136 /* LOCK */
2137 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002138 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002139 return 1;
2140 }
2141
roman4cb8bb12023-06-29 09:16:46 +02002142 if (is_ssh(node)) {
2143 /* ssh */
roman8341e8b2023-11-23 16:12:42 +01002144 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02002145 ret = 1;
2146 goto cleanup;
2147 }
2148
2149 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002150 free(hostkey->key.privkey_data);
2151 hostkey->key.privkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002152 NC_CHECK_ERRMEM_GOTO(!hostkey->key.privkey_data, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02002153 } else {
roman6430c152023-10-12 11:28:47 +02002154 free(hostkey->key.privkey_data);
2155 hostkey->key.privkey_data = NULL;
roman5cbb6532023-06-22 12:53:17 +02002156 }
romanb6f44032023-06-30 15:07:56 +02002157 } else if (is_tls(node)) {
2158 /* tls */
roman8341e8b2023-11-23 16:12:42 +01002159 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002160 ret = 1;
2161 goto cleanup;
2162 }
2163
roman5cbb6532023-06-22 12:53:17 +02002164 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002165 free(opts->privkey_data);
2166 opts->privkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002167 NC_CHECK_ERRMEM_GOTO(!opts->privkey_data, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02002168 } else {
roman6430c152023-10-12 11:28:47 +02002169 free(opts->privkey_data);
2170 opts->privkey_data = NULL;
roman5cbb6532023-06-22 12:53:17 +02002171 }
roman5cbb6532023-06-22 12:53:17 +02002172 }
2173
2174cleanup:
romanba93eac2023-07-18 14:36:48 +02002175 if (is_ch(node)) {
2176 /* UNLOCK */
2177 nc_ch_client_unlock(ch_client);
2178 }
roman5cbb6532023-06-22 12:53:17 +02002179 return ret;
2180}
2181
roman5cbb6532023-06-22 12:53:17 +02002182/* leaf */
2183static int
2184nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op)
2185{
2186 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02002187 struct nc_hostkey *hostkey;
roman8341e8b2023-11-23 16:12:42 +01002188 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02002189
2190 assert(!strcmp(LYD_NAME(node), "keystore-reference"));
2191
romanba93eac2023-07-18 14:36:48 +02002192 /* LOCK */
2193 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002194 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002195 return 1;
2196 }
2197
roman4cb8bb12023-06-29 09:16:46 +02002198 if (is_ssh(node) && equal_parent_name(node, 3, "server-identity")) {
roman8341e8b2023-11-23 16:12:42 +01002199 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02002200 ret = 1;
2201 goto cleanup;
2202 }
2203
2204 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2205 /* set to keystore */
2206 hostkey->store = NC_STORE_KEYSTORE;
2207
roman6430c152023-10-12 11:28:47 +02002208 free(hostkey->ks_ref);
romandd019a92023-09-14 10:17:07 +02002209 hostkey->ks_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002210 NC_CHECK_ERRMEM_GOTO(!hostkey->ks_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002211 } else if (op == NC_OP_DELETE) {
2212 free(hostkey->ks_ref);
roman5cbb6532023-06-22 12:53:17 +02002213 hostkey->ks_ref = NULL;
2214 }
roman3f9b65c2023-06-05 14:26:58 +02002215 }
romanc1d2b092023-02-02 08:58:27 +01002216
2217cleanup:
romanba93eac2023-07-18 14:36:48 +02002218 if (is_ch(node)) {
2219 /* UNLOCK */
2220 nc_ch_client_unlock(ch_client);
2221 }
romanc1d2b092023-02-02 08:58:27 +01002222 return ret;
2223}
2224
2225static int
roman6430c152023-10-12 11:28:47 +02002226nc_server_config_create_auth_client(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01002227{
romanf02273a2023-05-25 09:44:11 +02002228 node = lyd_child(node);
2229 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01002230
romanf02273a2023-05-25 09:44:11 +02002231 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 +01002232}
2233
2234/* list */
2235static int
romane028ef92023-02-24 16:33:08 +01002236nc_server_config_user(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002237{
roman5cbb6532023-06-22 12:53:17 +02002238 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002239 struct nc_auth_client *auth_client;
roman4cb8bb12023-06-29 09:16:46 +02002240 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002241 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002242
2243 assert(!strcmp(LYD_NAME(node), "user"));
2244
romanba93eac2023-07-18 14:36:48 +02002245 /* LOCK */
2246 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002247 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002248 return 1;
2249 }
2250
roman8341e8b2023-11-23 16:12:42 +01002251 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002252 ret = 1;
2253 goto cleanup;
2254 }
2255
2256 if (op == NC_OP_CREATE) {
roman6430c152023-10-12 11:28:47 +02002257 ret = nc_server_config_create_auth_client(node, opts);
roman4cb8bb12023-06-29 09:16:46 +02002258 if (ret) {
2259 goto cleanup;
2260 }
2261 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01002262 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002263 ret = 1;
2264 goto cleanup;
2265 }
2266
roman4cb8bb12023-06-29 09:16:46 +02002267 nc_server_config_del_auth_client(opts, auth_client);
romanc1d2b092023-02-02 08:58:27 +01002268 }
2269
2270cleanup:
romanba93eac2023-07-18 14:36:48 +02002271 if (is_ch(node)) {
2272 /* UNLOCK */
2273 nc_ch_client_unlock(ch_client);
2274 }
romanc1d2b092023-02-02 08:58:27 +01002275 return ret;
2276}
2277
2278static int
romane028ef92023-02-24 16:33:08 +01002279nc_server_config_auth_attempts(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002280{
romanc1d2b092023-02-02 08:58:27 +01002281 int ret = 0;
roman4cb8bb12023-06-29 09:16:46 +02002282 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002283 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002284
2285 assert(!strcmp(LYD_NAME(node), "auth-attempts"));
2286
romanba93eac2023-07-18 14:36:48 +02002287 /* LOCK */
2288 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002289 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002290 return 1;
2291 }
2292
roman8341e8b2023-11-23 16:12:42 +01002293 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002294 ret = 1;
2295 goto cleanup;
2296 }
romanc1d2b092023-02-02 08:58:27 +01002297
roman4cb8bb12023-06-29 09:16:46 +02002298 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02002299 opts->auth_attempts = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01002300 }
2301
2302cleanup:
romanba93eac2023-07-18 14:36:48 +02002303 if (is_ch(node)) {
2304 /* UNLOCK */
2305 nc_ch_client_unlock(ch_client);
2306 }
romanc1d2b092023-02-02 08:58:27 +01002307 return ret;
2308}
2309
2310static int
romane028ef92023-02-24 16:33:08 +01002311nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002312{
romanc1d2b092023-02-02 08:58:27 +01002313 int ret = 0;
roman4cb8bb12023-06-29 09:16:46 +02002314 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002315 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002316
2317 assert(!strcmp(LYD_NAME(node), "auth-timeout"));
2318
romanba93eac2023-07-18 14:36:48 +02002319 /* LOCK */
2320 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002321 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002322 return 1;
2323 }
2324
roman8341e8b2023-11-23 16:12:42 +01002325 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002326 ret = 1;
2327 goto cleanup;
2328 }
romanc1d2b092023-02-02 08:58:27 +01002329
roman4cb8bb12023-06-29 09:16:46 +02002330 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02002331 opts->auth_timeout = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01002332 }
2333
2334cleanup:
romanba93eac2023-07-18 14:36:48 +02002335 if (is_ch(node)) {
2336 /* UNLOCK */
2337 nc_ch_client_unlock(ch_client);
2338 }
romanc1d2b092023-02-02 08:58:27 +01002339 return ret;
2340}
2341
romanc1d2b092023-02-02 08:58:27 +01002342/* leaf */
2343static int
romane028ef92023-02-24 16:33:08 +01002344nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002345{
romanc1d2b092023-02-02 08:58:27 +01002346 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002347 struct nc_auth_client *auth_client;
roman8341e8b2023-11-23 16:12:42 +01002348 struct nc_ch_client *ch_client = NULL;
roman6430c152023-10-12 11:28:47 +02002349 struct nc_server_tls_opts *opts;
2350 struct nc_cert_grouping *certs_grp;
romanc1d2b092023-02-02 08:58:27 +01002351
2352 assert(!strcmp(LYD_NAME(node), "truststore-reference"));
2353
romanba93eac2023-07-18 14:36:48 +02002354 /* LOCK */
2355 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002356 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002357 return 1;
2358 }
2359
roman4cb8bb12023-06-29 09:16:46 +02002360 if (is_ssh(node) && equal_parent_name(node, 1, "public-keys")) {
roman8341e8b2023-11-23 16:12:42 +01002361 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002362 ret = 1;
2363 goto cleanup;
2364 }
2365
2366 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02002367 /* set to truststore */
roman874fed12023-05-25 10:20:01 +02002368 auth_client->store = NC_STORE_TRUSTSTORE;
romanf02273a2023-05-25 09:44:11 +02002369
roman6430c152023-10-12 11:28:47 +02002370 free(auth_client->ts_ref);
2371 auth_client->ts_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002372 NC_CHECK_ERRMEM_GOTO(!auth_client->ts_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002373 } else if (op == NC_OP_DELETE) {
2374 free(auth_client->ts_ref);
romand57b3722023-04-05 11:26:25 +02002375 auth_client->ts_ref = NULL;
romanc1d2b092023-02-02 08:58:27 +01002376 }
roman6430c152023-10-12 11:28:47 +02002377 } else if (is_tls(node) && (equal_parent_name(node, 1, "ca-certs") || equal_parent_name(node, 1, "ee-certs"))) {
2378 /* ee-certs or ca-certs */
roman8341e8b2023-11-23 16:12:42 +01002379 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002380 ret = 1;
2381 goto cleanup;
2382 }
2383
roman6430c152023-10-12 11:28:47 +02002384 if (equal_parent_name(node, 1, "ca-certs")) {
2385 certs_grp = &opts->ca_certs;
roman3f9b65c2023-06-05 14:26:58 +02002386 } else {
roman6430c152023-10-12 11:28:47 +02002387 certs_grp = &opts->ee_certs;
roman4cb8bb12023-06-29 09:16:46 +02002388 }
2389
roman3f9b65c2023-06-05 14:26:58 +02002390 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2391 /* set to truststore */
roman6430c152023-10-12 11:28:47 +02002392 certs_grp->store = NC_STORE_TRUSTSTORE;
roman3f9b65c2023-06-05 14:26:58 +02002393
roman6430c152023-10-12 11:28:47 +02002394 free(certs_grp->ts_ref);
2395 certs_grp->ts_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002396 NC_CHECK_ERRMEM_GOTO(!certs_grp->ts_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002397 } else if (op == NC_OP_DELETE) {
2398 free(certs_grp->ts_ref);
2399 certs_grp->ts_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002400 }
2401 }
romanc1d2b092023-02-02 08:58:27 +01002402
2403cleanup:
romanba93eac2023-07-18 14:36:48 +02002404 if (is_ch(node)) {
2405 /* UNLOCK */
2406 nc_ch_client_unlock(ch_client);
2407 }
romanc1d2b092023-02-02 08:58:27 +01002408 return ret;
2409}
2410
romanc1d2b092023-02-02 08:58:27 +01002411/* leaf */
2412static int
romane028ef92023-02-24 16:33:08 +01002413nc_server_config_password(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002414{
roman5cbb6532023-06-22 12:53:17 +02002415 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002416 struct nc_auth_client *auth_client;
roman8341e8b2023-11-23 16:12:42 +01002417 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002418
2419 assert(!strcmp(LYD_NAME(node), "password"));
2420
romanba93eac2023-07-18 14:36:48 +02002421 /* LOCK */
2422 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002423 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002424 return 1;
2425 }
2426
roman8341e8b2023-11-23 16:12:42 +01002427 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
roman4cb8bb12023-06-29 09:16:46 +02002428 ret = 1;
2429 goto cleanup;
2430 }
2431
2432 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002433 free(auth_client->password);
2434 auth_client->password = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002435 NC_CHECK_ERRMEM_GOTO(!auth_client->password, ret = 1, cleanup);
roman4cb8bb12023-06-29 09:16:46 +02002436 } else {
roman6430c152023-10-12 11:28:47 +02002437 free(auth_client->password);
2438 auth_client->password = NULL;
romanc1d2b092023-02-02 08:58:27 +01002439 }
2440
2441cleanup:
romanba93eac2023-07-18 14:36:48 +02002442 if (is_ch(node)) {
2443 /* UNLOCK */
2444 nc_ch_client_unlock(ch_client);
2445 }
romanc1d2b092023-02-02 08:58:27 +01002446 return ret;
2447}
2448
2449static int
roman808f3f62023-11-23 16:01:04 +01002450nc_server_config_kb_int(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002451{
roman5cbb6532023-06-22 12:53:17 +02002452 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002453 struct nc_auth_client *auth_client;
roman808f3f62023-11-23 16:01:04 +01002454 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002455
roman808f3f62023-11-23 16:01:04 +01002456 assert(!strcmp(LYD_NAME(node), "keyboard-interactive"));
romanc1d2b092023-02-02 08:58:27 +01002457
romanba93eac2023-07-18 14:36:48 +02002458 /* LOCK */
2459 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002460 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002461 return 1;
2462 }
2463
roman8341e8b2023-11-23 16:12:42 +01002464 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
roman4cb8bb12023-06-29 09:16:46 +02002465 ret = 1;
2466 goto cleanup;
2467 }
2468
roman808f3f62023-11-23 16:01:04 +01002469 if (op == NC_OP_CREATE) {
2470 auth_client->kb_int_enabled = 1;
roman4cb8bb12023-06-29 09:16:46 +02002471 } else {
roman808f3f62023-11-23 16:01:04 +01002472 auth_client->kb_int_enabled = 0;
romanc1d2b092023-02-02 08:58:27 +01002473 }
2474
2475cleanup:
romanba93eac2023-07-18 14:36:48 +02002476 if (is_ch(node)) {
2477 /* UNLOCK */
2478 nc_ch_client_unlock(ch_client);
2479 }
romanc1d2b092023-02-02 08:58:27 +01002480 return ret;
2481}
2482
2483/* leaf */
2484static int
romane028ef92023-02-24 16:33:08 +01002485nc_server_config_none(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002486{
roman5cbb6532023-06-22 12:53:17 +02002487 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002488 struct nc_auth_client *auth_client;
roman8341e8b2023-11-23 16:12:42 +01002489 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002490
2491 assert(!strcmp(LYD_NAME(node), "none"));
2492
romanba93eac2023-07-18 14:36:48 +02002493 /* LOCK */
2494 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002495 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002496 return 1;
2497 }
2498
roman8341e8b2023-11-23 16:12:42 +01002499 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
roman4cb8bb12023-06-29 09:16:46 +02002500 ret = 1;
2501 goto cleanup;
2502 }
romanc1d2b092023-02-02 08:58:27 +01002503
roman4cb8bb12023-06-29 09:16:46 +02002504 if (op == NC_OP_CREATE) {
roman808f3f62023-11-23 16:01:04 +01002505 auth_client->none_enabled = 1;
roman4cb8bb12023-06-29 09:16:46 +02002506 } else {
roman808f3f62023-11-23 16:01:04 +01002507 auth_client->none_enabled = 0;
romanc1d2b092023-02-02 08:58:27 +01002508 }
2509
2510cleanup:
romanba93eac2023-07-18 14:36:48 +02002511 if (is_ch(node)) {
2512 /* UNLOCK */
2513 nc_ch_client_unlock(ch_client);
2514 }
romanc1d2b092023-02-02 08:58:27 +01002515 return ret;
2516}
2517
2518static int
romanc135c6d2023-10-25 13:32:30 +02002519nc_server_config_delete_substring(const char *haystack, const char *needle, const char delim)
2520{
2521 size_t needle_len = strlen(needle);
2522 char *substr;
2523 int substr_found = 0, ret = 0;
2524
2525 while ((substr = strstr(haystack, needle))) {
2526 /* iterate over all the substrings */
2527 if (((substr == haystack) && (*(substr + needle_len) == delim)) ||
2528 ((substr != haystack) && (*(substr - 1) == delim) && (*(substr + needle_len) == delim))) {
2529 /* either the first element of the string or somewhere in the middle */
2530 memmove(substr, substr + needle_len + 1, strlen(substr + needle_len + 1));
2531 substr_found = 1;
2532 break;
2533 } else if ((*(substr - 1) == delim) && (*(substr + needle_len) == '\0')) {
2534 /* the last element of the string */
2535 *(substr - 1) = '\0';
2536 substr_found = 1;
2537 break;
2538 }
2539 haystack = substr + 1;
2540 }
2541 if (!substr_found) {
2542 ret = 1;
2543 }
2544
2545 return ret;
2546}
2547
2548static int
romana6bf6ab2023-05-26 13:26:02 +02002549nc_server_config_transport_params(const char *algorithm, char **alg_store, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002550{
romanc135c6d2023-10-25 13:32:30 +02002551 int ret = 0;
2552 char *alg = NULL;
romana6bf6ab2023-05-26 13:26:02 +02002553
2554 if (!strncmp(algorithm, "openssh-", 8)) {
2555 /* if the name starts with openssh, convert it to it's original libssh accepted form */
roman3a95bb22023-10-26 11:07:17 +02002556 ret = asprintf(&alg, "%s@openssh.com", algorithm + 8);
2557 NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; alg = NULL, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002558 } else if (!strncmp(algorithm, "libssh-", 7)) {
2559 /* if the name starts with libssh, convert it to it's original libssh accepted form */
roman3a95bb22023-10-26 11:07:17 +02002560 ret = asprintf(&alg, "%s@libssh.org", algorithm + 7);
2561 NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; alg = NULL, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002562 } else {
2563 alg = strdup(algorithm);
roman3a95bb22023-10-26 11:07:17 +02002564 NC_CHECK_ERRMEM_GOTO(!alg, ret = 1, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002565 }
2566
romanc1d2b092023-02-02 08:58:27 +01002567 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2568 if (!*alg_store) {
2569 /* first call */
2570 *alg_store = strdup(alg);
roman3a95bb22023-10-26 11:07:17 +02002571 NC_CHECK_ERRMEM_GOTO(!*alg_store, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01002572 } else {
2573 /* +1 because of ',' between algorithms */
roman3a95bb22023-10-26 11:07:17 +02002574 *alg_store = nc_realloc(*alg_store, strlen(*alg_store) + strlen(alg) + 1 + 1);
2575 NC_CHECK_ERRMEM_GOTO(!*alg_store, ret = 1, cleanup);
roman08f67f42023-06-08 13:51:54 +02002576 strcat(*alg_store, ",");
2577 strcat(*alg_store, alg);
romanc1d2b092023-02-02 08:58:27 +01002578 }
2579 } else {
2580 /* delete */
romanc135c6d2023-10-25 13:32:30 +02002581 ret = nc_server_config_delete_substring(*alg_store, alg, ',');
2582 if (ret) {
romanc1d2b092023-02-02 08:58:27 +01002583 ERR(NULL, "Unable to delete an algorithm (%s), which was not previously added.", alg);
romanc135c6d2023-10-25 13:32:30 +02002584 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002585 }
2586 }
2587
2588cleanup:
romana6bf6ab2023-05-26 13:26:02 +02002589 free(alg);
romanc1d2b092023-02-02 08:58:27 +01002590 return ret;
2591}
2592
2593/* leaf-list */
2594static int
romane028ef92023-02-24 16:33:08 +01002595nc_server_config_host_key_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002596{
roman5cbb6532023-06-22 12:53:17 +02002597 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002598 const char *alg;
2599 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002600 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002601 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002602
roman5cbb6532023-06-22 12:53:17 +02002603 assert(!strcmp(LYD_NAME(node), "host-key-alg"));
romanc1d2b092023-02-02 08:58:27 +01002604
romanba93eac2023-07-18 14:36:48 +02002605 /* LOCK */
2606 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002607 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002608 return 1;
2609 }
2610
roman8341e8b2023-11-23 16:12:42 +01002611 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002612 ret = 1;
2613 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002614 }
2615
roman5cbb6532023-06-22 12:53:17 +02002616 /* get the algorithm name and compare it with algs supported by libssh */
2617 alg = ((struct lyd_node_term *)node)->value.ident->name;
romanc1d2b092023-02-02 08:58:27 +01002618 i = 0;
2619 while (supported_hostkey_algs[i]) {
2620 if (!strcmp(supported_hostkey_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002621 if (nc_server_config_transport_params(alg, &opts->hostkey_algs, op)) {
2622 ret = 1;
2623 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002624 }
2625 break;
2626 }
2627 i++;
2628 }
2629 if (!supported_hostkey_algs[i]) {
2630 /* algorithm not supported */
2631 ERR(NULL, "Public key algorithm (%s) not supported by libssh.", alg);
2632 ret = 1;
2633 }
2634
2635cleanup:
romanba93eac2023-07-18 14:36:48 +02002636 if (is_ch(node)) {
2637 /* UNLOCK */
2638 nc_ch_client_unlock(ch_client);
2639 }
romanc1d2b092023-02-02 08:58:27 +01002640 return ret;
2641}
2642
2643/* leaf-list */
2644static int
romane028ef92023-02-24 16:33:08 +01002645nc_server_config_kex_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002646{
roman5cbb6532023-06-22 12:53:17 +02002647 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002648 const char *alg;
2649 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002650 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002651 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002652
roman5cbb6532023-06-22 12:53:17 +02002653 assert(!strcmp(LYD_NAME(node), "key-exchange-alg"));
romanc1d2b092023-02-02 08:58:27 +01002654
romanba93eac2023-07-18 14:36:48 +02002655 /* LOCK */
2656 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002657 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002658 return 1;
2659 }
2660
roman8341e8b2023-11-23 16:12:42 +01002661 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002662 ret = 1;
2663 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002664 }
2665
roman5cbb6532023-06-22 12:53:17 +02002666 /* get the algorithm name and compare it with algs supported by libssh */
2667 alg = ((struct lyd_node_term *)node)->value.ident->name;
romanc1d2b092023-02-02 08:58:27 +01002668 i = 0;
2669 while (supported_kex_algs[i]) {
2670 if (!strcmp(supported_kex_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002671 if (nc_server_config_transport_params(alg, &opts->kex_algs, op)) {
2672 ret = 1;
2673 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002674 }
2675 break;
2676 }
2677 i++;
2678 }
2679 if (!supported_kex_algs[i]) {
2680 /* algorithm not supported */
2681 ERR(NULL, "Key exchange algorithm (%s) not supported by libssh.", alg);
2682 ret = 1;
2683 }
2684
2685cleanup:
romanba93eac2023-07-18 14:36:48 +02002686 if (is_ch(node)) {
2687 /* UNLOCK */
2688 nc_ch_client_unlock(ch_client);
2689 }
romanc1d2b092023-02-02 08:58:27 +01002690 return ret;
2691}
2692
2693/* leaf-list */
2694static int
romane028ef92023-02-24 16:33:08 +01002695nc_server_config_encryption_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002696{
roman5cbb6532023-06-22 12:53:17 +02002697 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002698 const char *alg;
2699 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002700 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002701 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002702
roman5cbb6532023-06-22 12:53:17 +02002703 assert(!strcmp(LYD_NAME(node), "encryption-alg"));
romanc1d2b092023-02-02 08:58:27 +01002704
romanba93eac2023-07-18 14:36:48 +02002705 /* LOCK */
2706 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002707 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002708 return 1;
2709 }
2710
roman8341e8b2023-11-23 16:12:42 +01002711 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002712 ret = 1;
2713 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002714 }
2715
roman5cbb6532023-06-22 12:53:17 +02002716 /* get the algorithm name and compare it with algs supported by libssh */
2717 alg = ((struct lyd_node_term *)node)->value.ident->name;
romanc1d2b092023-02-02 08:58:27 +01002718 i = 0;
2719 while (supported_encryption_algs[i]) {
2720 if (!strcmp(supported_encryption_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002721 if (nc_server_config_transport_params(alg, &opts->encryption_algs, op)) {
2722 ret = 1;
2723 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002724 }
2725 break;
2726 }
2727 i++;
2728 }
2729 if (!supported_encryption_algs[i]) {
2730 /* algorithm not supported */
2731 ERR(NULL, "Encryption algorithm (%s) not supported by libssh.", alg);
2732 ret = 1;
2733 }
2734
2735cleanup:
romanba93eac2023-07-18 14:36:48 +02002736 if (is_ch(node)) {
2737 /* UNLOCK */
2738 nc_ch_client_unlock(ch_client);
2739 }
romanc1d2b092023-02-02 08:58:27 +01002740 return ret;
2741}
2742
2743/* leaf-list */
2744static int
romane028ef92023-02-24 16:33:08 +01002745nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002746{
roman5cbb6532023-06-22 12:53:17 +02002747 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002748 const char *alg;
2749 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002750 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002751 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002752
roman5cbb6532023-06-22 12:53:17 +02002753 assert(!strcmp(LYD_NAME(node), "mac-alg"));
romanc1d2b092023-02-02 08:58:27 +01002754
romanba93eac2023-07-18 14:36:48 +02002755 /* LOCK */
2756 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002757 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002758 return 1;
2759 }
2760
roman8341e8b2023-11-23 16:12:42 +01002761 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002762 ret = 1;
2763 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002764 }
2765
roman5cbb6532023-06-22 12:53:17 +02002766 /* get the algorithm name and compare it with algs supported by libssh */
2767 alg = ((struct lyd_node_term *)node)->value.ident->name;
romanc1d2b092023-02-02 08:58:27 +01002768 i = 0;
2769 while (supported_mac_algs[i]) {
2770 if (!strcmp(supported_mac_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002771 if (nc_server_config_transport_params(alg, &opts->mac_algs, op)) {
2772 ret = 1;
2773 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002774 }
2775 break;
2776 }
2777 i++;
2778 }
2779 if (!supported_mac_algs[i]) {
2780 /* algorithm not supported */
2781 ERR(NULL, "MAC algorithm (%s) not supported by libssh.", alg);
2782 ret = 1;
2783 }
2784
2785cleanup:
romanba93eac2023-07-18 14:36:48 +02002786 if (is_ch(node)) {
2787 /* UNLOCK */
2788 nc_ch_client_unlock(ch_client);
2789 }
romanc1d2b092023-02-02 08:58:27 +01002790 return ret;
2791}
2792
roman2eab4742023-06-06 10:00:26 +02002793#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02002794
romanc1d2b092023-02-02 08:58:27 +01002795static int
roman874fed12023-05-25 10:20:01 +02002796nc_server_config_create_unix_socket(struct nc_endpt *endpt)
roman83683fb2023-02-24 09:15:23 +01002797{
2798 endpt->ti = NC_TI_UNIX;
2799 endpt->opts.unixsock = calloc(1, sizeof *endpt->opts.unixsock);
roman3a95bb22023-10-26 11:07:17 +02002800 NC_CHECK_ERRMEM_RET(!endpt->opts.unixsock, 1);
roman83683fb2023-02-24 09:15:23 +01002801
2802 /* set default values */
2803 endpt->opts.unixsock->mode = -1;
2804 endpt->opts.unixsock->uid = -1;
2805 endpt->opts.unixsock->gid = -1;
2806
2807 return 0;
2808}
2809
2810static int
romane028ef92023-02-24 16:33:08 +01002811nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op)
roman83683fb2023-02-24 09:15:23 +01002812{
2813 int ret = 0;
roman84fe3252023-10-25 11:28:32 +02002814 uint32_t log_options = 0;
roman83683fb2023-02-24 09:15:23 +01002815 struct nc_endpt *endpt;
2816 struct nc_bind *bind;
2817 struct nc_server_unix_opts *opts;
2818 struct lyd_node *data = NULL;
2819
2820 assert(!strcmp(LYD_NAME(node), "unix-socket"));
2821
romanf02273a2023-05-25 09:44:11 +02002822 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
roman83683fb2023-02-24 09:15:23 +01002823 ret = 1;
2824 goto cleanup;
2825 }
2826
2827 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +02002828 if (nc_server_config_create_unix_socket(endpt)) {
roman83683fb2023-02-24 09:15:23 +01002829 ret = 1;
2830 goto cleanup;
2831 }
2832
2833 opts = endpt->opts.unixsock;
2834
2835 lyd_find_path(node, "path", 0, &data);
2836 assert(data);
2837
2838 opts->address = strdup(lyd_get_value(data));
2839 bind->address = strdup(lyd_get_value(data));
roman3a95bb22023-10-26 11:07:17 +02002840 NC_CHECK_ERRMEM_GOTO(!opts->address || !bind->address, ret = 1, cleanup);
roman83683fb2023-02-24 09:15:23 +01002841
2842 /* silently search for non-mandatory parameters */
roman84fe3252023-10-25 11:28:32 +02002843 ly_temp_log_options(&log_options);
roman83683fb2023-02-24 09:15:23 +01002844 ret = lyd_find_path(node, "mode", 0, &data);
2845 if (!ret) {
2846 opts->mode = strtol(lyd_get_value(data), NULL, 8);
2847 }
2848
2849 ret = lyd_find_path(node, "uid", 0, &data);
2850 if (!ret) {
2851 opts->uid = strtol(lyd_get_value(data), NULL, 10);
2852 }
2853
2854 ret = lyd_find_path(node, "gid", 0, &data);
2855 if (!ret) {
2856 opts->gid = strtol(lyd_get_value(data), NULL, 10);
2857 }
2858
2859 /* reset the logging options */
roman84fe3252023-10-25 11:28:32 +02002860 ly_temp_log_options(NULL);
roman83683fb2023-02-24 09:15:23 +01002861
2862 ret = nc_server_config_set_address_port(endpt, bind, NULL, 0);
2863 if (ret) {
2864 goto cleanup;
2865 }
2866 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02002867 nc_server_config_del_unix_socket_opts(bind, endpt->opts.unixsock);
roman83683fb2023-02-24 09:15:23 +01002868 }
2869
2870cleanup:
2871 return ret;
2872}
2873
roman2eab4742023-06-06 10:00:26 +02002874#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02002875
roman78df0fa2023-11-02 10:33:57 +01002876static int
2877nc_server_config_check_endpt_reference_cycle(struct nc_endpt *original, struct nc_endpt *next)
2878{
2879 if (!next->referenced_endpt_name) {
2880 /* no further reference -> no cycle */
2881 return 0;
2882 }
2883
2884 if (!strcmp(original->name, next->referenced_endpt_name)) {
2885 /* found cycle */
2886 return 1;
2887 } else {
2888 if (nc_server_get_referenced_endpt(next->referenced_endpt_name, &next)) {
2889 /* referenced endpoint does not exist */
2890 return 1;
2891 }
2892
2893 /* continue further */
2894 return nc_server_config_check_endpt_reference_cycle(original, next);
2895 }
2896}
2897
roman0bbc19c2023-05-26 09:59:09 +02002898/**
roman78df0fa2023-11-02 10:33:57 +01002899 * @brief Set all endpoint references.
roman0bbc19c2023-05-26 09:59:09 +02002900 *
2901 * @return 0 on success, 1 on error.
2902 */
2903static int
roman78df0fa2023-11-02 10:33:57 +01002904nc_server_config_check_endpt_references(void)
roman0bbc19c2023-05-26 09:59:09 +02002905{
2906 uint16_t i, j;
roman78df0fa2023-11-02 10:33:57 +01002907 struct nc_endpt *referenced_endpt = NULL;
roman0bbc19c2023-05-26 09:59:09 +02002908
roman78df0fa2023-11-02 10:33:57 +01002909 /* first do listen endpoints */
roman0bbc19c2023-05-26 09:59:09 +02002910 for (i = 0; i < server_opts.endpt_count; i++) {
roman6430c152023-10-12 11:28:47 +02002911 /* go through all the endpoints */
roman0bbc19c2023-05-26 09:59:09 +02002912 if (server_opts.endpts[i].referenced_endpt_name) {
roman78df0fa2023-11-02 10:33:57 +01002913 /* get referenced endpt */
2914 if (nc_server_get_referenced_endpt(server_opts.endpts[i].referenced_endpt_name, &referenced_endpt)) {
2915 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" does not exist.",
roman0bbc19c2023-05-26 09:59:09 +02002916 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2917 return 1;
2918 }
roman78df0fa2023-11-02 10:33:57 +01002919
2920 /* check if the endpoint references itself */
2921 if (&server_opts.endpts[i] == referenced_endpt) {
2922 ERR(NULL, "Endpoint \"%s\" references itself.", server_opts.endpts[i].name);
2923 return 1;
2924 }
2925
2926 /* check transport */
2927 if ((server_opts.endpts[i].ti != referenced_endpt->ti)) {
2928 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" has different transport type.",
2929 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2930 return 1;
2931 } else if ((referenced_endpt->ti != NC_TI_LIBSSH) && (referenced_endpt->ti != NC_TI_OPENSSL)) {
2932 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" has unsupported transport type.",
2933 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2934 return 1;
2935 }
2936
2937 /* check cyclic reference */
2938 if (nc_server_config_check_endpt_reference_cycle(&server_opts.endpts[i], referenced_endpt)) {
2939 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" creates a cycle.",
2940 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2941 return 1;
2942 }
2943
2944 /* all went well, assign the name to the opts, so we can access it for auth */
2945 if (server_opts.endpts[i].ti == NC_TI_LIBSSH) {
2946 server_opts.endpts[i].opts.ssh->referenced_endpt_name = referenced_endpt->name;
2947 } else {
2948 server_opts.endpts[i].opts.tls->referenced_endpt_name = referenced_endpt->name;
2949 }
roman0bbc19c2023-05-26 09:59:09 +02002950 }
2951 }
2952
roman78df0fa2023-11-02 10:33:57 +01002953 /* now check all the call home endpoints */
2954 /* LOCK */
2955 pthread_rwlock_rdlock(&server_opts.ch_client_lock);
2956 for (i = 0; i < server_opts.ch_client_count; i++) {
2957 /* LOCK */
2958 pthread_mutex_lock(&server_opts.ch_clients[i].lock);
2959 for (j = 0; j < server_opts.ch_clients[i].ch_endpt_count; j++) {
2960 if (server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name) {
2961 /* get referenced endpt */
2962 if (nc_server_get_referenced_endpt(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, &referenced_endpt)) {
2963 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" does not exist.",
2964 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
2965 goto ch_fail;
2966 }
2967
2968 /* check transport */
2969 if (server_opts.ch_clients[i].ch_endpts[j].ti != referenced_endpt->ti) {
2970 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" has different transport type.",
2971 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
2972 goto ch_fail;
2973 } else if ((referenced_endpt->ti != NC_TI_LIBSSH) && (referenced_endpt->ti != NC_TI_OPENSSL)) {
2974 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" has unsupported transport type.",
2975 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
2976 goto ch_fail;
2977 }
2978
2979 /* check cyclic reference */
2980 if (nc_server_config_check_endpt_reference_cycle(referenced_endpt, referenced_endpt)) {
2981 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" creates a cycle.",
2982 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
2983 goto ch_fail;
2984 }
2985
2986 /* all went well, assign the name to the opts, so we can access it for auth */
2987 if (server_opts.ch_clients[i].ch_endpts[j].ti == NC_TI_LIBSSH) {
2988 server_opts.ch_clients[i].ch_endpts[j].opts.ssh->referenced_endpt_name = referenced_endpt->name;
2989 } else {
2990 server_opts.ch_clients[i].ch_endpts[j].opts.tls->referenced_endpt_name = referenced_endpt->name;
2991 }
2992 }
2993 }
2994 /* UNLOCK */
2995 pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
2996 }
2997
2998 /* UNLOCK */
2999 pthread_rwlock_unlock(&server_opts.ch_client_lock);
roman0bbc19c2023-05-26 09:59:09 +02003000 return 0;
roman78df0fa2023-11-02 10:33:57 +01003001
3002ch_fail:
3003 /* UNLOCK */
3004 pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
3005 /* UNLOCK */
3006 pthread_rwlock_unlock(&server_opts.ch_client_lock);
roman96c27f92023-11-02 11:09:46 +01003007 return 1;
roman0bbc19c2023-05-26 09:59:09 +02003008}
3009
3010static int
roman78df0fa2023-11-02 10:33:57 +01003011nc_server_config_endpoint_reference(const struct lyd_node *node, NC_OPERATION op)
roman0bbc19c2023-05-26 09:59:09 +02003012{
3013 int ret = 0;
roman78df0fa2023-11-02 10:33:57 +01003014 struct nc_endpt *endpt = NULL;
roman8341e8b2023-11-23 16:12:42 +01003015 struct nc_ch_client *ch_client = NULL;
roman78df0fa2023-11-02 10:33:57 +01003016 struct nc_ch_endpt *ch_endpt = NULL;
3017 struct nc_server_ssh_opts *ssh = NULL;
3018 struct nc_server_tls_opts *tls = NULL;
roman0bbc19c2023-05-26 09:59:09 +02003019
roman78df0fa2023-11-02 10:33:57 +01003020 assert(!strcmp(LYD_NAME(node), "endpoint-reference"));
roman0bbc19c2023-05-26 09:59:09 +02003021
roman78df0fa2023-11-02 10:33:57 +01003022 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
3023 /* to avoid unlock on fail */
3024 return 1;
3025 }
3026
3027 /* get endpt */
3028 if (is_listen(node)) {
3029 ret = nc_server_config_get_endpt(node, &endpt, NULL);
3030 } else {
roman8341e8b2023-11-23 16:12:42 +01003031 ret = nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt);
roman78df0fa2023-11-02 10:33:57 +01003032 }
roman0bbc19c2023-05-26 09:59:09 +02003033 if (ret) {
3034 goto cleanup;
3035 }
3036
3037 if (op == NC_OP_DELETE) {
roman78df0fa2023-11-02 10:33:57 +01003038 if (endpt) {
romanb7bfa652023-11-09 12:36:35 +01003039 /* listen */
roman78df0fa2023-11-02 10:33:57 +01003040 free(endpt->referenced_endpt_name);
3041 endpt->referenced_endpt_name = NULL;
roman2e797ef2023-06-19 10:47:49 +02003042 } else {
romanb7bfa652023-11-09 12:36:35 +01003043 /* call home */
roman78df0fa2023-11-02 10:33:57 +01003044 free(ch_endpt->referenced_endpt_name);
3045 ch_endpt->referenced_endpt_name = NULL;
roman2e797ef2023-06-19 10:47:49 +02003046 }
roman78df0fa2023-11-02 10:33:57 +01003047 if (is_ssh(node)) {
roman8341e8b2023-11-23 16:12:42 +01003048 if (nc_server_config_get_ssh_opts(node, ch_client, &ssh)) {
roman78df0fa2023-11-02 10:33:57 +01003049 ret = 1;
3050 goto cleanup;
3051 }
roman96c27f92023-11-02 11:09:46 +01003052
roman78df0fa2023-11-02 10:33:57 +01003053 ssh->referenced_endpt_name = NULL;
3054 } else {
roman8341e8b2023-11-23 16:12:42 +01003055 if (nc_server_config_get_tls_opts(node, ch_client, &tls)) {
roman78df0fa2023-11-02 10:33:57 +01003056 ret = 1;
3057 goto cleanup;
3058 }
roman0bbc19c2023-05-26 09:59:09 +02003059
roman78df0fa2023-11-02 10:33:57 +01003060 tls->referenced_endpt_name = NULL;
roman0bbc19c2023-05-26 09:59:09 +02003061 }
roman0bbc19c2023-05-26 09:59:09 +02003062
roman0bbc19c2023-05-26 09:59:09 +02003063 goto cleanup;
roman2e797ef2023-06-19 10:47:49 +02003064 } else {
roman78df0fa2023-11-02 10:33:57 +01003065 /* just set the name, check it once configuring of all nodes is done */
3066 if (endpt) {
3067 free(endpt->referenced_endpt_name);
3068 endpt->referenced_endpt_name = strdup(lyd_get_value(node));
3069 NC_CHECK_ERRMEM_GOTO(!endpt->referenced_endpt_name, ret = 1, cleanup);
3070 } else {
3071 free(ch_endpt->referenced_endpt_name);
3072 ch_endpt->referenced_endpt_name = strdup(lyd_get_value(node));
3073 NC_CHECK_ERRMEM_GOTO(!ch_endpt->referenced_endpt_name, ret = 1, cleanup);
3074 }
3075
3076 goto cleanup;
roman2e797ef2023-06-19 10:47:49 +02003077 }
roman0bbc19c2023-05-26 09:59:09 +02003078
3079cleanup:
roman78df0fa2023-11-02 10:33:57 +01003080 if (is_ch(node)) {
3081 /* UNLOCK */
3082 nc_ch_client_unlock(ch_client);
3083 }
3084
roman0bbc19c2023-05-26 09:59:09 +02003085 return ret;
3086}
3087
roman3f9b65c2023-06-05 14:26:58 +02003088static int
roman3f9b65c2023-06-05 14:26:58 +02003089nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op)
3090{
3091 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02003092 struct nc_certificate *cert;
romanb6f44032023-06-30 15:07:56 +02003093 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01003094 struct nc_ch_client *ch_client = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003095
3096 assert(!strcmp(LYD_NAME(node), "cert-data"));
3097
romanba93eac2023-07-18 14:36:48 +02003098 /* LOCK */
3099 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003100 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003101 return 1;
3102 }
3103
romanb6f44032023-06-30 15:07:56 +02003104 if (equal_parent_name(node, 3, "server-identity")) {
roman8341e8b2023-11-23 16:12:42 +01003105 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
romanb6f44032023-06-30 15:07:56 +02003106 ret = 1;
3107 goto cleanup;
3108 }
roman3f9b65c2023-06-05 14:26:58 +02003109
roman3f9b65c2023-06-05 14:26:58 +02003110 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003111 free(opts->cert_data);
3112 opts->cert_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003113 NC_CHECK_ERRMEM_GOTO(!opts->cert_data, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003114 }
roman6430c152023-10-12 11:28:47 +02003115 } else if (equal_parent_name(node, 3, "ca-certs") || equal_parent_name(node, 3, "ee-certs")) {
roman8341e8b2023-11-23 16:12:42 +01003116 if (nc_server_config_get_cert(node, ch_client, &cert)) {
roman3f9b65c2023-06-05 14:26:58 +02003117 ret = 1;
3118 goto cleanup;
3119 }
3120
3121 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003122 free(cert->data);
3123 cert->data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003124 NC_CHECK_ERRMEM_GOTO(!cert->data, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003125 } else {
roman6430c152023-10-12 11:28:47 +02003126 free(cert->data);
3127 cert->data = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003128 }
3129 }
3130
3131cleanup:
romanba93eac2023-07-18 14:36:48 +02003132 if (is_ch(node)) {
3133 /* UNLOCK */
3134 nc_ch_client_unlock(ch_client);
3135 }
roman3f9b65c2023-06-05 14:26:58 +02003136 return ret;
3137}
3138
3139static int
roman3f9b65c2023-06-05 14:26:58 +02003140nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op)
3141{
3142 int ret = 0;
roman78df0fa2023-11-02 10:33:57 +01003143 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01003144 struct nc_ch_client *ch_client = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003145
3146 assert(!strcmp(LYD_NAME(node), "asymmetric-key"));
3147
romanba93eac2023-07-18 14:36:48 +02003148 /* LOCK */
3149 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003150 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003151 return 1;
3152 }
3153
roman8341e8b2023-11-23 16:12:42 +01003154 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02003155 ret = 1;
3156 goto cleanup;
3157 }
3158
3159 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
3160 /* set to keystore */
roman78df0fa2023-11-02 10:33:57 +01003161 opts->store = NC_STORE_KEYSTORE;
roman3f9b65c2023-06-05 14:26:58 +02003162
roman78df0fa2023-11-02 10:33:57 +01003163 free(opts->key_ref);
3164 opts->key_ref = strdup(lyd_get_value(node));
3165 NC_CHECK_ERRMEM_GOTO(!opts->key_ref, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003166 } else {
roman78df0fa2023-11-02 10:33:57 +01003167 free(opts->key_ref);
3168 opts->key_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003169 }
3170
3171cleanup:
romanba93eac2023-07-18 14:36:48 +02003172 if (is_ch(node)) {
3173 /* UNLOCK */
3174 nc_ch_client_unlock(ch_client);
3175 }
roman3f9b65c2023-06-05 14:26:58 +02003176 return ret;
3177}
3178
3179static int
roman3f9b65c2023-06-05 14:26:58 +02003180nc_server_config_create_ca_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
3181{
3182 assert(!strcmp(LYD_NAME(node), "certificate"));
3183
3184 node = lyd_child(node);
3185 assert(!strcmp(LYD_NAME(node), "name"));
3186
3187 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ca_certs.certs, sizeof *opts->ca_certs.certs, &opts->ca_certs.cert_count);
3188}
3189
3190static int
3191nc_server_config_create_ee_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
3192{
3193 assert(!strcmp(LYD_NAME(node), "certificate"));
3194
3195 node = lyd_child(node);
3196 assert(!strcmp(LYD_NAME(node), "name"));
3197
3198 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ee_certs.certs, sizeof *opts->ee_certs.certs, &opts->ee_certs.cert_count);
3199}
3200
3201static int
3202nc_server_config_certificate(const struct lyd_node *node, NC_OPERATION op)
3203{
3204 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003205 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01003206 struct nc_ch_client *ch_client = NULL;
roman6430c152023-10-12 11:28:47 +02003207 struct nc_certificate *cert;
roman3f9b65c2023-06-05 14:26:58 +02003208
3209 assert(!strcmp(LYD_NAME(node), "certificate"));
3210
romanba93eac2023-07-18 14:36:48 +02003211 /* LOCK */
3212 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003213 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003214 return 1;
3215 }
3216
roman8341e8b2023-11-23 16:12:42 +01003217 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02003218 ret = 1;
3219 goto cleanup;
3220 }
3221
romanb6f44032023-06-30 15:07:56 +02003222 if (equal_parent_name(node, 1, "keystore-reference")) {
3223 /* TLS server-identity */
roman3f9b65c2023-06-05 14:26:58 +02003224 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
3225 /* set to keystore */
romanb6f44032023-06-30 15:07:56 +02003226 opts->store = NC_STORE_KEYSTORE;
roman3f9b65c2023-06-05 14:26:58 +02003227
roman6430c152023-10-12 11:28:47 +02003228 free(opts->cert_ref);
3229 opts->cert_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003230 NC_CHECK_ERRMEM_GOTO(!opts->cert_ref, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003231 } else {
roman6430c152023-10-12 11:28:47 +02003232 free(opts->cert_ref);
romanb6f44032023-06-30 15:07:56 +02003233 opts->cert_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003234 }
romanb6f44032023-06-30 15:07:56 +02003235 } else if (equal_parent_name(node, 2, "ca-certs")) {
3236 /* TLS client auth certificate authority */
roman3f9b65c2023-06-05 14:26:58 +02003237 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003238 ret = nc_server_config_create_ca_certs_certificate(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02003239 if (ret) {
3240 goto cleanup;
3241 }
3242 } else {
roman8341e8b2023-11-23 16:12:42 +01003243 if (nc_server_config_get_cert(node, ch_client, &cert)) {
roman6430c152023-10-12 11:28:47 +02003244 ret = 1;
3245 goto cleanup;
3246 }
3247 nc_server_config_del_cert(&opts->ca_certs, cert);
roman3f9b65c2023-06-05 14:26:58 +02003248 }
romanb6f44032023-06-30 15:07:56 +02003249 } else if (equal_parent_name(node, 2, "ee-certs")) {
3250 /* TLS client auth end entity */
roman3f9b65c2023-06-05 14:26:58 +02003251 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003252 ret = nc_server_config_create_ee_certs_certificate(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02003253 if (ret) {
3254 goto cleanup;
3255 }
3256 } else {
roman8341e8b2023-11-23 16:12:42 +01003257 if (nc_server_config_get_cert(node, ch_client, &cert)) {
roman6430c152023-10-12 11:28:47 +02003258 ret = 1;
3259 goto cleanup;
3260 }
3261 nc_server_config_del_cert(&opts->ee_certs, cert);
roman3f9b65c2023-06-05 14:26:58 +02003262 }
3263 }
3264
3265cleanup:
romanba93eac2023-07-18 14:36:48 +02003266 if (is_ch(node)) {
3267 /* UNLOCK */
3268 nc_ch_client_unlock(ch_client);
3269 }
roman3f9b65c2023-06-05 14:26:58 +02003270 return ret;
3271}
3272
3273static int
3274nc_server_config_create_cert_to_name(const struct lyd_node *node, struct nc_server_tls_opts *opts)
3275{
3276 int ret = 0;
3277 struct lyd_node *n;
3278 struct nc_ctn *new, *iter;
3279 const char *map_type, *name;
3280 uint32_t id;
3281 NC_TLS_CTN_MAPTYPE m_type;
3282
3283 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
3284
roman3f9b65c2023-06-05 14:26:58 +02003285 /* get all the data */
3286 /* find the list's key */
3287 lyd_find_path(node, "id", 0, &n);
3288 assert(n);
roman9cdb7b52023-10-25 13:59:55 +02003289 id = ((struct lyd_node_term *)n)->value.uint32;
roman3f9b65c2023-06-05 14:26:58 +02003290
3291 /* find the ctn's name */
3292 lyd_find_path(node, "name", 0, &n);
3293 assert(n);
3294 name = lyd_get_value(n);
3295
3296 /* find the ctn's map-type */
3297 lyd_find_path(node, "map-type", 0, &n);
3298 assert(n);
3299 map_type = ((struct lyd_node_term *)n)->value.ident->name;
3300 if (!strcmp(map_type, "specified")) {
3301 m_type = NC_TLS_CTN_SPECIFIED;
3302 } else if (!strcmp(map_type, "san-rfc822-name")) {
3303 m_type = NC_TLS_CTN_SAN_RFC822_NAME;
3304 } else if (!strcmp(map_type, "san-dns-name")) {
3305 m_type = NC_TLS_CTN_SAN_DNS_NAME;
3306 } else if (!strcmp(map_type, "san-ip-address")) {
3307 m_type = NC_TLS_CTN_SAN_IP_ADDRESS;
3308 } else if (!strcmp(map_type, "san-any")) {
3309 m_type = NC_TLS_CTN_SAN_ANY;
3310 } else if (!strcmp(map_type, "common-name")) {
3311 m_type = NC_TLS_CTN_COMMON_NAME;
3312 } else {
3313 ERR(NULL, "Map-type identity \"%s\" not supported.", map_type);
3314 ret = 1;
3315 goto cleanup;
3316 }
3317
roman6430c152023-10-12 11:28:47 +02003318 /* create new ctn */
3319 new = calloc(1, sizeof *new);
roman3a95bb22023-10-26 11:07:17 +02003320 NC_CHECK_ERRMEM_GOTO(!new, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02003321
roman3f9b65c2023-06-05 14:26:58 +02003322 /* find the right place for insertion */
3323 if (!opts->ctn) {
3324 /* inserting the first one */
3325 opts->ctn = new;
Roytak421eb0c2023-08-01 22:18:27 +02003326 } else if (opts->ctn->id > id) {
roman3f9b65c2023-06-05 14:26:58 +02003327 /* insert at the beginning */
3328 new->next = opts->ctn;
3329 opts->ctn = new;
3330 } else {
3331 /* have to find the right place */
Roytak421eb0c2023-08-01 22:18:27 +02003332 for (iter = opts->ctn; iter->next && iter->next->id <= id; iter = iter->next) {}
3333 if (iter->id == id) {
roman3f9b65c2023-06-05 14:26:58 +02003334 /* collision */
romanb7bfa652023-11-09 12:36:35 +01003335 free(new);
roman3f9b65c2023-06-05 14:26:58 +02003336 new = iter;
3337 } else {
3338 new->next = iter->next;
3339 iter->next = new;
3340 }
3341 }
3342
3343 /* insert the right data */
3344 new->id = id;
roman6430c152023-10-12 11:28:47 +02003345 free(new->name);
roman3f9b65c2023-06-05 14:26:58 +02003346 new->name = strdup(name);
roman3a95bb22023-10-26 11:07:17 +02003347 NC_CHECK_ERRMEM_GOTO(!new->name, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003348 new->map_type = m_type;
3349
3350cleanup:
3351 return ret;
3352}
3353
3354static int
3355nc_server_config_cert_to_name(const struct lyd_node *node, NC_OPERATION op)
3356{
3357 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003358 struct nc_server_tls_opts *opts;
roman3f9b65c2023-06-05 14:26:58 +02003359 struct nc_ctn *ctn;
roman8341e8b2023-11-23 16:12:42 +01003360 struct nc_ch_client *ch_client = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003361
3362 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
3363
romanba93eac2023-07-18 14:36:48 +02003364 /* LOCK */
3365 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003366 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003367 return 1;
3368 }
3369
roman8341e8b2023-11-23 16:12:42 +01003370 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02003371 ret = 1;
3372 goto cleanup;
3373 }
3374
3375 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003376 ret = nc_server_config_create_cert_to_name(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02003377 if (ret) {
3378 goto cleanup;
3379 }
3380 } else {
3381 /* find the given ctn entry */
roman8341e8b2023-11-23 16:12:42 +01003382 if (nc_server_config_get_ctn(node, ch_client, &ctn)) {
roman3f9b65c2023-06-05 14:26:58 +02003383 ret = 1;
3384 goto cleanup;
3385 }
romanb6f44032023-06-30 15:07:56 +02003386 nc_server_config_del_ctn(opts, ctn);
roman3f9b65c2023-06-05 14:26:58 +02003387 }
3388
3389cleanup:
romanba93eac2023-07-18 14:36:48 +02003390 if (is_ch(node)) {
3391 /* UNLOCK */
3392 nc_ch_client_unlock(ch_client);
3393 }
roman3f9b65c2023-06-05 14:26:58 +02003394 return ret;
3395}
3396
3397static int
roman3f9b65c2023-06-05 14:26:58 +02003398nc_server_config_fingerprint(const struct lyd_node *node, NC_OPERATION op)
3399{
3400 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02003401 struct nc_ctn *ctn;
roman8341e8b2023-11-23 16:12:42 +01003402 struct nc_ch_client *ch_client = NULL;
romanba93eac2023-07-18 14:36:48 +02003403
3404 assert(!strcmp(LYD_NAME(node), "fingerprint"));
3405
3406 /* LOCK */
3407 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003408 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003409 return 1;
3410 }
roman3f9b65c2023-06-05 14:26:58 +02003411
roman8341e8b2023-11-23 16:12:42 +01003412 if (nc_server_config_get_ctn(node, ch_client, &ctn)) {
roman3f9b65c2023-06-05 14:26:58 +02003413 ret = 1;
3414 goto cleanup;
3415 }
3416
3417 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003418 free(ctn->fingerprint);
3419 ctn->fingerprint = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003420 NC_CHECK_ERRMEM_GOTO(!ctn->fingerprint, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003421 } else {
roman6430c152023-10-12 11:28:47 +02003422 free(ctn->fingerprint);
3423 ctn->fingerprint = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003424 }
3425
3426cleanup:
romanba93eac2023-07-18 14:36:48 +02003427 if (is_ch(node)) {
3428 /* UNLOCK */
3429 nc_ch_client_unlock(ch_client);
3430 }
roman3f9b65c2023-06-05 14:26:58 +02003431 return ret;
3432}
3433
roman12644fe2023-06-08 11:06:42 +02003434static int
3435nc_server_config_tls_version(const struct lyd_node *node, NC_OPERATION op)
3436{
3437 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003438 struct nc_server_tls_opts *opts;
roman12644fe2023-06-08 11:06:42 +02003439 const char *version = NULL;
roman8341e8b2023-11-23 16:12:42 +01003440 struct nc_ch_client *ch_client = NULL;
roman6430c152023-10-12 11:28:47 +02003441 NC_TLS_VERSION tls_version;
roman12644fe2023-06-08 11:06:42 +02003442
3443 assert(!strcmp(LYD_NAME(node), "tls-version"));
3444
romanba93eac2023-07-18 14:36:48 +02003445 /* LOCK */
3446 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003447 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003448 return 1;
3449 }
3450
roman8341e8b2023-11-23 16:12:42 +01003451 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman12644fe2023-06-08 11:06:42 +02003452 ret = 1;
3453 goto cleanup;
3454 }
3455
roman6430c152023-10-12 11:28:47 +02003456 /* str to tls_version */
roman12644fe2023-06-08 11:06:42 +02003457 version = ((struct lyd_node_term *)node)->value.ident->name;
3458 if (!strcmp(version, "tls10")) {
roman6430c152023-10-12 11:28:47 +02003459 tls_version = NC_TLS_VERSION_10;
roman12644fe2023-06-08 11:06:42 +02003460 } else if (!strcmp(version, "tls11")) {
roman6430c152023-10-12 11:28:47 +02003461 tls_version = NC_TLS_VERSION_11;
roman12644fe2023-06-08 11:06:42 +02003462 } else if (!strcmp(version, "tls12")) {
roman6430c152023-10-12 11:28:47 +02003463 tls_version = NC_TLS_VERSION_12;
roman12644fe2023-06-08 11:06:42 +02003464 } else if (!strcmp(version, "tls13")) {
roman6430c152023-10-12 11:28:47 +02003465 tls_version = NC_TLS_VERSION_13;
roman12644fe2023-06-08 11:06:42 +02003466 } else {
3467 ERR(NULL, "TLS version \"%s\" not supported.", version);
3468 ret = 1;
3469 goto cleanup;
3470 }
3471
roman6430c152023-10-12 11:28:47 +02003472 if (op == NC_OP_CREATE) {
3473 /* add the version if it isn't there already */
3474 opts->tls_versions |= tls_version;
3475 } else if ((op == NC_OP_DELETE) && (opts->tls_versions & tls_version)) {
3476 /* delete the version if it is there */
roman84fe3252023-10-25 11:28:32 +02003477 opts->tls_versions &= ~tls_version;
roman6430c152023-10-12 11:28:47 +02003478 }
3479
roman12644fe2023-06-08 11:06:42 +02003480cleanup:
romanba93eac2023-07-18 14:36:48 +02003481 if (is_ch(node)) {
3482 /* UNLOCK */
3483 nc_ch_client_unlock(ch_client);
3484 }
roman12644fe2023-06-08 11:06:42 +02003485 return ret;
3486}
3487
3488static int
3489nc_server_config_create_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher)
3490{
3491 int ret = 0;
3492 char *ssl_cipher = NULL;
3493 uint16_t i;
roman6430c152023-10-12 11:28:47 +02003494 void *tmp;
roman12644fe2023-06-08 11:06:42 +02003495
3496 ssl_cipher = malloc(strlen(cipher) + 1);
roman3a95bb22023-10-26 11:07:17 +02003497 NC_CHECK_ERRMEM_GOTO(!ssl_cipher, ret = 1, cleanup);
roman12644fe2023-06-08 11:06:42 +02003498
3499 for (i = 0; cipher[i]; i++) {
3500 if (cipher[i] == '-') {
3501 /* OpenSSL requires _ instead of - in cipher names */
3502 ssl_cipher[i] = '_';
3503 } else {
3504 /* and requires uppercase unlike the identities */
3505 ssl_cipher[i] = toupper(cipher[i]);
3506 }
3507 }
3508 ssl_cipher[i] = '\0';
3509
3510 if (!opts->ciphers) {
3511 /* first entry */
3512 opts->ciphers = strdup(ssl_cipher);
roman3a95bb22023-10-26 11:07:17 +02003513 NC_CHECK_ERRMEM_GOTO(!opts->ciphers, ret = 1, cleanup);
roman12644fe2023-06-08 11:06:42 +02003514 } else {
3515 /* + 1 because of : between entries */
roman6430c152023-10-12 11:28:47 +02003516 tmp = nc_realloc(opts->ciphers, strlen(opts->ciphers) + strlen(ssl_cipher) + 1 + 1);
roman3a95bb22023-10-26 11:07:17 +02003517 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02003518 opts->ciphers = tmp;
roman08f67f42023-06-08 13:51:54 +02003519 strcat(opts->ciphers, ":");
3520 strcat(opts->ciphers, ssl_cipher);
roman12644fe2023-06-08 11:06:42 +02003521 }
3522
3523cleanup:
3524 free(ssl_cipher);
3525 return ret;
3526}
3527
3528static int
romanb6f44032023-06-30 15:07:56 +02003529nc_server_config_del_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher)
roman12644fe2023-06-08 11:06:42 +02003530{
romanc135c6d2023-10-25 13:32:30 +02003531 int ret = 0;
roman12644fe2023-06-08 11:06:42 +02003532
romanc135c6d2023-10-25 13:32:30 +02003533 ret = nc_server_config_delete_substring(opts->ciphers, cipher, ':');
3534 if (ret) {
roman12644fe2023-06-08 11:06:42 +02003535 ERR(NULL, "Unable to delete a cipher (%s), which was not previously added.", cipher);
3536 return 1;
3537 }
3538
3539 return 0;
3540}
3541
3542static int
3543nc_server_config_cipher_suite(const struct lyd_node *node, NC_OPERATION op)
3544{
3545 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003546 struct nc_server_tls_opts *opts;
roman12644fe2023-06-08 11:06:42 +02003547 const char *cipher = NULL;
roman8341e8b2023-11-23 16:12:42 +01003548 struct nc_ch_client *ch_client = NULL;
roman12644fe2023-06-08 11:06:42 +02003549
romanfaecc582023-06-15 16:13:31 +02003550 assert(!strcmp(LYD_NAME(node), "cipher-suite"));
3551
romanba93eac2023-07-18 14:36:48 +02003552 /* LOCK */
3553 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003554 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003555 return 1;
3556 }
3557
roman8341e8b2023-11-23 16:12:42 +01003558 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman12644fe2023-06-08 11:06:42 +02003559 ret = 1;
3560 goto cleanup;
3561 }
3562
3563 cipher = ((struct lyd_node_term *)node)->value.ident->name;
3564 if (op == NC_OP_CREATE) {
romanb6f44032023-06-30 15:07:56 +02003565 ret = nc_server_config_create_cipher_suite(opts, cipher);
roman12644fe2023-06-08 11:06:42 +02003566 if (ret) {
3567 goto cleanup;
3568 }
3569 } else if (op == NC_OP_DELETE) {
romanb6f44032023-06-30 15:07:56 +02003570 ret = nc_server_config_del_cipher_suite(opts, cipher);
roman12644fe2023-06-08 11:06:42 +02003571 if (ret) {
3572 goto cleanup;
3573 }
3574 }
3575
3576cleanup:
romanba93eac2023-07-18 14:36:48 +02003577 if (is_ch(node)) {
3578 /* UNLOCK */
3579 nc_ch_client_unlock(ch_client);
3580 }
roman12644fe2023-06-08 11:06:42 +02003581 return ret;
3582}
3583
romanfaecc582023-06-15 16:13:31 +02003584static int
3585nc_server_config_crl_url(const struct lyd_node *node, NC_OPERATION op)
3586{
3587 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003588 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01003589 struct nc_ch_client *ch_client = NULL;
romanfaecc582023-06-15 16:13:31 +02003590
3591 assert(!strcmp(LYD_NAME(node), "crl-url"));
3592
romanba93eac2023-07-18 14:36:48 +02003593 /* LOCK */
3594 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003595 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003596 return 1;
3597 }
3598
roman8341e8b2023-11-23 16:12:42 +01003599 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
romanfaecc582023-06-15 16:13:31 +02003600 ret = 1;
3601 goto cleanup;
3602 }
3603
3604 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003605 free(opts->crl_url);
romanb6f44032023-06-30 15:07:56 +02003606 opts->crl_url = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003607 NC_CHECK_ERRMEM_GOTO(!opts->crl_url, ret = 1, cleanup);
romanfaecc582023-06-15 16:13:31 +02003608 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02003609 free(opts->crl_url);
3610 opts->crl_url = NULL;
romanfaecc582023-06-15 16:13:31 +02003611 }
3612
3613cleanup:
romanba93eac2023-07-18 14:36:48 +02003614 if (is_ch(node)) {
3615 /* UNLOCK */
3616 nc_ch_client_unlock(ch_client);
3617 }
romanfaecc582023-06-15 16:13:31 +02003618 return ret;
3619}
3620
3621static int
3622nc_server_config_crl_path(const struct lyd_node *node, NC_OPERATION op)
3623{
3624 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003625 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01003626 struct nc_ch_client *ch_client = NULL;
romanfaecc582023-06-15 16:13:31 +02003627
3628 assert(!strcmp(LYD_NAME(node), "crl-path"));
3629
romanba93eac2023-07-18 14:36:48 +02003630 /* LOCK */
3631 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003632 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003633 return 1;
3634 }
3635
roman8341e8b2023-11-23 16:12:42 +01003636 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
romanfaecc582023-06-15 16:13:31 +02003637 ret = 1;
3638 goto cleanup;
3639 }
3640
3641 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003642 free(opts->crl_path);
romanb6f44032023-06-30 15:07:56 +02003643 opts->crl_path = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003644 NC_CHECK_ERRMEM_GOTO(!opts->crl_path, ret = 1, cleanup);
romanfaecc582023-06-15 16:13:31 +02003645 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02003646 free(opts->crl_path);
3647 opts->crl_path = NULL;
romanfaecc582023-06-15 16:13:31 +02003648 }
3649
3650cleanup:
romanba93eac2023-07-18 14:36:48 +02003651 if (is_ch(node)) {
3652 /* UNLOCK */
3653 nc_ch_client_unlock(ch_client);
3654 }
romanfaecc582023-06-15 16:13:31 +02003655 return ret;
3656}
3657
3658static int
3659nc_server_config_crl_cert_ext(const struct lyd_node *node, NC_OPERATION op)
3660{
3661 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003662 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01003663 struct nc_ch_client *ch_client = NULL;
romanfaecc582023-06-15 16:13:31 +02003664
3665 assert(!strcmp(LYD_NAME(node), "crl-cert-ext"));
3666
romanba93eac2023-07-18 14:36:48 +02003667 /* LOCK */
3668 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003669 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003670 return 1;
3671 }
3672
roman8341e8b2023-11-23 16:12:42 +01003673 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
romanfaecc582023-06-15 16:13:31 +02003674 ret = 1;
3675 goto cleanup;
3676 }
3677
3678 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003679 opts->crl_cert_ext = 1;
romanfaecc582023-06-15 16:13:31 +02003680 } else if (op == NC_OP_DELETE) {
romanb6f44032023-06-30 15:07:56 +02003681 opts->crl_cert_ext = 0;
romanfaecc582023-06-15 16:13:31 +02003682 }
3683
3684cleanup:
romanba93eac2023-07-18 14:36:48 +02003685 if (is_ch(node)) {
3686 /* UNLOCK */
3687 nc_ch_client_unlock(ch_client);
3688 }
romanfaecc582023-06-15 16:13:31 +02003689 return ret;
3690}
3691
roman2eab4742023-06-06 10:00:26 +02003692#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02003693
roman83683fb2023-02-24 09:15:23 +01003694static int
roman5cbb6532023-06-22 12:53:17 +02003695nc_server_config_create_netconf_client(const struct lyd_node *node)
3696{
3697 int ret = 0;
3698
3699 node = lyd_child(node);
3700 assert(!strcmp(LYD_NAME(node), "name"));
3701
3702 /* LOCK */
3703 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
3704
3705 ret = nc_server_config_realloc(lyd_get_value(node), (void **)&server_opts.ch_clients, sizeof *server_opts.ch_clients, &server_opts.ch_client_count);
3706 if (ret) {
3707 goto cleanup;
3708 }
3709
3710 server_opts.ch_clients[server_opts.ch_client_count - 1].id = ATOMIC_INC_RELAXED(server_opts.new_client_id);
3711 server_opts.ch_clients[server_opts.ch_client_count - 1].start_with = NC_CH_FIRST_LISTED;
roman6430c152023-10-12 11:28:47 +02003712 server_opts.ch_clients[server_opts.ch_client_count - 1].max_attempts = 3;
roman5cbb6532023-06-22 12:53:17 +02003713
3714 pthread_mutex_init(&server_opts.ch_clients[server_opts.ch_client_count - 1].lock, NULL);
3715
3716cleanup:
3717 /* UNLOCK */
3718 pthread_rwlock_unlock(&server_opts.ch_client_lock);
3719 return ret;
3720}
3721
3722static int
3723nc_server_config_netconf_client(const struct lyd_node *node, NC_OPERATION op)
3724{
3725 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02003726
3727 assert(!strcmp(LYD_NAME(node), "netconf-client"));
3728
3729 if (op == NC_OP_CREATE) {
3730 ret = nc_server_config_create_netconf_client(node);
3731 if (ret) {
3732 goto cleanup;
3733 }
roman450c00b2023-11-02 10:31:45 +01003734
roman96c27f92023-11-02 11:09:46 +01003735#ifdef NC_ENABLED_SSH_TLS
roman450c00b2023-11-02 10:31:45 +01003736 if (server_opts.ch_dispatch_data.acquire_ctx_cb && server_opts.ch_dispatch_data.release_ctx_cb &&
roman96c27f92023-11-02 11:09:46 +01003737 server_opts.ch_dispatch_data.new_session_cb) {
roman450c00b2023-11-02 10:31:45 +01003738 /* we have all we need for dispatching a new call home thread */
3739 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 +01003740 server_opts.ch_dispatch_data.release_ctx_cb, server_opts.ch_dispatch_data.ctx_cb_data,
3741 server_opts.ch_dispatch_data.new_session_cb, server_opts.ch_dispatch_data.new_session_cb_data);
roman450c00b2023-11-02 10:31:45 +01003742 if (ret) {
3743 ERR(NULL, "Dispatching a new Call Home thread failed for Call Home client \"%s\".", lyd_get_value(lyd_child(node)));
3744 goto cleanup;
3745 }
3746 }
roman96c27f92023-11-02 11:09:46 +01003747#endif /* NC_ENABLED_SSH_TLS */
roman5cbb6532023-06-22 12:53:17 +02003748 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01003749 nc_server_config_ch_del_client(node);
roman5cbb6532023-06-22 12:53:17 +02003750 }
3751
3752cleanup:
3753 return ret;
3754}
3755
3756#ifdef NC_ENABLED_SSH_TLS
3757
3758static int
3759nc_server_config_remote_address(const struct lyd_node *node, NC_OPERATION op)
3760{
3761 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02003762 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01003763 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02003764
romanb6f44032023-06-30 15:07:56 +02003765 assert(!strcmp(LYD_NAME(node), "remote-address"));
3766
romanba93eac2023-07-18 14:36:48 +02003767 /* LOCK */
3768 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003769 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003770 return 1;
3771 }
3772
roman8341e8b2023-11-23 16:12:42 +01003773 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02003774 ret = 1;
3775 goto cleanup;
3776 }
3777
3778 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003779 free(ch_endpt->address);
roman5cbb6532023-06-22 12:53:17 +02003780 ch_endpt->address = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003781 NC_CHECK_ERRMEM_GOTO(!ch_endpt->address, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02003782 } else {
roman6430c152023-10-12 11:28:47 +02003783 free(ch_endpt->address);
3784 ch_endpt->address = NULL;
roman5cbb6532023-06-22 12:53:17 +02003785 }
3786
3787cleanup:
romanba93eac2023-07-18 14:36:48 +02003788 /* UNLOCK */
3789 nc_ch_client_unlock(ch_client);
roman5cbb6532023-06-22 12:53:17 +02003790 return ret;
3791}
3792
3793static int
3794nc_server_config_remote_port(const struct lyd_node *node, NC_OPERATION op)
3795{
3796 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02003797 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01003798 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02003799
romanb6f44032023-06-30 15:07:56 +02003800 assert(!strcmp(LYD_NAME(node), "remote-port"));
3801
romanba93eac2023-07-18 14:36:48 +02003802 /* LOCK */
3803 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003804 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003805 return 1;
3806 }
3807
roman8341e8b2023-11-23 16:12:42 +01003808 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02003809 ret = 1;
3810 goto cleanup;
3811 }
3812
3813 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02003814 ch_endpt->port = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02003815 } else {
3816 ch_endpt->port = 0;
3817 }
3818
3819cleanup:
romanba93eac2023-07-18 14:36:48 +02003820 /* UNLOCK */
3821 nc_ch_client_unlock(ch_client);
roman5cbb6532023-06-22 12:53:17 +02003822 return ret;
3823}
3824
3825#endif /* NC_ENABLED_SSH_TLS */
3826
3827static int
romanb6f44032023-06-30 15:07:56 +02003828nc_server_config_persistent(const struct lyd_node *node, NC_OPERATION op)
3829{
3830 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003831 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003832
3833 assert(!strcmp(LYD_NAME(node), "persistent"));
3834
3835 (void) op;
3836
romanba93eac2023-07-18 14:36:48 +02003837 /* LOCK */
3838 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003839 /* to avoid unlock on fail */
3840 return 1;
romanb6f44032023-06-30 15:07:56 +02003841 }
3842
3843 ch_client->conn_type = NC_CH_PERSIST;
3844
romanba93eac2023-07-18 14:36:48 +02003845 /* UNLOCK */
3846 nc_ch_client_unlock(ch_client);
3847
romanb6f44032023-06-30 15:07:56 +02003848 return ret;
3849}
3850
3851static int
3852nc_server_config_periodic(const struct lyd_node *node, NC_OPERATION op)
3853{
3854 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003855 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003856
3857 assert(!strcmp(LYD_NAME(node), "periodic"));
3858
3859 (void) op;
3860
romanba93eac2023-07-18 14:36:48 +02003861 /* LOCK */
3862 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003863 /* to avoid unlock on fail */
3864 return 1;
romanb6f44032023-06-30 15:07:56 +02003865 }
3866
3867 ch_client->conn_type = NC_CH_PERIOD;
3868 /* set default values */
3869 ch_client->period = 60;
3870 ch_client->anchor_time = 0;
3871 ch_client->idle_timeout = 180;
3872
romanba93eac2023-07-18 14:36:48 +02003873 /* UNLOCK */
3874 nc_ch_client_unlock(ch_client);
3875
romanb6f44032023-06-30 15:07:56 +02003876 return ret;
3877}
3878
3879static int
3880nc_server_config_period(const struct lyd_node *node, NC_OPERATION op)
3881{
3882 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003883 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003884
3885 assert(!strcmp(LYD_NAME(node), "period"));
3886
romanba93eac2023-07-18 14:36:48 +02003887 /* LOCK */
3888 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003889 /* to avoid unlock on fail */
3890 return 1;
romanb6f44032023-06-30 15:07:56 +02003891 }
3892
3893 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02003894 ch_client->period = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02003895 } else if (op == NC_OP_DELETE) {
3896 ch_client->period = 60;
3897 }
3898
romanba93eac2023-07-18 14:36:48 +02003899 /* UNLOCK */
3900 nc_ch_client_unlock(ch_client);
3901
romanb6f44032023-06-30 15:07:56 +02003902 return ret;
3903}
3904
3905static int
3906nc_server_config_anchor_time(const struct lyd_node *node, NC_OPERATION op)
3907{
3908 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003909 struct nc_ch_client *ch_client = NULL;
romana3c95c72023-10-26 11:15:53 +02003910 struct lyd_value_date_and_time *anchor_time;
romanb6f44032023-06-30 15:07:56 +02003911
3912 assert(!strcmp(LYD_NAME(node), "anchor-time"));
3913
romanba93eac2023-07-18 14:36:48 +02003914 /* LOCK */
3915 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003916 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003917 return 1;
romanb6f44032023-06-30 15:07:56 +02003918 }
3919
romana3c95c72023-10-26 11:15:53 +02003920 /* get the value of time from the node directly */
3921 LYD_VALUE_GET(&((struct lyd_node_term *)node)->value, anchor_time);
romanb6f44032023-06-30 15:07:56 +02003922
3923 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romana3c95c72023-10-26 11:15:53 +02003924 ch_client->anchor_time = anchor_time->time;
romanb6f44032023-06-30 15:07:56 +02003925 } else if (op == NC_OP_DELETE) {
3926 ch_client->anchor_time = 0;
3927 }
3928
romanba93eac2023-07-18 14:36:48 +02003929 /* UNLOCK */
3930 nc_ch_client_unlock(ch_client);
romanb6f44032023-06-30 15:07:56 +02003931 return ret;
3932}
3933
3934static int
3935nc_server_config_reconnect_strategy(const struct lyd_node *node, NC_OPERATION op)
3936{
3937 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003938 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003939
3940 assert(!strcmp(LYD_NAME(node), "reconnect-strategy"));
3941
3942 (void) op;
3943
romanba93eac2023-07-18 14:36:48 +02003944 /* LOCK */
3945 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003946 /* to avoid unlock on fail */
3947 return 1;
romanb6f44032023-06-30 15:07:56 +02003948 }
3949
3950 /* set to default values */
3951 ch_client->start_with = NC_CH_FIRST_LISTED;
3952 ch_client->max_wait = 5;
3953 ch_client->max_attempts = 3;
3954
romanba93eac2023-07-18 14:36:48 +02003955 /* UNLOCK */
3956 nc_ch_client_unlock(ch_client);
3957
romanb6f44032023-06-30 15:07:56 +02003958 return ret;
3959}
3960
3961static int
3962nc_server_config_start_with(const struct lyd_node *node, NC_OPERATION op)
3963{
3964 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003965 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003966 const char *value;
3967
3968 assert(!strcmp(LYD_NAME(node), "start-with"));
3969
romanba93eac2023-07-18 14:36:48 +02003970 /* LOCK */
3971 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003972 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003973 return 1;
romanb6f44032023-06-30 15:07:56 +02003974 }
3975
3976 if (op == NC_OP_DELETE) {
3977 ch_client->start_with = NC_CH_FIRST_LISTED;
3978 goto cleanup;
3979 }
3980
3981 value = lyd_get_value(node);
3982 if (!strcmp(value, "first-listed")) {
3983 ch_client->start_with = NC_CH_FIRST_LISTED;
3984 } else if (!strcmp(value, "last-connected")) {
3985 ch_client->start_with = NC_CH_LAST_CONNECTED;
3986 } else if (!strcmp(value, "random-selection")) {
3987 ch_client->start_with = NC_CH_RANDOM;
3988 } else {
3989 ERR(NULL, "Unexpected start-with value \"%s\".", value);
3990 ret = 1;
3991 goto cleanup;
3992 }
3993
3994cleanup:
romanba93eac2023-07-18 14:36:48 +02003995 /* UNLOCK */
3996 nc_ch_client_unlock(ch_client);
romanb6f44032023-06-30 15:07:56 +02003997 return ret;
3998}
3999
4000static int
4001nc_server_config_max_wait(const struct lyd_node *node, NC_OPERATION op)
4002{
4003 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01004004 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02004005
4006 assert(!strcmp(LYD_NAME(node), "max-wait"));
4007
romanba93eac2023-07-18 14:36:48 +02004008 /* LOCK */
4009 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02004010 /* to avoid unlock on fail */
4011 return 1;
romanb6f44032023-06-30 15:07:56 +02004012 }
4013
4014 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02004015 ch_client->max_wait = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02004016 } else {
4017 ch_client->max_wait = 5;
4018 }
4019
romanba93eac2023-07-18 14:36:48 +02004020 /* UNLOCK */
4021 nc_ch_client_unlock(ch_client);
4022
romanb6f44032023-06-30 15:07:56 +02004023 return ret;
4024}
4025
4026static int
4027nc_server_config_max_attempts(const struct lyd_node *node, NC_OPERATION op)
4028{
4029 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01004030 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02004031
4032 assert(!strcmp(LYD_NAME(node), "max-attempts"));
4033
romanba93eac2023-07-18 14:36:48 +02004034 /* LOCK */
4035 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02004036 /* to avoid unlock on fail */
4037 return 1;
romanb6f44032023-06-30 15:07:56 +02004038 }
4039
4040 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02004041 ch_client->max_attempts = ((struct lyd_node_term *)node)->value.uint8;
romanb6f44032023-06-30 15:07:56 +02004042 } else {
4043 ch_client->max_attempts = 3;
4044 }
4045
romanba93eac2023-07-18 14:36:48 +02004046 /* UNLOCK */
4047 nc_ch_client_unlock(ch_client);
4048
romanb6f44032023-06-30 15:07:56 +02004049 return ret;
4050}
4051
4052static int
romanf02273a2023-05-25 09:44:11 +02004053nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01004054{
4055 const char *name = LYD_NAME(node);
roman6430c152023-10-12 11:28:47 +02004056 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01004057
4058 if (!strcmp(name, "listen")) {
roman6430c152023-10-12 11:28:47 +02004059 ret = nc_server_config_listen(node, op);
4060 } else if (!strcmp(name, "call-home")) {
4061 ret = nc_server_config_ch(node, op);
romaneaf84c72023-10-19 14:38:05 +02004062 } else if (!strcmp(name, "hello-timeout")) {
4063 ret = nc_server_config_hello_timeout(node, op);
romanc1d2b092023-02-02 08:58:27 +01004064 } else if (!strcmp(name, "endpoint")) {
roman6430c152023-10-12 11:28:47 +02004065 ret = nc_server_config_endpoint(node, op);
roman2eab4742023-06-06 10:00:26 +02004066 } else if (!strcmp(name, "unix-socket")) {
roman6430c152023-10-12 11:28:47 +02004067 ret = nc_server_config_unix_socket(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004068 }
roman2eab4742023-06-06 10:00:26 +02004069#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02004070 else if (!strcmp(name, "ssh")) {
roman6430c152023-10-12 11:28:47 +02004071 ret = nc_server_config_ssh(node, op);
roman2eab4742023-06-06 10:00:26 +02004072 } else if (!strcmp(name, "local-address")) {
roman6430c152023-10-12 11:28:47 +02004073 ret = nc_server_config_local_address(node, op);
romanc1d2b092023-02-02 08:58:27 +01004074 } else if (!strcmp(name, "local-port")) {
roman6430c152023-10-12 11:28:47 +02004075 ret = nc_server_config_local_port(node, op);
romanc1d2b092023-02-02 08:58:27 +01004076 } else if (!strcmp(name, "keepalives")) {
roman6430c152023-10-12 11:28:47 +02004077 ret = nc_server_config_keepalives(node, op);
romanc1d2b092023-02-02 08:58:27 +01004078 } else if (!strcmp(name, "idle-time")) {
roman6430c152023-10-12 11:28:47 +02004079 ret = nc_server_config_idle_time(node, op);
romanc1d2b092023-02-02 08:58:27 +01004080 } else if (!strcmp(name, "max-probes")) {
roman6430c152023-10-12 11:28:47 +02004081 ret = nc_server_config_max_probes(node, op);
romanc1d2b092023-02-02 08:58:27 +01004082 } else if (!strcmp(name, "probe-interval")) {
roman6430c152023-10-12 11:28:47 +02004083 ret = nc_server_config_probe_interval(node, op);
roman2eab4742023-06-06 10:00:26 +02004084 } else if (!strcmp(name, "host-key")) {
roman6430c152023-10-12 11:28:47 +02004085 ret = nc_server_config_host_key(node, op);
roman2eab4742023-06-06 10:00:26 +02004086 } else if (!strcmp(name, "public-key-format")) {
roman6430c152023-10-12 11:28:47 +02004087 ret = nc_server_config_public_key_format(node, op);
romanc1d2b092023-02-02 08:58:27 +01004088 } else if (!strcmp(name, "public-key")) {
roman6430c152023-10-12 11:28:47 +02004089 ret = nc_server_config_public_key(node, op);
romanc1d2b092023-02-02 08:58:27 +01004090 } else if (!strcmp(name, "private-key-format")) {
roman6430c152023-10-12 11:28:47 +02004091 ret = nc_server_config_private_key_format(node, op);
romanc1d2b092023-02-02 08:58:27 +01004092 } else if (!strcmp(name, "cleartext-private-key")) {
roman6430c152023-10-12 11:28:47 +02004093 ret = nc_server_config_cleartext_private_key(node, op);
roman2eab4742023-06-06 10:00:26 +02004094 } else if (!strcmp(name, "keystore-reference")) {
roman6430c152023-10-12 11:28:47 +02004095 ret = nc_server_config_keystore_reference(node, op);
romanc1d2b092023-02-02 08:58:27 +01004096 } else if (!strcmp(name, "user")) {
roman6430c152023-10-12 11:28:47 +02004097 ret = nc_server_config_user(node, op);
romanc1d2b092023-02-02 08:58:27 +01004098 } else if (!strcmp(name, "auth-attempts")) {
roman6430c152023-10-12 11:28:47 +02004099 ret = nc_server_config_auth_attempts(node, op);
romanc1d2b092023-02-02 08:58:27 +01004100 } else if (!strcmp(name, "auth-timeout")) {
roman6430c152023-10-12 11:28:47 +02004101 ret = nc_server_config_auth_timeout(node, op);
roman2eab4742023-06-06 10:00:26 +02004102 } else if (!strcmp(name, "truststore-reference")) {
roman6430c152023-10-12 11:28:47 +02004103 ret = nc_server_config_truststore_reference(node, op);
roman2eab4742023-06-06 10:00:26 +02004104 } else if (!strcmp(name, "password")) {
roman6430c152023-10-12 11:28:47 +02004105 ret = nc_server_config_password(node, op);
roman808f3f62023-11-23 16:01:04 +01004106 } else if (!strcmp(name, "keyboard-interactive")) {
4107 ret = nc_server_config_kb_int(node, op);
romanc1d2b092023-02-02 08:58:27 +01004108 } else if (!strcmp(name, "none")) {
roman6430c152023-10-12 11:28:47 +02004109 ret = nc_server_config_none(node, op);
romanc1d2b092023-02-02 08:58:27 +01004110 } else if (!strcmp(name, "host-key-alg")) {
roman6430c152023-10-12 11:28:47 +02004111 ret = nc_server_config_host_key_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01004112 } else if (!strcmp(name, "key-exchange-alg")) {
roman6430c152023-10-12 11:28:47 +02004113 ret = nc_server_config_kex_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01004114 } else if (!strcmp(name, "encryption-alg")) {
roman6430c152023-10-12 11:28:47 +02004115 ret = nc_server_config_encryption_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01004116 } else if (!strcmp(name, "mac-alg")) {
roman6430c152023-10-12 11:28:47 +02004117 ret = nc_server_config_mac_alg(node, op);
roman78df0fa2023-11-02 10:33:57 +01004118 } else if (!strcmp(name, "endpoint-reference")) {
4119 ret = nc_server_config_endpoint_reference(node, op);
roman2eab4742023-06-06 10:00:26 +02004120 } else if (!strcmp(name, "tls")) {
roman6430c152023-10-12 11:28:47 +02004121 ret = nc_server_config_tls(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004122 } else if (!strcmp(name, "cert-data")) {
roman6430c152023-10-12 11:28:47 +02004123 ret = nc_server_config_cert_data(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004124 } else if (!strcmp(name, "asymmetric-key")) {
roman6430c152023-10-12 11:28:47 +02004125 ret = nc_server_config_asymmetric_key(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004126 } else if (!strcmp(name, "certificate")) {
roman6430c152023-10-12 11:28:47 +02004127 ret = nc_server_config_certificate(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004128 } else if (!strcmp(name, "cert-to-name")) {
roman6430c152023-10-12 11:28:47 +02004129 ret = nc_server_config_cert_to_name(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004130 } else if (!strcmp(name, "fingerprint")) {
roman6430c152023-10-12 11:28:47 +02004131 ret = nc_server_config_fingerprint(node, op);
roman12644fe2023-06-08 11:06:42 +02004132 } else if (!strcmp(name, "tls-version")) {
roman6430c152023-10-12 11:28:47 +02004133 ret = nc_server_config_tls_version(node, op);
roman12644fe2023-06-08 11:06:42 +02004134 } else if (!strcmp(name, "cipher-suite")) {
roman6430c152023-10-12 11:28:47 +02004135 ret = nc_server_config_cipher_suite(node, op);
romanfaecc582023-06-15 16:13:31 +02004136 } else if (!strcmp(name, "crl-url")) {
roman6430c152023-10-12 11:28:47 +02004137 ret = nc_server_config_crl_url(node, op);
romanfaecc582023-06-15 16:13:31 +02004138 } else if (!strcmp(name, "crl-path")) {
roman6430c152023-10-12 11:28:47 +02004139 ret = nc_server_config_crl_path(node, op);
romanfaecc582023-06-15 16:13:31 +02004140 } else if (!strcmp(name, "crl-cert-ext")) {
roman6430c152023-10-12 11:28:47 +02004141 ret = nc_server_config_crl_cert_ext(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004142 }
roman2eab4742023-06-06 10:00:26 +02004143#endif /* NC_ENABLED_SSH_TLS */
roman5cbb6532023-06-22 12:53:17 +02004144 else if (!strcmp(name, "netconf-client")) {
roman6430c152023-10-12 11:28:47 +02004145 ret = nc_server_config_netconf_client(node, op);
roman5cbb6532023-06-22 12:53:17 +02004146 }
4147#ifdef NC_ENABLED_SSH_TLS
4148 else if (!strcmp(name, "remote-address")) {
roman6430c152023-10-12 11:28:47 +02004149 ret = nc_server_config_remote_address(node, op);
roman5cbb6532023-06-22 12:53:17 +02004150 } else if (!strcmp(name, "remote-port")) {
roman6430c152023-10-12 11:28:47 +02004151 ret = nc_server_config_remote_port(node, op);
roman5cbb6532023-06-22 12:53:17 +02004152 }
4153#endif /* NC_ENABLED_SSH_TLS */
romanb6f44032023-06-30 15:07:56 +02004154 else if (!strcmp(name, "persistent")) {
roman6430c152023-10-12 11:28:47 +02004155 ret = nc_server_config_persistent(node, op);
romanb6f44032023-06-30 15:07:56 +02004156 } else if (!strcmp(name, "periodic")) {
roman6430c152023-10-12 11:28:47 +02004157 ret = nc_server_config_periodic(node, op);
romanb6f44032023-06-30 15:07:56 +02004158 } else if (!strcmp(name, "period")) {
roman6430c152023-10-12 11:28:47 +02004159 ret = nc_server_config_period(node, op);
romanb6f44032023-06-30 15:07:56 +02004160 } else if (!strcmp(name, "anchor-time")) {
roman6430c152023-10-12 11:28:47 +02004161 ret = nc_server_config_anchor_time(node, op);
romaneaf84c72023-10-19 14:38:05 +02004162 } else if (!strcmp(name, "idle-timeout")) {
4163 ret = nc_server_config_idle_timeout(node, op);
romanb6f44032023-06-30 15:07:56 +02004164 } else if (!strcmp(name, "reconnect-strategy")) {
roman6430c152023-10-12 11:28:47 +02004165 ret = nc_server_config_reconnect_strategy(node, op);
romanb6f44032023-06-30 15:07:56 +02004166 } else if (!strcmp(name, "start-with")) {
roman6430c152023-10-12 11:28:47 +02004167 ret = nc_server_config_start_with(node, op);
romanb6f44032023-06-30 15:07:56 +02004168 } else if (!strcmp(name, "max-wait")) {
roman6430c152023-10-12 11:28:47 +02004169 ret = nc_server_config_max_wait(node, op);
romanb6f44032023-06-30 15:07:56 +02004170 } else if (!strcmp(name, "max-attempts")) {
roman6430c152023-10-12 11:28:47 +02004171 ret = nc_server_config_max_attempts(node, op);
4172 }
4173
4174 if (ret) {
4175 ERR(NULL, "Configuring node \"%s\" failed.", LYD_NAME(node));
4176 return 1;
romanb6f44032023-06-30 15:07:56 +02004177 }
romanc1d2b092023-02-02 08:58:27 +01004178
4179 return 0;
romanc1d2b092023-02-02 08:58:27 +01004180}
4181
4182int
roman0bbc19c2023-05-26 09:59:09 +02004183nc_server_config_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, NC_MODULE module)
romanc1d2b092023-02-02 08:58:27 +01004184{
4185 struct lyd_node *child;
4186 struct lyd_meta *m;
romanf9906b42023-05-22 14:04:29 +02004187 NC_OPERATION current_op = NC_OP_UNKNOWN;
romanf02273a2023-05-25 09:44:11 +02004188 int ret;
romanc1d2b092023-02-02 08:58:27 +01004189
4190 assert(node);
4191
romanf9906b42023-05-22 14:04:29 +02004192 /* get current op if there is any */
4193 if ((m = lyd_find_meta(node->meta, NULL, "yang:operation"))) {
4194 if (!strcmp(lyd_get_meta_value(m), "create")) {
4195 current_op = NC_OP_CREATE;
4196 } else if (!strcmp(lyd_get_meta_value(m), "delete")) {
4197 current_op = NC_OP_DELETE;
4198 } else if (!strcmp(lyd_get_meta_value(m), "replace")) {
4199 current_op = NC_OP_REPLACE;
4200 } else if (!strcmp(lyd_get_meta_value(m), "none")) {
4201 current_op = NC_OP_NONE;
romanc1d2b092023-02-02 08:58:27 +01004202 }
4203 }
4204
4205 /* node has no op, inherit from the parent */
romanf9906b42023-05-22 14:04:29 +02004206 if (!current_op) {
4207 if (!parent_op) {
4208 ERR(NULL, "Unknown operation for node \"%s\".", LYD_NAME(node));
4209 return 1;
4210 }
4211
romanc1d2b092023-02-02 08:58:27 +01004212 current_op = parent_op;
4213 }
4214
4215 switch (current_op) {
4216 case NC_OP_NONE:
4217 break;
4218 case NC_OP_CREATE:
4219 case NC_OP_DELETE:
4220 case NC_OP_REPLACE:
roman2eab4742023-06-06 10:00:26 +02004221#ifdef NC_ENABLED_SSH_TLS
4222 if (module == NC_MODULE_KEYSTORE) {
romanf02273a2023-05-25 09:44:11 +02004223 ret = nc_server_config_parse_keystore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02004224 } else if (module == NC_MODULE_TRUSTSTORE) {
romanf02273a2023-05-25 09:44:11 +02004225 ret = nc_server_config_parse_truststore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02004226 } else
4227#endif /* NC_ENABLED_SSH_TLS */
4228 {
4229 ret = nc_server_config_parse_netconf_server(node, current_op);
romanf02273a2023-05-25 09:44:11 +02004230 }
4231 if (ret) {
4232 return ret;
romanc1d2b092023-02-02 08:58:27 +01004233 }
4234 break;
4235 default:
4236 break;
4237 }
4238
4239 if (current_op != NC_OP_DELETE) {
4240 LY_LIST_FOR(lyd_child(node), child) {
roman0bbc19c2023-05-26 09:59:09 +02004241 if (nc_server_config_parse_tree(child, current_op, module)) {
romanc1d2b092023-02-02 08:58:27 +01004242 return 1;
4243 }
4244 }
4245 }
4246 return 0;
4247}
4248
romanc1d2b092023-02-02 08:58:27 +01004249API int
4250nc_server_config_load_modules(struct ly_ctx **ctx)
4251{
4252 int i, new_ctx = 0;
4253
4254 if (!*ctx) {
4255 if (ly_ctx_new(NC_SERVER_SEARCH_DIR, 0, ctx)) {
4256 ERR(NULL, "Couldn't create new libyang context.\n");
4257 goto error;
4258 }
4259 new_ctx = 1;
4260 }
4261
4262 /* all features */
4263 const char *ietf_nectonf_server[] = {"ssh-listen", "tls-listen", "ssh-call-home", "tls-call-home", "central-netconf-server-supported", NULL};
4264 /* all features */
4265 const char *ietf_x509_cert_to_name[] = {NULL};
roman7fdc84d2023-06-06 13:14:53 +02004266 /* no private-key-encryption, csr-generation, p10-csr-format, certificate-expiration-notification,
roman3c6c7e62023-09-14 10:19:19 +02004267 * encrypted-passwords, hidden-symmetric-keys, encrypted-symmetric-keys, hidden-private-keys, encrypted-private-keys,
4268 * one-symmetric-key-format, one-asymmetric-key-format, symmetrically-encrypted-value-format,
4269 * asymmetrically-encrypted-value-format, cms-enveloped-data-format, cms-encrypted-data-format,
Roytakb2794852023-10-18 14:30:22 +02004270 * cleartext-symmetric-keys */
roman3c6c7e62023-09-14 10:19:19 +02004271 const char *ietf_crypto_types[] = {"cleartext-passwords", "cleartext-private-keys", NULL};
romanc1d2b092023-02-02 08:58:27 +01004272 /* all features */
4273 const char *ietf_tcp_common[] = {"keepalives-supported", NULL};
roman7fdc84d2023-06-06 13:14:53 +02004274 /* all features */
4275 const char *ietf_tcp_server[] = {"tcp-server-keepalives", NULL};
Roytakb2794852023-10-18 14:30:22 +02004276 /* no proxy-connect, socks5-gss-api, socks5-username-password, local-binding-supported ? */
4277 const char *ietf_tcp_client[] = {"tcp-client-keepalives", NULL};
roman3c6c7e62023-09-14 10:19:19 +02004278 /* no ssh-x509-certs, public-key-generation */
4279 const char *ietf_ssh_common[] = {"transport-params", NULL};
roman7fdc84d2023-06-06 13:14:53 +02004280 /* no ssh-server-keepalives and local-user-auth-hostbased */
4281 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 +01004282 /* all features */
4283 const char *iana_ssh_encryption_algs[] = {NULL};
4284 /* all features */
4285 const char *iana_ssh_key_exchange_algs[] = {NULL};
4286 /* all features */
4287 const char *iana_ssh_mac_algs[] = {NULL};
4288 /* all features */
4289 const char *iana_ssh_public_key_algs[] = {NULL};
romanc1d2b092023-02-02 08:58:27 +01004290 /* all features */
roman7fdc84d2023-06-06 13:14:53 +02004291 const char *iana_crypt_hash[] = {"crypt-hash-md5", "crypt-hash-sha-256", "crypt-hash-sha-512", NULL};
4292 /* no symmetric-keys */
4293 const char *ietf_keystore[] = {"central-keystore-supported", "inline-definitions-supported", "asymmetric-keys", NULL};
4294 /* all features */
4295 const char *ietf_truststore[] = {"central-truststore-supported", "inline-definitions-supported", "certificates", "public-keys", NULL};
roman3c6c7e62023-09-14 10:19:19 +02004296 /* no public-key-generation */
4297 const char *ietf_tls_common[] = {"tls10", "tls11", "tls12", "tls13", "hello-params", NULL};
4298 /* no tls-server-keepalives, server-ident-raw-public-key, server-ident-tls12-psk, server-ident-tls13-epsk,
4299 * client-auth-raw-public-key, client-auth-tls12-psk, client-auth-tls13-epsk */
4300 const char *ietf_tls_server[] = {"server-ident-x509-cert", "client-auth-supported", "client-auth-x509-cert", NULL};
roman7fdc84d2023-06-06 13:14:53 +02004301 /* all features */
roman12644fe2023-06-08 11:06:42 +02004302 const char *iana_tls_cipher_suite_algs[] = {NULL};
romanc1d2b092023-02-02 08:58:27 +01004303 /* all features */
4304 const char *libnetconf2_netconf_server[] = {NULL};
4305
4306 const char *module_names[] = {
roman7fdc84d2023-06-06 13:14:53 +02004307 "ietf-netconf-server", "ietf-x509-cert-to-name", "ietf-crypto-types", "ietf-tcp-common", "ietf-tcp-server",
4308 "ietf-tcp-client", "ietf-ssh-common", "ietf-ssh-server", "iana-ssh-encryption-algs",
4309 "iana-ssh-key-exchange-algs", "iana-ssh-mac-algs", "iana-ssh-public-key-algs", "iana-crypt-hash",
roman12644fe2023-06-08 11:06:42 +02004310 "ietf-keystore", "ietf-truststore", "ietf-tls-common", "ietf-tls-server", "iana-tls-cipher-suite-algs",
4311 "libnetconf2-netconf-server", NULL
romanc1d2b092023-02-02 08:58:27 +01004312 };
4313
4314 const char **module_features[] = {
roman7fdc84d2023-06-06 13:14:53 +02004315 ietf_nectonf_server, ietf_x509_cert_to_name, ietf_crypto_types, ietf_tcp_common,
4316 ietf_tcp_server, ietf_tcp_client, ietf_ssh_common, ietf_ssh_server, iana_ssh_encryption_algs,
4317 iana_ssh_key_exchange_algs, iana_ssh_mac_algs, iana_ssh_public_key_algs, iana_crypt_hash,
roman12644fe2023-06-08 11:06:42 +02004318 ietf_keystore, ietf_truststore, ietf_tls_common, ietf_tls_server, iana_tls_cipher_suite_algs,
4319 libnetconf2_netconf_server, NULL
romanc1d2b092023-02-02 08:58:27 +01004320 };
4321
4322 for (i = 0; module_names[i] != NULL; i++) {
4323 if (!ly_ctx_load_module(*ctx, module_names[i], NULL, module_features[i])) {
4324 ERR(NULL, "Loading module \"%s\" failed.\n", module_names[i]);
4325 goto error;
4326 }
4327 }
4328
4329 return 0;
4330
4331error:
4332 if (new_ctx) {
4333 ly_ctx_destroy(*ctx);
4334 *ctx = NULL;
4335 }
4336 return 1;
4337}
4338
romanf9906b42023-05-22 14:04:29 +02004339static int
4340nc_server_config_fill_nectonf_server(const struct lyd_node *data, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01004341{
4342 int ret = 0;
roman84fe3252023-10-25 11:28:32 +02004343 uint32_t log_options = 0;
romanc1d2b092023-02-02 08:58:27 +01004344 struct lyd_node *tree;
romand57b3722023-04-05 11:26:25 +02004345
romanc9b62d62023-09-14 10:19:50 +02004346 /* silently search for ietf-netconf-server, it may not be present */
roman84fe3252023-10-25 11:28:32 +02004347 ly_temp_log_options(&log_options);
romanc9b62d62023-09-14 10:19:50 +02004348
romanc1d2b092023-02-02 08:58:27 +01004349 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &tree);
romanc9b62d62023-09-14 10:19:50 +02004350 if (ret || (tree->flags & LYD_DEFAULT)) {
4351 /* not found */
4352 ret = 0;
romanc1d2b092023-02-02 08:58:27 +01004353 goto cleanup;
4354 }
4355
roman0bbc19c2023-05-26 09:59:09 +02004356 if (nc_server_config_parse_tree(tree, op, NC_MODULE_NETCONF_SERVER)) {
4357 ret = 1;
4358 goto cleanup;
4359 }
4360
roman2eab4742023-06-06 10:00:26 +02004361#ifdef NC_ENABLED_SSH_TLS
roman78df0fa2023-11-02 10:33:57 +01004362 /* check and set all endpoint references */
4363 if (nc_server_config_check_endpt_references()) {
romanf9906b42023-05-22 14:04:29 +02004364 ret = 1;
4365 goto cleanup;
4366 }
roman2eab4742023-06-06 10:00:26 +02004367#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004368
4369cleanup:
romanc9b62d62023-09-14 10:19:50 +02004370 /* reset the logging options back to what they were */
roman84fe3252023-10-25 11:28:32 +02004371 ly_temp_log_options(NULL);
romanf9906b42023-05-22 14:04:29 +02004372 return ret;
4373}
4374
4375API int
romanf6f37a52023-05-25 14:27:51 +02004376nc_server_config_setup_diff(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02004377{
4378 int ret = 0;
4379
romanc9b62d62023-09-14 10:19:50 +02004380 NC_CHECK_ARG_RET(NULL, data, 1);
4381
romanf9906b42023-05-22 14:04:29 +02004382 /* LOCK */
4383 pthread_rwlock_wrlock(&server_opts.config_lock);
4384
roman2eab4742023-06-06 10:00:26 +02004385#ifdef NC_ENABLED_SSH_TLS
romanf9906b42023-05-22 14:04:29 +02004386 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02004387 ret = nc_server_config_fill_keystore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02004388 if (ret) {
4389 ERR(NULL, "Filling keystore failed.");
4390 goto cleanup;
4391 }
4392
4393 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02004394 ret = nc_server_config_fill_truststore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02004395 if (ret) {
4396 ERR(NULL, "Filling truststore failed.");
4397 goto cleanup;
4398 }
roman2eab4742023-06-06 10:00:26 +02004399#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004400
4401 /* configure netconf-server */
4402 ret = nc_server_config_fill_nectonf_server(data, NC_OP_UNKNOWN);
4403 if (ret) {
4404 ERR(NULL, "Filling netconf-server failed.");
4405 goto cleanup;
4406 }
4407
4408cleanup:
4409 /* UNLOCK */
4410 pthread_rwlock_unlock(&server_opts.config_lock);
4411 return ret;
4412}
4413
4414API int
romanf6f37a52023-05-25 14:27:51 +02004415nc_server_config_setup_data(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02004416{
4417 int ret = 0;
4418 struct lyd_node *tree, *iter, *root;
4419
romanc9b62d62023-09-14 10:19:50 +02004420 NC_CHECK_ARG_RET(NULL, data, 1);
4421
romanf9906b42023-05-22 14:04:29 +02004422 /* LOCK */
4423 pthread_rwlock_wrlock(&server_opts.config_lock);
4424
4425 /* find the netconf-server node */
4426 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &root);
4427 if (ret) {
4428 ERR(NULL, "Unable to find the netconf-server container in the YANG data.");
4429 goto cleanup;
4430 }
4431
4432 /* iterate through all the nodes and make sure there is no operation attribute */
4433 LY_LIST_FOR(root, tree) {
4434 LYD_TREE_DFS_BEGIN(tree, iter) {
4435 if (lyd_find_meta(iter->meta, NULL, "yang:operation")) {
4436 ERR(NULL, "Unexpected operation attribute in the YANG data.");
romanc1d2b092023-02-02 08:58:27 +01004437 ret = 1;
4438 goto cleanup;
4439 }
romanf9906b42023-05-22 14:04:29 +02004440 LYD_TREE_DFS_END(tree, iter);
romanc1d2b092023-02-02 08:58:27 +01004441 }
4442 }
4443
romanf9906b42023-05-22 14:04:29 +02004444 /* delete the current configuration */
romanf02273a2023-05-25 09:44:11 +02004445 nc_server_config_listen(NULL, NC_OP_DELETE);
roman4cb8bb12023-06-29 09:16:46 +02004446 nc_server_config_ch(NULL, NC_OP_DELETE);
roman2eab4742023-06-06 10:00:26 +02004447#ifdef NC_ENABLED_SSH_TLS
romanf02273a2023-05-25 09:44:11 +02004448 nc_server_config_ks_keystore(NULL, NC_OP_DELETE);
4449 nc_server_config_ts_truststore(NULL, NC_OP_DELETE);
romanf9906b42023-05-22 14:04:29 +02004450
4451 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02004452 ret = nc_server_config_fill_keystore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02004453 if (ret) {
4454 ERR(NULL, "Filling keystore failed.");
4455 goto cleanup;
4456 }
4457
4458 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02004459 ret = nc_server_config_fill_truststore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02004460 if (ret) {
4461 ERR(NULL, "Filling truststore failed.");
4462 goto cleanup;
4463 }
roman2eab4742023-06-06 10:00:26 +02004464#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004465
4466 /* configure netconf-server */
4467 ret = nc_server_config_fill_nectonf_server(data, NC_OP_CREATE);
4468 if (ret) {
4469 ERR(NULL, "Filling netconf-server failed.");
romanc1d2b092023-02-02 08:58:27 +01004470 goto cleanup;
4471 }
4472
4473cleanup:
4474 /* UNLOCK */
4475 pthread_rwlock_unlock(&server_opts.config_lock);
4476 return ret;
4477}
roman3f9b65c2023-06-05 14:26:58 +02004478
4479API int
4480nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path)
4481{
4482 struct lyd_node *tree = NULL;
4483 int ret = 0;
4484
4485 NC_CHECK_ARG_RET(NULL, path, 1);
4486
4487 ret = lyd_parse_data_path(ctx, path, LYD_UNKNOWN, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree);
4488 if (ret) {
4489 goto cleanup;
4490 }
4491
4492 ret = nc_server_config_setup_data(tree);
4493 if (ret) {
4494 goto cleanup;
4495 }
4496
4497cleanup:
4498 lyd_free_all(tree);
4499 return ret;
4500}