blob: 1f1c8143185e3b0932f866beec83b5313964bd24 [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
roman6430c152023-10-12 11:28:47 +020077/* returns true if a node is a part of the listen subtree */
roman4cb8bb12023-06-29 09:16:46 +020078static int
79is_listen(const struct lyd_node *node)
80{
81 assert(node);
82
83 while (node) {
84 if (!strcmp(LYD_NAME(node), "listen")) {
85 break;
86 }
87 node = lyd_parent(node);
88 }
89
90 return node != NULL;
91}
92
roman6430c152023-10-12 11:28:47 +020093/* returns true if a node is a part of the Call Home subtree */
roman4cb8bb12023-06-29 09:16:46 +020094static int
95is_ch(const struct lyd_node *node)
96{
97 assert(node);
98
99 while (node) {
100 if (!strcmp(LYD_NAME(node), "call-home")) {
101 break;
102 }
103 node = lyd_parent(node);
104 }
105
106 return node != NULL;
107}
108
109#ifdef NC_ENABLED_SSH_TLS
110
roman6430c152023-10-12 11:28:47 +0200111/* returns true if a node is a part of the ssh subtree */
roman4cb8bb12023-06-29 09:16:46 +0200112static int
113is_ssh(const struct lyd_node *node)
114{
115 assert(node);
116
117 while (node) {
118 if (!strcmp(LYD_NAME(node), "ssh")) {
119 break;
120 }
121 node = lyd_parent(node);
122 }
123
124 return node != NULL;
125}
126
roman6430c152023-10-12 11:28:47 +0200127/* returns true if a node is a part of the tls subtree */
roman4cb8bb12023-06-29 09:16:46 +0200128static int
129is_tls(const struct lyd_node *node)
130{
131 assert(node);
132
133 while (node) {
134 if (!strcmp(LYD_NAME(node), "tls")) {
135 break;
136 }
137 node = lyd_parent(node);
138 }
139
140 return node != NULL;
141}
142
143#endif /* NC_ENABLED_SSH_TLS */
144
roman6430c152023-10-12 11:28:47 +0200145/* gets the endpoint struct (and optionally bind) based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200146static int
romanf02273a2023-05-25 09:44:11 +0200147nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, struct nc_bind **bind)
romanc1d2b092023-02-02 08:58:27 +0100148{
149 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200150 const char *name;
romanc1d2b092023-02-02 08:58:27 +0100151
roman4cb8bb12023-06-29 09:16:46 +0200152 assert(node && endpt);
romanb9beb112023-07-18 09:06:58 +0200153 name = LYD_NAME(node);
romanc1d2b092023-02-02 08:58:27 +0100154
155 while (node) {
156 if (!strcmp(LYD_NAME(node), "endpoint")) {
157 break;
158 }
159 node = lyd_parent(node);
160 }
161
162 if (!node) {
romanb9beb112023-07-18 09:06:58 +0200163 ERR(NULL, "Node \"%s\" is not contained in an endpoint subtree.", name);
romanc1d2b092023-02-02 08:58:27 +0100164 return 1;
165 }
166
167 node = lyd_child(node);
168 assert(!strcmp(LYD_NAME(node), "name"));
romanb9beb112023-07-18 09:06:58 +0200169 name = lyd_get_value(node);
romanc1d2b092023-02-02 08:58:27 +0100170
171 for (i = 0; i < server_opts.endpt_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200172 if (!strcmp(server_opts.endpts[i].name, name)) {
romanc1d2b092023-02-02 08:58:27 +0100173 *endpt = &server_opts.endpts[i];
174 if (bind) {
175 *bind = &server_opts.binds[i];
176 }
177 return 0;
178 }
179 }
180
romanb9beb112023-07-18 09:06:58 +0200181 ERR(NULL, "Endpoint \"%s\" was not found.", name);
romanc1d2b092023-02-02 08:58:27 +0100182 return 1;
183}
184
roman6430c152023-10-12 11:28:47 +0200185/* gets the ch_client struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200186static int
roman5cbb6532023-06-22 12:53:17 +0200187nc_server_config_get_ch_client(const struct lyd_node *node, struct nc_ch_client **ch_client)
188{
189 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200190 const char *name;
roman5cbb6532023-06-22 12:53:17 +0200191
roman4cb8bb12023-06-29 09:16:46 +0200192 assert(node && ch_client);
romanb9beb112023-07-18 09:06:58 +0200193 name = LYD_NAME(node);
roman4cb8bb12023-06-29 09:16:46 +0200194
roman5cbb6532023-06-22 12:53:17 +0200195 while (node) {
196 if (!strcmp(LYD_NAME(node), "netconf-client")) {
197 break;
198 }
199 node = lyd_parent(node);
200 }
201
202 if (!node) {
romanb9beb112023-07-18 09:06:58 +0200203 ERR(NULL, "Node \"%s\" is not contained in a netconf-client subtree.", name);
roman5cbb6532023-06-22 12:53:17 +0200204 return 1;
205 }
206
207 node = lyd_child(node);
208 assert(!strcmp(LYD_NAME(node), "name"));
romanb9beb112023-07-18 09:06:58 +0200209 name = lyd_get_value(node);
roman5cbb6532023-06-22 12:53:17 +0200210
romanb9beb112023-07-18 09:06:58 +0200211 /* LOCK */
212 pthread_rwlock_rdlock(&server_opts.ch_client_lock);
roman5cbb6532023-06-22 12:53:17 +0200213 for (i = 0; i < server_opts.ch_client_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200214 if (!strcmp(server_opts.ch_clients[i].name, name)) {
roman5cbb6532023-06-22 12:53:17 +0200215 *ch_client = &server_opts.ch_clients[i];
romanb9beb112023-07-18 09:06:58 +0200216 /* UNLOCK */
217 pthread_rwlock_unlock(&server_opts.ch_client_lock);
roman5cbb6532023-06-22 12:53:17 +0200218 return 0;
219 }
220 }
221
romanb9beb112023-07-18 09:06:58 +0200222 /* UNLOCK */
223 pthread_rwlock_unlock(&server_opts.ch_client_lock);
224 ERR(NULL, "Call-home client \"%s\" was not found.", name);
roman5cbb6532023-06-22 12:53:17 +0200225 return 1;
226}
227
roman6430c152023-10-12 11:28:47 +0200228/* gets the ch_endpt struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200229static int
230nc_server_config_get_ch_endpt(const struct lyd_node *node, struct nc_ch_endpt **ch_endpt)
roman5cbb6532023-06-22 12:53:17 +0200231{
232 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200233 const char *name;
roman4cb8bb12023-06-29 09:16:46 +0200234 struct nc_ch_client *ch_client;
235
236 assert(node && ch_endpt);
romanb9beb112023-07-18 09:06:58 +0200237 name = LYD_NAME(node);
roman4cb8bb12023-06-29 09:16:46 +0200238
239 if (nc_server_config_get_ch_client(node, &ch_client)) {
240 return 1;
241 }
roman5cbb6532023-06-22 12:53:17 +0200242
243 while (node) {
244 if (!strcmp(LYD_NAME(node), "endpoint")) {
245 break;
246 }
247 node = lyd_parent(node);
248 }
249
250 if (!node) {
romanb9beb112023-07-18 09:06:58 +0200251 ERR(NULL, "Node \"%s\" is not contained in a call-home endpoint subtree.", name);
roman5cbb6532023-06-22 12:53:17 +0200252 return 1;
253 }
254
255 node = lyd_child(node);
256 assert(!strcmp(LYD_NAME(node), "name"));
romanb9beb112023-07-18 09:06:58 +0200257 name = lyd_get_value(node);
roman5cbb6532023-06-22 12:53:17 +0200258
roman6430c152023-10-12 11:28:47 +0200259 /* LOCK */
260 pthread_rwlock_rdlock(&server_opts.ch_client_lock);
roman5cbb6532023-06-22 12:53:17 +0200261 for (i = 0; i < ch_client->ch_endpt_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200262 if (!strcmp(ch_client->ch_endpts[i].name, name)) {
roman5cbb6532023-06-22 12:53:17 +0200263 *ch_endpt = &ch_client->ch_endpts[i];
roman6430c152023-10-12 11:28:47 +0200264 /* UNLOCK */
265 pthread_rwlock_unlock(&server_opts.ch_client_lock);
roman5cbb6532023-06-22 12:53:17 +0200266 return 0;
267 }
268 }
269
roman6430c152023-10-12 11:28:47 +0200270 /* UNLOCK */
271 pthread_rwlock_unlock(&server_opts.ch_client_lock);
romanb9beb112023-07-18 09:06:58 +0200272 ERR(NULL, "Call-home client's \"%s\" endpoint \"%s\" was not found.", ch_client->name, name);
roman5cbb6532023-06-22 12:53:17 +0200273 return 1;
274}
275
roman6430c152023-10-12 11:28:47 +0200276#ifdef NC_ENABLED_SSH_TLS
277
278/* gets the ssh_opts struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200279static int
280nc_server_config_get_ssh_opts(const struct lyd_node *node, struct nc_server_ssh_opts **opts)
281{
282 struct nc_endpt *endpt;
283 struct nc_ch_endpt *ch_endpt;
roman3f9b65c2023-06-05 14:26:58 +0200284
roman4cb8bb12023-06-29 09:16:46 +0200285 assert(node && opts);
286
287 if (is_listen(node)) {
288 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
289 return 1;
290 }
291 *opts = endpt->opts.ssh;
292 } else {
293 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
294 return 1;
295 }
296 *opts = ch_endpt->opts.ssh;
297 }
298
299 return 0;
300}
301
roman6430c152023-10-12 11:28:47 +0200302/* gets the hostkey struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200303static int
304nc_server_config_get_hostkey(const struct lyd_node *node, struct nc_hostkey **hostkey)
romanc1d2b092023-02-02 08:58:27 +0100305{
306 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200307 const char *name;
roman4cb8bb12023-06-29 09:16:46 +0200308 struct nc_server_ssh_opts *opts;
romanc1d2b092023-02-02 08:58:27 +0100309
roman4cb8bb12023-06-29 09:16:46 +0200310 assert(node && hostkey);
romanb9beb112023-07-18 09:06:58 +0200311 name = LYD_NAME(node);
romanc1d2b092023-02-02 08:58:27 +0100312
313 while (node) {
314 if (!strcmp(LYD_NAME(node), "host-key")) {
315 break;
316 }
317 node = lyd_parent(node);
318 }
319
320 if (!node) {
romanb9beb112023-07-18 09:06:58 +0200321 ERR(NULL, "Node \"%s\" is not contained in a host-key subtree.", name);
romanc1d2b092023-02-02 08:58:27 +0100322 return 1;
323 }
324
325 node = lyd_child(node);
326 assert(!strcmp(LYD_NAME(node), "name"));
romanb9beb112023-07-18 09:06:58 +0200327 name = lyd_get_value(node);
romanc1d2b092023-02-02 08:58:27 +0100328
romanb9beb112023-07-18 09:06:58 +0200329 if (nc_server_config_get_ssh_opts(node, &opts)) {
330 return 1;
331 }
romanc1d2b092023-02-02 08:58:27 +0100332 for (i = 0; i < opts->hostkey_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200333 if (!strcmp(opts->hostkeys[i].name, name)) {
romanc1d2b092023-02-02 08:58:27 +0100334 *hostkey = &opts->hostkeys[i];
335 return 0;
336 }
337 }
338
romanb9beb112023-07-18 09:06:58 +0200339 ERR(NULL, "Host-key \"%s\" was not found.", name);
romanc1d2b092023-02-02 08:58:27 +0100340 return 1;
341}
342
roman6430c152023-10-12 11:28:47 +0200343/* gets the client_auth struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200344static int
roman6430c152023-10-12 11:28:47 +0200345nc_server_config_get_auth_client(const struct lyd_node *node, struct nc_auth_client **auth_client)
romanc1d2b092023-02-02 08:58:27 +0100346{
347 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200348 const char *name;
roman4cb8bb12023-06-29 09:16:46 +0200349 struct nc_server_ssh_opts *opts;
romanc1d2b092023-02-02 08:58:27 +0100350
roman4cb8bb12023-06-29 09:16:46 +0200351 assert(node && auth_client);
romanb9beb112023-07-18 09:06:58 +0200352 name = LYD_NAME(node);
romanc1d2b092023-02-02 08:58:27 +0100353
354 while (node) {
355 if (!strcmp(LYD_NAME(node), "user")) {
356 break;
357 }
358 node = lyd_parent(node);
359 }
360
361 if (!node) {
romanb9beb112023-07-18 09:06:58 +0200362 ERR(NULL, "Node \"%s\" is not contained in a client-authentication subtree.", name);
romanc1d2b092023-02-02 08:58:27 +0100363 return 1;
364 }
365
366 node = lyd_child(node);
367 assert(!strcmp(LYD_NAME(node), "name"));
romanb9beb112023-07-18 09:06:58 +0200368 name = lyd_get_value(node);
romanc1d2b092023-02-02 08:58:27 +0100369
romanb9beb112023-07-18 09:06:58 +0200370 if (nc_server_config_get_ssh_opts(node, &opts)) {
371 return 1;
372 }
romanc1d2b092023-02-02 08:58:27 +0100373 for (i = 0; i < opts->client_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200374 if (!strcmp(opts->auth_clients[i].username, name)) {
romanc1d2b092023-02-02 08:58:27 +0100375 *auth_client = &opts->auth_clients[i];
376 return 0;
377 }
378 }
379
romanb9beb112023-07-18 09:06:58 +0200380 ERR(NULL, "Authorized key \"%s\" was not found.", name);
romanc1d2b092023-02-02 08:58:27 +0100381 return 1;
382}
383
roman6430c152023-10-12 11:28:47 +0200384/* gets the pubkey struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200385static int
386nc_server_config_get_pubkey(const struct lyd_node *node, struct nc_public_key **pubkey)
romanc1d2b092023-02-02 08:58:27 +0100387{
388 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200389 const char *name;
roman6430c152023-10-12 11:28:47 +0200390 struct nc_auth_client *auth_client;
romanc1d2b092023-02-02 08:58:27 +0100391
roman4cb8bb12023-06-29 09:16:46 +0200392 assert(node && pubkey);
romanb9beb112023-07-18 09:06:58 +0200393 name = LYD_NAME(node);
romanc1d2b092023-02-02 08:58:27 +0100394
395 node = lyd_parent(node);
396 while (node) {
397 if (!strcmp(LYD_NAME(node), "public-key")) {
398 break;
399 }
400 node = lyd_parent(node);
401 }
402
403 if (!node) {
romanb9beb112023-07-18 09:06:58 +0200404 ERR(NULL, "Node \"%s\" is not contained in a public-key subtree.", name);
romanc1d2b092023-02-02 08:58:27 +0100405 return 1;
406 }
407
408 node = lyd_child(node);
409 assert(!strcmp(LYD_NAME(node), "name"));
romanb9beb112023-07-18 09:06:58 +0200410 name = lyd_get_value(node);
romanc1d2b092023-02-02 08:58:27 +0100411
romanb9beb112023-07-18 09:06:58 +0200412 if (nc_server_config_get_auth_client(node, &auth_client)) {
413 return 1;
414 }
romanc1d2b092023-02-02 08:58:27 +0100415 for (i = 0; i < auth_client->pubkey_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200416 if (!strcmp(auth_client->pubkeys[i].name, name)) {
romanc1d2b092023-02-02 08:58:27 +0100417 *pubkey = &auth_client->pubkeys[i];
418 return 0;
419 }
420 }
421
romanb9beb112023-07-18 09:06:58 +0200422 ERR(NULL, "Public key \"%s\" was not found.", name);
romanc1d2b092023-02-02 08:58:27 +0100423 return 1;
424}
425
roman6430c152023-10-12 11:28:47 +0200426/* gets the tls_opts struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200427static int
romanb6f44032023-06-30 15:07:56 +0200428nc_server_config_get_tls_opts(const struct lyd_node *node, struct nc_server_tls_opts **opts)
429{
430 struct nc_endpt *endpt;
431 struct nc_ch_endpt *ch_endpt;
432
433 assert(node && opts);
434
435 if (is_listen(node)) {
436 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
437 return 1;
438 }
439 *opts = endpt->opts.tls;
440 } else {
441 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
442 return 1;
443 }
444 *opts = ch_endpt->opts.tls;
445 }
446
447 return 0;
448}
449
roman6430c152023-10-12 11:28:47 +0200450/* gets the cert struct based on node's location in the YANG data tree */
romanb6f44032023-06-30 15:07:56 +0200451static int
roman6430c152023-10-12 11:28:47 +0200452nc_server_config_get_cert(const struct lyd_node *node, struct nc_certificate **cert)
roman3f9b65c2023-06-05 14:26:58 +0200453{
454 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200455 const char *name;
roman4cb8bb12023-06-29 09:16:46 +0200456 struct nc_cert_grouping *auth_client;
romanb6f44032023-06-30 15:07:56 +0200457 struct nc_server_tls_opts *opts;
roman6430c152023-10-12 11:28:47 +0200458 int is_cert_end_entity;
459 struct lyd_node *name_node;
roman3f9b65c2023-06-05 14:26:58 +0200460
roman4cb8bb12023-06-29 09:16:46 +0200461 assert(node && cert);
romanb9beb112023-07-18 09:06:58 +0200462 name = LYD_NAME(node);
roman3f9b65c2023-06-05 14:26:58 +0200463
roman6430c152023-10-12 11:28:47 +0200464 /* check if node is in certificate subtree */
roman3f9b65c2023-06-05 14:26:58 +0200465 while (node) {
466 if (!strcmp(LYD_NAME(node), "certificate")) {
467 break;
468 }
469 node = lyd_parent(node);
470 }
roman3f9b65c2023-06-05 14:26:58 +0200471 if (!node) {
romanb9beb112023-07-18 09:06:58 +0200472 ERR(NULL, "Node \"%s\" is not contained in a certificate subtree.", name);
roman3f9b65c2023-06-05 14:26:58 +0200473 return 1;
474 }
475
roman6430c152023-10-12 11:28:47 +0200476 /* it's child should be the list's key, check later */
477 name_node = lyd_child(node);
478
479 /* it's in certificate node, now check if it's end entity or certificate authority */
480 while (node) {
481 if (!strcmp(LYD_NAME(node), "ee-certs")) {
482 is_cert_end_entity = 1;
483 break;
484 } else if (!strcmp(LYD_NAME(node), "ca-certs")) {
485 is_cert_end_entity = 0;
486 break;
487 }
488 node = lyd_parent(node);
489 }
490 if (!node) {
491 ERR(NULL, "Node \"%s\" is not contained in ee-certs nor ca-certs subtree.", name);
492 return 1;
493 }
494
495 assert(!strcmp(LYD_NAME(name_node), "name"));
496 name = lyd_get_value(name_node);
romanb9beb112023-07-18 09:06:58 +0200497
498 if (nc_server_config_get_tls_opts(node, &opts)) {
499 return 1;
500 }
roman6430c152023-10-12 11:28:47 +0200501 if (is_cert_end_entity) {
romanb9beb112023-07-18 09:06:58 +0200502 auth_client = &opts->ee_certs;
503 } else {
504 auth_client = &opts->ca_certs;
505 }
roman3f9b65c2023-06-05 14:26:58 +0200506
507 for (i = 0; i < auth_client->cert_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200508 if (!strcmp(auth_client->certs[i].name, name)) {
roman3f9b65c2023-06-05 14:26:58 +0200509 *cert = &auth_client->certs[i];
510 return 0;
511 }
512 }
513
romanb9beb112023-07-18 09:06:58 +0200514 ERR(NULL, "Certificate \"%s\" was not found.", name);
roman3f9b65c2023-06-05 14:26:58 +0200515 return 1;
516}
517
roman6430c152023-10-12 11:28:47 +0200518/* gets the ctn struct based on node's location in the YANG data tree */
roman3f9b65c2023-06-05 14:26:58 +0200519static int
roman4cb8bb12023-06-29 09:16:46 +0200520nc_server_config_get_ctn(const struct lyd_node *node, struct nc_ctn **ctn)
roman3f9b65c2023-06-05 14:26:58 +0200521{
522 uint32_t id;
523 struct nc_ctn *iter;
romanb6f44032023-06-30 15:07:56 +0200524 struct nc_server_tls_opts *opts;
romanb9beb112023-07-18 09:06:58 +0200525 const char *name;
roman3f9b65c2023-06-05 14:26:58 +0200526
roman4cb8bb12023-06-29 09:16:46 +0200527 assert(node && ctn);
romanb9beb112023-07-18 09:06:58 +0200528 name = LYD_NAME(node);
roman3f9b65c2023-06-05 14:26:58 +0200529
530 node = lyd_parent(node);
531 while (node) {
532 if (!strcmp(LYD_NAME(node), "cert-to-name")) {
533 break;
534 }
535 node = lyd_parent(node);
536 }
537
538 if (!node) {
romanb9beb112023-07-18 09:06:58 +0200539 ERR(NULL, "Node \"%s\" is not contained in a cert-to-name subtree.", name);
roman3f9b65c2023-06-05 14:26:58 +0200540 return 1;
541 }
542
543 node = lyd_child(node);
544 assert(!strcmp(LYD_NAME(node), "id"));
roman91ffeb42023-10-25 13:32:03 +0200545 id = ((struct lyd_node_term *)node)->value.uint32;
roman3f9b65c2023-06-05 14:26:58 +0200546
romanb9beb112023-07-18 09:06:58 +0200547 if (nc_server_config_get_tls_opts(node, &opts)) {
548 return 1;
549 }
550
romanb6f44032023-06-30 15:07:56 +0200551 iter = opts->ctn;
roman3f9b65c2023-06-05 14:26:58 +0200552 while (iter) {
553 if (iter->id == id) {
554 *ctn = iter;
555 return 0;
556 }
557
558 iter = iter->next;
559 }
560
561 ERR(NULL, "Cert-to-name entry with id \"%d\" was not found.", id);
562 return 1;
563}
564
roman2eab4742023-06-06 10:00:26 +0200565NC_PRIVKEY_FORMAT
566nc_server_config_get_private_key_type(const char *format)
567{
568 if (!strcmp(format, "rsa-private-key-format")) {
569 return NC_PRIVKEY_FORMAT_RSA;
570 } else if (!strcmp(format, "ec-private-key-format")) {
571 return NC_PRIVKEY_FORMAT_EC;
roman13145912023-08-17 15:36:54 +0200572 } else if (!strcmp(format, "private-key-info-format")) {
roman2eab4742023-06-06 10:00:26 +0200573 return NC_PRIVKEY_FORMAT_X509;
574 } else if (!strcmp(format, "openssh-private-key-format")) {
575 return NC_PRIVKEY_FORMAT_OPENSSH;
576 } else {
577 ERR(NULL, "Private key format (%s) not supported.", format);
578 return NC_PRIVKEY_FORMAT_UNKNOWN;
579 }
580}
581
582#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200583
roman6430c152023-10-12 11:28:47 +0200584/* 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 +0200585static int
586nc_server_config_get_ch_client_with_lock(const struct lyd_node *node, struct nc_ch_client **ch_client)
587{
588 uint16_t i;
589 const char *name;
590
591 assert(node && ch_client);
592 name = LYD_NAME(node);
593
594 while (node) {
595 if (!strcmp(LYD_NAME(node), "netconf-client")) {
596 break;
597 }
598 node = lyd_parent(node);
599 }
600
601 if (!node) {
602 ERR(NULL, "Node \"%s\" is not contained in a netconf-client subtree.", name);
603 return 1;
604 }
605
606 node = lyd_child(node);
607 assert(!strcmp(LYD_NAME(node), "name"));
608 name = lyd_get_value(node);
609
610 /* LOCK */
611 pthread_rwlock_rdlock(&server_opts.ch_client_lock);
612 for (i = 0; i < server_opts.ch_client_count; i++) {
613 if (!strcmp(server_opts.ch_clients[i].name, name)) {
614 /* LOCK */
615 pthread_mutex_lock(&server_opts.ch_clients[i].lock);
616 *ch_client = &server_opts.ch_clients[i];
617 return 0;
618 }
619 }
620
roman6430c152023-10-12 11:28:47 +0200621 /* UNLOCK */
622 pthread_rwlock_unlock(&server_opts.ch_client_lock);
romanba93eac2023-07-18 14:36:48 +0200623 ERR(NULL, "Call-home client \"%s\" was not found.", name);
624 return 1;
625}
626
627static void
628nc_ch_client_unlock(struct nc_ch_client *client)
629{
630 assert(client);
631
632 pthread_mutex_unlock(&client->lock);
633 pthread_rwlock_unlock(&server_opts.ch_client_lock);
634}
635
romanf02273a2023-05-25 09:44:11 +0200636int
romanc1d2b092023-02-02 08:58:27 +0100637equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char *parent_name)
638{
639 uint16_t i;
640
roman6430c152023-10-12 11:28:47 +0200641 assert(node && parent_count && parent_name);
romanc1d2b092023-02-02 08:58:27 +0100642
643 node = lyd_parent(node);
644 for (i = 1; i < parent_count; i++) {
645 node = lyd_parent(node);
646 }
647
648 if (!strcmp(LYD_NAME(node), parent_name)) {
649 return 1;
650 }
651
652 return 0;
653}
654
romanf02273a2023-05-25 09:44:11 +0200655int
656nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uint16_t *count)
657{
658 int ret = 0;
659 void *tmp;
660 char **name;
661
662 tmp = realloc(*ptr, (*count + 1) * size);
roman3a95bb22023-10-26 11:07:17 +0200663 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
romanf02273a2023-05-25 09:44:11 +0200664 *ptr = tmp;
665
666 /* set the newly allocated memory to 0 */
667 memset((char *)(*ptr) + (*count * size), 0, size);
668 (*count)++;
669
670 /* access the first member of the supposed structure */
671 name = (char **)((*ptr) + ((*count - 1) * size));
672
673 /* and set it's value */
674 *name = strdup(key_value);
roman3a95bb22023-10-26 11:07:17 +0200675 NC_CHECK_ERRMEM_GOTO(!*name, ret = 1, cleanup);
romanf02273a2023-05-25 09:44:11 +0200676
677cleanup:
678 return ret;
679}
680
roman2eab4742023-06-06 10:00:26 +0200681#ifdef NC_ENABLED_SSH_TLS
682
roman3f9b65c2023-06-05 14:26:58 +0200683static void
roman874fed12023-05-25 10:20:01 +0200684nc_server_config_del_hostkey(struct nc_server_ssh_opts *opts, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100685{
roman874fed12023-05-25 10:20:01 +0200686 assert(hostkey->store == NC_STORE_LOCAL || hostkey->store == NC_STORE_KEYSTORE);
romanc1d2b092023-02-02 08:58:27 +0100687
roman6430c152023-10-12 11:28:47 +0200688 free(hostkey->name);
689
roman874fed12023-05-25 10:20:01 +0200690 if (hostkey->store == NC_STORE_LOCAL) {
roman6430c152023-10-12 11:28:47 +0200691 free(hostkey->key.pubkey_data);
692 free(hostkey->key.privkey_data);
romandd019a92023-09-14 10:17:07 +0200693 } else {
roman6430c152023-10-12 11:28:47 +0200694 free(hostkey->ks_ref);
romanc1d2b092023-02-02 08:58:27 +0100695 }
696
romanc1d2b092023-02-02 08:58:27 +0100697 opts->hostkey_count--;
698 if (!opts->hostkey_count) {
699 free(opts->hostkeys);
700 opts->hostkeys = NULL;
roman6430c152023-10-12 11:28:47 +0200701 } else if (hostkey != &opts->hostkeys[opts->hostkey_count]) {
roman33981232023-07-08 11:55:13 +0200702 memcpy(hostkey, &opts->hostkeys[opts->hostkey_count], sizeof *opts->hostkeys);
romanc1d2b092023-02-02 08:58:27 +0100703 }
704}
705
706static void
roman58f79d02023-10-06 10:20:31 +0200707nc_server_config_del_auth_client_pubkey(struct nc_auth_client *auth_client, struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +0100708{
roman6430c152023-10-12 11:28:47 +0200709 free(pubkey->name);
710 free(pubkey->data);
romanc1d2b092023-02-02 08:58:27 +0100711
712 auth_client->pubkey_count--;
713 if (!auth_client->pubkey_count) {
714 free(auth_client->pubkeys);
715 auth_client->pubkeys = NULL;
roman6430c152023-10-12 11:28:47 +0200716 } else if (pubkey != &auth_client->pubkeys[auth_client->pubkey_count]) {
roman33981232023-07-08 11:55:13 +0200717 memcpy(pubkey, &auth_client->pubkeys[auth_client->pubkey_count], sizeof *auth_client->pubkeys);
romanc1d2b092023-02-02 08:58:27 +0100718 }
719}
720
721static void
roman58f79d02023-10-06 10:20:31 +0200722nc_server_config_del_auth_client(struct nc_server_ssh_opts *opts, struct nc_auth_client *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100723{
724 uint16_t i, pubkey_count;
725
roman4cb8bb12023-06-29 09:16:46 +0200726 free(auth_client->username);
roman4cb8bb12023-06-29 09:16:46 +0200727
roman874fed12023-05-25 10:20:01 +0200728 if (auth_client->store == NC_STORE_LOCAL) {
romanc1d2b092023-02-02 08:58:27 +0100729 pubkey_count = auth_client->pubkey_count;
730 for (i = 0; i < pubkey_count; i++) {
roman874fed12023-05-25 10:20:01 +0200731 nc_server_config_del_auth_client_pubkey(auth_client, &auth_client->pubkeys[i]);
romanc1d2b092023-02-02 08:58:27 +0100732 }
roman6430c152023-10-12 11:28:47 +0200733 } else {
734 free(auth_client->ts_ref);
romanc1d2b092023-02-02 08:58:27 +0100735 }
736
roman6430c152023-10-12 11:28:47 +0200737 free(auth_client->password);
romanc1d2b092023-02-02 08:58:27 +0100738
739 opts->client_count--;
740 if (!opts->client_count) {
741 free(opts->auth_clients);
742 opts->auth_clients = NULL;
roman6430c152023-10-12 11:28:47 +0200743 } else if (auth_client != &opts->auth_clients[opts->client_count]) {
roman33981232023-07-08 11:55:13 +0200744 memcpy(auth_client, &opts->auth_clients[opts->client_count], sizeof *opts->auth_clients);
romanc1d2b092023-02-02 08:58:27 +0100745 }
746}
747
748static void
roman6430c152023-10-12 11:28:47 +0200749nc_server_config_del_ssh_opts(struct nc_bind *bind, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100750{
751 uint16_t i, hostkey_count, client_count;
752
roman5ae78282023-11-02 13:34:34 +0100753 if (bind) {
754 free(bind->address);
755 if (bind->sock > -1) {
756 close(bind->sock);
757 }
romanc1d2b092023-02-02 08:58:27 +0100758 }
759
760 /* store in variable because it gets decremented in the function call */
761 hostkey_count = opts->hostkey_count;
762 for (i = 0; i < hostkey_count; i++) {
roman874fed12023-05-25 10:20:01 +0200763 nc_server_config_del_hostkey(opts, &opts->hostkeys[i]);
romanc1d2b092023-02-02 08:58:27 +0100764 }
765
766 client_count = opts->client_count;
767 for (i = 0; i < client_count; i++) {
roman874fed12023-05-25 10:20:01 +0200768 nc_server_config_del_auth_client(opts, &opts->auth_clients[i]);
romanc1d2b092023-02-02 08:58:27 +0100769 }
770
roman6430c152023-10-12 11:28:47 +0200771 free(opts->hostkey_algs);
772 free(opts->kex_algs);
773 free(opts->encryption_algs);
774 free(opts->mac_algs);
romanc1d2b092023-02-02 08:58:27 +0100775
776 free(opts);
romanc1d2b092023-02-02 08:58:27 +0100777}
778
roman78df0fa2023-11-02 10:33:57 +0100779static void
780nc_server_config_del_endpt_references(const char *referenced_endpt_name)
781{
782 uint16_t i, j;
783
784 for (i = 0; i < server_opts.endpt_count; i++) {
785 if (server_opts.endpts[i].referenced_endpt_name) {
786 if (!strcmp(server_opts.endpts[i].referenced_endpt_name, referenced_endpt_name)) {
787 free(server_opts.endpts[i].referenced_endpt_name);
788 server_opts.endpts[i].referenced_endpt_name = NULL;
789
790 if (server_opts.endpts[i].ti == NC_TI_LIBSSH) {
791 server_opts.endpts[i].opts.ssh->referenced_endpt_name = NULL;
792 } else {
793 server_opts.endpts[i].opts.tls->referenced_endpt_name = NULL;
794 }
795 }
796 }
797 }
798
799 /* LOCK */
800 pthread_rwlock_rdlock(&server_opts.ch_client_lock);
801 for (i = 0; i < server_opts.ch_client_count; i++) {
802 /* LOCK */
803 pthread_mutex_lock(&server_opts.ch_clients[i].lock);
804 for (j = 0; j < server_opts.ch_clients[i].ch_endpt_count; j++) {
805 if (server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name) {
806 if (!strcmp(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, referenced_endpt_name)) {
807 free(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name);
808 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name = NULL;
809
810 if (server_opts.ch_clients[i].ch_endpts[j].ti == NC_TI_LIBSSH) {
811 server_opts.ch_clients[i].ch_endpts[j].opts.ssh->referenced_endpt_name = NULL;
812 } else {
813 server_opts.ch_clients[i].ch_endpts[j].opts.tls->referenced_endpt_name = NULL;
814 }
815 }
816 }
817 }
818 /* UNLOCK */
819 pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
820 }
821
822 /* UNLOCK */
823 pthread_rwlock_unlock(&server_opts.ch_client_lock);
824}
825
romanc1d2b092023-02-02 08:58:27 +0100826void
roman874fed12023-05-25 10:20:01 +0200827nc_server_config_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind)
romanc1d2b092023-02-02 08:58:27 +0100828{
roman78df0fa2023-11-02 10:33:57 +0100829 /* delete any references to this endpoint */
830 nc_server_config_del_endpt_references(endpt->name);
roman6430c152023-10-12 11:28:47 +0200831 free(endpt->name);
roman78df0fa2023-11-02 10:33:57 +0100832
roman6430c152023-10-12 11:28:47 +0200833 free(endpt->referenced_endpt_name);
834 nc_server_config_del_ssh_opts(bind, endpt->opts.ssh);
romanc1d2b092023-02-02 08:58:27 +0100835
836 server_opts.endpt_count--;
837 if (!server_opts.endpt_count) {
838 free(server_opts.endpts);
839 free(server_opts.binds);
840 server_opts.endpts = NULL;
841 server_opts.binds = NULL;
roman6430c152023-10-12 11:28:47 +0200842 } else if (endpt != &server_opts.endpts[server_opts.endpt_count]) {
roman33981232023-07-08 11:55:13 +0200843 memcpy(endpt, &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts);
844 memcpy(bind, &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds);
romanc1d2b092023-02-02 08:58:27 +0100845 }
846}
847
roman2eab4742023-06-06 10:00:26 +0200848#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200849
roman45cec4e2023-02-17 10:21:39 +0100850void
roman6430c152023-10-12 11:28:47 +0200851nc_server_config_del_unix_socket_opts(struct nc_bind *bind, struct nc_server_unix_opts *opts)
roman83683fb2023-02-24 09:15:23 +0100852{
853 if (bind->sock > -1) {
854 close(bind->sock);
855 }
856
romand0b78372023-09-14 10:06:03 +0200857 unlink(bind->address);
roman83683fb2023-02-24 09:15:23 +0100858 free(bind->address);
859 free(opts->address);
860
861 free(opts);
roman83683fb2023-02-24 09:15:23 +0100862}
863
864void
roman874fed12023-05-25 10:20:01 +0200865nc_server_config_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *bind)
roman83683fb2023-02-24 09:15:23 +0100866{
roman6430c152023-10-12 11:28:47 +0200867 free(endpt->name);
868 nc_server_config_del_unix_socket_opts(bind, endpt->opts.unixsock);
roman83683fb2023-02-24 09:15:23 +0100869
870 server_opts.endpt_count--;
871 if (!server_opts.endpt_count) {
872 free(server_opts.endpts);
873 free(server_opts.binds);
874 server_opts.endpts = NULL;
875 server_opts.binds = NULL;
roman6430c152023-10-12 11:28:47 +0200876 } else if (endpt != &server_opts.endpts[server_opts.endpt_count]) {
roman33981232023-07-08 11:55:13 +0200877 memcpy(endpt, &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts);
878 memcpy(bind, &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds);
roman83683fb2023-02-24 09:15:23 +0100879 }
880}
881
roman2eab4742023-06-06 10:00:26 +0200882#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +0200883
884static void
roman3f9b65c2023-06-05 14:26:58 +0200885nc_server_config_del_cert(struct nc_cert_grouping *certs, struct nc_certificate *cert)
886{
887 free(cert->name);
roman3f9b65c2023-06-05 14:26:58 +0200888 free(cert->data);
roman3f9b65c2023-06-05 14:26:58 +0200889
890 certs->cert_count--;
891 if (!certs->cert_count) {
892 free(certs->certs);
893 certs->certs = NULL;
roman6430c152023-10-12 11:28:47 +0200894 } else if (cert != &certs->certs[certs->cert_count]) {
roman33981232023-07-08 11:55:13 +0200895 memcpy(cert, &certs->certs[certs->cert_count], sizeof *certs->certs);
roman3f9b65c2023-06-05 14:26:58 +0200896 }
897}
898
899static void
roman6430c152023-10-12 11:28:47 +0200900nc_server_config_del_certs(struct nc_cert_grouping *certs_grp)
roman3f9b65c2023-06-05 14:26:58 +0200901{
roman6430c152023-10-12 11:28:47 +0200902 uint16_t i;
roman3f9b65c2023-06-05 14:26:58 +0200903
roman6430c152023-10-12 11:28:47 +0200904 if (certs_grp->store == NC_STORE_LOCAL) {
905 for (i = 0; i < certs_grp->cert_count; i++) {
906 free(certs_grp->certs[i].name);
907 free(certs_grp->certs[i].data);
roman3f9b65c2023-06-05 14:26:58 +0200908 }
roman6430c152023-10-12 11:28:47 +0200909 free(certs_grp->certs);
910 certs_grp->certs = NULL;
911 } else {
912 free(certs_grp->ts_ref);
roman3f9b65c2023-06-05 14:26:58 +0200913 }
914}
915
916static void
917nc_server_config_del_ctn(struct nc_server_tls_opts *opts, struct nc_ctn *ctn)
918{
919 struct nc_ctn *iter;
920
roman3f9b65c2023-06-05 14:26:58 +0200921 free(ctn->name);
roman6430c152023-10-12 11:28:47 +0200922 free(ctn->fingerprint);
roman3f9b65c2023-06-05 14:26:58 +0200923
924 if (opts->ctn == ctn) {
925 /* it's the first in the list */
926 opts->ctn = ctn->next;
927 free(ctn);
928 return;
929 }
930
roman84fe3252023-10-25 11:28:32 +0200931 for (iter = opts->ctn; iter; iter = iter->next) {
roman3f9b65c2023-06-05 14:26:58 +0200932 if (iter->next == ctn) {
933 /* found the ctn */
934 break;
935 }
roman3f9b65c2023-06-05 14:26:58 +0200936 }
937
romanb7bfa652023-11-09 12:36:35 +0100938 if (!iter) {
939 ERRINT;
940 return;
941 }
942
roman3f9b65c2023-06-05 14:26:58 +0200943 iter->next = ctn->next;
944 free(ctn);
945}
946
947static void
roman6430c152023-10-12 11:28:47 +0200948nc_server_config_del_ctns(struct nc_server_tls_opts *opts)
roman3f9b65c2023-06-05 14:26:58 +0200949{
950 struct nc_ctn *cur, *next;
951
roman84fe3252023-10-25 11:28:32 +0200952 for (cur = opts->ctn; cur; cur = next) {
roman3f9b65c2023-06-05 14:26:58 +0200953 next = cur->next;
roman3f9b65c2023-06-05 14:26:58 +0200954 free(cur->name);
roman6430c152023-10-12 11:28:47 +0200955 free(cur->fingerprint);
roman3f9b65c2023-06-05 14:26:58 +0200956 free(cur);
roman3f9b65c2023-06-05 14:26:58 +0200957 }
roman3a95bb22023-10-26 11:07:17 +0200958
roman3f9b65c2023-06-05 14:26:58 +0200959 opts->ctn = NULL;
960}
961
962static void
roman6430c152023-10-12 11:28:47 +0200963nc_server_config_del_tls_opts(struct nc_bind *bind, struct nc_server_tls_opts *opts)
roman3f9b65c2023-06-05 14:26:58 +0200964{
roman5ae78282023-11-02 13:34:34 +0100965 if (bind) {
966 free(bind->address);
967 if (bind->sock > -1) {
968 close(bind->sock);
969 }
roman3f9b65c2023-06-05 14:26:58 +0200970 }
971
972 if (opts->store == NC_STORE_LOCAL) {
roman6430c152023-10-12 11:28:47 +0200973 free(opts->pubkey_data);
974 free(opts->privkey_data);
975 free(opts->cert_data);
976 } else {
977 free(opts->key_ref);
978 free(opts->cert_ref);
roman3f9b65c2023-06-05 14:26:58 +0200979 }
980
roman6430c152023-10-12 11:28:47 +0200981 nc_server_config_del_certs(&opts->ca_certs);
982 nc_server_config_del_certs(&opts->ee_certs);
roman3f9b65c2023-06-05 14:26:58 +0200983
roman6430c152023-10-12 11:28:47 +0200984 free(opts->crl_path);
985 free(opts->crl_url);
romanfaecc582023-06-15 16:13:31 +0200986 X509_STORE_free(opts->crl_store);
romanfaecc582023-06-15 16:13:31 +0200987
roman6430c152023-10-12 11:28:47 +0200988 nc_server_config_del_ctns(opts);
989 free(opts->ciphers);
roman3f9b65c2023-06-05 14:26:58 +0200990 free(opts);
991}
992
993static void
994nc_server_config_del_endpt_tls(struct nc_endpt *endpt, struct nc_bind *bind)
995{
roman78df0fa2023-11-02 10:33:57 +0100996 /* delete any references to this endpoint */
997 nc_server_config_del_endpt_references(endpt->name);
roman6430c152023-10-12 11:28:47 +0200998 free(endpt->name);
roman78df0fa2023-11-02 10:33:57 +0100999
roman6430c152023-10-12 11:28:47 +02001000 free(endpt->referenced_endpt_name);
1001
1002 nc_server_config_del_tls_opts(bind, endpt->opts.tls);
roman3f9b65c2023-06-05 14:26:58 +02001003
1004 server_opts.endpt_count--;
1005 if (!server_opts.endpt_count) {
1006 free(server_opts.endpts);
1007 free(server_opts.binds);
1008 server_opts.endpts = NULL;
1009 server_opts.binds = NULL;
roman6430c152023-10-12 11:28:47 +02001010 } else if (endpt != &server_opts.endpts[server_opts.endpt_count]) {
roman33981232023-07-08 11:55:13 +02001011 memcpy(endpt, &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts);
1012 memcpy(bind, &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds);
roman3f9b65c2023-06-05 14:26:58 +02001013 }
1014}
1015
roman2eab4742023-06-06 10:00:26 +02001016#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02001017
romanc1d2b092023-02-02 08:58:27 +01001018/* presence container */
1019int
roman6430c152023-10-12 11:28:47 +02001020nc_server_config_listen(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001021{
roman0bbc19c2023-05-26 09:59:09 +02001022 uint16_t i, endpt_count;
romanc1d2b092023-02-02 08:58:27 +01001023
romanf02273a2023-05-25 09:44:11 +02001024 (void) node;
1025
romanc1d2b092023-02-02 08:58:27 +01001026 assert(op == NC_OP_CREATE || op == NC_OP_DELETE);
1027
1028 if (op == NC_OP_DELETE) {
roman0bbc19c2023-05-26 09:59:09 +02001029 endpt_count = server_opts.endpt_count;
1030 for (i = 0; i < endpt_count; i++) {
roman456f92d2023-04-28 10:28:12 +02001031 switch (server_opts.endpts[i].ti) {
roman2eab4742023-06-06 10:00:26 +02001032#ifdef NC_ENABLED_SSH_TLS
roman456f92d2023-04-28 10:28:12 +02001033 case NC_TI_LIBSSH:
roman874fed12023-05-25 10:20:01 +02001034 nc_server_config_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]);
roman456f92d2023-04-28 10:28:12 +02001035 break;
roman456f92d2023-04-28 10:28:12 +02001036 case NC_TI_OPENSSL:
roman3f9b65c2023-06-05 14:26:58 +02001037 nc_server_config_del_endpt_tls(&server_opts.endpts[i], &server_opts.binds[i]);
roman456f92d2023-04-28 10:28:12 +02001038 break;
roman2eab4742023-06-06 10:00:26 +02001039#endif /* NC_ENABLED_SSH_TLS */
roman456f92d2023-04-28 10:28:12 +02001040 case NC_TI_UNIX:
roman874fed12023-05-25 10:20:01 +02001041 nc_server_config_del_endpt_unix_socket(&server_opts.endpts[i], &server_opts.binds[i]);
roman456f92d2023-04-28 10:28:12 +02001042 break;
1043 case NC_TI_NONE:
1044 case NC_TI_FD:
1045 ERRINT;
1046 return 1;
roman83683fb2023-02-24 09:15:23 +01001047 }
romanc1d2b092023-02-02 08:58:27 +01001048 }
1049 }
1050
1051 return 0;
1052}
1053
roman5cbb6532023-06-22 12:53:17 +02001054static void
1055nc_server_config_ch_del_endpt(struct nc_ch_client *ch_client, struct nc_ch_endpt *ch_endpt)
1056{
1057 free(ch_endpt->name);
roman5cbb6532023-06-22 12:53:17 +02001058
1059#ifdef NC_ENABLED_SSH_TLS
roman6430c152023-10-12 11:28:47 +02001060 free(ch_endpt->address);
roman5cbb6532023-06-22 12:53:17 +02001061 if (ch_endpt->sock_pending > -1) {
1062 close(ch_endpt->sock_pending);
1063 ch_endpt->sock_pending = -1;
1064 }
roman5ae78282023-11-02 13:34:34 +01001065 free(ch_endpt->referenced_endpt_name);
roman5cbb6532023-06-22 12:53:17 +02001066#endif /* NC_ENABLED_SSH_TLS */
1067
1068 switch (ch_endpt->ti) {
1069#ifdef NC_ENABLED_SSH_TLS
1070 case NC_TI_LIBSSH:
roman5ae78282023-11-02 13:34:34 +01001071 nc_server_config_del_ssh_opts(NULL, ch_endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +02001072 break;
romanb6f44032023-06-30 15:07:56 +02001073 case NC_TI_OPENSSL:
roman5ae78282023-11-02 13:34:34 +01001074 nc_server_config_del_tls_opts(NULL, ch_endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +02001075 break;
roman5cbb6532023-06-22 12:53:17 +02001076#endif /* NC_ENABLED_SSH_TLS */
1077 default:
1078 ERRINT;
1079 break;
1080 }
1081
1082 ch_client->ch_endpt_count--;
1083 if (!ch_client->ch_endpt_count) {
1084 free(ch_client->ch_endpts);
1085 ch_client->ch_endpts = NULL;
1086 }
1087}
1088
1089static void
1090nc_server_config_ch_del_client(struct nc_ch_client *ch_client)
1091{
1092 uint16_t i, ch_endpt_count;
romanba93eac2023-07-18 14:36:48 +02001093 struct nc_ch_client client;
1094 pthread_t tid;
roman5cbb6532023-06-22 12:53:17 +02001095
romanba93eac2023-07-18 14:36:48 +02001096 /* WR LOCK */
roman5cbb6532023-06-22 12:53:17 +02001097 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
1098
romanba93eac2023-07-18 14:36:48 +02001099 /* copy the client we want to delete into a local variable */
1100 memcpy(&client, ch_client, sizeof *ch_client);
1101 /* get his tid */
1102 tid = client.tid;
roman5cbb6532023-06-22 12:53:17 +02001103
romanba93eac2023-07-18 14:36:48 +02001104 /* delete the client */
roman5cbb6532023-06-22 12:53:17 +02001105 server_opts.ch_client_count--;
1106 if (!server_opts.ch_client_count) {
1107 free(server_opts.ch_clients);
1108 server_opts.ch_clients = NULL;
romanba93eac2023-07-18 14:36:48 +02001109 } else {
1110 memcpy(ch_client, &server_opts.ch_clients[server_opts.ch_client_count], sizeof *server_opts.ch_clients);
roman5cbb6532023-06-22 12:53:17 +02001111 }
1112
romanba93eac2023-07-18 14:36:48 +02001113 /* WR UNLOCK */
roman5cbb6532023-06-22 12:53:17 +02001114 pthread_rwlock_unlock(&server_opts.ch_client_lock);
romanba93eac2023-07-18 14:36:48 +02001115
1116 /* RD LOCK */
1117 pthread_rwlock_rdlock(&server_opts.ch_client_lock);
roman84fe3252023-10-25 11:28:32 +02001118 /* MUTEX LOCK */
1119 pthread_mutex_lock(&client.lock);
romanba93eac2023-07-18 14:36:48 +02001120
1121 if (client.thread_data->thread_running) {
1122 /* CH COND LOCK */
1123 pthread_mutex_lock(&client.thread_data->cond_lock);
1124 client.thread_data->thread_running = 0;
1125 pthread_cond_signal(&client.thread_data->cond);
1126 /* CH COND UNLOCK */
1127 pthread_mutex_unlock(&client.thread_data->cond_lock);
1128
roman84fe3252023-10-25 11:28:32 +02001129 /* MUTEX UNLOCK */
1130 pthread_mutex_unlock(&client.lock);
romanba93eac2023-07-18 14:36:48 +02001131 /* RD UNLOCK */
1132 pthread_rwlock_unlock(&server_opts.ch_client_lock);
1133
1134 /* wait for the thread to terminate */
1135 pthread_join(tid, NULL);
1136 }
1137
1138 /* free its members */
1139 free(client.name);
1140
1141 ch_endpt_count = client.ch_endpt_count;
1142 for (i = 0; i < ch_endpt_count; i++) {
1143 nc_server_config_ch_del_endpt(&client, &client.ch_endpts[i]);
1144 }
roman5cbb6532023-06-22 12:53:17 +02001145}
1146
roman6430c152023-10-12 11:28:47 +02001147int
roman5cbb6532023-06-22 12:53:17 +02001148nc_server_config_ch(const struct lyd_node *node, NC_OPERATION op)
1149{
1150 uint16_t i, ch_client_count;
1151
1152 (void) node;
1153
1154 if (op == NC_OP_DELETE) {
1155 ch_client_count = server_opts.ch_client_count;
1156 for (i = 0; i < ch_client_count; i++) {
1157 nc_server_config_ch_del_client(&server_opts.ch_clients[i]);
1158 }
1159 }
roman6430c152023-10-12 11:28:47 +02001160
1161 return 0;
roman5cbb6532023-06-22 12:53:17 +02001162}
1163
romanc1d2b092023-02-02 08:58:27 +01001164/* default leaf */
1165static int
romaneaf84c72023-10-19 14:38:05 +02001166nc_server_config_hello_timeout(const struct lyd_node *node, NC_OPERATION op)
1167{
1168 assert(!strcmp(LYD_NAME(node), "hello-timeout"));
1169
1170 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001171 server_opts.hello_timeout = ((struct lyd_node_term *)node)->value.uint16;
romaneaf84c72023-10-19 14:38:05 +02001172 } else {
1173 /* default value */
1174 server_opts.hello_timeout = 60;
1175 }
1176
1177 return 0;
1178}
1179
1180/* default leaf */
1181static int
romane028ef92023-02-24 16:33:08 +01001182nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001183{
romanb6f44032023-06-30 15:07:56 +02001184 struct nc_ch_client *ch_client;
1185
romanc1d2b092023-02-02 08:58:27 +01001186 assert(!strcmp(LYD_NAME(node), "idle-timeout"));
1187
romaneaf84c72023-10-19 14:38:05 +02001188 if (is_ch(node)) {
romanb6f44032023-06-30 15:07:56 +02001189 /* call-home idle timeout */
roman6430c152023-10-12 11:28:47 +02001190 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
1191 /* to avoid unlock on fail */
romanb6f44032023-06-30 15:07:56 +02001192 return 1;
1193 }
1194
1195 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001196 ch_client->idle_timeout = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02001197 } else if (op == NC_OP_DELETE) {
1198 ch_client->idle_timeout = 180;
1199 }
roman6430c152023-10-12 11:28:47 +02001200
1201 nc_ch_client_unlock(ch_client);
romaneaf84c72023-10-19 14:38:05 +02001202 } else {
1203 /* whole server idle timeout */
1204 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001205 server_opts.idle_timeout = ((struct lyd_node_term *)node)->value.uint16;
romaneaf84c72023-10-19 14:38:05 +02001206 } else {
1207 /* default value */
1208 server_opts.idle_timeout = 0;
1209 }
romanc1d2b092023-02-02 08:58:27 +01001210 }
1211
1212 return 0;
1213}
1214
1215static int
roman874fed12023-05-25 10:20:01 +02001216nc_server_config_create_bind(void)
romanc1d2b092023-02-02 08:58:27 +01001217{
1218 int ret = 0;
1219 void *tmp;
1220
1221 tmp = realloc(server_opts.binds, (server_opts.endpt_count + 1) * sizeof *server_opts.binds);
roman3a95bb22023-10-26 11:07:17 +02001222 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01001223 server_opts.binds = tmp;
1224 memset(&server_opts.binds[server_opts.endpt_count], 0, sizeof *server_opts.binds);
1225
1226 server_opts.binds[server_opts.endpt_count].sock = -1;
1227
1228cleanup:
1229 return ret;
1230}
1231
1232static int
roman874fed12023-05-25 10:20:01 +02001233nc_server_config_create_endpoint(const struct lyd_node *node)
romanc1d2b092023-02-02 08:58:27 +01001234{
roman874fed12023-05-25 10:20:01 +02001235 if (nc_server_config_create_bind()) {
romanf02273a2023-05-25 09:44:11 +02001236 return 1;
romanc1d2b092023-02-02 08:58:27 +01001237 }
romanc1d2b092023-02-02 08:58:27 +01001238
1239 node = lyd_child(node);
1240 assert(!strcmp(LYD_NAME(node), "name"));
1241
romanf02273a2023-05-25 09:44:11 +02001242 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 +01001243}
1244
roman5cbb6532023-06-22 12:53:17 +02001245static int
1246nc_server_config_ch_create_endpoint(const struct lyd_node *node, struct nc_ch_client *ch_client)
1247{
1248 node = lyd_child(node);
1249 assert(!strcmp(LYD_NAME(node), "name"));
1250
1251 return nc_server_config_realloc(lyd_get_value(node), (void **)&ch_client->ch_endpts, sizeof *ch_client->ch_endpts, &ch_client->ch_endpt_count);
1252}
1253
romanc1d2b092023-02-02 08:58:27 +01001254/* list */
1255static int
romane028ef92023-02-24 16:33:08 +01001256nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001257{
1258 int ret = 0;
1259 struct nc_endpt *endpt;
1260 struct nc_bind *bind;
roman6430c152023-10-12 11:28:47 +02001261 struct nc_ch_endpt *ch_endpt;
roman5cbb6532023-06-22 12:53:17 +02001262 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001263
1264 assert(!strcmp(LYD_NAME(node), "endpoint"));
1265
roman5cbb6532023-06-22 12:53:17 +02001266 if (is_listen(node)) {
1267 /* listen */
1268 if (op == NC_OP_CREATE) {
1269 ret = nc_server_config_create_endpoint(node);
1270 if (ret) {
1271 goto cleanup;
1272 }
1273 } else if (op == NC_OP_DELETE) {
1274 /* free all children */
1275 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1276 ret = 1;
1277 goto cleanup;
1278 }
1279
1280 switch (endpt->ti) {
1281#ifdef NC_ENABLED_SSH_TLS
1282 case NC_TI_LIBSSH:
1283 nc_server_config_del_endpt_ssh(endpt, bind);
1284 break;
1285 case NC_TI_OPENSSL:
1286 nc_server_config_del_endpt_tls(endpt, bind);
1287 break;
1288#endif /* NC_ENABLED_SSH_TLS */
1289 case NC_TI_UNIX:
1290 nc_server_config_del_endpt_unix_socket(endpt, bind);
1291 break;
1292 case NC_TI_NONE:
1293 case NC_TI_FD:
1294 ERRINT;
1295 ret = 1;
1296 goto cleanup;
1297 }
romanc1d2b092023-02-02 08:58:27 +01001298 }
roman5cbb6532023-06-22 12:53:17 +02001299 } else if (is_ch(node)) {
romanba93eac2023-07-18 14:36:48 +02001300 /* LOCK */
1301 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001302 /* to avoid unlock on fail */
1303 return 1;
romanc1d2b092023-02-02 08:58:27 +01001304 }
roman3f9b65c2023-06-05 14:26:58 +02001305
roman5cbb6532023-06-22 12:53:17 +02001306 if (op == NC_OP_CREATE) {
1307 ret = nc_server_config_ch_create_endpoint(node, ch_client);
1308 if (ret) {
1309 goto cleanup;
1310 }
1311
1312 /* init ch sock */
1313 ch_client->ch_endpts[ch_client->ch_endpt_count - 1].sock_pending = -1;
roman6430c152023-10-12 11:28:47 +02001314 } else if (op == NC_OP_DELETE) {
1315 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
1316 ret = 1;
1317 goto cleanup;
1318 }
1319
1320 nc_server_config_ch_del_endpt(ch_client, ch_endpt);
roman3f9b65c2023-06-05 14:26:58 +02001321 }
romanc1d2b092023-02-02 08:58:27 +01001322 }
1323
1324cleanup:
romanba93eac2023-07-18 14:36:48 +02001325 if (is_ch(node)) {
1326 /* UNLOCK */
1327 nc_ch_client_unlock(ch_client);
1328 }
romanc1d2b092023-02-02 08:58:27 +01001329 return ret;
1330}
1331
roman2eab4742023-06-06 10:00:26 +02001332#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02001333
romanc1d2b092023-02-02 08:58:27 +01001334static int
roman874fed12023-05-25 10:20:01 +02001335nc_server_config_create_ssh(struct nc_endpt *endpt)
romanc1d2b092023-02-02 08:58:27 +01001336{
1337 endpt->ti = NC_TI_LIBSSH;
1338 endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
roman3a95bb22023-10-26 11:07:17 +02001339 NC_CHECK_ERRMEM_RET(!endpt->opts.ssh, 1);
romanc1d2b092023-02-02 08:58:27 +01001340
1341 return 0;
1342}
1343
roman5cbb6532023-06-22 12:53:17 +02001344static int
1345nc_server_config_ch_create_ssh(struct nc_ch_endpt *ch_endpt)
1346{
1347 ch_endpt->ti = NC_TI_LIBSSH;
1348 ch_endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
roman3a95bb22023-10-26 11:07:17 +02001349 NC_CHECK_ERRMEM_RET(!ch_endpt->opts.ssh, 1);
roman5cbb6532023-06-22 12:53:17 +02001350
1351 return 0;
1352}
1353
romanc1d2b092023-02-02 08:58:27 +01001354/* NP container */
1355static int
romane028ef92023-02-24 16:33:08 +01001356nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001357{
1358 struct nc_endpt *endpt;
1359 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001360 struct nc_ch_endpt *ch_endpt;
romanba93eac2023-07-18 14:36:48 +02001361 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001362 int ret = 0;
1363
1364 assert(!strcmp(LYD_NAME(node), "ssh"));
1365
roman5cbb6532023-06-22 12:53:17 +02001366 if (is_listen(node)) {
1367 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1368 ret = 1;
romanc1d2b092023-02-02 08:58:27 +01001369 goto cleanup;
1370 }
roman5cbb6532023-06-22 12:53:17 +02001371
1372 if (op == NC_OP_CREATE) {
1373 ret = nc_server_config_create_ssh(endpt);
1374 if (ret) {
1375 goto cleanup;
1376 }
1377 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02001378 nc_server_config_del_ssh_opts(bind, endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +02001379 }
1380 } else {
romanba93eac2023-07-18 14:36:48 +02001381 /* LOCK */
1382 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001383 /* to avoid unlock on fail */
1384 return 1;
romanba93eac2023-07-18 14:36:48 +02001385 }
1386
roman4cb8bb12023-06-29 09:16:46 +02001387 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001388 ret = 1;
1389 goto cleanup;
1390 }
1391
1392 if (op == NC_OP_CREATE) {
1393 ret = nc_server_config_ch_create_ssh(ch_endpt);
1394 if (ret) {
1395 goto cleanup;
1396 }
romanb6f44032023-06-30 15:07:56 +02001397 } else if (op == NC_OP_DELETE) {
roman5ae78282023-11-02 13:34:34 +01001398 nc_server_config_del_ssh_opts(NULL, ch_endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +02001399 }
romanc1d2b092023-02-02 08:58:27 +01001400 }
1401
1402cleanup:
romanba93eac2023-07-18 14:36:48 +02001403 if (is_ch(node)) {
1404 /* UNLOCK */
1405 nc_ch_client_unlock(ch_client);
1406 }
romanc1d2b092023-02-02 08:58:27 +01001407 return ret;
1408}
1409
roman3f9b65c2023-06-05 14:26:58 +02001410static int
1411nc_server_config_create_tls(struct nc_endpt *endpt)
1412{
1413 endpt->ti = NC_TI_OPENSSL;
1414 endpt->opts.tls = calloc(1, sizeof *endpt->opts.tls);
roman3a95bb22023-10-26 11:07:17 +02001415 NC_CHECK_ERRMEM_RET(!endpt->opts.tls, 1);
roman3f9b65c2023-06-05 14:26:58 +02001416
1417 return 0;
1418}
1419
1420static int
romanb6f44032023-06-30 15:07:56 +02001421nc_server_config_ch_create_tls(struct nc_ch_endpt *ch_endpt)
1422{
1423 ch_endpt->ti = NC_TI_OPENSSL;
1424 ch_endpt->opts.tls = calloc(1, sizeof(struct nc_server_tls_opts));
roman3a95bb22023-10-26 11:07:17 +02001425 NC_CHECK_ERRMEM_RET(!ch_endpt->opts.tls, 1);
romanb6f44032023-06-30 15:07:56 +02001426
1427 return 0;
1428}
1429
1430static int
roman3f9b65c2023-06-05 14:26:58 +02001431nc_server_config_tls(const struct lyd_node *node, NC_OPERATION op)
1432{
1433 struct nc_endpt *endpt;
1434 struct nc_bind *bind;
romanb6f44032023-06-30 15:07:56 +02001435 struct nc_ch_endpt *ch_endpt;
romanba93eac2023-07-18 14:36:48 +02001436 struct nc_ch_client *ch_client;
roman3f9b65c2023-06-05 14:26:58 +02001437 int ret = 0;
1438
1439 assert(!strcmp(LYD_NAME(node), "tls"));
1440
romanb6f44032023-06-30 15:07:56 +02001441 if (is_listen(node)) {
1442 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1443 ret = 1;
roman3f9b65c2023-06-05 14:26:58 +02001444 goto cleanup;
1445 }
romanb6f44032023-06-30 15:07:56 +02001446
1447 if (op == NC_OP_CREATE) {
1448 ret = nc_server_config_create_tls(endpt);
1449 if (ret) {
1450 goto cleanup;
1451 }
1452 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02001453 nc_server_config_del_tls_opts(bind, endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +02001454 }
1455 } else {
romanba93eac2023-07-18 14:36:48 +02001456 /* LOCK */
1457 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001458 /* to avoid unlock on fail */
1459 return 1;
romanba93eac2023-07-18 14:36:48 +02001460 }
1461
romanb6f44032023-06-30 15:07:56 +02001462 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
1463 ret = 1;
1464 goto cleanup;
1465 }
1466
1467 if (op == NC_OP_CREATE) {
1468 ret = nc_server_config_ch_create_tls(ch_endpt);
1469 if (ret) {
1470 goto cleanup;
1471 }
roman6430c152023-10-12 11:28:47 +02001472 } else if (op == NC_OP_DELETE) {
roman5ae78282023-11-02 13:34:34 +01001473 nc_server_config_del_tls_opts(NULL, ch_endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +02001474 }
roman3f9b65c2023-06-05 14:26:58 +02001475 }
1476
1477cleanup:
romanba93eac2023-07-18 14:36:48 +02001478 if (is_ch(node)) {
1479 /* UNLOCK */
1480 nc_ch_client_unlock(ch_client);
1481 }
roman3f9b65c2023-06-05 14:26:58 +02001482 return ret;
1483}
1484
roman2eab4742023-06-06 10:00:26 +02001485#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02001486
romanc1d2b092023-02-02 08:58:27 +01001487static int
1488nc_server_config_set_address_port(struct nc_endpt *endpt, struct nc_bind *bind, const char *address, uint16_t port)
1489{
1490 int sock = -1, set_addr, ret = 0;
1491
roman83683fb2023-02-24 09:15:23 +01001492 assert((address && !port) || (!address && port) || (endpt->ti == NC_TI_UNIX));
romanc1d2b092023-02-02 08:58:27 +01001493
1494 if (address) {
1495 set_addr = 1;
1496 } else {
1497 set_addr = 0;
1498 }
1499
1500 if (set_addr) {
1501 port = bind->port;
1502 } else {
1503 address = bind->address;
1504 }
1505
romanc1d2b092023-02-02 08:58:27 +01001506 /* we have all the information we need to create a listening socket */
roman83683fb2023-02-24 09:15:23 +01001507 if ((address && port) || (endpt->ti == NC_TI_UNIX)) {
romanc1d2b092023-02-02 08:58:27 +01001508 /* create new socket, close the old one */
roman83683fb2023-02-24 09:15:23 +01001509 if (endpt->ti == NC_TI_UNIX) {
1510 sock = nc_sock_listen_unix(endpt->opts.unixsock);
1511 } else {
1512 sock = nc_sock_listen_inet(address, port, &endpt->ka);
1513 }
1514
romanc1d2b092023-02-02 08:58:27 +01001515 if (sock == -1) {
1516 ret = 1;
1517 goto cleanup;
1518 }
1519
1520 if (bind->sock > -1) {
1521 close(bind->sock);
1522 }
1523 bind->sock = sock;
1524 }
1525
1526 if (sock > -1) {
1527 switch (endpt->ti) {
roman83683fb2023-02-24 09:15:23 +01001528 case NC_TI_UNIX:
1529 VRB(NULL, "Listening on %s for UNIX connections.", endpt->opts.unixsock->address);
1530 break;
roman2eab4742023-06-06 10:00:26 +02001531#ifdef NC_ENABLED_SSH_TLS
romanc1d2b092023-02-02 08:58:27 +01001532 case NC_TI_LIBSSH:
1533 VRB(NULL, "Listening on %s:%u for SSH connections.", address, port);
1534 break;
romanc1d2b092023-02-02 08:58:27 +01001535 case NC_TI_OPENSSL:
1536 VRB(NULL, "Listening on %s:%u for TLS connections.", address, port);
1537 break;
roman2eab4742023-06-06 10:00:26 +02001538#endif /* NC_ENABLED_SSH_TLS */
romanc1d2b092023-02-02 08:58:27 +01001539 default:
1540 ERRINT;
1541 ret = 1;
1542 break;
1543 }
1544 }
1545
1546cleanup:
1547 return ret;
1548}
1549
roman2eab4742023-06-06 10:00:26 +02001550#ifdef NC_ENABLED_SSH_TLS
1551
romanc1d2b092023-02-02 08:58:27 +01001552/* mandatory leaf */
1553static int
romane028ef92023-02-24 16:33:08 +01001554nc_server_config_local_address(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001555{
1556 struct nc_endpt *endpt;
1557 struct nc_bind *bind;
1558 int ret = 0;
1559
1560 (void) op;
1561
1562 assert(!strcmp(LYD_NAME(node), "local-address"));
1563
1564 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001565 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001566 ret = 1;
1567 goto cleanup;
1568 }
1569
roman6430c152023-10-12 11:28:47 +02001570 free(bind->address);
romanc1d2b092023-02-02 08:58:27 +01001571 bind->address = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001572 NC_CHECK_ERRMEM_GOTO(!bind->address, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01001573
1574 ret = nc_server_config_set_address_port(endpt, bind, lyd_get_value(node), 0);
1575 if (ret) {
1576 goto cleanup;
1577 }
1578 }
1579
1580cleanup:
1581 return ret;
1582}
1583
1584/* leaf with default value */
1585static int
romane028ef92023-02-24 16:33:08 +01001586nc_server_config_local_port(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001587{
1588 struct nc_endpt *endpt;
1589 struct nc_bind *bind;
1590 int ret = 0;
1591
1592 assert(!strcmp(LYD_NAME(node), "local-port"));
1593
1594 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001595 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001596 ret = 1;
1597 goto cleanup;
1598 }
1599
1600 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001601 bind->port = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001602 } else {
1603 /* delete -> set to default */
1604 bind->port = 0;
1605 }
1606
1607 ret = nc_server_config_set_address_port(endpt, bind, NULL, bind->port);
1608 if (ret) {
1609 goto cleanup;
1610 }
1611 }
1612
1613cleanup:
1614 return ret;
1615}
1616
1617/* P container */
1618static int
romane028ef92023-02-24 16:33:08 +01001619nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001620{
roman5cbb6532023-06-22 12:53:17 +02001621 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001622 struct nc_endpt *endpt;
1623 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001624 struct nc_ch_endpt *ch_endpt;
roman6cb86ea2023-11-08 15:12:05 +01001625 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001626
1627 assert(!strcmp(LYD_NAME(node), "keepalives"));
1628
roman5cbb6532023-06-22 12:53:17 +02001629 if (is_listen(node) && equal_parent_name(node, 1, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001630 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001631 ret = 1;
1632 goto cleanup;
1633 }
1634
1635 if (op == NC_OP_CREATE) {
1636 endpt->ka.enabled = 1;
1637 } else {
1638 endpt->ka.enabled = 0;
1639 }
1640 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1641 if (ret) {
1642 goto cleanup;
1643 }
roman5cbb6532023-06-22 12:53:17 +02001644 } else if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001645 /* LOCK */
1646 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001647 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001648 return 1;
1649 }
1650
roman4cb8bb12023-06-29 09:16:46 +02001651 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001652 ret = 1;
1653 goto cleanup;
1654 }
1655
1656 if (op == NC_OP_CREATE) {
1657 ch_endpt->ka.enabled = 1;
1658 } else {
1659 ch_endpt->ka.enabled = 0;
1660 }
romanc1d2b092023-02-02 08:58:27 +01001661 }
1662
1663cleanup:
romanba93eac2023-07-18 14:36:48 +02001664 if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) {
1665 /* UNLOCK */
1666 nc_ch_client_unlock(ch_client);
1667 }
romanc1d2b092023-02-02 08:58:27 +01001668 return ret;
1669}
1670
1671/* mandatory leaf */
1672static int
romane028ef92023-02-24 16:33:08 +01001673nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001674{
roman5cbb6532023-06-22 12:53:17 +02001675 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001676 struct nc_endpt *endpt;
1677 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001678 struct nc_ch_endpt *ch_endpt;
romanba93eac2023-07-18 14:36:48 +02001679 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001680
1681 assert(!strcmp(LYD_NAME(node), "idle-time"));
1682
roman5cbb6532023-06-22 12:53:17 +02001683 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001684 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001685 ret = 1;
1686 goto cleanup;
1687 }
1688
1689 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001690 endpt->ka.idle_time = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001691 } else {
1692 endpt->ka.idle_time = 0;
1693 }
1694 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1695 if (ret) {
1696 goto cleanup;
1697 }
roman5cbb6532023-06-22 12:53:17 +02001698 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001699 /* LOCK */
1700 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001701 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001702 return 1;
1703 }
1704
roman4cb8bb12023-06-29 09:16:46 +02001705 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001706 ret = 1;
1707 goto cleanup;
1708 }
1709
1710 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001711 ch_endpt->ka.idle_time = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001712 } else {
1713 ch_endpt->ka.idle_time = 0;
1714 }
romanc1d2b092023-02-02 08:58:27 +01001715 }
1716
1717cleanup:
roman6430c152023-10-12 11:28:47 +02001718 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001719 /* UNLOCK */
1720 nc_ch_client_unlock(ch_client);
1721 }
romanc1d2b092023-02-02 08:58:27 +01001722 return ret;
1723}
1724
1725/* mandatory leaf */
1726static int
romane028ef92023-02-24 16:33:08 +01001727nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001728{
roman5cbb6532023-06-22 12:53:17 +02001729 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001730 struct nc_endpt *endpt;
1731 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001732 struct nc_ch_endpt *ch_endpt;
romanba93eac2023-07-18 14:36:48 +02001733 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001734
1735 assert(!strcmp(LYD_NAME(node), "max-probes"));
1736
roman5cbb6532023-06-22 12:53:17 +02001737 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001738 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001739 ret = 1;
1740 goto cleanup;
1741 }
1742
1743 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001744 endpt->ka.max_probes = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001745 } else {
1746 endpt->ka.max_probes = 0;
1747 }
1748 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1749 if (ret) {
1750 goto cleanup;
1751 }
roman5cbb6532023-06-22 12:53:17 +02001752 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001753 /* LOCK */
1754 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001755 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001756 return 1;
1757 }
1758
roman4cb8bb12023-06-29 09:16:46 +02001759 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001760 ret = 1;
1761 goto cleanup;
1762 }
1763
1764 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001765 ch_endpt->ka.max_probes = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001766 } else {
1767 ch_endpt->ka.max_probes = 0;
1768 }
romanc1d2b092023-02-02 08:58:27 +01001769 }
1770
1771cleanup:
roman6430c152023-10-12 11:28:47 +02001772 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001773 /* UNLOCK */
1774 nc_ch_client_unlock(ch_client);
1775 }
romanc1d2b092023-02-02 08:58:27 +01001776 return ret;
1777}
1778
1779/* mandatory leaf */
1780static int
romane028ef92023-02-24 16:33:08 +01001781nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001782{
roman5cbb6532023-06-22 12:53:17 +02001783 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001784 struct nc_endpt *endpt;
1785 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001786 struct nc_ch_endpt *ch_endpt;
romanba93eac2023-07-18 14:36:48 +02001787 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001788
1789 assert(!strcmp(LYD_NAME(node), "probe-interval"));
1790
roman5cbb6532023-06-22 12:53:17 +02001791 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001792 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001793 ret = 1;
1794 goto cleanup;
1795 }
1796
1797 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001798 endpt->ka.probe_interval = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001799 } else {
1800 endpt->ka.probe_interval = 0;
1801 }
1802 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1803 if (ret) {
1804 goto cleanup;
1805 }
roman5cbb6532023-06-22 12:53:17 +02001806 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001807 /* LOCK */
1808 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001809 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001810 return 1;
1811 }
1812
roman4cb8bb12023-06-29 09:16:46 +02001813 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001814 ret = 1;
1815 goto cleanup;
1816 }
1817
1818 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001819 ch_endpt->ka.probe_interval = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001820 } else {
1821 ch_endpt->ka.max_probes = 0;
1822 }
romanc1d2b092023-02-02 08:58:27 +01001823 }
1824
1825cleanup:
roman6430c152023-10-12 11:28:47 +02001826 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001827 /* UNLOCK */
1828 nc_ch_client_unlock(ch_client);
1829 }
romanc1d2b092023-02-02 08:58:27 +01001830 return ret;
1831}
1832
1833static int
roman874fed12023-05-25 10:20:01 +02001834nc_server_config_create_host_key(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01001835{
romanf02273a2023-05-25 09:44:11 +02001836 node = lyd_child(node);
1837 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01001838
romanf02273a2023-05-25 09:44:11 +02001839 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->hostkeys, sizeof *opts->hostkeys, &opts->hostkey_count);
romanc1d2b092023-02-02 08:58:27 +01001840}
1841
1842/* list */
1843static int
romane028ef92023-02-24 16:33:08 +01001844nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001845{
roman5cbb6532023-06-22 12:53:17 +02001846 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001847 struct nc_hostkey *hostkey;
roman4cb8bb12023-06-29 09:16:46 +02001848 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02001849 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001850
1851 assert(!strcmp(LYD_NAME(node), "host-key"));
1852
roman4cb8bb12023-06-29 09:16:46 +02001853 if (equal_parent_name(node, 1, "server-identity")) {
romanba93eac2023-07-18 14:36:48 +02001854 /* LOCK */
1855 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001856 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001857 return 1;
1858 }
1859
roman6cb86ea2023-11-08 15:12:05 +01001860 if (nc_server_config_get_ssh_opts(node, &opts)) {
1861 ret = 1;
1862 goto cleanup;
1863 }
1864
romanc1d2b092023-02-02 08:58:27 +01001865 if (op == NC_OP_CREATE) {
roman4cb8bb12023-06-29 09:16:46 +02001866 ret = nc_server_config_create_host_key(node, opts);
romanc1d2b092023-02-02 08:58:27 +01001867 if (ret) {
1868 goto cleanup;
1869 }
1870 } else if (op == NC_OP_DELETE) {
roman4cb8bb12023-06-29 09:16:46 +02001871 if (nc_server_config_get_hostkey(node, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001872 ret = 1;
1873 goto cleanup;
1874 }
roman4cb8bb12023-06-29 09:16:46 +02001875 nc_server_config_del_hostkey(opts, hostkey);
roman5cbb6532023-06-22 12:53:17 +02001876 }
romanc1d2b092023-02-02 08:58:27 +01001877 }
1878
1879cleanup:
romanba93eac2023-07-18 14:36:48 +02001880 if (is_ch(node) && equal_parent_name(node, 1, "server-identity")) {
1881 /* UNLOCK */
1882 nc_ch_client_unlock(ch_client);
1883 }
romanc1d2b092023-02-02 08:58:27 +01001884 return ret;
1885}
1886
1887/* mandatory leaf */
romane028ef92023-02-24 16:33:08 +01001888static int
1889nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001890{
roman3f9b65c2023-06-05 14:26:58 +02001891 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02001892 const char *format;
roman3f9b65c2023-06-05 14:26:58 +02001893 NC_PUBKEY_FORMAT pubkey_type;
roman8edee342023-03-31 13:25:48 +02001894 struct nc_public_key *pubkey;
romanc1d2b092023-02-02 08:58:27 +01001895 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02001896 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02001897 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001898
1899 assert(!strcmp(LYD_NAME(node), "public-key-format"));
1900
roman6cb86ea2023-11-08 15:12:05 +01001901 /* LOCK */
1902 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
1903 /* to avoid unlock on fail */
1904 return 1;
1905 }
1906
romanc1d2b092023-02-02 08:58:27 +01001907 format = ((struct lyd_node_term *)node)->value.ident->name;
roman3f9b65c2023-06-05 14:26:58 +02001908 if (!strcmp(format, "ssh-public-key-format")) {
roman13145912023-08-17 15:36:54 +02001909 pubkey_type = NC_PUBKEY_FORMAT_SSH;
roman3f9b65c2023-06-05 14:26:58 +02001910 } else if (!strcmp(format, "subject-public-key-info-format")) {
1911 pubkey_type = NC_PUBKEY_FORMAT_X509;
1912 } else {
1913 ERR(NULL, "Public key format (%s) not supported.", format);
1914 ret = 1;
1915 goto cleanup;
1916 }
romanc1d2b092023-02-02 08:58:27 +01001917
roman4cb8bb12023-06-29 09:16:46 +02001918 if (is_ssh(node) && equal_parent_name(node, 4, "server-identity")) {
roman5cbb6532023-06-22 12:53:17 +02001919 /* SSH hostkey public key fmt */
roman4cb8bb12023-06-29 09:16:46 +02001920 if (nc_server_config_get_hostkey(node, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02001921 ret = 1;
1922 goto cleanup;
1923 }
1924
1925 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1926 hostkey->key.pubkey_type = pubkey_type;
1927 }
roman4cb8bb12023-06-29 09:16:46 +02001928 } else if (is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) {
roman5cbb6532023-06-22 12:53:17 +02001929 /* SSH client auth public key fmt */
roman4cb8bb12023-06-29 09:16:46 +02001930 if (nc_server_config_get_pubkey(node, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001931 ret = 1;
1932 goto cleanup;
1933 }
1934
1935 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman3f9b65c2023-06-05 14:26:58 +02001936 pubkey->type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001937 }
romanb6f44032023-06-30 15:07:56 +02001938 } else if (is_tls(node) && equal_parent_name(node, 3, "server-identity")) {
1939 /* TLS server-identity */
1940 if (nc_server_config_get_tls_opts(node, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02001941 ret = 1;
1942 goto cleanup;
1943 }
1944
roman5cbb6532023-06-22 12:53:17 +02001945 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02001946 opts->pubkey_type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001947 }
romanc1d2b092023-02-02 08:58:27 +01001948 }
1949
1950cleanup:
romanba93eac2023-07-18 14:36:48 +02001951 if (is_ch(node)) {
1952 /* UNLOCK */
1953 nc_ch_client_unlock(ch_client);
1954 }
romanc1d2b092023-02-02 08:58:27 +01001955 return ret;
1956}
1957
1958static int
roman58f79d02023-10-06 10:20:31 +02001959nc_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 +01001960{
romanc1d2b092023-02-02 08:58:27 +01001961 assert(!strcmp(LYD_NAME(node), "public-key"));
1962
romanc1d2b092023-02-02 08:58:27 +01001963 node = lyd_child(node);
1964 assert(!strcmp(LYD_NAME(node), "name"));
1965
romanf02273a2023-05-25 09:44:11 +02001966 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 +01001967}
1968
1969static int
roman874fed12023-05-25 10:20:01 +02001970nc_server_config_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +01001971{
roman6430c152023-10-12 11:28:47 +02001972 free(pubkey->data);
roman3f9b65c2023-06-05 14:26:58 +02001973 pubkey->data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001974 NC_CHECK_ERRMEM_RET(!pubkey->data, 1);
romanc1d2b092023-02-02 08:58:27 +01001975
1976 return 0;
1977}
1978
1979static int
roman874fed12023-05-25 10:20:01 +02001980nc_server_config_replace_host_key_public_key(const struct lyd_node *node, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +01001981{
roman6430c152023-10-12 11:28:47 +02001982 free(hostkey->key.pubkey_data);
roman3f9b65c2023-06-05 14:26:58 +02001983 hostkey->key.pubkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001984 NC_CHECK_ERRMEM_RET(!hostkey->key.pubkey_data, 1);
romanc1d2b092023-02-02 08:58:27 +01001985
1986 return 0;
1987}
1988
roman3f9b65c2023-06-05 14:26:58 +02001989static int
1990nc_server_config_tls_replace_server_public_key(const struct lyd_node *node, struct nc_server_tls_opts *opts)
1991{
roman6430c152023-10-12 11:28:47 +02001992 free(opts->pubkey_data);
roman3f9b65c2023-06-05 14:26:58 +02001993 opts->pubkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001994 NC_CHECK_ERRMEM_RET(!opts->pubkey_data, 1);
roman3f9b65c2023-06-05 14:26:58 +02001995
1996 return 0;
1997}
1998
romanc1d2b092023-02-02 08:58:27 +01001999static int
romane028ef92023-02-24 16:33:08 +01002000nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002001{
roman3f9b65c2023-06-05 14:26:58 +02002002 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002003 struct nc_hostkey *hostkey;
roman58f79d02023-10-06 10:20:31 +02002004 struct nc_auth_client *auth_client;
roman8edee342023-03-31 13:25:48 +02002005 struct nc_public_key *pubkey;
romanb6f44032023-06-30 15:07:56 +02002006 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002007 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002008
2009 assert(!strcmp(LYD_NAME(node), "public-key"));
2010
romanba93eac2023-07-18 14:36:48 +02002011 /* LOCK */
2012 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002013 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002014 return 1;
2015 }
2016
roman4cb8bb12023-06-29 09:16:46 +02002017 if (is_ssh(node) && equal_parent_name(node, 3, "host-key")) {
roman3f9b65c2023-06-05 14:26:58 +02002018 /* server's public-key, mandatory leaf */
roman4cb8bb12023-06-29 09:16:46 +02002019 if (nc_server_config_get_hostkey(node, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01002020 ret = 1;
2021 goto cleanup;
2022 }
2023
roman13145912023-08-17 15:36:54 +02002024 /* the public key must not be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
roman51a1e192023-09-14 10:13:45 +02002025 if (nc_is_pk_subject_public_key_info(lyd_get_value(node))) {
roman13145912023-08-17 15:36:54 +02002026 ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH hostkey is forbidden!");
2027 ret = 1;
2028 goto cleanup;
2029 }
2030
romanc1d2b092023-02-02 08:58:27 +01002031 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02002032 /* set to local */
roman874fed12023-05-25 10:20:01 +02002033 hostkey->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02002034
roman874fed12023-05-25 10:20:01 +02002035 ret = nc_server_config_replace_host_key_public_key(node, hostkey);
romanc1d2b092023-02-02 08:58:27 +01002036 if (ret) {
2037 goto cleanup;
2038 }
2039 }
roman4cb8bb12023-06-29 09:16:46 +02002040 } else if (is_ssh(node) && equal_parent_name(node, 5, "client-authentication")) {
romanc1d2b092023-02-02 08:58:27 +01002041 /* client auth pubkeys, list */
roman4cb8bb12023-06-29 09:16:46 +02002042 if (nc_server_config_get_auth_client(node, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002043 ret = 1;
2044 goto cleanup;
2045 }
2046
2047 if (op == NC_OP_CREATE) {
romanf02273a2023-05-25 09:44:11 +02002048 /* set to local */
roman874fed12023-05-25 10:20:01 +02002049 auth_client->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02002050
roman874fed12023-05-25 10:20:01 +02002051 ret = nc_server_config_create_auth_key_public_key_list(node, auth_client);
romanc1d2b092023-02-02 08:58:27 +01002052 if (ret) {
2053 goto cleanup;
2054 }
2055 } else if (op == NC_OP_DELETE) {
roman4cb8bb12023-06-29 09:16:46 +02002056 if (nc_server_config_get_pubkey(node, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01002057 ret = 1;
2058 goto cleanup;
2059 }
2060
roman874fed12023-05-25 10:20:01 +02002061 nc_server_config_del_auth_client_pubkey(auth_client, pubkey);
romanc1d2b092023-02-02 08:58:27 +01002062 }
roman4cb8bb12023-06-29 09:16:46 +02002063 } else if (is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) {
romanc1d2b092023-02-02 08:58:27 +01002064 /* client auth pubkey, leaf */
roman4cb8bb12023-06-29 09:16:46 +02002065 if (nc_server_config_get_pubkey(node, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01002066 ret = 1;
2067 goto cleanup;
2068 }
2069
roman13145912023-08-17 15:36:54 +02002070 /* the public key must not be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
roman51a1e192023-09-14 10:13:45 +02002071 if (nc_is_pk_subject_public_key_info(lyd_get_value(node))) {
roman13145912023-08-17 15:36:54 +02002072 ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH user's key is forbidden!");
2073 ret = 1;
2074 goto cleanup;
2075 }
2076
romanc1d2b092023-02-02 08:58:27 +01002077 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02002078 ret = nc_server_config_replace_auth_key_public_key_leaf(node, pubkey);
romanc1d2b092023-02-02 08:58:27 +01002079 if (ret) {
2080 goto cleanup;
2081 }
roman6430c152023-10-12 11:28:47 +02002082 } else if (op == NC_OP_DELETE) {
2083 free(pubkey->data);
2084 pubkey->data = NULL;
romanc1d2b092023-02-02 08:58:27 +01002085 }
romanb6f44032023-06-30 15:07:56 +02002086 } else if (is_tls(node) && equal_parent_name(node, 3, "server-identity")) {
2087 /* TLS server-identity */
2088 if (nc_server_config_get_tls_opts(node, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002089 ret = 1;
2090 goto cleanup;
2091 }
2092
roman13145912023-08-17 15:36:54 +02002093 /* the public key must be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
roman51a1e192023-09-14 10:13:45 +02002094 if (!nc_is_pk_subject_public_key_info(lyd_get_value(node))) {
roman13145912023-08-17 15:36:54 +02002095 ERR(NULL, "TLS server certificate's Public Key must be in the SubjectPublicKeyInfo format!");
2096 ret = 1;
2097 goto cleanup;
2098 }
2099
roman3f9b65c2023-06-05 14:26:58 +02002100 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2101 /* set to local */
romanb6f44032023-06-30 15:07:56 +02002102 opts->store = NC_STORE_LOCAL;
roman3f9b65c2023-06-05 14:26:58 +02002103
romanb6f44032023-06-30 15:07:56 +02002104 ret = nc_server_config_tls_replace_server_public_key(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02002105 if (ret) {
2106 goto cleanup;
2107 }
2108 }
roman5cbb6532023-06-22 12:53:17 +02002109 }
2110
2111cleanup:
romanba93eac2023-07-18 14:36:48 +02002112 if (is_ch(node)) {
2113 /* UNLOCK */
2114 nc_ch_client_unlock(ch_client);
2115 }
roman5cbb6532023-06-22 12:53:17 +02002116 return ret;
2117}
2118
2119/* leaf */
2120static int
2121nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op)
2122{
2123 int ret = 0;
2124 const char *format;
2125 NC_PRIVKEY_FORMAT privkey_type;
roman5cbb6532023-06-22 12:53:17 +02002126 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02002127 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002128 struct nc_ch_client *ch_client;
roman5cbb6532023-06-22 12:53:17 +02002129
2130 (void) op;
2131
2132 assert(!strcmp(LYD_NAME(node), "private-key-format"));
2133
roman6cb86ea2023-11-08 15:12:05 +01002134 /* LOCK */
2135 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
2136 /* to avoid unlock on fail */
2137 return 1;
2138 }
2139
roman5cbb6532023-06-22 12:53:17 +02002140 format = ((struct lyd_node_term *)node)->value.ident->name;
2141 if (!format) {
2142 ret = 1;
2143 goto cleanup;
2144 }
2145
2146 privkey_type = nc_server_config_get_private_key_type(format);
2147 if (privkey_type == NC_PRIVKEY_FORMAT_UNKNOWN) {
2148 ERR(NULL, "Unknown private key format.");
2149 ret = 1;
2150 goto cleanup;
2151 }
2152
roman4cb8bb12023-06-29 09:16:46 +02002153 if (is_ssh(node)) {
2154 /* ssh */
2155 if (nc_server_config_get_hostkey(node, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02002156 ret = 1;
2157 goto cleanup;
2158 }
2159
2160 hostkey->key.privkey_type = privkey_type;
romanb6f44032023-06-30 15:07:56 +02002161 } else if (is_tls(node)) {
2162 /* tls */
2163 if (nc_server_config_get_tls_opts(node, &opts)) {
roman5cbb6532023-06-22 12:53:17 +02002164 ret = 1;
2165 goto cleanup;
2166 }
2167
romanb6f44032023-06-30 15:07:56 +02002168 opts->privkey_type = privkey_type;
roman5cbb6532023-06-22 12:53:17 +02002169 }
2170
2171cleanup:
romanba93eac2023-07-18 14:36:48 +02002172 if (is_ch(node)) {
2173 /* UNLOCK */
2174 nc_ch_client_unlock(ch_client);
2175 }
roman5cbb6532023-06-22 12:53:17 +02002176 return ret;
2177}
2178
2179static int
roman5cbb6532023-06-22 12:53:17 +02002180nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op)
2181{
2182 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02002183 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02002184 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002185 struct nc_ch_client *ch_client;
roman5cbb6532023-06-22 12:53:17 +02002186
2187 assert(!strcmp(LYD_NAME(node), "cleartext-private-key"));
2188
romanba93eac2023-07-18 14:36:48 +02002189 /* LOCK */
2190 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002191 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002192 return 1;
2193 }
2194
roman4cb8bb12023-06-29 09:16:46 +02002195 if (is_ssh(node)) {
2196 /* ssh */
2197 if (nc_server_config_get_hostkey(node, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02002198 ret = 1;
2199 goto cleanup;
2200 }
2201
2202 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002203 free(hostkey->key.privkey_data);
2204 hostkey->key.privkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002205 NC_CHECK_ERRMEM_GOTO(!hostkey->key.privkey_data, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02002206 } else {
roman6430c152023-10-12 11:28:47 +02002207 free(hostkey->key.privkey_data);
2208 hostkey->key.privkey_data = NULL;
roman5cbb6532023-06-22 12:53:17 +02002209 }
romanb6f44032023-06-30 15:07:56 +02002210 } else if (is_tls(node)) {
2211 /* tls */
2212 if (nc_server_config_get_tls_opts(node, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002213 ret = 1;
2214 goto cleanup;
2215 }
2216
roman5cbb6532023-06-22 12:53:17 +02002217 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002218 free(opts->privkey_data);
2219 opts->privkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002220 NC_CHECK_ERRMEM_GOTO(!opts->privkey_data, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02002221 } else {
roman6430c152023-10-12 11:28:47 +02002222 free(opts->privkey_data);
2223 opts->privkey_data = NULL;
roman5cbb6532023-06-22 12:53:17 +02002224 }
roman5cbb6532023-06-22 12:53:17 +02002225 }
2226
2227cleanup:
romanba93eac2023-07-18 14:36:48 +02002228 if (is_ch(node)) {
2229 /* UNLOCK */
2230 nc_ch_client_unlock(ch_client);
2231 }
roman5cbb6532023-06-22 12:53:17 +02002232 return ret;
2233}
2234
roman5cbb6532023-06-22 12:53:17 +02002235/* leaf */
2236static int
2237nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op)
2238{
2239 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02002240 struct nc_hostkey *hostkey;
romanba93eac2023-07-18 14:36:48 +02002241 struct nc_ch_client *ch_client;
roman5cbb6532023-06-22 12:53:17 +02002242
2243 assert(!strcmp(LYD_NAME(node), "keystore-reference"));
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)) {
roman6430c152023-10-12 11:28:47 +02002247 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002248 return 1;
2249 }
2250
roman4cb8bb12023-06-29 09:16:46 +02002251 if (is_ssh(node) && equal_parent_name(node, 3, "server-identity")) {
2252 if (nc_server_config_get_hostkey(node, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02002253 ret = 1;
2254 goto cleanup;
2255 }
2256
2257 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2258 /* set to keystore */
2259 hostkey->store = NC_STORE_KEYSTORE;
2260
roman6430c152023-10-12 11:28:47 +02002261 free(hostkey->ks_ref);
romandd019a92023-09-14 10:17:07 +02002262 hostkey->ks_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002263 NC_CHECK_ERRMEM_GOTO(!hostkey->ks_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002264 } else if (op == NC_OP_DELETE) {
2265 free(hostkey->ks_ref);
roman5cbb6532023-06-22 12:53:17 +02002266 hostkey->ks_ref = NULL;
2267 }
roman3f9b65c2023-06-05 14:26:58 +02002268 }
romanc1d2b092023-02-02 08:58:27 +01002269
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
roman6430c152023-10-12 11:28:47 +02002279nc_server_config_create_auth_client(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01002280{
romanf02273a2023-05-25 09:44:11 +02002281 node = lyd_child(node);
2282 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01002283
romanf02273a2023-05-25 09:44:11 +02002284 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 +01002285}
2286
2287/* list */
2288static int
romane028ef92023-02-24 16:33:08 +01002289nc_server_config_user(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002290{
roman5cbb6532023-06-22 12:53:17 +02002291 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002292 struct nc_auth_client *auth_client;
roman4cb8bb12023-06-29 09:16:46 +02002293 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002294 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002295
2296 assert(!strcmp(LYD_NAME(node), "user"));
2297
romanba93eac2023-07-18 14:36:48 +02002298 /* LOCK */
2299 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002300 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002301 return 1;
2302 }
2303
roman4cb8bb12023-06-29 09:16:46 +02002304 if (nc_server_config_get_ssh_opts(node, &opts)) {
2305 ret = 1;
2306 goto cleanup;
2307 }
2308
2309 if (op == NC_OP_CREATE) {
roman6430c152023-10-12 11:28:47 +02002310 ret = nc_server_config_create_auth_client(node, opts);
roman4cb8bb12023-06-29 09:16:46 +02002311 if (ret) {
2312 goto cleanup;
2313 }
2314 } else if (op == NC_OP_DELETE) {
2315 if (nc_server_config_get_auth_client(node, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002316 ret = 1;
2317 goto cleanup;
2318 }
2319
roman4cb8bb12023-06-29 09:16:46 +02002320 nc_server_config_del_auth_client(opts, auth_client);
romanc1d2b092023-02-02 08:58:27 +01002321 }
2322
2323cleanup:
romanba93eac2023-07-18 14:36:48 +02002324 if (is_ch(node)) {
2325 /* UNLOCK */
2326 nc_ch_client_unlock(ch_client);
2327 }
romanc1d2b092023-02-02 08:58:27 +01002328 return ret;
2329}
2330
2331static int
romane028ef92023-02-24 16:33:08 +01002332nc_server_config_auth_attempts(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002333{
romanc1d2b092023-02-02 08:58:27 +01002334 int ret = 0;
roman4cb8bb12023-06-29 09:16:46 +02002335 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002336 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002337
2338 assert(!strcmp(LYD_NAME(node), "auth-attempts"));
2339
romanba93eac2023-07-18 14:36:48 +02002340 /* LOCK */
2341 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002342 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002343 return 1;
2344 }
2345
roman4cb8bb12023-06-29 09:16:46 +02002346 if (nc_server_config_get_ssh_opts(node, &opts)) {
2347 ret = 1;
2348 goto cleanup;
2349 }
romanc1d2b092023-02-02 08:58:27 +01002350
roman4cb8bb12023-06-29 09:16:46 +02002351 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02002352 opts->auth_attempts = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01002353 }
2354
2355cleanup:
romanba93eac2023-07-18 14:36:48 +02002356 if (is_ch(node)) {
2357 /* UNLOCK */
2358 nc_ch_client_unlock(ch_client);
2359 }
romanc1d2b092023-02-02 08:58:27 +01002360 return ret;
2361}
2362
2363static int
romane028ef92023-02-24 16:33:08 +01002364nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002365{
romanc1d2b092023-02-02 08:58:27 +01002366 int ret = 0;
roman4cb8bb12023-06-29 09:16:46 +02002367 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002368 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002369
2370 assert(!strcmp(LYD_NAME(node), "auth-timeout"));
2371
romanba93eac2023-07-18 14:36:48 +02002372 /* LOCK */
2373 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002374 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002375 return 1;
2376 }
2377
roman4cb8bb12023-06-29 09:16:46 +02002378 if (nc_server_config_get_ssh_opts(node, &opts)) {
2379 ret = 1;
2380 goto cleanup;
2381 }
romanc1d2b092023-02-02 08:58:27 +01002382
roman4cb8bb12023-06-29 09:16:46 +02002383 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02002384 opts->auth_timeout = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01002385 }
2386
2387cleanup:
romanba93eac2023-07-18 14:36:48 +02002388 if (is_ch(node)) {
2389 /* UNLOCK */
2390 nc_ch_client_unlock(ch_client);
2391 }
romanc1d2b092023-02-02 08:58:27 +01002392 return ret;
2393}
2394
romanc1d2b092023-02-02 08:58:27 +01002395/* leaf */
2396static int
romane028ef92023-02-24 16:33:08 +01002397nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002398{
romanc1d2b092023-02-02 08:58:27 +01002399 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002400 struct nc_auth_client *auth_client;
romanba93eac2023-07-18 14:36:48 +02002401 struct nc_ch_client *ch_client;
roman6430c152023-10-12 11:28:47 +02002402 struct nc_server_tls_opts *opts;
2403 struct nc_cert_grouping *certs_grp;
romanc1d2b092023-02-02 08:58:27 +01002404
2405 assert(!strcmp(LYD_NAME(node), "truststore-reference"));
2406
romanba93eac2023-07-18 14:36:48 +02002407 /* LOCK */
2408 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002409 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002410 return 1;
2411 }
2412
roman4cb8bb12023-06-29 09:16:46 +02002413 if (is_ssh(node) && equal_parent_name(node, 1, "public-keys")) {
2414 if (nc_server_config_get_auth_client(node, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002415 ret = 1;
2416 goto cleanup;
2417 }
2418
2419 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02002420 /* set to truststore */
roman874fed12023-05-25 10:20:01 +02002421 auth_client->store = NC_STORE_TRUSTSTORE;
romanf02273a2023-05-25 09:44:11 +02002422
roman6430c152023-10-12 11:28:47 +02002423 free(auth_client->ts_ref);
2424 auth_client->ts_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002425 NC_CHECK_ERRMEM_GOTO(!auth_client->ts_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002426 } else if (op == NC_OP_DELETE) {
2427 free(auth_client->ts_ref);
romand57b3722023-04-05 11:26:25 +02002428 auth_client->ts_ref = NULL;
romanc1d2b092023-02-02 08:58:27 +01002429 }
roman6430c152023-10-12 11:28:47 +02002430 } else if (is_tls(node) && (equal_parent_name(node, 1, "ca-certs") || equal_parent_name(node, 1, "ee-certs"))) {
2431 /* ee-certs or ca-certs */
2432 if (nc_server_config_get_tls_opts(node, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002433 ret = 1;
2434 goto cleanup;
2435 }
2436
roman6430c152023-10-12 11:28:47 +02002437 if (equal_parent_name(node, 1, "ca-certs")) {
2438 certs_grp = &opts->ca_certs;
roman3f9b65c2023-06-05 14:26:58 +02002439 } else {
roman6430c152023-10-12 11:28:47 +02002440 certs_grp = &opts->ee_certs;
roman4cb8bb12023-06-29 09:16:46 +02002441 }
2442
roman3f9b65c2023-06-05 14:26:58 +02002443 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2444 /* set to truststore */
roman6430c152023-10-12 11:28:47 +02002445 certs_grp->store = NC_STORE_TRUSTSTORE;
roman3f9b65c2023-06-05 14:26:58 +02002446
roman6430c152023-10-12 11:28:47 +02002447 free(certs_grp->ts_ref);
2448 certs_grp->ts_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002449 NC_CHECK_ERRMEM_GOTO(!certs_grp->ts_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002450 } else if (op == NC_OP_DELETE) {
2451 free(certs_grp->ts_ref);
2452 certs_grp->ts_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002453 }
2454 }
romanc1d2b092023-02-02 08:58:27 +01002455
2456cleanup:
romanba93eac2023-07-18 14:36:48 +02002457 if (is_ch(node)) {
2458 /* UNLOCK */
2459 nc_ch_client_unlock(ch_client);
2460 }
romanc1d2b092023-02-02 08:58:27 +01002461 return ret;
2462}
2463
romanc1d2b092023-02-02 08:58:27 +01002464/* leaf */
2465static int
romane028ef92023-02-24 16:33:08 +01002466nc_server_config_password(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002467{
roman5cbb6532023-06-22 12:53:17 +02002468 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002469 struct nc_auth_client *auth_client;
romanba93eac2023-07-18 14:36:48 +02002470 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002471
2472 assert(!strcmp(LYD_NAME(node), "password"));
2473
romanba93eac2023-07-18 14:36:48 +02002474 /* LOCK */
2475 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002476 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002477 return 1;
2478 }
2479
roman4cb8bb12023-06-29 09:16:46 +02002480 if (nc_server_config_get_auth_client(node, &auth_client)) {
2481 ret = 1;
2482 goto cleanup;
2483 }
2484
2485 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002486 free(auth_client->password);
2487 auth_client->password = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002488 NC_CHECK_ERRMEM_GOTO(!auth_client->password, ret = 1, cleanup);
roman4cb8bb12023-06-29 09:16:46 +02002489 } else {
roman6430c152023-10-12 11:28:47 +02002490 free(auth_client->password);
2491 auth_client->password = NULL;
romanc1d2b092023-02-02 08:58:27 +01002492 }
2493
2494cleanup:
romanba93eac2023-07-18 14:36:48 +02002495 if (is_ch(node)) {
2496 /* UNLOCK */
2497 nc_ch_client_unlock(ch_client);
2498 }
romanc1d2b092023-02-02 08:58:27 +01002499 return ret;
2500}
2501
2502static int
roman808f3f62023-11-23 16:01:04 +01002503nc_server_config_kb_int(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002504{
roman5cbb6532023-06-22 12:53:17 +02002505 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002506 struct nc_auth_client *auth_client;
roman808f3f62023-11-23 16:01:04 +01002507 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002508
roman808f3f62023-11-23 16:01:04 +01002509 assert(!strcmp(LYD_NAME(node), "keyboard-interactive"));
romanc1d2b092023-02-02 08:58:27 +01002510
romanba93eac2023-07-18 14:36:48 +02002511 /* LOCK */
2512 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002513 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002514 return 1;
2515 }
2516
roman4cb8bb12023-06-29 09:16:46 +02002517 if (nc_server_config_get_auth_client(node, &auth_client)) {
2518 ret = 1;
2519 goto cleanup;
2520 }
2521
roman808f3f62023-11-23 16:01:04 +01002522 if (op == NC_OP_CREATE) {
2523 auth_client->kb_int_enabled = 1;
roman4cb8bb12023-06-29 09:16:46 +02002524 } else {
roman808f3f62023-11-23 16:01:04 +01002525 auth_client->kb_int_enabled = 0;
romanc1d2b092023-02-02 08:58:27 +01002526 }
2527
2528cleanup:
romanba93eac2023-07-18 14:36:48 +02002529 if (is_ch(node)) {
2530 /* UNLOCK */
2531 nc_ch_client_unlock(ch_client);
2532 }
romanc1d2b092023-02-02 08:58:27 +01002533 return ret;
2534}
2535
2536/* leaf */
2537static int
romane028ef92023-02-24 16:33:08 +01002538nc_server_config_none(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002539{
roman5cbb6532023-06-22 12:53:17 +02002540 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002541 struct nc_auth_client *auth_client;
romanba93eac2023-07-18 14:36:48 +02002542 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002543
2544 assert(!strcmp(LYD_NAME(node), "none"));
2545
romanba93eac2023-07-18 14:36:48 +02002546 /* LOCK */
2547 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002548 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002549 return 1;
2550 }
2551
roman4cb8bb12023-06-29 09:16:46 +02002552 if (nc_server_config_get_auth_client(node, &auth_client)) {
2553 ret = 1;
2554 goto cleanup;
2555 }
romanc1d2b092023-02-02 08:58:27 +01002556
roman4cb8bb12023-06-29 09:16:46 +02002557 if (op == NC_OP_CREATE) {
roman808f3f62023-11-23 16:01:04 +01002558 auth_client->none_enabled = 1;
roman4cb8bb12023-06-29 09:16:46 +02002559 } else {
roman808f3f62023-11-23 16:01:04 +01002560 auth_client->none_enabled = 0;
romanc1d2b092023-02-02 08:58:27 +01002561 }
2562
2563cleanup:
romanba93eac2023-07-18 14:36:48 +02002564 if (is_ch(node)) {
2565 /* UNLOCK */
2566 nc_ch_client_unlock(ch_client);
2567 }
romanc1d2b092023-02-02 08:58:27 +01002568 return ret;
2569}
2570
2571static int
romanc135c6d2023-10-25 13:32:30 +02002572nc_server_config_delete_substring(const char *haystack, const char *needle, const char delim)
2573{
2574 size_t needle_len = strlen(needle);
2575 char *substr;
2576 int substr_found = 0, ret = 0;
2577
2578 while ((substr = strstr(haystack, needle))) {
2579 /* iterate over all the substrings */
2580 if (((substr == haystack) && (*(substr + needle_len) == delim)) ||
2581 ((substr != haystack) && (*(substr - 1) == delim) && (*(substr + needle_len) == delim))) {
2582 /* either the first element of the string or somewhere in the middle */
2583 memmove(substr, substr + needle_len + 1, strlen(substr + needle_len + 1));
2584 substr_found = 1;
2585 break;
2586 } else if ((*(substr - 1) == delim) && (*(substr + needle_len) == '\0')) {
2587 /* the last element of the string */
2588 *(substr - 1) = '\0';
2589 substr_found = 1;
2590 break;
2591 }
2592 haystack = substr + 1;
2593 }
2594 if (!substr_found) {
2595 ret = 1;
2596 }
2597
2598 return ret;
2599}
2600
2601static int
romana6bf6ab2023-05-26 13:26:02 +02002602nc_server_config_transport_params(const char *algorithm, char **alg_store, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002603{
romanc135c6d2023-10-25 13:32:30 +02002604 int ret = 0;
2605 char *alg = NULL;
romana6bf6ab2023-05-26 13:26:02 +02002606
2607 if (!strncmp(algorithm, "openssh-", 8)) {
2608 /* if the name starts with openssh, convert it to it's original libssh accepted form */
roman3a95bb22023-10-26 11:07:17 +02002609 ret = asprintf(&alg, "%s@openssh.com", algorithm + 8);
2610 NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; alg = NULL, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002611 } else if (!strncmp(algorithm, "libssh-", 7)) {
2612 /* if the name starts with libssh, convert it to it's original libssh accepted form */
roman3a95bb22023-10-26 11:07:17 +02002613 ret = asprintf(&alg, "%s@libssh.org", algorithm + 7);
2614 NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; alg = NULL, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002615 } else {
2616 alg = strdup(algorithm);
roman3a95bb22023-10-26 11:07:17 +02002617 NC_CHECK_ERRMEM_GOTO(!alg, ret = 1, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002618 }
2619
romanc1d2b092023-02-02 08:58:27 +01002620 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2621 if (!*alg_store) {
2622 /* first call */
2623 *alg_store = strdup(alg);
roman3a95bb22023-10-26 11:07:17 +02002624 NC_CHECK_ERRMEM_GOTO(!*alg_store, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01002625 } else {
2626 /* +1 because of ',' between algorithms */
roman3a95bb22023-10-26 11:07:17 +02002627 *alg_store = nc_realloc(*alg_store, strlen(*alg_store) + strlen(alg) + 1 + 1);
2628 NC_CHECK_ERRMEM_GOTO(!*alg_store, ret = 1, cleanup);
roman08f67f42023-06-08 13:51:54 +02002629 strcat(*alg_store, ",");
2630 strcat(*alg_store, alg);
romanc1d2b092023-02-02 08:58:27 +01002631 }
2632 } else {
2633 /* delete */
romanc135c6d2023-10-25 13:32:30 +02002634 ret = nc_server_config_delete_substring(*alg_store, alg, ',');
2635 if (ret) {
romanc1d2b092023-02-02 08:58:27 +01002636 ERR(NULL, "Unable to delete an algorithm (%s), which was not previously added.", alg);
romanc135c6d2023-10-25 13:32:30 +02002637 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002638 }
2639 }
2640
2641cleanup:
romana6bf6ab2023-05-26 13:26:02 +02002642 free(alg);
romanc1d2b092023-02-02 08:58:27 +01002643 return ret;
2644}
2645
2646/* leaf-list */
2647static int
romane028ef92023-02-24 16:33:08 +01002648nc_server_config_host_key_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002649{
roman5cbb6532023-06-22 12:53:17 +02002650 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002651 const char *alg;
2652 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002653 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002654 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002655
roman5cbb6532023-06-22 12:53:17 +02002656 assert(!strcmp(LYD_NAME(node), "host-key-alg"));
romanc1d2b092023-02-02 08:58:27 +01002657
romanba93eac2023-07-18 14:36:48 +02002658 /* LOCK */
2659 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002660 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002661 return 1;
2662 }
2663
roman4cb8bb12023-06-29 09:16:46 +02002664 if (nc_server_config_get_ssh_opts(node, &opts)) {
2665 ret = 1;
2666 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002667 }
2668
roman5cbb6532023-06-22 12:53:17 +02002669 /* get the algorithm name and compare it with algs supported by libssh */
2670 alg = ((struct lyd_node_term *)node)->value.ident->name;
romanc1d2b092023-02-02 08:58:27 +01002671 i = 0;
2672 while (supported_hostkey_algs[i]) {
2673 if (!strcmp(supported_hostkey_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002674 if (nc_server_config_transport_params(alg, &opts->hostkey_algs, op)) {
2675 ret = 1;
2676 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002677 }
2678 break;
2679 }
2680 i++;
2681 }
2682 if (!supported_hostkey_algs[i]) {
2683 /* algorithm not supported */
2684 ERR(NULL, "Public key algorithm (%s) not supported by libssh.", alg);
2685 ret = 1;
2686 }
2687
2688cleanup:
romanba93eac2023-07-18 14:36:48 +02002689 if (is_ch(node)) {
2690 /* UNLOCK */
2691 nc_ch_client_unlock(ch_client);
2692 }
romanc1d2b092023-02-02 08:58:27 +01002693 return ret;
2694}
2695
2696/* leaf-list */
2697static int
romane028ef92023-02-24 16:33:08 +01002698nc_server_config_kex_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002699{
roman5cbb6532023-06-22 12:53:17 +02002700 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002701 const char *alg;
2702 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002703 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002704 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002705
roman5cbb6532023-06-22 12:53:17 +02002706 assert(!strcmp(LYD_NAME(node), "key-exchange-alg"));
romanc1d2b092023-02-02 08:58:27 +01002707
romanba93eac2023-07-18 14:36:48 +02002708 /* LOCK */
2709 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002710 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002711 return 1;
2712 }
2713
roman4cb8bb12023-06-29 09:16:46 +02002714 if (nc_server_config_get_ssh_opts(node, &opts)) {
2715 ret = 1;
2716 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002717 }
2718
roman5cbb6532023-06-22 12:53:17 +02002719 /* get the algorithm name and compare it with algs supported by libssh */
2720 alg = ((struct lyd_node_term *)node)->value.ident->name;
romanc1d2b092023-02-02 08:58:27 +01002721 i = 0;
2722 while (supported_kex_algs[i]) {
2723 if (!strcmp(supported_kex_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002724 if (nc_server_config_transport_params(alg, &opts->kex_algs, op)) {
2725 ret = 1;
2726 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002727 }
2728 break;
2729 }
2730 i++;
2731 }
2732 if (!supported_kex_algs[i]) {
2733 /* algorithm not supported */
2734 ERR(NULL, "Key exchange algorithm (%s) not supported by libssh.", alg);
2735 ret = 1;
2736 }
2737
2738cleanup:
romanba93eac2023-07-18 14:36:48 +02002739 if (is_ch(node)) {
2740 /* UNLOCK */
2741 nc_ch_client_unlock(ch_client);
2742 }
romanc1d2b092023-02-02 08:58:27 +01002743 return ret;
2744}
2745
2746/* leaf-list */
2747static int
romane028ef92023-02-24 16:33:08 +01002748nc_server_config_encryption_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002749{
roman5cbb6532023-06-22 12:53:17 +02002750 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002751 const char *alg;
2752 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002753 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002754 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002755
roman5cbb6532023-06-22 12:53:17 +02002756 assert(!strcmp(LYD_NAME(node), "encryption-alg"));
romanc1d2b092023-02-02 08:58:27 +01002757
romanba93eac2023-07-18 14:36:48 +02002758 /* LOCK */
2759 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002760 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002761 return 1;
2762 }
2763
roman4cb8bb12023-06-29 09:16:46 +02002764 if (nc_server_config_get_ssh_opts(node, &opts)) {
2765 ret = 1;
2766 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002767 }
2768
roman5cbb6532023-06-22 12:53:17 +02002769 /* get the algorithm name and compare it with algs supported by libssh */
2770 alg = ((struct lyd_node_term *)node)->value.ident->name;
romanc1d2b092023-02-02 08:58:27 +01002771 i = 0;
2772 while (supported_encryption_algs[i]) {
2773 if (!strcmp(supported_encryption_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002774 if (nc_server_config_transport_params(alg, &opts->encryption_algs, op)) {
2775 ret = 1;
2776 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002777 }
2778 break;
2779 }
2780 i++;
2781 }
2782 if (!supported_encryption_algs[i]) {
2783 /* algorithm not supported */
2784 ERR(NULL, "Encryption algorithm (%s) not supported by libssh.", alg);
2785 ret = 1;
2786 }
2787
2788cleanup:
romanba93eac2023-07-18 14:36:48 +02002789 if (is_ch(node)) {
2790 /* UNLOCK */
2791 nc_ch_client_unlock(ch_client);
2792 }
romanc1d2b092023-02-02 08:58:27 +01002793 return ret;
2794}
2795
2796/* leaf-list */
2797static int
romane028ef92023-02-24 16:33:08 +01002798nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002799{
roman5cbb6532023-06-22 12:53:17 +02002800 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002801 const char *alg;
2802 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002803 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002804 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002805
roman5cbb6532023-06-22 12:53:17 +02002806 assert(!strcmp(LYD_NAME(node), "mac-alg"));
romanc1d2b092023-02-02 08:58:27 +01002807
romanba93eac2023-07-18 14:36:48 +02002808 /* LOCK */
2809 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002810 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002811 return 1;
2812 }
2813
roman4cb8bb12023-06-29 09:16:46 +02002814 if (nc_server_config_get_ssh_opts(node, &opts)) {
2815 ret = 1;
2816 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002817 }
2818
roman5cbb6532023-06-22 12:53:17 +02002819 /* get the algorithm name and compare it with algs supported by libssh */
2820 alg = ((struct lyd_node_term *)node)->value.ident->name;
romanc1d2b092023-02-02 08:58:27 +01002821 i = 0;
2822 while (supported_mac_algs[i]) {
2823 if (!strcmp(supported_mac_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002824 if (nc_server_config_transport_params(alg, &opts->mac_algs, op)) {
2825 ret = 1;
2826 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002827 }
2828 break;
2829 }
2830 i++;
2831 }
2832 if (!supported_mac_algs[i]) {
2833 /* algorithm not supported */
2834 ERR(NULL, "MAC algorithm (%s) not supported by libssh.", alg);
2835 ret = 1;
2836 }
2837
2838cleanup:
romanba93eac2023-07-18 14:36:48 +02002839 if (is_ch(node)) {
2840 /* UNLOCK */
2841 nc_ch_client_unlock(ch_client);
2842 }
romanc1d2b092023-02-02 08:58:27 +01002843 return ret;
2844}
2845
roman2eab4742023-06-06 10:00:26 +02002846#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02002847
romanc1d2b092023-02-02 08:58:27 +01002848static int
roman874fed12023-05-25 10:20:01 +02002849nc_server_config_create_unix_socket(struct nc_endpt *endpt)
roman83683fb2023-02-24 09:15:23 +01002850{
2851 endpt->ti = NC_TI_UNIX;
2852 endpt->opts.unixsock = calloc(1, sizeof *endpt->opts.unixsock);
roman3a95bb22023-10-26 11:07:17 +02002853 NC_CHECK_ERRMEM_RET(!endpt->opts.unixsock, 1);
roman83683fb2023-02-24 09:15:23 +01002854
2855 /* set default values */
2856 endpt->opts.unixsock->mode = -1;
2857 endpt->opts.unixsock->uid = -1;
2858 endpt->opts.unixsock->gid = -1;
2859
2860 return 0;
2861}
2862
2863static int
romane028ef92023-02-24 16:33:08 +01002864nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op)
roman83683fb2023-02-24 09:15:23 +01002865{
2866 int ret = 0;
roman84fe3252023-10-25 11:28:32 +02002867 uint32_t log_options = 0;
roman83683fb2023-02-24 09:15:23 +01002868 struct nc_endpt *endpt;
2869 struct nc_bind *bind;
2870 struct nc_server_unix_opts *opts;
2871 struct lyd_node *data = NULL;
2872
2873 assert(!strcmp(LYD_NAME(node), "unix-socket"));
2874
romanf02273a2023-05-25 09:44:11 +02002875 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
roman83683fb2023-02-24 09:15:23 +01002876 ret = 1;
2877 goto cleanup;
2878 }
2879
2880 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +02002881 if (nc_server_config_create_unix_socket(endpt)) {
roman83683fb2023-02-24 09:15:23 +01002882 ret = 1;
2883 goto cleanup;
2884 }
2885
2886 opts = endpt->opts.unixsock;
2887
2888 lyd_find_path(node, "path", 0, &data);
2889 assert(data);
2890
2891 opts->address = strdup(lyd_get_value(data));
2892 bind->address = strdup(lyd_get_value(data));
roman3a95bb22023-10-26 11:07:17 +02002893 NC_CHECK_ERRMEM_GOTO(!opts->address || !bind->address, ret = 1, cleanup);
roman83683fb2023-02-24 09:15:23 +01002894
2895 /* silently search for non-mandatory parameters */
roman84fe3252023-10-25 11:28:32 +02002896 ly_temp_log_options(&log_options);
roman83683fb2023-02-24 09:15:23 +01002897 ret = lyd_find_path(node, "mode", 0, &data);
2898 if (!ret) {
2899 opts->mode = strtol(lyd_get_value(data), NULL, 8);
2900 }
2901
2902 ret = lyd_find_path(node, "uid", 0, &data);
2903 if (!ret) {
2904 opts->uid = strtol(lyd_get_value(data), NULL, 10);
2905 }
2906
2907 ret = lyd_find_path(node, "gid", 0, &data);
2908 if (!ret) {
2909 opts->gid = strtol(lyd_get_value(data), NULL, 10);
2910 }
2911
2912 /* reset the logging options */
roman84fe3252023-10-25 11:28:32 +02002913 ly_temp_log_options(NULL);
roman83683fb2023-02-24 09:15:23 +01002914
2915 ret = nc_server_config_set_address_port(endpt, bind, NULL, 0);
2916 if (ret) {
2917 goto cleanup;
2918 }
2919 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02002920 nc_server_config_del_unix_socket_opts(bind, endpt->opts.unixsock);
roman83683fb2023-02-24 09:15:23 +01002921 }
2922
2923cleanup:
2924 return ret;
2925}
2926
roman2eab4742023-06-06 10:00:26 +02002927#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02002928
roman78df0fa2023-11-02 10:33:57 +01002929static int
2930nc_server_config_check_endpt_reference_cycle(struct nc_endpt *original, struct nc_endpt *next)
2931{
2932 if (!next->referenced_endpt_name) {
2933 /* no further reference -> no cycle */
2934 return 0;
2935 }
2936
2937 if (!strcmp(original->name, next->referenced_endpt_name)) {
2938 /* found cycle */
2939 return 1;
2940 } else {
2941 if (nc_server_get_referenced_endpt(next->referenced_endpt_name, &next)) {
2942 /* referenced endpoint does not exist */
2943 return 1;
2944 }
2945
2946 /* continue further */
2947 return nc_server_config_check_endpt_reference_cycle(original, next);
2948 }
2949}
2950
roman0bbc19c2023-05-26 09:59:09 +02002951/**
roman78df0fa2023-11-02 10:33:57 +01002952 * @brief Set all endpoint references.
roman0bbc19c2023-05-26 09:59:09 +02002953 *
2954 * @return 0 on success, 1 on error.
2955 */
2956static int
roman78df0fa2023-11-02 10:33:57 +01002957nc_server_config_check_endpt_references(void)
roman0bbc19c2023-05-26 09:59:09 +02002958{
2959 uint16_t i, j;
roman78df0fa2023-11-02 10:33:57 +01002960 struct nc_endpt *referenced_endpt = NULL;
roman0bbc19c2023-05-26 09:59:09 +02002961
roman78df0fa2023-11-02 10:33:57 +01002962 /* first do listen endpoints */
roman0bbc19c2023-05-26 09:59:09 +02002963 for (i = 0; i < server_opts.endpt_count; i++) {
roman6430c152023-10-12 11:28:47 +02002964 /* go through all the endpoints */
roman0bbc19c2023-05-26 09:59:09 +02002965 if (server_opts.endpts[i].referenced_endpt_name) {
roman78df0fa2023-11-02 10:33:57 +01002966 /* get referenced endpt */
2967 if (nc_server_get_referenced_endpt(server_opts.endpts[i].referenced_endpt_name, &referenced_endpt)) {
2968 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" does not exist.",
roman0bbc19c2023-05-26 09:59:09 +02002969 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2970 return 1;
2971 }
roman78df0fa2023-11-02 10:33:57 +01002972
2973 /* check if the endpoint references itself */
2974 if (&server_opts.endpts[i] == referenced_endpt) {
2975 ERR(NULL, "Endpoint \"%s\" references itself.", server_opts.endpts[i].name);
2976 return 1;
2977 }
2978
2979 /* check transport */
2980 if ((server_opts.endpts[i].ti != referenced_endpt->ti)) {
2981 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" has different transport type.",
2982 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2983 return 1;
2984 } else if ((referenced_endpt->ti != NC_TI_LIBSSH) && (referenced_endpt->ti != NC_TI_OPENSSL)) {
2985 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" has unsupported transport type.",
2986 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2987 return 1;
2988 }
2989
2990 /* check cyclic reference */
2991 if (nc_server_config_check_endpt_reference_cycle(&server_opts.endpts[i], referenced_endpt)) {
2992 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" creates a cycle.",
2993 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2994 return 1;
2995 }
2996
2997 /* all went well, assign the name to the opts, so we can access it for auth */
2998 if (server_opts.endpts[i].ti == NC_TI_LIBSSH) {
2999 server_opts.endpts[i].opts.ssh->referenced_endpt_name = referenced_endpt->name;
3000 } else {
3001 server_opts.endpts[i].opts.tls->referenced_endpt_name = referenced_endpt->name;
3002 }
roman0bbc19c2023-05-26 09:59:09 +02003003 }
3004 }
3005
roman78df0fa2023-11-02 10:33:57 +01003006 /* now check all the call home endpoints */
3007 /* LOCK */
3008 pthread_rwlock_rdlock(&server_opts.ch_client_lock);
3009 for (i = 0; i < server_opts.ch_client_count; i++) {
3010 /* LOCK */
3011 pthread_mutex_lock(&server_opts.ch_clients[i].lock);
3012 for (j = 0; j < server_opts.ch_clients[i].ch_endpt_count; j++) {
3013 if (server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name) {
3014 /* get referenced endpt */
3015 if (nc_server_get_referenced_endpt(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, &referenced_endpt)) {
3016 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" does not exist.",
3017 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
3018 goto ch_fail;
3019 }
3020
3021 /* check transport */
3022 if (server_opts.ch_clients[i].ch_endpts[j].ti != referenced_endpt->ti) {
3023 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" has different transport type.",
3024 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
3025 goto ch_fail;
3026 } else if ((referenced_endpt->ti != NC_TI_LIBSSH) && (referenced_endpt->ti != NC_TI_OPENSSL)) {
3027 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" has unsupported transport type.",
3028 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
3029 goto ch_fail;
3030 }
3031
3032 /* check cyclic reference */
3033 if (nc_server_config_check_endpt_reference_cycle(referenced_endpt, referenced_endpt)) {
3034 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" creates a cycle.",
3035 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
3036 goto ch_fail;
3037 }
3038
3039 /* all went well, assign the name to the opts, so we can access it for auth */
3040 if (server_opts.ch_clients[i].ch_endpts[j].ti == NC_TI_LIBSSH) {
3041 server_opts.ch_clients[i].ch_endpts[j].opts.ssh->referenced_endpt_name = referenced_endpt->name;
3042 } else {
3043 server_opts.ch_clients[i].ch_endpts[j].opts.tls->referenced_endpt_name = referenced_endpt->name;
3044 }
3045 }
3046 }
3047 /* UNLOCK */
3048 pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
3049 }
3050
3051 /* UNLOCK */
3052 pthread_rwlock_unlock(&server_opts.ch_client_lock);
roman0bbc19c2023-05-26 09:59:09 +02003053 return 0;
roman78df0fa2023-11-02 10:33:57 +01003054
3055ch_fail:
3056 /* UNLOCK */
3057 pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
3058 /* UNLOCK */
3059 pthread_rwlock_unlock(&server_opts.ch_client_lock);
roman96c27f92023-11-02 11:09:46 +01003060 return 1;
roman0bbc19c2023-05-26 09:59:09 +02003061}
3062
3063static int
roman78df0fa2023-11-02 10:33:57 +01003064nc_server_config_endpoint_reference(const struct lyd_node *node, NC_OPERATION op)
roman0bbc19c2023-05-26 09:59:09 +02003065{
3066 int ret = 0;
roman78df0fa2023-11-02 10:33:57 +01003067 struct nc_endpt *endpt = NULL;
3068 struct nc_ch_client *ch_client;
3069 struct nc_ch_endpt *ch_endpt = NULL;
3070 struct nc_server_ssh_opts *ssh = NULL;
3071 struct nc_server_tls_opts *tls = NULL;
roman0bbc19c2023-05-26 09:59:09 +02003072
roman78df0fa2023-11-02 10:33:57 +01003073 assert(!strcmp(LYD_NAME(node), "endpoint-reference"));
roman0bbc19c2023-05-26 09:59:09 +02003074
roman78df0fa2023-11-02 10:33:57 +01003075 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
3076 /* to avoid unlock on fail */
3077 return 1;
3078 }
3079
3080 /* get endpt */
3081 if (is_listen(node)) {
3082 ret = nc_server_config_get_endpt(node, &endpt, NULL);
3083 } else {
3084 ret = nc_server_config_get_ch_endpt(node, &ch_endpt);
3085 }
roman0bbc19c2023-05-26 09:59:09 +02003086 if (ret) {
3087 goto cleanup;
3088 }
3089
3090 if (op == NC_OP_DELETE) {
roman78df0fa2023-11-02 10:33:57 +01003091 if (endpt) {
romanb7bfa652023-11-09 12:36:35 +01003092 /* listen */
roman78df0fa2023-11-02 10:33:57 +01003093 free(endpt->referenced_endpt_name);
3094 endpt->referenced_endpt_name = NULL;
roman2e797ef2023-06-19 10:47:49 +02003095 } else {
romanb7bfa652023-11-09 12:36:35 +01003096 /* call home */
roman78df0fa2023-11-02 10:33:57 +01003097 free(ch_endpt->referenced_endpt_name);
3098 ch_endpt->referenced_endpt_name = NULL;
roman2e797ef2023-06-19 10:47:49 +02003099 }
roman78df0fa2023-11-02 10:33:57 +01003100 if (is_ssh(node)) {
3101 if (nc_server_config_get_ssh_opts(node, &ssh)) {
3102 ret = 1;
3103 goto cleanup;
3104 }
roman96c27f92023-11-02 11:09:46 +01003105
roman78df0fa2023-11-02 10:33:57 +01003106 ssh->referenced_endpt_name = NULL;
3107 } else {
3108 if (nc_server_config_get_tls_opts(node, &tls)) {
3109 ret = 1;
3110 goto cleanup;
3111 }
roman0bbc19c2023-05-26 09:59:09 +02003112
roman78df0fa2023-11-02 10:33:57 +01003113 tls->referenced_endpt_name = NULL;
roman0bbc19c2023-05-26 09:59:09 +02003114 }
roman0bbc19c2023-05-26 09:59:09 +02003115
roman0bbc19c2023-05-26 09:59:09 +02003116 goto cleanup;
roman2e797ef2023-06-19 10:47:49 +02003117 } else {
roman78df0fa2023-11-02 10:33:57 +01003118 /* just set the name, check it once configuring of all nodes is done */
3119 if (endpt) {
3120 free(endpt->referenced_endpt_name);
3121 endpt->referenced_endpt_name = strdup(lyd_get_value(node));
3122 NC_CHECK_ERRMEM_GOTO(!endpt->referenced_endpt_name, ret = 1, cleanup);
3123 } else {
3124 free(ch_endpt->referenced_endpt_name);
3125 ch_endpt->referenced_endpt_name = strdup(lyd_get_value(node));
3126 NC_CHECK_ERRMEM_GOTO(!ch_endpt->referenced_endpt_name, ret = 1, cleanup);
3127 }
3128
3129 goto cleanup;
roman2e797ef2023-06-19 10:47:49 +02003130 }
roman0bbc19c2023-05-26 09:59:09 +02003131
3132cleanup:
roman78df0fa2023-11-02 10:33:57 +01003133 if (is_ch(node)) {
3134 /* UNLOCK */
3135 nc_ch_client_unlock(ch_client);
3136 }
3137
roman0bbc19c2023-05-26 09:59:09 +02003138 return ret;
3139}
3140
roman3f9b65c2023-06-05 14:26:58 +02003141static int
roman3f9b65c2023-06-05 14:26:58 +02003142nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op)
3143{
3144 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02003145 struct nc_certificate *cert;
romanb6f44032023-06-30 15:07:56 +02003146 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02003147 struct nc_ch_client *ch_client;
roman3f9b65c2023-06-05 14:26:58 +02003148
3149 assert(!strcmp(LYD_NAME(node), "cert-data"));
3150
romanba93eac2023-07-18 14:36:48 +02003151 /* LOCK */
3152 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003153 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003154 return 1;
3155 }
3156
romanb6f44032023-06-30 15:07:56 +02003157 if (equal_parent_name(node, 3, "server-identity")) {
3158 if (nc_server_config_get_tls_opts(node, &opts)) {
3159 ret = 1;
3160 goto cleanup;
3161 }
roman3f9b65c2023-06-05 14:26:58 +02003162
roman3f9b65c2023-06-05 14:26:58 +02003163 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003164 free(opts->cert_data);
3165 opts->cert_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003166 NC_CHECK_ERRMEM_GOTO(!opts->cert_data, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003167 }
roman6430c152023-10-12 11:28:47 +02003168 } else if (equal_parent_name(node, 3, "ca-certs") || equal_parent_name(node, 3, "ee-certs")) {
3169 if (nc_server_config_get_cert(node, &cert)) {
roman3f9b65c2023-06-05 14:26:58 +02003170 ret = 1;
3171 goto cleanup;
3172 }
3173
3174 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003175 free(cert->data);
3176 cert->data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003177 NC_CHECK_ERRMEM_GOTO(!cert->data, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003178 } else {
roman6430c152023-10-12 11:28:47 +02003179 free(cert->data);
3180 cert->data = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003181 }
3182 }
3183
3184cleanup:
romanba93eac2023-07-18 14:36:48 +02003185 if (is_ch(node)) {
3186 /* UNLOCK */
3187 nc_ch_client_unlock(ch_client);
3188 }
roman3f9b65c2023-06-05 14:26:58 +02003189 return ret;
3190}
3191
3192static int
roman3f9b65c2023-06-05 14:26:58 +02003193nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op)
3194{
3195 int ret = 0;
roman78df0fa2023-11-02 10:33:57 +01003196 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02003197 struct nc_ch_client *ch_client;
roman3f9b65c2023-06-05 14:26:58 +02003198
3199 assert(!strcmp(LYD_NAME(node), "asymmetric-key"));
3200
romanba93eac2023-07-18 14:36:48 +02003201 /* LOCK */
3202 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003203 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003204 return 1;
3205 }
3206
roman78df0fa2023-11-02 10:33:57 +01003207 if (nc_server_config_get_tls_opts(node, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02003208 ret = 1;
3209 goto cleanup;
3210 }
3211
3212 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
3213 /* set to keystore */
roman78df0fa2023-11-02 10:33:57 +01003214 opts->store = NC_STORE_KEYSTORE;
roman3f9b65c2023-06-05 14:26:58 +02003215
roman78df0fa2023-11-02 10:33:57 +01003216 free(opts->key_ref);
3217 opts->key_ref = strdup(lyd_get_value(node));
3218 NC_CHECK_ERRMEM_GOTO(!opts->key_ref, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003219 } else {
roman78df0fa2023-11-02 10:33:57 +01003220 free(opts->key_ref);
3221 opts->key_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003222 }
3223
3224cleanup:
romanba93eac2023-07-18 14:36:48 +02003225 if (is_ch(node)) {
3226 /* UNLOCK */
3227 nc_ch_client_unlock(ch_client);
3228 }
roman3f9b65c2023-06-05 14:26:58 +02003229 return ret;
3230}
3231
3232static int
roman3f9b65c2023-06-05 14:26:58 +02003233nc_server_config_create_ca_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
3234{
3235 assert(!strcmp(LYD_NAME(node), "certificate"));
3236
3237 node = lyd_child(node);
3238 assert(!strcmp(LYD_NAME(node), "name"));
3239
3240 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ca_certs.certs, sizeof *opts->ca_certs.certs, &opts->ca_certs.cert_count);
3241}
3242
3243static int
3244nc_server_config_create_ee_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
3245{
3246 assert(!strcmp(LYD_NAME(node), "certificate"));
3247
3248 node = lyd_child(node);
3249 assert(!strcmp(LYD_NAME(node), "name"));
3250
3251 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ee_certs.certs, sizeof *opts->ee_certs.certs, &opts->ee_certs.cert_count);
3252}
3253
3254static int
3255nc_server_config_certificate(const struct lyd_node *node, NC_OPERATION op)
3256{
3257 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003258 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02003259 struct nc_ch_client *ch_client;
roman6430c152023-10-12 11:28:47 +02003260 struct nc_certificate *cert;
roman3f9b65c2023-06-05 14:26:58 +02003261
3262 assert(!strcmp(LYD_NAME(node), "certificate"));
3263
romanba93eac2023-07-18 14:36:48 +02003264 /* LOCK */
3265 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003266 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003267 return 1;
3268 }
3269
romanb6f44032023-06-30 15:07:56 +02003270 if (nc_server_config_get_tls_opts(node, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02003271 ret = 1;
3272 goto cleanup;
3273 }
3274
romanb6f44032023-06-30 15:07:56 +02003275 if (equal_parent_name(node, 1, "keystore-reference")) {
3276 /* TLS server-identity */
roman3f9b65c2023-06-05 14:26:58 +02003277 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
3278 /* set to keystore */
romanb6f44032023-06-30 15:07:56 +02003279 opts->store = NC_STORE_KEYSTORE;
roman3f9b65c2023-06-05 14:26:58 +02003280
roman6430c152023-10-12 11:28:47 +02003281 free(opts->cert_ref);
3282 opts->cert_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003283 NC_CHECK_ERRMEM_GOTO(!opts->cert_ref, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003284 } else {
roman6430c152023-10-12 11:28:47 +02003285 free(opts->cert_ref);
romanb6f44032023-06-30 15:07:56 +02003286 opts->cert_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003287 }
romanb6f44032023-06-30 15:07:56 +02003288 } else if (equal_parent_name(node, 2, "ca-certs")) {
3289 /* TLS client auth certificate authority */
roman3f9b65c2023-06-05 14:26:58 +02003290 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003291 ret = nc_server_config_create_ca_certs_certificate(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02003292 if (ret) {
3293 goto cleanup;
3294 }
3295 } else {
roman6430c152023-10-12 11:28:47 +02003296 if (nc_server_config_get_cert(node, &cert)) {
3297 ret = 1;
3298 goto cleanup;
3299 }
3300 nc_server_config_del_cert(&opts->ca_certs, cert);
roman3f9b65c2023-06-05 14:26:58 +02003301 }
romanb6f44032023-06-30 15:07:56 +02003302 } else if (equal_parent_name(node, 2, "ee-certs")) {
3303 /* TLS client auth end entity */
roman3f9b65c2023-06-05 14:26:58 +02003304 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003305 ret = nc_server_config_create_ee_certs_certificate(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02003306 if (ret) {
3307 goto cleanup;
3308 }
3309 } else {
roman6430c152023-10-12 11:28:47 +02003310 if (nc_server_config_get_cert(node, &cert)) {
3311 ret = 1;
3312 goto cleanup;
3313 }
3314 nc_server_config_del_cert(&opts->ee_certs, cert);
roman3f9b65c2023-06-05 14:26:58 +02003315 }
3316 }
3317
3318cleanup:
romanba93eac2023-07-18 14:36:48 +02003319 if (is_ch(node)) {
3320 /* UNLOCK */
3321 nc_ch_client_unlock(ch_client);
3322 }
roman3f9b65c2023-06-05 14:26:58 +02003323 return ret;
3324}
3325
3326static int
3327nc_server_config_create_cert_to_name(const struct lyd_node *node, struct nc_server_tls_opts *opts)
3328{
3329 int ret = 0;
3330 struct lyd_node *n;
3331 struct nc_ctn *new, *iter;
3332 const char *map_type, *name;
3333 uint32_t id;
3334 NC_TLS_CTN_MAPTYPE m_type;
3335
3336 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
3337
roman3f9b65c2023-06-05 14:26:58 +02003338 /* get all the data */
3339 /* find the list's key */
3340 lyd_find_path(node, "id", 0, &n);
3341 assert(n);
roman9cdb7b52023-10-25 13:59:55 +02003342 id = ((struct lyd_node_term *)n)->value.uint32;
roman3f9b65c2023-06-05 14:26:58 +02003343
3344 /* find the ctn's name */
3345 lyd_find_path(node, "name", 0, &n);
3346 assert(n);
3347 name = lyd_get_value(n);
3348
3349 /* find the ctn's map-type */
3350 lyd_find_path(node, "map-type", 0, &n);
3351 assert(n);
3352 map_type = ((struct lyd_node_term *)n)->value.ident->name;
3353 if (!strcmp(map_type, "specified")) {
3354 m_type = NC_TLS_CTN_SPECIFIED;
3355 } else if (!strcmp(map_type, "san-rfc822-name")) {
3356 m_type = NC_TLS_CTN_SAN_RFC822_NAME;
3357 } else if (!strcmp(map_type, "san-dns-name")) {
3358 m_type = NC_TLS_CTN_SAN_DNS_NAME;
3359 } else if (!strcmp(map_type, "san-ip-address")) {
3360 m_type = NC_TLS_CTN_SAN_IP_ADDRESS;
3361 } else if (!strcmp(map_type, "san-any")) {
3362 m_type = NC_TLS_CTN_SAN_ANY;
3363 } else if (!strcmp(map_type, "common-name")) {
3364 m_type = NC_TLS_CTN_COMMON_NAME;
3365 } else {
3366 ERR(NULL, "Map-type identity \"%s\" not supported.", map_type);
3367 ret = 1;
3368 goto cleanup;
3369 }
3370
roman6430c152023-10-12 11:28:47 +02003371 /* create new ctn */
3372 new = calloc(1, sizeof *new);
roman3a95bb22023-10-26 11:07:17 +02003373 NC_CHECK_ERRMEM_GOTO(!new, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02003374
roman3f9b65c2023-06-05 14:26:58 +02003375 /* find the right place for insertion */
3376 if (!opts->ctn) {
3377 /* inserting the first one */
3378 opts->ctn = new;
Roytak421eb0c2023-08-01 22:18:27 +02003379 } else if (opts->ctn->id > id) {
roman3f9b65c2023-06-05 14:26:58 +02003380 /* insert at the beginning */
3381 new->next = opts->ctn;
3382 opts->ctn = new;
3383 } else {
3384 /* have to find the right place */
Roytak421eb0c2023-08-01 22:18:27 +02003385 for (iter = opts->ctn; iter->next && iter->next->id <= id; iter = iter->next) {}
3386 if (iter->id == id) {
roman3f9b65c2023-06-05 14:26:58 +02003387 /* collision */
romanb7bfa652023-11-09 12:36:35 +01003388 free(new);
roman3f9b65c2023-06-05 14:26:58 +02003389 new = iter;
3390 } else {
3391 new->next = iter->next;
3392 iter->next = new;
3393 }
3394 }
3395
3396 /* insert the right data */
3397 new->id = id;
roman6430c152023-10-12 11:28:47 +02003398 free(new->name);
roman3f9b65c2023-06-05 14:26:58 +02003399 new->name = strdup(name);
roman3a95bb22023-10-26 11:07:17 +02003400 NC_CHECK_ERRMEM_GOTO(!new->name, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003401 new->map_type = m_type;
3402
3403cleanup:
3404 return ret;
3405}
3406
3407static int
3408nc_server_config_cert_to_name(const struct lyd_node *node, NC_OPERATION op)
3409{
3410 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003411 struct nc_server_tls_opts *opts;
roman3f9b65c2023-06-05 14:26:58 +02003412 struct nc_ctn *ctn;
romanba93eac2023-07-18 14:36:48 +02003413 struct nc_ch_client *ch_client;
roman3f9b65c2023-06-05 14:26:58 +02003414
3415 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
3416
romanba93eac2023-07-18 14:36:48 +02003417 /* LOCK */
3418 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003419 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003420 return 1;
3421 }
3422
romanb6f44032023-06-30 15:07:56 +02003423 if (nc_server_config_get_tls_opts(node, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02003424 ret = 1;
3425 goto cleanup;
3426 }
3427
3428 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003429 ret = nc_server_config_create_cert_to_name(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02003430 if (ret) {
3431 goto cleanup;
3432 }
3433 } else {
3434 /* find the given ctn entry */
roman4cb8bb12023-06-29 09:16:46 +02003435 if (nc_server_config_get_ctn(node, &ctn)) {
roman3f9b65c2023-06-05 14:26:58 +02003436 ret = 1;
3437 goto cleanup;
3438 }
romanb6f44032023-06-30 15:07:56 +02003439 nc_server_config_del_ctn(opts, ctn);
roman3f9b65c2023-06-05 14:26:58 +02003440 }
3441
3442cleanup:
romanba93eac2023-07-18 14:36:48 +02003443 if (is_ch(node)) {
3444 /* UNLOCK */
3445 nc_ch_client_unlock(ch_client);
3446 }
roman3f9b65c2023-06-05 14:26:58 +02003447 return ret;
3448}
3449
3450static int
roman3f9b65c2023-06-05 14:26:58 +02003451nc_server_config_fingerprint(const struct lyd_node *node, NC_OPERATION op)
3452{
3453 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02003454 struct nc_ctn *ctn;
romanba93eac2023-07-18 14:36:48 +02003455 struct nc_ch_client *ch_client;
3456
3457 assert(!strcmp(LYD_NAME(node), "fingerprint"));
3458
3459 /* LOCK */
3460 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003461 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003462 return 1;
3463 }
roman3f9b65c2023-06-05 14:26:58 +02003464
roman4cb8bb12023-06-29 09:16:46 +02003465 if (nc_server_config_get_ctn(node, &ctn)) {
roman3f9b65c2023-06-05 14:26:58 +02003466 ret = 1;
3467 goto cleanup;
3468 }
3469
3470 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003471 free(ctn->fingerprint);
3472 ctn->fingerprint = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003473 NC_CHECK_ERRMEM_GOTO(!ctn->fingerprint, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003474 } else {
roman6430c152023-10-12 11:28:47 +02003475 free(ctn->fingerprint);
3476 ctn->fingerprint = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003477 }
3478
3479cleanup:
romanba93eac2023-07-18 14:36:48 +02003480 if (is_ch(node)) {
3481 /* UNLOCK */
3482 nc_ch_client_unlock(ch_client);
3483 }
roman3f9b65c2023-06-05 14:26:58 +02003484 return ret;
3485}
3486
roman12644fe2023-06-08 11:06:42 +02003487static int
3488nc_server_config_tls_version(const struct lyd_node *node, NC_OPERATION op)
3489{
3490 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003491 struct nc_server_tls_opts *opts;
roman12644fe2023-06-08 11:06:42 +02003492 const char *version = NULL;
romanba93eac2023-07-18 14:36:48 +02003493 struct nc_ch_client *ch_client;
roman6430c152023-10-12 11:28:47 +02003494 NC_TLS_VERSION tls_version;
roman12644fe2023-06-08 11:06:42 +02003495
3496 assert(!strcmp(LYD_NAME(node), "tls-version"));
3497
romanba93eac2023-07-18 14:36:48 +02003498 /* LOCK */
3499 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003500 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003501 return 1;
3502 }
3503
romanb6f44032023-06-30 15:07:56 +02003504 if (nc_server_config_get_tls_opts(node, &opts)) {
roman12644fe2023-06-08 11:06:42 +02003505 ret = 1;
3506 goto cleanup;
3507 }
3508
roman6430c152023-10-12 11:28:47 +02003509 /* str to tls_version */
roman12644fe2023-06-08 11:06:42 +02003510 version = ((struct lyd_node_term *)node)->value.ident->name;
3511 if (!strcmp(version, "tls10")) {
roman6430c152023-10-12 11:28:47 +02003512 tls_version = NC_TLS_VERSION_10;
roman12644fe2023-06-08 11:06:42 +02003513 } else if (!strcmp(version, "tls11")) {
roman6430c152023-10-12 11:28:47 +02003514 tls_version = NC_TLS_VERSION_11;
roman12644fe2023-06-08 11:06:42 +02003515 } else if (!strcmp(version, "tls12")) {
roman6430c152023-10-12 11:28:47 +02003516 tls_version = NC_TLS_VERSION_12;
roman12644fe2023-06-08 11:06:42 +02003517 } else if (!strcmp(version, "tls13")) {
roman6430c152023-10-12 11:28:47 +02003518 tls_version = NC_TLS_VERSION_13;
roman12644fe2023-06-08 11:06:42 +02003519 } else {
3520 ERR(NULL, "TLS version \"%s\" not supported.", version);
3521 ret = 1;
3522 goto cleanup;
3523 }
3524
roman6430c152023-10-12 11:28:47 +02003525 if (op == NC_OP_CREATE) {
3526 /* add the version if it isn't there already */
3527 opts->tls_versions |= tls_version;
3528 } else if ((op == NC_OP_DELETE) && (opts->tls_versions & tls_version)) {
3529 /* delete the version if it is there */
roman84fe3252023-10-25 11:28:32 +02003530 opts->tls_versions &= ~tls_version;
roman6430c152023-10-12 11:28:47 +02003531 }
3532
roman12644fe2023-06-08 11:06:42 +02003533cleanup:
romanba93eac2023-07-18 14:36:48 +02003534 if (is_ch(node)) {
3535 /* UNLOCK */
3536 nc_ch_client_unlock(ch_client);
3537 }
roman12644fe2023-06-08 11:06:42 +02003538 return ret;
3539}
3540
3541static int
3542nc_server_config_create_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher)
3543{
3544 int ret = 0;
3545 char *ssl_cipher = NULL;
3546 uint16_t i;
roman6430c152023-10-12 11:28:47 +02003547 void *tmp;
roman12644fe2023-06-08 11:06:42 +02003548
3549 ssl_cipher = malloc(strlen(cipher) + 1);
roman3a95bb22023-10-26 11:07:17 +02003550 NC_CHECK_ERRMEM_GOTO(!ssl_cipher, ret = 1, cleanup);
roman12644fe2023-06-08 11:06:42 +02003551
3552 for (i = 0; cipher[i]; i++) {
3553 if (cipher[i] == '-') {
3554 /* OpenSSL requires _ instead of - in cipher names */
3555 ssl_cipher[i] = '_';
3556 } else {
3557 /* and requires uppercase unlike the identities */
3558 ssl_cipher[i] = toupper(cipher[i]);
3559 }
3560 }
3561 ssl_cipher[i] = '\0';
3562
3563 if (!opts->ciphers) {
3564 /* first entry */
3565 opts->ciphers = strdup(ssl_cipher);
roman3a95bb22023-10-26 11:07:17 +02003566 NC_CHECK_ERRMEM_GOTO(!opts->ciphers, ret = 1, cleanup);
roman12644fe2023-06-08 11:06:42 +02003567 } else {
3568 /* + 1 because of : between entries */
roman6430c152023-10-12 11:28:47 +02003569 tmp = nc_realloc(opts->ciphers, strlen(opts->ciphers) + strlen(ssl_cipher) + 1 + 1);
roman3a95bb22023-10-26 11:07:17 +02003570 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02003571 opts->ciphers = tmp;
roman08f67f42023-06-08 13:51:54 +02003572 strcat(opts->ciphers, ":");
3573 strcat(opts->ciphers, ssl_cipher);
roman12644fe2023-06-08 11:06:42 +02003574 }
3575
3576cleanup:
3577 free(ssl_cipher);
3578 return ret;
3579}
3580
3581static int
romanb6f44032023-06-30 15:07:56 +02003582nc_server_config_del_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher)
roman12644fe2023-06-08 11:06:42 +02003583{
romanc135c6d2023-10-25 13:32:30 +02003584 int ret = 0;
roman12644fe2023-06-08 11:06:42 +02003585
romanc135c6d2023-10-25 13:32:30 +02003586 ret = nc_server_config_delete_substring(opts->ciphers, cipher, ':');
3587 if (ret) {
roman12644fe2023-06-08 11:06:42 +02003588 ERR(NULL, "Unable to delete a cipher (%s), which was not previously added.", cipher);
3589 return 1;
3590 }
3591
3592 return 0;
3593}
3594
3595static int
3596nc_server_config_cipher_suite(const struct lyd_node *node, NC_OPERATION op)
3597{
3598 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003599 struct nc_server_tls_opts *opts;
roman12644fe2023-06-08 11:06:42 +02003600 const char *cipher = NULL;
romanba93eac2023-07-18 14:36:48 +02003601 struct nc_ch_client *ch_client;
roman12644fe2023-06-08 11:06:42 +02003602
romanfaecc582023-06-15 16:13:31 +02003603 assert(!strcmp(LYD_NAME(node), "cipher-suite"));
3604
romanba93eac2023-07-18 14:36:48 +02003605 /* LOCK */
3606 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003607 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003608 return 1;
3609 }
3610
romanb6f44032023-06-30 15:07:56 +02003611 if (nc_server_config_get_tls_opts(node, &opts)) {
roman12644fe2023-06-08 11:06:42 +02003612 ret = 1;
3613 goto cleanup;
3614 }
3615
3616 cipher = ((struct lyd_node_term *)node)->value.ident->name;
3617 if (op == NC_OP_CREATE) {
romanb6f44032023-06-30 15:07:56 +02003618 ret = nc_server_config_create_cipher_suite(opts, cipher);
roman12644fe2023-06-08 11:06:42 +02003619 if (ret) {
3620 goto cleanup;
3621 }
3622 } else if (op == NC_OP_DELETE) {
romanb6f44032023-06-30 15:07:56 +02003623 ret = nc_server_config_del_cipher_suite(opts, cipher);
roman12644fe2023-06-08 11:06:42 +02003624 if (ret) {
3625 goto cleanup;
3626 }
3627 }
3628
3629cleanup:
romanba93eac2023-07-18 14:36:48 +02003630 if (is_ch(node)) {
3631 /* UNLOCK */
3632 nc_ch_client_unlock(ch_client);
3633 }
roman12644fe2023-06-08 11:06:42 +02003634 return ret;
3635}
3636
romanfaecc582023-06-15 16:13:31 +02003637static int
3638nc_server_config_crl_url(const struct lyd_node *node, NC_OPERATION op)
3639{
3640 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003641 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02003642 struct nc_ch_client *ch_client;
romanfaecc582023-06-15 16:13:31 +02003643
3644 assert(!strcmp(LYD_NAME(node), "crl-url"));
3645
romanba93eac2023-07-18 14:36:48 +02003646 /* LOCK */
3647 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003648 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003649 return 1;
3650 }
3651
romanb6f44032023-06-30 15:07:56 +02003652 if (nc_server_config_get_tls_opts(node, &opts)) {
romanfaecc582023-06-15 16:13:31 +02003653 ret = 1;
3654 goto cleanup;
3655 }
3656
3657 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003658 free(opts->crl_url);
romanb6f44032023-06-30 15:07:56 +02003659 opts->crl_url = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003660 NC_CHECK_ERRMEM_GOTO(!opts->crl_url, ret = 1, cleanup);
romanfaecc582023-06-15 16:13:31 +02003661 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02003662 free(opts->crl_url);
3663 opts->crl_url = NULL;
romanfaecc582023-06-15 16:13:31 +02003664 }
3665
3666cleanup:
romanba93eac2023-07-18 14:36:48 +02003667 if (is_ch(node)) {
3668 /* UNLOCK */
3669 nc_ch_client_unlock(ch_client);
3670 }
romanfaecc582023-06-15 16:13:31 +02003671 return ret;
3672}
3673
3674static int
3675nc_server_config_crl_path(const struct lyd_node *node, NC_OPERATION op)
3676{
3677 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003678 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02003679 struct nc_ch_client *ch_client;
romanfaecc582023-06-15 16:13:31 +02003680
3681 assert(!strcmp(LYD_NAME(node), "crl-path"));
3682
romanba93eac2023-07-18 14:36:48 +02003683 /* LOCK */
3684 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003685 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003686 return 1;
3687 }
3688
romanb6f44032023-06-30 15:07:56 +02003689 if (nc_server_config_get_tls_opts(node, &opts)) {
romanfaecc582023-06-15 16:13:31 +02003690 ret = 1;
3691 goto cleanup;
3692 }
3693
3694 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003695 free(opts->crl_path);
romanb6f44032023-06-30 15:07:56 +02003696 opts->crl_path = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003697 NC_CHECK_ERRMEM_GOTO(!opts->crl_path, ret = 1, cleanup);
romanfaecc582023-06-15 16:13:31 +02003698 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02003699 free(opts->crl_path);
3700 opts->crl_path = NULL;
romanfaecc582023-06-15 16:13:31 +02003701 }
3702
3703cleanup:
romanba93eac2023-07-18 14:36:48 +02003704 if (is_ch(node)) {
3705 /* UNLOCK */
3706 nc_ch_client_unlock(ch_client);
3707 }
romanfaecc582023-06-15 16:13:31 +02003708 return ret;
3709}
3710
3711static int
3712nc_server_config_crl_cert_ext(const struct lyd_node *node, NC_OPERATION op)
3713{
3714 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003715 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02003716 struct nc_ch_client *ch_client;
romanfaecc582023-06-15 16:13:31 +02003717
3718 assert(!strcmp(LYD_NAME(node), "crl-cert-ext"));
3719
romanba93eac2023-07-18 14:36:48 +02003720 /* LOCK */
3721 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003722 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003723 return 1;
3724 }
3725
romanb6f44032023-06-30 15:07:56 +02003726 if (nc_server_config_get_tls_opts(node, &opts)) {
romanfaecc582023-06-15 16:13:31 +02003727 ret = 1;
3728 goto cleanup;
3729 }
3730
3731 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003732 opts->crl_cert_ext = 1;
romanfaecc582023-06-15 16:13:31 +02003733 } else if (op == NC_OP_DELETE) {
romanb6f44032023-06-30 15:07:56 +02003734 opts->crl_cert_ext = 0;
romanfaecc582023-06-15 16:13:31 +02003735 }
3736
3737cleanup:
romanba93eac2023-07-18 14:36:48 +02003738 if (is_ch(node)) {
3739 /* UNLOCK */
3740 nc_ch_client_unlock(ch_client);
3741 }
romanfaecc582023-06-15 16:13:31 +02003742 return ret;
3743}
3744
roman2eab4742023-06-06 10:00:26 +02003745#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02003746
roman83683fb2023-02-24 09:15:23 +01003747static int
roman5cbb6532023-06-22 12:53:17 +02003748nc_server_config_create_netconf_client(const struct lyd_node *node)
3749{
3750 int ret = 0;
3751
3752 node = lyd_child(node);
3753 assert(!strcmp(LYD_NAME(node), "name"));
3754
3755 /* LOCK */
3756 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
3757
3758 ret = nc_server_config_realloc(lyd_get_value(node), (void **)&server_opts.ch_clients, sizeof *server_opts.ch_clients, &server_opts.ch_client_count);
3759 if (ret) {
3760 goto cleanup;
3761 }
3762
3763 server_opts.ch_clients[server_opts.ch_client_count - 1].id = ATOMIC_INC_RELAXED(server_opts.new_client_id);
3764 server_opts.ch_clients[server_opts.ch_client_count - 1].start_with = NC_CH_FIRST_LISTED;
roman6430c152023-10-12 11:28:47 +02003765 server_opts.ch_clients[server_opts.ch_client_count - 1].max_attempts = 3;
roman5cbb6532023-06-22 12:53:17 +02003766
3767 pthread_mutex_init(&server_opts.ch_clients[server_opts.ch_client_count - 1].lock, NULL);
3768
3769cleanup:
3770 /* UNLOCK */
3771 pthread_rwlock_unlock(&server_opts.ch_client_lock);
3772 return ret;
3773}
3774
3775static int
3776nc_server_config_netconf_client(const struct lyd_node *node, NC_OPERATION op)
3777{
3778 int ret = 0;
3779 struct nc_ch_client *ch_client;
3780
3781 assert(!strcmp(LYD_NAME(node), "netconf-client"));
3782
3783 if (op == NC_OP_CREATE) {
3784 ret = nc_server_config_create_netconf_client(node);
3785 if (ret) {
3786 goto cleanup;
3787 }
roman450c00b2023-11-02 10:31:45 +01003788
roman96c27f92023-11-02 11:09:46 +01003789#ifdef NC_ENABLED_SSH_TLS
roman450c00b2023-11-02 10:31:45 +01003790 if (server_opts.ch_dispatch_data.acquire_ctx_cb && server_opts.ch_dispatch_data.release_ctx_cb &&
roman96c27f92023-11-02 11:09:46 +01003791 server_opts.ch_dispatch_data.new_session_cb) {
roman450c00b2023-11-02 10:31:45 +01003792 /* we have all we need for dispatching a new call home thread */
3793 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 +01003794 server_opts.ch_dispatch_data.release_ctx_cb, server_opts.ch_dispatch_data.ctx_cb_data,
3795 server_opts.ch_dispatch_data.new_session_cb, server_opts.ch_dispatch_data.new_session_cb_data);
roman450c00b2023-11-02 10:31:45 +01003796 if (ret) {
3797 ERR(NULL, "Dispatching a new Call Home thread failed for Call Home client \"%s\".", lyd_get_value(lyd_child(node)));
3798 goto cleanup;
3799 }
3800 }
roman96c27f92023-11-02 11:09:46 +01003801#endif /* NC_ENABLED_SSH_TLS */
roman5cbb6532023-06-22 12:53:17 +02003802 } else if (op == NC_OP_DELETE) {
3803 if (nc_server_config_get_ch_client(node, &ch_client)) {
3804 ret = 1;
3805 goto cleanup;
3806 }
3807
3808 nc_server_config_ch_del_client(ch_client);
3809 }
3810
3811cleanup:
3812 return ret;
3813}
3814
3815#ifdef NC_ENABLED_SSH_TLS
3816
3817static int
3818nc_server_config_remote_address(const struct lyd_node *node, NC_OPERATION op)
3819{
3820 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02003821 struct nc_ch_endpt *ch_endpt;
romanba93eac2023-07-18 14:36:48 +02003822 struct nc_ch_client *ch_client;
roman5cbb6532023-06-22 12:53:17 +02003823
romanb6f44032023-06-30 15:07:56 +02003824 assert(!strcmp(LYD_NAME(node), "remote-address"));
3825
romanba93eac2023-07-18 14:36:48 +02003826 /* LOCK */
3827 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003828 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003829 return 1;
3830 }
3831
roman4cb8bb12023-06-29 09:16:46 +02003832 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02003833 ret = 1;
3834 goto cleanup;
3835 }
3836
3837 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003838 free(ch_endpt->address);
roman5cbb6532023-06-22 12:53:17 +02003839 ch_endpt->address = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003840 NC_CHECK_ERRMEM_GOTO(!ch_endpt->address, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02003841 } else {
roman6430c152023-10-12 11:28:47 +02003842 free(ch_endpt->address);
3843 ch_endpt->address = NULL;
roman5cbb6532023-06-22 12:53:17 +02003844 }
3845
3846cleanup:
romanba93eac2023-07-18 14:36:48 +02003847 /* UNLOCK */
3848 nc_ch_client_unlock(ch_client);
roman5cbb6532023-06-22 12:53:17 +02003849 return ret;
3850}
3851
3852static int
3853nc_server_config_remote_port(const struct lyd_node *node, NC_OPERATION op)
3854{
3855 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02003856 struct nc_ch_endpt *ch_endpt;
romanba93eac2023-07-18 14:36:48 +02003857 struct nc_ch_client *ch_client;
roman5cbb6532023-06-22 12:53:17 +02003858
romanb6f44032023-06-30 15:07:56 +02003859 assert(!strcmp(LYD_NAME(node), "remote-port"));
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 */
romanba93eac2023-07-18 14:36:48 +02003864 return 1;
3865 }
3866
roman4cb8bb12023-06-29 09:16:46 +02003867 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02003868 ret = 1;
3869 goto cleanup;
3870 }
3871
3872 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02003873 ch_endpt->port = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02003874 } else {
3875 ch_endpt->port = 0;
3876 }
3877
3878cleanup:
romanba93eac2023-07-18 14:36:48 +02003879 /* UNLOCK */
3880 nc_ch_client_unlock(ch_client);
roman5cbb6532023-06-22 12:53:17 +02003881 return ret;
3882}
3883
3884#endif /* NC_ENABLED_SSH_TLS */
3885
3886static int
romanb6f44032023-06-30 15:07:56 +02003887nc_server_config_persistent(const struct lyd_node *node, NC_OPERATION op)
3888{
3889 int ret = 0;
3890 struct nc_ch_client *ch_client;
3891
3892 assert(!strcmp(LYD_NAME(node), "persistent"));
3893
3894 (void) op;
3895
romanba93eac2023-07-18 14:36:48 +02003896 /* LOCK */
3897 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003898 /* to avoid unlock on fail */
3899 return 1;
romanb6f44032023-06-30 15:07:56 +02003900 }
3901
3902 ch_client->conn_type = NC_CH_PERSIST;
3903
romanba93eac2023-07-18 14:36:48 +02003904 /* UNLOCK */
3905 nc_ch_client_unlock(ch_client);
3906
romanb6f44032023-06-30 15:07:56 +02003907 return ret;
3908}
3909
3910static int
3911nc_server_config_periodic(const struct lyd_node *node, NC_OPERATION op)
3912{
3913 int ret = 0;
3914 struct nc_ch_client *ch_client;
3915
3916 assert(!strcmp(LYD_NAME(node), "periodic"));
3917
3918 (void) op;
3919
romanba93eac2023-07-18 14:36:48 +02003920 /* LOCK */
3921 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003922 /* to avoid unlock on fail */
3923 return 1;
romanb6f44032023-06-30 15:07:56 +02003924 }
3925
3926 ch_client->conn_type = NC_CH_PERIOD;
3927 /* set default values */
3928 ch_client->period = 60;
3929 ch_client->anchor_time = 0;
3930 ch_client->idle_timeout = 180;
3931
romanba93eac2023-07-18 14:36:48 +02003932 /* UNLOCK */
3933 nc_ch_client_unlock(ch_client);
3934
romanb6f44032023-06-30 15:07:56 +02003935 return ret;
3936}
3937
3938static int
3939nc_server_config_period(const struct lyd_node *node, NC_OPERATION op)
3940{
3941 int ret = 0;
3942 struct nc_ch_client *ch_client;
3943
3944 assert(!strcmp(LYD_NAME(node), "period"));
3945
romanba93eac2023-07-18 14:36:48 +02003946 /* LOCK */
3947 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003948 /* to avoid unlock on fail */
3949 return 1;
romanb6f44032023-06-30 15:07:56 +02003950 }
3951
3952 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02003953 ch_client->period = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02003954 } else if (op == NC_OP_DELETE) {
3955 ch_client->period = 60;
3956 }
3957
romanba93eac2023-07-18 14:36:48 +02003958 /* UNLOCK */
3959 nc_ch_client_unlock(ch_client);
3960
romanb6f44032023-06-30 15:07:56 +02003961 return ret;
3962}
3963
3964static int
3965nc_server_config_anchor_time(const struct lyd_node *node, NC_OPERATION op)
3966{
3967 int ret = 0;
3968 struct nc_ch_client *ch_client;
romana3c95c72023-10-26 11:15:53 +02003969 struct lyd_value_date_and_time *anchor_time;
romanb6f44032023-06-30 15:07:56 +02003970
3971 assert(!strcmp(LYD_NAME(node), "anchor-time"));
3972
romanba93eac2023-07-18 14:36:48 +02003973 /* LOCK */
3974 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003975 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003976 return 1;
romanb6f44032023-06-30 15:07:56 +02003977 }
3978
romana3c95c72023-10-26 11:15:53 +02003979 /* get the value of time from the node directly */
3980 LYD_VALUE_GET(&((struct lyd_node_term *)node)->value, anchor_time);
romanb6f44032023-06-30 15:07:56 +02003981
3982 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romana3c95c72023-10-26 11:15:53 +02003983 ch_client->anchor_time = anchor_time->time;
romanb6f44032023-06-30 15:07:56 +02003984 } else if (op == NC_OP_DELETE) {
3985 ch_client->anchor_time = 0;
3986 }
3987
romanba93eac2023-07-18 14:36:48 +02003988 /* UNLOCK */
3989 nc_ch_client_unlock(ch_client);
romanb6f44032023-06-30 15:07:56 +02003990 return ret;
3991}
3992
3993static int
3994nc_server_config_reconnect_strategy(const struct lyd_node *node, NC_OPERATION op)
3995{
3996 int ret = 0;
3997 struct nc_ch_client *ch_client;
3998
3999 assert(!strcmp(LYD_NAME(node), "reconnect-strategy"));
4000
4001 (void) op;
4002
romanba93eac2023-07-18 14:36:48 +02004003 /* LOCK */
4004 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02004005 /* to avoid unlock on fail */
4006 return 1;
romanb6f44032023-06-30 15:07:56 +02004007 }
4008
4009 /* set to default values */
4010 ch_client->start_with = NC_CH_FIRST_LISTED;
4011 ch_client->max_wait = 5;
4012 ch_client->max_attempts = 3;
4013
romanba93eac2023-07-18 14:36:48 +02004014 /* UNLOCK */
4015 nc_ch_client_unlock(ch_client);
4016
romanb6f44032023-06-30 15:07:56 +02004017 return ret;
4018}
4019
4020static int
4021nc_server_config_start_with(const struct lyd_node *node, NC_OPERATION op)
4022{
4023 int ret = 0;
4024 struct nc_ch_client *ch_client;
4025 const char *value;
4026
4027 assert(!strcmp(LYD_NAME(node), "start-with"));
4028
romanba93eac2023-07-18 14:36:48 +02004029 /* LOCK */
4030 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02004031 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02004032 return 1;
romanb6f44032023-06-30 15:07:56 +02004033 }
4034
4035 if (op == NC_OP_DELETE) {
4036 ch_client->start_with = NC_CH_FIRST_LISTED;
4037 goto cleanup;
4038 }
4039
4040 value = lyd_get_value(node);
4041 if (!strcmp(value, "first-listed")) {
4042 ch_client->start_with = NC_CH_FIRST_LISTED;
4043 } else if (!strcmp(value, "last-connected")) {
4044 ch_client->start_with = NC_CH_LAST_CONNECTED;
4045 } else if (!strcmp(value, "random-selection")) {
4046 ch_client->start_with = NC_CH_RANDOM;
4047 } else {
4048 ERR(NULL, "Unexpected start-with value \"%s\".", value);
4049 ret = 1;
4050 goto cleanup;
4051 }
4052
4053cleanup:
romanba93eac2023-07-18 14:36:48 +02004054 /* UNLOCK */
4055 nc_ch_client_unlock(ch_client);
romanb6f44032023-06-30 15:07:56 +02004056 return ret;
4057}
4058
4059static int
4060nc_server_config_max_wait(const struct lyd_node *node, NC_OPERATION op)
4061{
4062 int ret = 0;
4063 struct nc_ch_client *ch_client;
4064
4065 assert(!strcmp(LYD_NAME(node), "max-wait"));
4066
romanba93eac2023-07-18 14:36:48 +02004067 /* LOCK */
4068 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02004069 /* to avoid unlock on fail */
4070 return 1;
romanb6f44032023-06-30 15:07:56 +02004071 }
4072
4073 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02004074 ch_client->max_wait = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02004075 } else {
4076 ch_client->max_wait = 5;
4077 }
4078
romanba93eac2023-07-18 14:36:48 +02004079 /* UNLOCK */
4080 nc_ch_client_unlock(ch_client);
4081
romanb6f44032023-06-30 15:07:56 +02004082 return ret;
4083}
4084
4085static int
4086nc_server_config_max_attempts(const struct lyd_node *node, NC_OPERATION op)
4087{
4088 int ret = 0;
4089 struct nc_ch_client *ch_client;
4090
4091 assert(!strcmp(LYD_NAME(node), "max-attempts"));
4092
romanba93eac2023-07-18 14:36:48 +02004093 /* LOCK */
4094 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02004095 /* to avoid unlock on fail */
4096 return 1;
romanb6f44032023-06-30 15:07:56 +02004097 }
4098
4099 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02004100 ch_client->max_attempts = ((struct lyd_node_term *)node)->value.uint8;
romanb6f44032023-06-30 15:07:56 +02004101 } else {
4102 ch_client->max_attempts = 3;
4103 }
4104
romanba93eac2023-07-18 14:36:48 +02004105 /* UNLOCK */
4106 nc_ch_client_unlock(ch_client);
4107
romanb6f44032023-06-30 15:07:56 +02004108 return ret;
4109}
4110
4111static int
romanf02273a2023-05-25 09:44:11 +02004112nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01004113{
4114 const char *name = LYD_NAME(node);
roman6430c152023-10-12 11:28:47 +02004115 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01004116
4117 if (!strcmp(name, "listen")) {
roman6430c152023-10-12 11:28:47 +02004118 ret = nc_server_config_listen(node, op);
4119 } else if (!strcmp(name, "call-home")) {
4120 ret = nc_server_config_ch(node, op);
romaneaf84c72023-10-19 14:38:05 +02004121 } else if (!strcmp(name, "hello-timeout")) {
4122 ret = nc_server_config_hello_timeout(node, op);
romanc1d2b092023-02-02 08:58:27 +01004123 } else if (!strcmp(name, "endpoint")) {
roman6430c152023-10-12 11:28:47 +02004124 ret = nc_server_config_endpoint(node, op);
roman2eab4742023-06-06 10:00:26 +02004125 } else if (!strcmp(name, "unix-socket")) {
roman6430c152023-10-12 11:28:47 +02004126 ret = nc_server_config_unix_socket(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004127 }
roman2eab4742023-06-06 10:00:26 +02004128#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02004129 else if (!strcmp(name, "ssh")) {
roman6430c152023-10-12 11:28:47 +02004130 ret = nc_server_config_ssh(node, op);
roman2eab4742023-06-06 10:00:26 +02004131 } else if (!strcmp(name, "local-address")) {
roman6430c152023-10-12 11:28:47 +02004132 ret = nc_server_config_local_address(node, op);
romanc1d2b092023-02-02 08:58:27 +01004133 } else if (!strcmp(name, "local-port")) {
roman6430c152023-10-12 11:28:47 +02004134 ret = nc_server_config_local_port(node, op);
romanc1d2b092023-02-02 08:58:27 +01004135 } else if (!strcmp(name, "keepalives")) {
roman6430c152023-10-12 11:28:47 +02004136 ret = nc_server_config_keepalives(node, op);
romanc1d2b092023-02-02 08:58:27 +01004137 } else if (!strcmp(name, "idle-time")) {
roman6430c152023-10-12 11:28:47 +02004138 ret = nc_server_config_idle_time(node, op);
romanc1d2b092023-02-02 08:58:27 +01004139 } else if (!strcmp(name, "max-probes")) {
roman6430c152023-10-12 11:28:47 +02004140 ret = nc_server_config_max_probes(node, op);
romanc1d2b092023-02-02 08:58:27 +01004141 } else if (!strcmp(name, "probe-interval")) {
roman6430c152023-10-12 11:28:47 +02004142 ret = nc_server_config_probe_interval(node, op);
roman2eab4742023-06-06 10:00:26 +02004143 } else if (!strcmp(name, "host-key")) {
roman6430c152023-10-12 11:28:47 +02004144 ret = nc_server_config_host_key(node, op);
roman2eab4742023-06-06 10:00:26 +02004145 } else if (!strcmp(name, "public-key-format")) {
roman6430c152023-10-12 11:28:47 +02004146 ret = nc_server_config_public_key_format(node, op);
romanc1d2b092023-02-02 08:58:27 +01004147 } else if (!strcmp(name, "public-key")) {
roman6430c152023-10-12 11:28:47 +02004148 ret = nc_server_config_public_key(node, op);
romanc1d2b092023-02-02 08:58:27 +01004149 } else if (!strcmp(name, "private-key-format")) {
roman6430c152023-10-12 11:28:47 +02004150 ret = nc_server_config_private_key_format(node, op);
romanc1d2b092023-02-02 08:58:27 +01004151 } else if (!strcmp(name, "cleartext-private-key")) {
roman6430c152023-10-12 11:28:47 +02004152 ret = nc_server_config_cleartext_private_key(node, op);
roman2eab4742023-06-06 10:00:26 +02004153 } else if (!strcmp(name, "keystore-reference")) {
roman6430c152023-10-12 11:28:47 +02004154 ret = nc_server_config_keystore_reference(node, op);
romanc1d2b092023-02-02 08:58:27 +01004155 } else if (!strcmp(name, "user")) {
roman6430c152023-10-12 11:28:47 +02004156 ret = nc_server_config_user(node, op);
romanc1d2b092023-02-02 08:58:27 +01004157 } else if (!strcmp(name, "auth-attempts")) {
roman6430c152023-10-12 11:28:47 +02004158 ret = nc_server_config_auth_attempts(node, op);
romanc1d2b092023-02-02 08:58:27 +01004159 } else if (!strcmp(name, "auth-timeout")) {
roman6430c152023-10-12 11:28:47 +02004160 ret = nc_server_config_auth_timeout(node, op);
roman2eab4742023-06-06 10:00:26 +02004161 } else if (!strcmp(name, "truststore-reference")) {
roman6430c152023-10-12 11:28:47 +02004162 ret = nc_server_config_truststore_reference(node, op);
roman2eab4742023-06-06 10:00:26 +02004163 } else if (!strcmp(name, "password")) {
roman6430c152023-10-12 11:28:47 +02004164 ret = nc_server_config_password(node, op);
roman808f3f62023-11-23 16:01:04 +01004165 } else if (!strcmp(name, "keyboard-interactive")) {
4166 ret = nc_server_config_kb_int(node, op);
romanc1d2b092023-02-02 08:58:27 +01004167 } else if (!strcmp(name, "none")) {
roman6430c152023-10-12 11:28:47 +02004168 ret = nc_server_config_none(node, op);
romanc1d2b092023-02-02 08:58:27 +01004169 } else if (!strcmp(name, "host-key-alg")) {
roman6430c152023-10-12 11:28:47 +02004170 ret = nc_server_config_host_key_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01004171 } else if (!strcmp(name, "key-exchange-alg")) {
roman6430c152023-10-12 11:28:47 +02004172 ret = nc_server_config_kex_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01004173 } else if (!strcmp(name, "encryption-alg")) {
roman6430c152023-10-12 11:28:47 +02004174 ret = nc_server_config_encryption_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01004175 } else if (!strcmp(name, "mac-alg")) {
roman6430c152023-10-12 11:28:47 +02004176 ret = nc_server_config_mac_alg(node, op);
roman78df0fa2023-11-02 10:33:57 +01004177 } else if (!strcmp(name, "endpoint-reference")) {
4178 ret = nc_server_config_endpoint_reference(node, op);
roman2eab4742023-06-06 10:00:26 +02004179 } else if (!strcmp(name, "tls")) {
roman6430c152023-10-12 11:28:47 +02004180 ret = nc_server_config_tls(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004181 } else if (!strcmp(name, "cert-data")) {
roman6430c152023-10-12 11:28:47 +02004182 ret = nc_server_config_cert_data(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004183 } else if (!strcmp(name, "asymmetric-key")) {
roman6430c152023-10-12 11:28:47 +02004184 ret = nc_server_config_asymmetric_key(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004185 } else if (!strcmp(name, "certificate")) {
roman6430c152023-10-12 11:28:47 +02004186 ret = nc_server_config_certificate(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004187 } else if (!strcmp(name, "cert-to-name")) {
roman6430c152023-10-12 11:28:47 +02004188 ret = nc_server_config_cert_to_name(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004189 } else if (!strcmp(name, "fingerprint")) {
roman6430c152023-10-12 11:28:47 +02004190 ret = nc_server_config_fingerprint(node, op);
roman12644fe2023-06-08 11:06:42 +02004191 } else if (!strcmp(name, "tls-version")) {
roman6430c152023-10-12 11:28:47 +02004192 ret = nc_server_config_tls_version(node, op);
roman12644fe2023-06-08 11:06:42 +02004193 } else if (!strcmp(name, "cipher-suite")) {
roman6430c152023-10-12 11:28:47 +02004194 ret = nc_server_config_cipher_suite(node, op);
romanfaecc582023-06-15 16:13:31 +02004195 } else if (!strcmp(name, "crl-url")) {
roman6430c152023-10-12 11:28:47 +02004196 ret = nc_server_config_crl_url(node, op);
romanfaecc582023-06-15 16:13:31 +02004197 } else if (!strcmp(name, "crl-path")) {
roman6430c152023-10-12 11:28:47 +02004198 ret = nc_server_config_crl_path(node, op);
romanfaecc582023-06-15 16:13:31 +02004199 } else if (!strcmp(name, "crl-cert-ext")) {
roman6430c152023-10-12 11:28:47 +02004200 ret = nc_server_config_crl_cert_ext(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004201 }
roman2eab4742023-06-06 10:00:26 +02004202#endif /* NC_ENABLED_SSH_TLS */
roman5cbb6532023-06-22 12:53:17 +02004203 else if (!strcmp(name, "netconf-client")) {
roman6430c152023-10-12 11:28:47 +02004204 ret = nc_server_config_netconf_client(node, op);
roman5cbb6532023-06-22 12:53:17 +02004205 }
4206#ifdef NC_ENABLED_SSH_TLS
4207 else if (!strcmp(name, "remote-address")) {
roman6430c152023-10-12 11:28:47 +02004208 ret = nc_server_config_remote_address(node, op);
roman5cbb6532023-06-22 12:53:17 +02004209 } else if (!strcmp(name, "remote-port")) {
roman6430c152023-10-12 11:28:47 +02004210 ret = nc_server_config_remote_port(node, op);
roman5cbb6532023-06-22 12:53:17 +02004211 }
4212#endif /* NC_ENABLED_SSH_TLS */
romanb6f44032023-06-30 15:07:56 +02004213 else if (!strcmp(name, "persistent")) {
roman6430c152023-10-12 11:28:47 +02004214 ret = nc_server_config_persistent(node, op);
romanb6f44032023-06-30 15:07:56 +02004215 } else if (!strcmp(name, "periodic")) {
roman6430c152023-10-12 11:28:47 +02004216 ret = nc_server_config_periodic(node, op);
romanb6f44032023-06-30 15:07:56 +02004217 } else if (!strcmp(name, "period")) {
roman6430c152023-10-12 11:28:47 +02004218 ret = nc_server_config_period(node, op);
romanb6f44032023-06-30 15:07:56 +02004219 } else if (!strcmp(name, "anchor-time")) {
roman6430c152023-10-12 11:28:47 +02004220 ret = nc_server_config_anchor_time(node, op);
romaneaf84c72023-10-19 14:38:05 +02004221 } else if (!strcmp(name, "idle-timeout")) {
4222 ret = nc_server_config_idle_timeout(node, op);
romanb6f44032023-06-30 15:07:56 +02004223 } else if (!strcmp(name, "reconnect-strategy")) {
roman6430c152023-10-12 11:28:47 +02004224 ret = nc_server_config_reconnect_strategy(node, op);
romanb6f44032023-06-30 15:07:56 +02004225 } else if (!strcmp(name, "start-with")) {
roman6430c152023-10-12 11:28:47 +02004226 ret = nc_server_config_start_with(node, op);
romanb6f44032023-06-30 15:07:56 +02004227 } else if (!strcmp(name, "max-wait")) {
roman6430c152023-10-12 11:28:47 +02004228 ret = nc_server_config_max_wait(node, op);
romanb6f44032023-06-30 15:07:56 +02004229 } else if (!strcmp(name, "max-attempts")) {
roman6430c152023-10-12 11:28:47 +02004230 ret = nc_server_config_max_attempts(node, op);
4231 }
4232
4233 if (ret) {
4234 ERR(NULL, "Configuring node \"%s\" failed.", LYD_NAME(node));
4235 return 1;
romanb6f44032023-06-30 15:07:56 +02004236 }
romanc1d2b092023-02-02 08:58:27 +01004237
4238 return 0;
romanc1d2b092023-02-02 08:58:27 +01004239}
4240
4241int
roman0bbc19c2023-05-26 09:59:09 +02004242nc_server_config_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, NC_MODULE module)
romanc1d2b092023-02-02 08:58:27 +01004243{
4244 struct lyd_node *child;
4245 struct lyd_meta *m;
romanf9906b42023-05-22 14:04:29 +02004246 NC_OPERATION current_op = NC_OP_UNKNOWN;
romanf02273a2023-05-25 09:44:11 +02004247 int ret;
romanc1d2b092023-02-02 08:58:27 +01004248
4249 assert(node);
4250
romanf9906b42023-05-22 14:04:29 +02004251 /* get current op if there is any */
4252 if ((m = lyd_find_meta(node->meta, NULL, "yang:operation"))) {
4253 if (!strcmp(lyd_get_meta_value(m), "create")) {
4254 current_op = NC_OP_CREATE;
4255 } else if (!strcmp(lyd_get_meta_value(m), "delete")) {
4256 current_op = NC_OP_DELETE;
4257 } else if (!strcmp(lyd_get_meta_value(m), "replace")) {
4258 current_op = NC_OP_REPLACE;
4259 } else if (!strcmp(lyd_get_meta_value(m), "none")) {
4260 current_op = NC_OP_NONE;
romanc1d2b092023-02-02 08:58:27 +01004261 }
4262 }
4263
4264 /* node has no op, inherit from the parent */
romanf9906b42023-05-22 14:04:29 +02004265 if (!current_op) {
4266 if (!parent_op) {
4267 ERR(NULL, "Unknown operation for node \"%s\".", LYD_NAME(node));
4268 return 1;
4269 }
4270
romanc1d2b092023-02-02 08:58:27 +01004271 current_op = parent_op;
4272 }
4273
4274 switch (current_op) {
4275 case NC_OP_NONE:
4276 break;
4277 case NC_OP_CREATE:
4278 case NC_OP_DELETE:
4279 case NC_OP_REPLACE:
roman2eab4742023-06-06 10:00:26 +02004280#ifdef NC_ENABLED_SSH_TLS
4281 if (module == NC_MODULE_KEYSTORE) {
romanf02273a2023-05-25 09:44:11 +02004282 ret = nc_server_config_parse_keystore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02004283 } else if (module == NC_MODULE_TRUSTSTORE) {
romanf02273a2023-05-25 09:44:11 +02004284 ret = nc_server_config_parse_truststore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02004285 } else
4286#endif /* NC_ENABLED_SSH_TLS */
4287 {
4288 ret = nc_server_config_parse_netconf_server(node, current_op);
romanf02273a2023-05-25 09:44:11 +02004289 }
4290 if (ret) {
4291 return ret;
romanc1d2b092023-02-02 08:58:27 +01004292 }
4293 break;
4294 default:
4295 break;
4296 }
4297
4298 if (current_op != NC_OP_DELETE) {
4299 LY_LIST_FOR(lyd_child(node), child) {
roman0bbc19c2023-05-26 09:59:09 +02004300 if (nc_server_config_parse_tree(child, current_op, module)) {
romanc1d2b092023-02-02 08:58:27 +01004301 return 1;
4302 }
4303 }
4304 }
4305 return 0;
4306}
4307
romanc1d2b092023-02-02 08:58:27 +01004308API int
4309nc_server_config_load_modules(struct ly_ctx **ctx)
4310{
4311 int i, new_ctx = 0;
4312
4313 if (!*ctx) {
4314 if (ly_ctx_new(NC_SERVER_SEARCH_DIR, 0, ctx)) {
4315 ERR(NULL, "Couldn't create new libyang context.\n");
4316 goto error;
4317 }
4318 new_ctx = 1;
4319 }
4320
4321 /* all features */
4322 const char *ietf_nectonf_server[] = {"ssh-listen", "tls-listen", "ssh-call-home", "tls-call-home", "central-netconf-server-supported", NULL};
4323 /* all features */
4324 const char *ietf_x509_cert_to_name[] = {NULL};
roman7fdc84d2023-06-06 13:14:53 +02004325 /* no private-key-encryption, csr-generation, p10-csr-format, certificate-expiration-notification,
roman3c6c7e62023-09-14 10:19:19 +02004326 * encrypted-passwords, hidden-symmetric-keys, encrypted-symmetric-keys, hidden-private-keys, encrypted-private-keys,
4327 * one-symmetric-key-format, one-asymmetric-key-format, symmetrically-encrypted-value-format,
4328 * asymmetrically-encrypted-value-format, cms-enveloped-data-format, cms-encrypted-data-format,
Roytakb2794852023-10-18 14:30:22 +02004329 * cleartext-symmetric-keys */
roman3c6c7e62023-09-14 10:19:19 +02004330 const char *ietf_crypto_types[] = {"cleartext-passwords", "cleartext-private-keys", NULL};
romanc1d2b092023-02-02 08:58:27 +01004331 /* all features */
4332 const char *ietf_tcp_common[] = {"keepalives-supported", NULL};
roman7fdc84d2023-06-06 13:14:53 +02004333 /* all features */
4334 const char *ietf_tcp_server[] = {"tcp-server-keepalives", NULL};
Roytakb2794852023-10-18 14:30:22 +02004335 /* no proxy-connect, socks5-gss-api, socks5-username-password, local-binding-supported ? */
4336 const char *ietf_tcp_client[] = {"tcp-client-keepalives", NULL};
roman3c6c7e62023-09-14 10:19:19 +02004337 /* no ssh-x509-certs, public-key-generation */
4338 const char *ietf_ssh_common[] = {"transport-params", NULL};
roman7fdc84d2023-06-06 13:14:53 +02004339 /* no ssh-server-keepalives and local-user-auth-hostbased */
4340 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 +01004341 /* all features */
4342 const char *iana_ssh_encryption_algs[] = {NULL};
4343 /* all features */
4344 const char *iana_ssh_key_exchange_algs[] = {NULL};
4345 /* all features */
4346 const char *iana_ssh_mac_algs[] = {NULL};
4347 /* all features */
4348 const char *iana_ssh_public_key_algs[] = {NULL};
romanc1d2b092023-02-02 08:58:27 +01004349 /* all features */
roman7fdc84d2023-06-06 13:14:53 +02004350 const char *iana_crypt_hash[] = {"crypt-hash-md5", "crypt-hash-sha-256", "crypt-hash-sha-512", NULL};
4351 /* no symmetric-keys */
4352 const char *ietf_keystore[] = {"central-keystore-supported", "inline-definitions-supported", "asymmetric-keys", NULL};
4353 /* all features */
4354 const char *ietf_truststore[] = {"central-truststore-supported", "inline-definitions-supported", "certificates", "public-keys", NULL};
roman3c6c7e62023-09-14 10:19:19 +02004355 /* no public-key-generation */
4356 const char *ietf_tls_common[] = {"tls10", "tls11", "tls12", "tls13", "hello-params", NULL};
4357 /* no tls-server-keepalives, server-ident-raw-public-key, server-ident-tls12-psk, server-ident-tls13-epsk,
4358 * client-auth-raw-public-key, client-auth-tls12-psk, client-auth-tls13-epsk */
4359 const char *ietf_tls_server[] = {"server-ident-x509-cert", "client-auth-supported", "client-auth-x509-cert", NULL};
roman7fdc84d2023-06-06 13:14:53 +02004360 /* all features */
roman12644fe2023-06-08 11:06:42 +02004361 const char *iana_tls_cipher_suite_algs[] = {NULL};
romanc1d2b092023-02-02 08:58:27 +01004362 /* all features */
4363 const char *libnetconf2_netconf_server[] = {NULL};
4364
4365 const char *module_names[] = {
roman7fdc84d2023-06-06 13:14:53 +02004366 "ietf-netconf-server", "ietf-x509-cert-to-name", "ietf-crypto-types", "ietf-tcp-common", "ietf-tcp-server",
4367 "ietf-tcp-client", "ietf-ssh-common", "ietf-ssh-server", "iana-ssh-encryption-algs",
4368 "iana-ssh-key-exchange-algs", "iana-ssh-mac-algs", "iana-ssh-public-key-algs", "iana-crypt-hash",
roman12644fe2023-06-08 11:06:42 +02004369 "ietf-keystore", "ietf-truststore", "ietf-tls-common", "ietf-tls-server", "iana-tls-cipher-suite-algs",
4370 "libnetconf2-netconf-server", NULL
romanc1d2b092023-02-02 08:58:27 +01004371 };
4372
4373 const char **module_features[] = {
roman7fdc84d2023-06-06 13:14:53 +02004374 ietf_nectonf_server, ietf_x509_cert_to_name, ietf_crypto_types, ietf_tcp_common,
4375 ietf_tcp_server, ietf_tcp_client, ietf_ssh_common, ietf_ssh_server, iana_ssh_encryption_algs,
4376 iana_ssh_key_exchange_algs, iana_ssh_mac_algs, iana_ssh_public_key_algs, iana_crypt_hash,
roman12644fe2023-06-08 11:06:42 +02004377 ietf_keystore, ietf_truststore, ietf_tls_common, ietf_tls_server, iana_tls_cipher_suite_algs,
4378 libnetconf2_netconf_server, NULL
romanc1d2b092023-02-02 08:58:27 +01004379 };
4380
4381 for (i = 0; module_names[i] != NULL; i++) {
4382 if (!ly_ctx_load_module(*ctx, module_names[i], NULL, module_features[i])) {
4383 ERR(NULL, "Loading module \"%s\" failed.\n", module_names[i]);
4384 goto error;
4385 }
4386 }
4387
4388 return 0;
4389
4390error:
4391 if (new_ctx) {
4392 ly_ctx_destroy(*ctx);
4393 *ctx = NULL;
4394 }
4395 return 1;
4396}
4397
romanf9906b42023-05-22 14:04:29 +02004398static int
4399nc_server_config_fill_nectonf_server(const struct lyd_node *data, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01004400{
4401 int ret = 0;
roman84fe3252023-10-25 11:28:32 +02004402 uint32_t log_options = 0;
romanc1d2b092023-02-02 08:58:27 +01004403 struct lyd_node *tree;
romand57b3722023-04-05 11:26:25 +02004404
romanc9b62d62023-09-14 10:19:50 +02004405 /* silently search for ietf-netconf-server, it may not be present */
roman84fe3252023-10-25 11:28:32 +02004406 ly_temp_log_options(&log_options);
romanc9b62d62023-09-14 10:19:50 +02004407
romanc1d2b092023-02-02 08:58:27 +01004408 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &tree);
romanc9b62d62023-09-14 10:19:50 +02004409 if (ret || (tree->flags & LYD_DEFAULT)) {
4410 /* not found */
4411 ret = 0;
romanc1d2b092023-02-02 08:58:27 +01004412 goto cleanup;
4413 }
4414
roman0bbc19c2023-05-26 09:59:09 +02004415 if (nc_server_config_parse_tree(tree, op, NC_MODULE_NETCONF_SERVER)) {
4416 ret = 1;
4417 goto cleanup;
4418 }
4419
roman2eab4742023-06-06 10:00:26 +02004420#ifdef NC_ENABLED_SSH_TLS
roman78df0fa2023-11-02 10:33:57 +01004421 /* check and set all endpoint references */
4422 if (nc_server_config_check_endpt_references()) {
romanf9906b42023-05-22 14:04:29 +02004423 ret = 1;
4424 goto cleanup;
4425 }
roman2eab4742023-06-06 10:00:26 +02004426#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004427
4428cleanup:
romanc9b62d62023-09-14 10:19:50 +02004429 /* reset the logging options back to what they were */
roman84fe3252023-10-25 11:28:32 +02004430 ly_temp_log_options(NULL);
romanf9906b42023-05-22 14:04:29 +02004431 return ret;
4432}
4433
4434API int
romanf6f37a52023-05-25 14:27:51 +02004435nc_server_config_setup_diff(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02004436{
4437 int ret = 0;
4438
romanc9b62d62023-09-14 10:19:50 +02004439 NC_CHECK_ARG_RET(NULL, data, 1);
4440
romanf9906b42023-05-22 14:04:29 +02004441 /* LOCK */
4442 pthread_rwlock_wrlock(&server_opts.config_lock);
4443
roman2eab4742023-06-06 10:00:26 +02004444#ifdef NC_ENABLED_SSH_TLS
romanf9906b42023-05-22 14:04:29 +02004445 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02004446 ret = nc_server_config_fill_keystore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02004447 if (ret) {
4448 ERR(NULL, "Filling keystore failed.");
4449 goto cleanup;
4450 }
4451
4452 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02004453 ret = nc_server_config_fill_truststore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02004454 if (ret) {
4455 ERR(NULL, "Filling truststore failed.");
4456 goto cleanup;
4457 }
roman2eab4742023-06-06 10:00:26 +02004458#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004459
4460 /* configure netconf-server */
4461 ret = nc_server_config_fill_nectonf_server(data, NC_OP_UNKNOWN);
4462 if (ret) {
4463 ERR(NULL, "Filling netconf-server failed.");
4464 goto cleanup;
4465 }
4466
4467cleanup:
4468 /* UNLOCK */
4469 pthread_rwlock_unlock(&server_opts.config_lock);
4470 return ret;
4471}
4472
4473API int
romanf6f37a52023-05-25 14:27:51 +02004474nc_server_config_setup_data(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02004475{
4476 int ret = 0;
4477 struct lyd_node *tree, *iter, *root;
4478
romanc9b62d62023-09-14 10:19:50 +02004479 NC_CHECK_ARG_RET(NULL, data, 1);
4480
romanf9906b42023-05-22 14:04:29 +02004481 /* LOCK */
4482 pthread_rwlock_wrlock(&server_opts.config_lock);
4483
4484 /* find the netconf-server node */
4485 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &root);
4486 if (ret) {
4487 ERR(NULL, "Unable to find the netconf-server container in the YANG data.");
4488 goto cleanup;
4489 }
4490
4491 /* iterate through all the nodes and make sure there is no operation attribute */
4492 LY_LIST_FOR(root, tree) {
4493 LYD_TREE_DFS_BEGIN(tree, iter) {
4494 if (lyd_find_meta(iter->meta, NULL, "yang:operation")) {
4495 ERR(NULL, "Unexpected operation attribute in the YANG data.");
romanc1d2b092023-02-02 08:58:27 +01004496 ret = 1;
4497 goto cleanup;
4498 }
romanf9906b42023-05-22 14:04:29 +02004499 LYD_TREE_DFS_END(tree, iter);
romanc1d2b092023-02-02 08:58:27 +01004500 }
4501 }
4502
romanf9906b42023-05-22 14:04:29 +02004503 /* delete the current configuration */
romanf02273a2023-05-25 09:44:11 +02004504 nc_server_config_listen(NULL, NC_OP_DELETE);
roman4cb8bb12023-06-29 09:16:46 +02004505 nc_server_config_ch(NULL, NC_OP_DELETE);
roman2eab4742023-06-06 10:00:26 +02004506#ifdef NC_ENABLED_SSH_TLS
romanf02273a2023-05-25 09:44:11 +02004507 nc_server_config_ks_keystore(NULL, NC_OP_DELETE);
4508 nc_server_config_ts_truststore(NULL, NC_OP_DELETE);
romanf9906b42023-05-22 14:04:29 +02004509
4510 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02004511 ret = nc_server_config_fill_keystore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02004512 if (ret) {
4513 ERR(NULL, "Filling keystore failed.");
4514 goto cleanup;
4515 }
4516
4517 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02004518 ret = nc_server_config_fill_truststore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02004519 if (ret) {
4520 ERR(NULL, "Filling truststore failed.");
4521 goto cleanup;
4522 }
roman2eab4742023-06-06 10:00:26 +02004523#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004524
4525 /* configure netconf-server */
4526 ret = nc_server_config_fill_nectonf_server(data, NC_OP_CREATE);
4527 if (ret) {
4528 ERR(NULL, "Filling netconf-server failed.");
romanc1d2b092023-02-02 08:58:27 +01004529 goto cleanup;
4530 }
4531
4532cleanup:
4533 /* UNLOCK */
4534 pthread_rwlock_unlock(&server_opts.config_lock);
4535 return ret;
4536}
roman3f9b65c2023-06-05 14:26:58 +02004537
4538API int
4539nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path)
4540{
4541 struct lyd_node *tree = NULL;
4542 int ret = 0;
4543
4544 NC_CHECK_ARG_RET(NULL, path, 1);
4545
4546 ret = lyd_parse_data_path(ctx, path, LYD_UNKNOWN, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree);
4547 if (ret) {
4548 goto cleanup;
4549 }
4550
4551 ret = nc_server_config_setup_data(tree);
4552 if (ret) {
4553 goto cleanup;
4554 }
4555
4556cleanup:
4557 lyd_free_all(tree);
4558 return ret;
4559}