blob: a33fbcfb75e41fc5b95bfa1abeb8c9b1cb84db1f [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>
27
romanfaecc582023-06-15 16:13:31 +020028#ifdef NC_ENABLED_SSH_TLS
29#include <openssl/x509_vfy.h> // X509_STORE_free
30#endif
31
romanc1d2b092023-02-02 08:58:27 +010032#include "compat.h"
roman3f9b65c2023-06-05 14:26:58 +020033#include "config.h"
34#include "log_p.h"
romane028ef92023-02-24 16:33:08 +010035#include "server_config.h"
romanf02273a2023-05-25 09:44:11 +020036#include "server_config_p.h"
roman3f9b65c2023-06-05 14:26:58 +020037#include "session_p.h"
38
roman2eab4742023-06-06 10:00:26 +020039#ifdef NC_ENABLED_SSH_TLS
romanc1d2b092023-02-02 08:58:27 +010040
41/* All libssh supported host-key, key-exchange, encryption and mac algorithms as of version 0.10.90 */
42
43static const char *supported_hostkey_algs[] = {
romana6bf6ab2023-05-26 13:26:02 +020044 "openssh-ssh-ed25519-cert-v01", "openssh-ecdsa-sha2-nistp521-cert-v01",
45 "openssh-ecdsa-sha2-nistp384-cert-v01", "openssh-ecdsa-sha2-nistp256-cert-v01",
46 "openssh-rsa-sha2-512-cert-v01", "openssh-rsa-sha2-256-cert-v01",
47 "openssh-ssh-rsa-cert-v01", "openssh-ssh-dss-cert-v01",
romanc1d2b092023-02-02 08:58:27 +010048 "ssh-ed25519", "ecdsa-sha2-nistp521", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp256",
49 "rsa-sha2-512", "rsa-sha2-256", "ssh-rsa", "ssh-dss", NULL
50};
51
52static const char *supported_kex_algs[] = {
romana6bf6ab2023-05-26 13:26:02 +020053 "diffie-hellman-group-exchange-sha1", "curve25519-sha256", "libssh-curve25519-sha256",
romanc1d2b092023-02-02 08:58:27 +010054 "ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", "diffie-hellman-group18-sha512",
55 "diffie-hellman-group16-sha512", "diffie-hellman-group-exchange-sha256", "diffie-hellman-group14-sha256", NULL
56};
57
58static const char *supported_encryption_algs[] = {
romana6bf6ab2023-05-26 13:26:02 +020059 "openssh-chacha20-poly1305", "openssh-aes256-gcm", "openssh-aes128-gcm",
romanc1d2b092023-02-02 08:58:27 +010060 "aes256-ctr", "aes192-ctr", "aes128-ctr", "aes256-cbc", "aes192-cbc", "aes128-cbc",
roman27215242023-03-10 14:55:00 +010061 "blowfish-cbc", "triple-des-cbc", "none", NULL
romanc1d2b092023-02-02 08:58:27 +010062};
63
64static const char *supported_mac_algs[] = {
romana6bf6ab2023-05-26 13:26:02 +020065 "openssh-hmac-sha2-256-etm", "openssh-hmac-sha2-512-etm", "openssh-hmac-sha1-etm",
romanc1d2b092023-02-02 08:58:27 +010066 "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1", NULL
67};
68
roman2eab4742023-06-06 10:00:26 +020069#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +020070
romanc1d2b092023-02-02 08:58:27 +010071extern struct nc_server_opts server_opts;
72
roman4cb8bb12023-06-29 09:16:46 +020073static int
74is_listen(const struct lyd_node *node)
75{
76 assert(node);
77
78 while (node) {
79 if (!strcmp(LYD_NAME(node), "listen")) {
80 break;
81 }
82 node = lyd_parent(node);
83 }
84
85 return node != NULL;
86}
87
88static int
89is_ch(const struct lyd_node *node)
90{
91 assert(node);
92
93 while (node) {
94 if (!strcmp(LYD_NAME(node), "call-home")) {
95 break;
96 }
97 node = lyd_parent(node);
98 }
99
100 return node != NULL;
101}
102
103#ifdef NC_ENABLED_SSH_TLS
104
105static int
106is_ssh(const struct lyd_node *node)
107{
108 assert(node);
109
110 while (node) {
111 if (!strcmp(LYD_NAME(node), "ssh")) {
112 break;
113 }
114 node = lyd_parent(node);
115 }
116
117 return node != NULL;
118}
119
120static int
121is_tls(const struct lyd_node *node)
122{
123 assert(node);
124
125 while (node) {
126 if (!strcmp(LYD_NAME(node), "tls")) {
127 break;
128 }
129 node = lyd_parent(node);
130 }
131
132 return node != NULL;
133}
134
135#endif /* NC_ENABLED_SSH_TLS */
136
137static int
romanf02273a2023-05-25 09:44:11 +0200138nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, struct nc_bind **bind)
romanc1d2b092023-02-02 08:58:27 +0100139{
140 uint16_t i;
141 const char *endpt_name;
142
roman4cb8bb12023-06-29 09:16:46 +0200143 assert(node && endpt);
romanc1d2b092023-02-02 08:58:27 +0100144
145 while (node) {
146 if (!strcmp(LYD_NAME(node), "endpoint")) {
147 break;
148 }
149 node = lyd_parent(node);
150 }
151
152 if (!node) {
153 ERR(NULL, "Node \"%s\" is not contained in an endpoint subtree.", LYD_NAME(node));
154 return 1;
155 }
156
157 node = lyd_child(node);
158 assert(!strcmp(LYD_NAME(node), "name"));
159 endpt_name = lyd_get_value(node);
160
161 for (i = 0; i < server_opts.endpt_count; i++) {
162 if (!strcmp(server_opts.endpts[i].name, endpt_name)) {
163 *endpt = &server_opts.endpts[i];
164 if (bind) {
165 *bind = &server_opts.binds[i];
166 }
167 return 0;
168 }
169 }
170
171 ERR(NULL, "Endpoint \"%s\" was not found.", endpt_name);
172 return 1;
173}
174
roman4cb8bb12023-06-29 09:16:46 +0200175static int
roman5cbb6532023-06-22 12:53:17 +0200176nc_server_config_get_ch_client(const struct lyd_node *node, struct nc_ch_client **ch_client)
177{
178 uint16_t i;
179 const char *ch_client_name;
180
roman4cb8bb12023-06-29 09:16:46 +0200181 assert(node && ch_client);
182
roman5cbb6532023-06-22 12:53:17 +0200183 while (node) {
184 if (!strcmp(LYD_NAME(node), "netconf-client")) {
185 break;
186 }
187 node = lyd_parent(node);
188 }
189
190 if (!node) {
191 ERR(NULL, "Node \"%s\" is not contained in a netconf-client subtree.", LYD_NAME(node));
192 return 1;
193 }
194
195 node = lyd_child(node);
196 assert(!strcmp(LYD_NAME(node), "name"));
197 ch_client_name = lyd_get_value(node);
198
199 for (i = 0; i < server_opts.ch_client_count; i++) {
200 if (!strcmp(server_opts.ch_clients[i].name, ch_client_name)) {
201 *ch_client = &server_opts.ch_clients[i];
202 return 0;
203 }
204 }
205
206 ERR(NULL, "Call-home client \"%s\" was not found.", ch_client_name);
207 return 1;
208}
209
roman4cb8bb12023-06-29 09:16:46 +0200210#ifdef NC_ENABLED_SSH_TLS
211
212static int
213nc_server_config_get_ch_endpt(const struct lyd_node *node, struct nc_ch_endpt **ch_endpt)
roman5cbb6532023-06-22 12:53:17 +0200214{
215 uint16_t i;
216 const char *ch_endpt_name;
roman4cb8bb12023-06-29 09:16:46 +0200217 struct nc_ch_client *ch_client;
218
219 assert(node && ch_endpt);
220
221 if (nc_server_config_get_ch_client(node, &ch_client)) {
222 return 1;
223 }
roman5cbb6532023-06-22 12:53:17 +0200224
225 while (node) {
226 if (!strcmp(LYD_NAME(node), "endpoint")) {
227 break;
228 }
229 node = lyd_parent(node);
230 }
231
232 if (!node) {
233 ERR(NULL, "Node \"%s\" is not contained in a call-home endpoint subtree.", LYD_NAME(node));
234 return 1;
235 }
236
237 node = lyd_child(node);
238 assert(!strcmp(LYD_NAME(node), "name"));
239 ch_endpt_name = lyd_get_value(node);
240
241 for (i = 0; i < ch_client->ch_endpt_count; i++) {
242 if (!strcmp(ch_client->ch_endpts[i].name, ch_endpt_name)) {
243 *ch_endpt = &ch_client->ch_endpts[i];
244 return 0;
245 }
246 }
247
248 ERR(NULL, "Call-home client's \"%s\" endpoint \"%s\" was not found.", ch_client->name, ch_endpt_name);
249 return 1;
250}
251
roman4cb8bb12023-06-29 09:16:46 +0200252static int
253nc_server_config_get_ssh_opts(const struct lyd_node *node, struct nc_server_ssh_opts **opts)
254{
255 struct nc_endpt *endpt;
256 struct nc_ch_endpt *ch_endpt;
roman3f9b65c2023-06-05 14:26:58 +0200257
roman4cb8bb12023-06-29 09:16:46 +0200258 assert(node && opts);
259
260 if (is_listen(node)) {
261 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
262 return 1;
263 }
264 *opts = endpt->opts.ssh;
265 } else {
266 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
267 return 1;
268 }
269 *opts = ch_endpt->opts.ssh;
270 }
271
272 return 0;
273}
274
275static int
276nc_server_config_get_hostkey(const struct lyd_node *node, struct nc_hostkey **hostkey)
romanc1d2b092023-02-02 08:58:27 +0100277{
278 uint16_t i;
279 const char *hostkey_name;
roman4cb8bb12023-06-29 09:16:46 +0200280 struct nc_endpt *endpt;
281 struct nc_ch_endpt *ch_endpt;
282 struct nc_server_ssh_opts *opts;
romanc1d2b092023-02-02 08:58:27 +0100283
roman4cb8bb12023-06-29 09:16:46 +0200284 assert(node && hostkey);
285
286 if (is_listen(node)) {
287 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
288 return 1;
289 }
290 opts = endpt->opts.ssh;
291 } else {
292 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
293 return 1;
294 }
295 opts = ch_endpt->opts.ssh;
296 }
romanc1d2b092023-02-02 08:58:27 +0100297
298 while (node) {
299 if (!strcmp(LYD_NAME(node), "host-key")) {
300 break;
301 }
302 node = lyd_parent(node);
303 }
304
305 if (!node) {
306 ERR(NULL, "Node \"%s\" is not contained in a host-key subtree.", LYD_NAME(node));
307 return 1;
308 }
309
310 node = lyd_child(node);
311 assert(!strcmp(LYD_NAME(node), "name"));
312 hostkey_name = lyd_get_value(node);
313
314 for (i = 0; i < opts->hostkey_count; i++) {
315 if (!strcmp(opts->hostkeys[i].name, hostkey_name)) {
316 *hostkey = &opts->hostkeys[i];
317 return 0;
318 }
319 }
320
321 ERR(NULL, "Host-key \"%s\" was not found.", hostkey_name);
322 return 1;
323}
324
roman4cb8bb12023-06-29 09:16:46 +0200325static int
326nc_server_config_get_auth_client(const struct lyd_node *node, struct nc_client_auth **auth_client)
romanc1d2b092023-02-02 08:58:27 +0100327{
328 uint16_t i;
329 const char *authkey_name;
roman4cb8bb12023-06-29 09:16:46 +0200330 struct nc_endpt *endpt;
331 struct nc_ch_endpt *ch_endpt;
332 struct nc_server_ssh_opts *opts;
romanc1d2b092023-02-02 08:58:27 +0100333
roman4cb8bb12023-06-29 09:16:46 +0200334 assert(node && auth_client);
335
336 if (is_listen(node)) {
337 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
338 return 1;
339 }
340 opts = endpt->opts.ssh;
341 } else {
342 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
343 return 1;
344 }
345 opts = ch_endpt->opts.ssh;
346 }
romanc1d2b092023-02-02 08:58:27 +0100347
348 while (node) {
349 if (!strcmp(LYD_NAME(node), "user")) {
350 break;
351 }
352 node = lyd_parent(node);
353 }
354
355 if (!node) {
356 ERR(NULL, "Node \"%s\" is not contained in a client-authentication subtree.", LYD_NAME(node));
357 return 1;
358 }
359
360 node = lyd_child(node);
361 assert(!strcmp(LYD_NAME(node), "name"));
362 authkey_name = lyd_get_value(node);
363
364 for (i = 0; i < opts->client_count; i++) {
365 if (!strcmp(opts->auth_clients[i].username, authkey_name)) {
366 *auth_client = &opts->auth_clients[i];
367 return 0;
368 }
369 }
370
371 ERR(NULL, "Authorized key \"%s\" was not found.", authkey_name);
372 return 1;
373}
374
roman4cb8bb12023-06-29 09:16:46 +0200375static int
376nc_server_config_get_pubkey(const struct lyd_node *node, struct nc_public_key **pubkey)
romanc1d2b092023-02-02 08:58:27 +0100377{
378 uint16_t i;
379 const char *pubkey_name;
roman4cb8bb12023-06-29 09:16:46 +0200380 struct nc_client_auth *auth_client;
romanc1d2b092023-02-02 08:58:27 +0100381
roman4cb8bb12023-06-29 09:16:46 +0200382 assert(node && pubkey);
383
384 if (nc_server_config_get_auth_client(node, &auth_client)) {
385 return 1;
386 }
romanc1d2b092023-02-02 08:58:27 +0100387
388 node = lyd_parent(node);
389 while (node) {
390 if (!strcmp(LYD_NAME(node), "public-key")) {
391 break;
392 }
393 node = lyd_parent(node);
394 }
395
396 if (!node) {
397 ERR(NULL, "Node \"%s\" is not contained in a public-key subtree.", LYD_NAME(node));
398 return 1;
399 }
400
401 node = lyd_child(node);
402 assert(!strcmp(LYD_NAME(node), "name"));
403 pubkey_name = lyd_get_value(node);
404
405 for (i = 0; i < auth_client->pubkey_count; i++) {
406 if (!strcmp(auth_client->pubkeys[i].name, pubkey_name)) {
407 *pubkey = &auth_client->pubkeys[i];
408 return 0;
409 }
410 }
411
412 ERR(NULL, "Public key \"%s\" was not found.", pubkey_name);
413 return 1;
414}
415
roman4cb8bb12023-06-29 09:16:46 +0200416static int
romanb6f44032023-06-30 15:07:56 +0200417nc_server_config_get_tls_opts(const struct lyd_node *node, struct nc_server_tls_opts **opts)
418{
419 struct nc_endpt *endpt;
420 struct nc_ch_endpt *ch_endpt;
421
422 assert(node && opts);
423
424 if (is_listen(node)) {
425 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
426 return 1;
427 }
428 *opts = endpt->opts.tls;
429 } else {
430 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
431 return 1;
432 }
433 *opts = ch_endpt->opts.tls;
434 }
435
436 return 0;
437}
438
439static int
roman4cb8bb12023-06-29 09:16:46 +0200440nc_server_config_get_cert(const struct lyd_node *node, int is_ee, struct nc_certificate **cert)
roman3f9b65c2023-06-05 14:26:58 +0200441{
442 uint16_t i;
443 const char *cert_name;
roman4cb8bb12023-06-29 09:16:46 +0200444 struct nc_cert_grouping *auth_client;
romanb6f44032023-06-30 15:07:56 +0200445 struct nc_server_tls_opts *opts;
roman3f9b65c2023-06-05 14:26:58 +0200446
roman4cb8bb12023-06-29 09:16:46 +0200447 assert(node && cert);
448
romanb6f44032023-06-30 15:07:56 +0200449 if (nc_server_config_get_tls_opts(node, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +0200450 return 1;
451 }
452
453 if (is_ee) {
romanb6f44032023-06-30 15:07:56 +0200454 auth_client = &opts->ee_certs;
roman4cb8bb12023-06-29 09:16:46 +0200455 } else {
romanb6f44032023-06-30 15:07:56 +0200456 auth_client = &opts->ca_certs;
roman4cb8bb12023-06-29 09:16:46 +0200457 }
roman3f9b65c2023-06-05 14:26:58 +0200458
459 while (node) {
460 if (!strcmp(LYD_NAME(node), "certificate")) {
461 break;
462 }
463 node = lyd_parent(node);
464 }
465
466 if (!node) {
467 ERR(NULL, "Node \"%s\" is not contained in a certificate subtree.", LYD_NAME(node));
468 return 1;
469 }
470
471 node = lyd_child(node);
472 assert(!strcmp(LYD_NAME(node), "name"));
473 cert_name = lyd_get_value(node);
474
475 for (i = 0; i < auth_client->cert_count; i++) {
476 if (!strcmp(auth_client->certs[i].name, cert_name)) {
477 *cert = &auth_client->certs[i];
478 return 0;
479 }
480 }
481
482 ERR(NULL, "Certificate \"%s\" was not found.", cert_name);
483 return 1;
484}
485
486static int
roman4cb8bb12023-06-29 09:16:46 +0200487nc_server_config_get_ctn(const struct lyd_node *node, struct nc_ctn **ctn)
roman3f9b65c2023-06-05 14:26:58 +0200488{
489 uint32_t id;
490 struct nc_ctn *iter;
romanb6f44032023-06-30 15:07:56 +0200491 struct nc_server_tls_opts *opts;
roman3f9b65c2023-06-05 14:26:58 +0200492
roman4cb8bb12023-06-29 09:16:46 +0200493 assert(node && ctn);
494
romanb6f44032023-06-30 15:07:56 +0200495 if (nc_server_config_get_tls_opts(node, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +0200496 return 1;
497 }
roman3f9b65c2023-06-05 14:26:58 +0200498
499 node = lyd_parent(node);
500 while (node) {
501 if (!strcmp(LYD_NAME(node), "cert-to-name")) {
502 break;
503 }
504 node = lyd_parent(node);
505 }
506
507 if (!node) {
508 ERR(NULL, "Node \"%s\" is not contained in a cert-to-name subtree.", LYD_NAME(node));
509 return 1;
510 }
511
512 node = lyd_child(node);
513 assert(!strcmp(LYD_NAME(node), "id"));
514 id = strtoul(lyd_get_value(node), NULL, 10);
515
romanb6f44032023-06-30 15:07:56 +0200516 iter = opts->ctn;
roman3f9b65c2023-06-05 14:26:58 +0200517 while (iter) {
518 if (iter->id == id) {
519 *ctn = iter;
520 return 0;
521 }
522
523 iter = iter->next;
524 }
525
526 ERR(NULL, "Cert-to-name entry with id \"%d\" was not found.", id);
527 return 1;
528}
529
roman2eab4742023-06-06 10:00:26 +0200530NC_PRIVKEY_FORMAT
531nc_server_config_get_private_key_type(const char *format)
532{
533 if (!strcmp(format, "rsa-private-key-format")) {
534 return NC_PRIVKEY_FORMAT_RSA;
535 } else if (!strcmp(format, "ec-private-key-format")) {
536 return NC_PRIVKEY_FORMAT_EC;
537 } else if (!strcmp(format, "subject-private-key-info-format")) {
538 return NC_PRIVKEY_FORMAT_X509;
539 } else if (!strcmp(format, "openssh-private-key-format")) {
540 return NC_PRIVKEY_FORMAT_OPENSSH;
541 } else {
542 ERR(NULL, "Private key format (%s) not supported.", format);
543 return NC_PRIVKEY_FORMAT_UNKNOWN;
544 }
545}
546
547#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200548
romanf02273a2023-05-25 09:44:11 +0200549int
romanc1d2b092023-02-02 08:58:27 +0100550equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char *parent_name)
551{
552 uint16_t i;
553
554 assert(node && parent_count > 0 && parent_name);
555
556 node = lyd_parent(node);
557 for (i = 1; i < parent_count; i++) {
558 node = lyd_parent(node);
559 }
560
561 if (!strcmp(LYD_NAME(node), parent_name)) {
562 return 1;
563 }
564
565 return 0;
566}
567
romanf02273a2023-05-25 09:44:11 +0200568int
569nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uint16_t *count)
570{
571 int ret = 0;
572 void *tmp;
573 char **name;
574
575 tmp = realloc(*ptr, (*count + 1) * size);
576 if (!tmp) {
577 ERRMEM;
578 ret = 1;
579 goto cleanup;
580 }
581 *ptr = tmp;
582
583 /* set the newly allocated memory to 0 */
584 memset((char *)(*ptr) + (*count * size), 0, size);
585 (*count)++;
586
587 /* access the first member of the supposed structure */
588 name = (char **)((*ptr) + ((*count - 1) * size));
589
590 /* and set it's value */
591 *name = strdup(key_value);
592 if (!*name) {
593 ERRMEM;
594 ret = 1;
595 goto cleanup;
596 }
597
598cleanup:
599 return ret;
600}
601
roman3f9b65c2023-06-05 14:26:58 +0200602static void
603nc_server_config_del_endpt_name(struct nc_endpt *endpt)
604{
605 free(endpt->name);
606 endpt->name = NULL;
607}
608
roman2eab4742023-06-06 10:00:26 +0200609#ifdef NC_ENABLED_SSH_TLS
610
roman3f9b65c2023-06-05 14:26:58 +0200611static void
612nc_server_config_del_local_address(struct nc_bind *bind)
613{
614 free(bind->address);
615 bind->address = NULL;
616}
617
romanc1d2b092023-02-02 08:58:27 +0100618static void
roman874fed12023-05-25 10:20:01 +0200619nc_server_config_del_auth_client_pam_name(struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100620{
621 free(auth_client->pam_config_name);
622 auth_client->pam_config_name = NULL;
623}
624
625static void
roman874fed12023-05-25 10:20:01 +0200626nc_server_config_del_auth_client_pam_dir(struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100627{
628 free(auth_client->pam_config_dir);
629 auth_client->pam_config_dir = NULL;
630}
631
632static void
roman0bbc19c2023-05-26 09:59:09 +0200633nc_server_config_del_endpt_reference(struct nc_endpt *endpt)
634{
635 free(endpt->referenced_endpt_name);
636 endpt->referenced_endpt_name = NULL;
637}
638
639static void
roman874fed12023-05-25 10:20:01 +0200640nc_server_config_del_hostkey_name(struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100641{
642 free(hostkey->name);
643 hostkey->name = NULL;
644}
645
646static void
roman874fed12023-05-25 10:20:01 +0200647nc_server_config_del_public_key(struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100648{
roman3f9b65c2023-06-05 14:26:58 +0200649 free(hostkey->key.pubkey_data);
650 hostkey->key.pubkey_data = NULL;
romanc1d2b092023-02-02 08:58:27 +0100651}
652
653static void
roman874fed12023-05-25 10:20:01 +0200654nc_server_config_del_private_key(struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100655{
roman3f9b65c2023-06-05 14:26:58 +0200656 free(hostkey->key.privkey_data);
657 hostkey->key.privkey_data = NULL;
romanc1d2b092023-02-02 08:58:27 +0100658}
659
660static void
roman874fed12023-05-25 10:20:01 +0200661nc_server_config_del_auth_client_pubkey_name(struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +0100662{
663 free(pubkey->name);
664 pubkey->name = NULL;
665}
666
667static void
roman874fed12023-05-25 10:20:01 +0200668nc_server_config_del_auth_client_pubkey_pub_base64(struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +0100669{
roman3f9b65c2023-06-05 14:26:58 +0200670 free(pubkey->data);
671 pubkey->data = NULL;
romanc1d2b092023-02-02 08:58:27 +0100672}
673
674static void
roman874fed12023-05-25 10:20:01 +0200675nc_server_config_del_auth_client_password(struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100676{
677 free(auth_client->password);
678 auth_client->password = NULL;
679}
680
681static void
roman874fed12023-05-25 10:20:01 +0200682nc_server_config_del_hostkey_algs(struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100683{
684 free(opts->hostkey_algs);
685 opts->hostkey_algs = NULL;
686}
687
688static void
roman874fed12023-05-25 10:20:01 +0200689nc_server_config_del_kex_algs(struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100690{
691 free(opts->kex_algs);
692 opts->kex_algs = NULL;
693}
694
695static void
roman874fed12023-05-25 10:20:01 +0200696nc_server_config_del_encryption_algs(struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100697{
698 free(opts->encryption_algs);
699 opts->encryption_algs = NULL;
700}
701
702static void
roman874fed12023-05-25 10:20:01 +0200703nc_server_config_del_mac_algs(struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100704{
705 free(opts->mac_algs);
706 opts->mac_algs = NULL;
707}
708
709static void
roman874fed12023-05-25 10:20:01 +0200710nc_server_config_del_hostkey(struct nc_server_ssh_opts *opts, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100711{
roman874fed12023-05-25 10:20:01 +0200712 assert(hostkey->store == NC_STORE_LOCAL || hostkey->store == NC_STORE_KEYSTORE);
romanc1d2b092023-02-02 08:58:27 +0100713
roman874fed12023-05-25 10:20:01 +0200714 if (hostkey->store == NC_STORE_LOCAL) {
715 nc_server_config_del_public_key(hostkey);
716 nc_server_config_del_private_key(hostkey);
romanc1d2b092023-02-02 08:58:27 +0100717 }
718
roman874fed12023-05-25 10:20:01 +0200719 nc_server_config_del_hostkey_name(hostkey);
romanc1d2b092023-02-02 08:58:27 +0100720 opts->hostkey_count--;
721 if (!opts->hostkey_count) {
722 free(opts->hostkeys);
723 opts->hostkeys = NULL;
724 }
725}
726
727static void
roman874fed12023-05-25 10:20:01 +0200728nc_server_config_del_auth_client_pubkey(struct nc_client_auth *auth_client, struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +0100729{
roman874fed12023-05-25 10:20:01 +0200730 nc_server_config_del_auth_client_pubkey_name(pubkey);
731 nc_server_config_del_auth_client_pubkey_pub_base64(pubkey);
romanc1d2b092023-02-02 08:58:27 +0100732
733 auth_client->pubkey_count--;
734 if (!auth_client->pubkey_count) {
735 free(auth_client->pubkeys);
736 auth_client->pubkeys = NULL;
737 }
738}
739
740static void
roman874fed12023-05-25 10:20:01 +0200741nc_server_config_del_auth_client(struct nc_server_ssh_opts *opts, struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100742{
743 uint16_t i, pubkey_count;
744
roman4cb8bb12023-06-29 09:16:46 +0200745 free(auth_client->username);
746 auth_client->username = NULL;
747
roman874fed12023-05-25 10:20:01 +0200748 if (auth_client->store == NC_STORE_LOCAL) {
romanc1d2b092023-02-02 08:58:27 +0100749 pubkey_count = auth_client->pubkey_count;
750 for (i = 0; i < pubkey_count; i++) {
roman874fed12023-05-25 10:20:01 +0200751 nc_server_config_del_auth_client_pubkey(auth_client, &auth_client->pubkeys[i]);
romanc1d2b092023-02-02 08:58:27 +0100752 }
romanc1d2b092023-02-02 08:58:27 +0100753 }
754
roman874fed12023-05-25 10:20:01 +0200755 nc_server_config_del_auth_client_password(auth_client);
756 nc_server_config_del_auth_client_pam_name(auth_client);
757 nc_server_config_del_auth_client_pam_dir(auth_client);
romanc1d2b092023-02-02 08:58:27 +0100758
759 opts->client_count--;
760 if (!opts->client_count) {
761 free(opts->auth_clients);
762 opts->auth_clients = NULL;
763 }
764}
765
766static void
roman874fed12023-05-25 10:20:01 +0200767nc_server_config_del_ssh(struct nc_bind *bind, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100768{
769 uint16_t i, hostkey_count, client_count;
770
roman874fed12023-05-25 10:20:01 +0200771 nc_server_config_del_local_address(bind);
romanc1d2b092023-02-02 08:58:27 +0100772 if (bind->sock > -1) {
773 close(bind->sock);
774 }
775
776 /* store in variable because it gets decremented in the function call */
777 hostkey_count = opts->hostkey_count;
778 for (i = 0; i < hostkey_count; i++) {
roman874fed12023-05-25 10:20:01 +0200779 nc_server_config_del_hostkey(opts, &opts->hostkeys[i]);
romanc1d2b092023-02-02 08:58:27 +0100780 }
781
782 client_count = opts->client_count;
783 for (i = 0; i < client_count; i++) {
roman874fed12023-05-25 10:20:01 +0200784 nc_server_config_del_auth_client(opts, &opts->auth_clients[i]);
romanc1d2b092023-02-02 08:58:27 +0100785 }
786
roman874fed12023-05-25 10:20:01 +0200787 nc_server_config_del_hostkey_algs(opts);
788 nc_server_config_del_kex_algs(opts);
789 nc_server_config_del_encryption_algs(opts);
790 nc_server_config_del_mac_algs(opts);
romanc1d2b092023-02-02 08:58:27 +0100791
792 free(opts);
793 opts = NULL;
794}
795
796void
roman874fed12023-05-25 10:20:01 +0200797nc_server_config_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind)
romanc1d2b092023-02-02 08:58:27 +0100798{
roman874fed12023-05-25 10:20:01 +0200799 nc_server_config_del_endpt_name(endpt);
roman0bbc19c2023-05-26 09:59:09 +0200800 nc_server_config_del_endpt_reference(endpt);
roman874fed12023-05-25 10:20:01 +0200801 nc_server_config_del_ssh(bind, endpt->opts.ssh);
romanc1d2b092023-02-02 08:58:27 +0100802
803 server_opts.endpt_count--;
804 if (!server_opts.endpt_count) {
805 free(server_opts.endpts);
806 free(server_opts.binds);
807 server_opts.endpts = NULL;
808 server_opts.binds = NULL;
809 }
810}
811
roman2eab4742023-06-06 10:00:26 +0200812#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200813
roman45cec4e2023-02-17 10:21:39 +0100814void
roman874fed12023-05-25 10:20:01 +0200815nc_server_config_del_unix_socket(struct nc_bind *bind, struct nc_server_unix_opts *opts)
roman83683fb2023-02-24 09:15:23 +0100816{
817 if (bind->sock > -1) {
818 close(bind->sock);
819 }
820
821 free(bind->address);
822 free(opts->address);
823
824 free(opts);
roman83683fb2023-02-24 09:15:23 +0100825}
826
827void
roman874fed12023-05-25 10:20:01 +0200828nc_server_config_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *bind)
roman83683fb2023-02-24 09:15:23 +0100829{
roman874fed12023-05-25 10:20:01 +0200830 nc_server_config_del_endpt_name(endpt);
831 nc_server_config_del_unix_socket(bind, endpt->opts.unixsock);
roman83683fb2023-02-24 09:15:23 +0100832
833 server_opts.endpt_count--;
834 if (!server_opts.endpt_count) {
835 free(server_opts.endpts);
836 free(server_opts.binds);
837 server_opts.endpts = NULL;
838 server_opts.binds = NULL;
839 }
840}
841
roman2eab4742023-06-06 10:00:26 +0200842#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +0200843
844static void
romanfaecc582023-06-15 16:13:31 +0200845nc_server_config_del_url(struct nc_server_tls_opts *opts)
846{
847 free(opts->crl_url);
848 opts->crl_url = NULL;
849}
850
851static void
852nc_server_config_del_path(struct nc_server_tls_opts *opts)
853{
854 free(opts->crl_path);
855 opts->crl_path = NULL;
856}
857
858static void
roman12644fe2023-06-08 11:06:42 +0200859nc_server_config_tls_del_ciphers(struct nc_server_tls_opts *opts)
860{
861 free(opts->ciphers);
862 opts->ciphers = NULL;
863}
864
865static void
roman3f9b65c2023-06-05 14:26:58 +0200866nc_server_config_tls_del_public_key(struct nc_server_tls_opts *opts)
867{
868 free(opts->pubkey_data);
869 opts->pubkey_data = NULL;
870}
871
872static void
873nc_server_config_tls_del_cleartext_private_key(struct nc_server_tls_opts *opts)
874{
875 free(opts->privkey_data);
876 opts->privkey_data = NULL;
877}
878
879static void
880nc_server_config_tls_del_cert_data(struct nc_server_tls_opts *opts)
881{
882 free(opts->cert_data);
883 opts->cert_data = NULL;
884}
885
886static void
887nc_server_config_tls_del_cert_data_certificate(struct nc_certificate *cert)
888{
889 free(cert->data);
890 cert->data = NULL;
891}
892
893static void
894nc_server_config_del_fingerprint(struct nc_ctn *ctn)
895{
896 free(ctn->fingerprint);
897 ctn->fingerprint = NULL;
898}
899
900static void
901nc_server_config_del_cert(struct nc_cert_grouping *certs, struct nc_certificate *cert)
902{
903 free(cert->name);
904 cert->name = NULL;
905
906 free(cert->data);
907 cert->data = NULL;
908
909 certs->cert_count--;
910 if (!certs->cert_count) {
911 free(certs->certs);
912 certs->certs = NULL;
913 }
914}
915
916static void
917nc_server_config_tls_del_certs(struct nc_cert_grouping *ca)
918{
919 uint16_t i, cert_count;
920
921 if (ca->store == NC_STORE_LOCAL) {
922 cert_count = ca->cert_count;
923 for (i = 0; i < cert_count; i++) {
924 nc_server_config_del_cert(ca, &ca->certs[i]);
925 }
926 }
927}
928
929static void
930nc_server_config_del_ctn(struct nc_server_tls_opts *opts, struct nc_ctn *ctn)
931{
932 struct nc_ctn *iter;
933
934 free(ctn->fingerprint);
935 ctn->fingerprint = NULL;
936
937 free(ctn->name);
938 ctn->name = NULL;
939
940 if (opts->ctn == ctn) {
941 /* it's the first in the list */
942 opts->ctn = ctn->next;
943 free(ctn);
944 return;
945 }
946
947 iter = opts->ctn;
948 while (iter) {
949 if (iter->next == ctn) {
950 /* found the ctn */
951 break;
952 }
953 iter = iter->next;
954 }
955
956 iter->next = ctn->next;
957 free(ctn);
958}
959
960static void
roman12644fe2023-06-08 11:06:42 +0200961nc_server_config_tls_del_ctns(struct nc_server_tls_opts *opts)
roman3f9b65c2023-06-05 14:26:58 +0200962{
963 struct nc_ctn *cur, *next;
964
965 cur = opts->ctn;
966 while (cur) {
967 next = cur->next;
968 free(cur->fingerprint);
969 free(cur->name);
970 free(cur);
971 cur = next;
972 }
973 opts->ctn = NULL;
974}
975
976static void
977nc_server_config_del_tls(struct nc_bind *bind, struct nc_server_tls_opts *opts)
978{
979 nc_server_config_del_local_address(bind);
980 if (bind->sock > -1) {
981 close(bind->sock);
982 }
983
984 if (opts->store == NC_STORE_LOCAL) {
985 nc_server_config_tls_del_public_key(opts);
986 nc_server_config_tls_del_cleartext_private_key(opts);
987 nc_server_config_tls_del_cert_data(opts);
988 }
989
990 nc_server_config_tls_del_certs(&opts->ca_certs);
991 nc_server_config_tls_del_certs(&opts->ee_certs);
992
romanfaecc582023-06-15 16:13:31 +0200993 nc_server_config_del_path(opts);
994 nc_server_config_del_url(opts);
995 X509_STORE_free(opts->crl_store);
996 opts->crl_store = NULL;
997
roman12644fe2023-06-08 11:06:42 +0200998 nc_server_config_tls_del_ctns(opts);
999 nc_server_config_tls_del_ciphers(opts);
roman3f9b65c2023-06-05 14:26:58 +02001000
1001 free(opts);
1002}
1003
1004static void
1005nc_server_config_del_endpt_tls(struct nc_endpt *endpt, struct nc_bind *bind)
1006{
1007 nc_server_config_del_endpt_name(endpt);
roman2e797ef2023-06-19 10:47:49 +02001008 nc_server_config_del_endpt_reference(endpt);
roman3f9b65c2023-06-05 14:26:58 +02001009 nc_server_config_del_tls(bind, endpt->opts.tls);
1010
1011 server_opts.endpt_count--;
1012 if (!server_opts.endpt_count) {
1013 free(server_opts.endpts);
1014 free(server_opts.binds);
1015 server_opts.endpts = NULL;
1016 server_opts.binds = NULL;
1017 }
1018}
1019
roman5cbb6532023-06-22 12:53:17 +02001020static void
1021nc_server_config_del_remote_address(struct nc_ch_endpt *ch_endpt)
1022{
1023 free(ch_endpt->address);
1024 ch_endpt->address = NULL;
1025}
1026
roman2eab4742023-06-06 10:00:26 +02001027#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02001028
romanc1d2b092023-02-02 08:58:27 +01001029/* presence container */
1030int
romanf02273a2023-05-25 09:44:11 +02001031nc_server_config_listen(struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001032{
roman0bbc19c2023-05-26 09:59:09 +02001033 uint16_t i, endpt_count;
romanc1d2b092023-02-02 08:58:27 +01001034
romanf02273a2023-05-25 09:44:11 +02001035 (void) node;
1036
romanc1d2b092023-02-02 08:58:27 +01001037 assert(op == NC_OP_CREATE || op == NC_OP_DELETE);
1038
1039 if (op == NC_OP_DELETE) {
roman0bbc19c2023-05-26 09:59:09 +02001040 endpt_count = server_opts.endpt_count;
1041 for (i = 0; i < endpt_count; i++) {
roman456f92d2023-04-28 10:28:12 +02001042 switch (server_opts.endpts[i].ti) {
roman2eab4742023-06-06 10:00:26 +02001043#ifdef NC_ENABLED_SSH_TLS
roman456f92d2023-04-28 10:28:12 +02001044 case NC_TI_LIBSSH:
roman874fed12023-05-25 10:20:01 +02001045 nc_server_config_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]);
roman456f92d2023-04-28 10:28:12 +02001046 break;
roman456f92d2023-04-28 10:28:12 +02001047 case NC_TI_OPENSSL:
roman3f9b65c2023-06-05 14:26:58 +02001048 nc_server_config_del_endpt_tls(&server_opts.endpts[i], &server_opts.binds[i]);
roman456f92d2023-04-28 10:28:12 +02001049 break;
roman2eab4742023-06-06 10:00:26 +02001050#endif /* NC_ENABLED_SSH_TLS */
roman456f92d2023-04-28 10:28:12 +02001051 case NC_TI_UNIX:
roman874fed12023-05-25 10:20:01 +02001052 nc_server_config_del_endpt_unix_socket(&server_opts.endpts[i], &server_opts.binds[i]);
roman456f92d2023-04-28 10:28:12 +02001053 break;
1054 case NC_TI_NONE:
1055 case NC_TI_FD:
1056 ERRINT;
1057 return 1;
roman83683fb2023-02-24 09:15:23 +01001058 }
romanc1d2b092023-02-02 08:58:27 +01001059 }
1060 }
1061
1062 return 0;
1063}
1064
roman5cbb6532023-06-22 12:53:17 +02001065#ifdef NC_ENABLED_SSH_TLS
1066
1067static void
1068nc_server_config_ch_del_ssh(struct nc_server_ssh_opts *opts)
1069{
1070 uint16_t i, hostkey_count, client_count;
1071
1072 /* store in variable because it gets decremented in the function call */
1073 hostkey_count = opts->hostkey_count;
1074 for (i = 0; i < hostkey_count; i++) {
1075 nc_server_config_del_hostkey(opts, &opts->hostkeys[i]);
1076 }
1077
1078 client_count = opts->client_count;
1079 for (i = 0; i < client_count; i++) {
1080 nc_server_config_del_auth_client(opts, &opts->auth_clients[i]);
1081 }
1082
1083 nc_server_config_del_hostkey_algs(opts);
1084 nc_server_config_del_kex_algs(opts);
1085 nc_server_config_del_encryption_algs(opts);
1086 nc_server_config_del_mac_algs(opts);
1087
1088 free(opts);
1089 opts = NULL;
1090}
1091
1092static void
romanb6f44032023-06-30 15:07:56 +02001093nc_server_config_ch_del_tls(struct nc_server_tls_opts *opts)
1094{
1095 if (opts->store == NC_STORE_LOCAL) {
1096 nc_server_config_tls_del_public_key(opts);
1097 nc_server_config_tls_del_cleartext_private_key(opts);
1098 nc_server_config_tls_del_cert_data(opts);
1099 }
1100
1101 nc_server_config_tls_del_certs(&opts->ca_certs);
1102 nc_server_config_tls_del_certs(&opts->ee_certs);
1103
1104 nc_server_config_del_path(opts);
1105 nc_server_config_del_url(opts);
1106 X509_STORE_free(opts->crl_store);
1107 opts->crl_store = NULL;
1108
1109 nc_server_config_tls_del_ctns(opts);
1110 nc_server_config_tls_del_ciphers(opts);
1111
1112 free(opts);
1113}
1114
1115static void
roman5cbb6532023-06-22 12:53:17 +02001116nc_server_config_ch_del_endpt_address(struct nc_ch_endpt *ch_endpt)
1117{
1118 free(ch_endpt->address);
1119 ch_endpt->address = NULL;
1120}
1121
1122#endif /* NC_ENABLED_SSH_TLS */
1123
1124static void
1125nc_server_config_ch_del_endpt(struct nc_ch_client *ch_client, struct nc_ch_endpt *ch_endpt)
1126{
1127 free(ch_endpt->name);
1128 ch_endpt->name = NULL;
1129
1130#ifdef NC_ENABLED_SSH_TLS
1131 nc_server_config_ch_del_endpt_address(ch_endpt);
1132 if (ch_endpt->sock_pending > -1) {
1133 close(ch_endpt->sock_pending);
1134 ch_endpt->sock_pending = -1;
1135 }
1136#endif /* NC_ENABLED_SSH_TLS */
1137
1138 switch (ch_endpt->ti) {
1139#ifdef NC_ENABLED_SSH_TLS
1140 case NC_TI_LIBSSH:
1141 nc_server_config_ch_del_ssh(ch_endpt->opts.ssh);
1142 break;
romanb6f44032023-06-30 15:07:56 +02001143 case NC_TI_OPENSSL:
1144 nc_server_config_ch_del_tls(ch_endpt->opts.tls);
1145 break;
roman5cbb6532023-06-22 12:53:17 +02001146#endif /* NC_ENABLED_SSH_TLS */
1147 default:
1148 ERRINT;
1149 break;
1150 }
1151
1152 ch_client->ch_endpt_count--;
1153 if (!ch_client->ch_endpt_count) {
1154 free(ch_client->ch_endpts);
1155 ch_client->ch_endpts = NULL;
1156 }
1157}
1158
1159static void
1160nc_server_config_ch_del_client(struct nc_ch_client *ch_client)
1161{
1162 uint16_t i, ch_endpt_count;
1163
1164 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
1165
1166 free(ch_client->name);
1167 ch_client->name = NULL;
1168
1169 if (ch_client->session) {
1170 pthread_mutex_lock(&ch_client->session->opts.server.ch_lock);
1171 pthread_cond_signal(&ch_client->session->opts.server.ch_cond);
1172 pthread_mutex_unlock(&ch_client->session->opts.server.ch_lock);
romanb6f44032023-06-30 15:07:56 +02001173 ch_client->session = NULL;
roman5cbb6532023-06-22 12:53:17 +02001174 }
1175
roman5cbb6532023-06-22 12:53:17 +02001176 pthread_rwlock_unlock(&server_opts.ch_client_lock);
1177
romanb6f44032023-06-30 15:07:56 +02001178 if (ch_client->tid) {
1179 pthread_join(ch_client->tid, NULL);
1180 }
roman5cbb6532023-06-22 12:53:17 +02001181
1182 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
1183
1184 ch_endpt_count = ch_client->ch_endpt_count;
1185 for (i = 0; i < ch_endpt_count; i++) {
1186 nc_server_config_ch_del_endpt(ch_client, &ch_client->ch_endpts[i]);
1187 }
1188
1189 server_opts.ch_client_count--;
1190 if (!server_opts.ch_client_count) {
1191 free(server_opts.ch_clients);
1192 server_opts.ch_clients = NULL;
1193 }
1194
1195 pthread_rwlock_unlock(&server_opts.ch_client_lock);
1196}
1197
1198void
1199nc_server_config_ch(const struct lyd_node *node, NC_OPERATION op)
1200{
1201 uint16_t i, ch_client_count;
1202
1203 (void) node;
1204
1205 if (op == NC_OP_DELETE) {
1206 ch_client_count = server_opts.ch_client_count;
1207 for (i = 0; i < ch_client_count; i++) {
1208 nc_server_config_ch_del_client(&server_opts.ch_clients[i]);
1209 }
1210 }
1211}
1212
romanc1d2b092023-02-02 08:58:27 +01001213/* default leaf */
1214static int
romane028ef92023-02-24 16:33:08 +01001215nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001216{
romanb6f44032023-06-30 15:07:56 +02001217 struct nc_ch_client *ch_client;
1218
romanc1d2b092023-02-02 08:58:27 +01001219 assert(!strcmp(LYD_NAME(node), "idle-timeout"));
1220
romanb6f44032023-06-30 15:07:56 +02001221 if (is_listen(node)) {
romanc1d2b092023-02-02 08:58:27 +01001222 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1223 server_opts.idle_timeout = strtoul(lyd_get_value(node), NULL, 10);
1224 } else {
1225 /* default value */
1226 server_opts.idle_timeout = 3600;
1227 }
romanb6f44032023-06-30 15:07:56 +02001228 } else {
1229 /* call-home idle timeout */
1230 if (nc_server_config_get_ch_client(node, &ch_client)) {
1231 return 1;
1232 }
1233
1234 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1235 ch_client->idle_timeout = strtoul(lyd_get_value(node), NULL, 10);
1236 } else if (op == NC_OP_DELETE) {
1237 ch_client->idle_timeout = 180;
1238 }
romanc1d2b092023-02-02 08:58:27 +01001239 }
1240
1241 return 0;
1242}
1243
1244static int
roman874fed12023-05-25 10:20:01 +02001245nc_server_config_create_bind(void)
romanc1d2b092023-02-02 08:58:27 +01001246{
1247 int ret = 0;
1248 void *tmp;
1249
1250 tmp = realloc(server_opts.binds, (server_opts.endpt_count + 1) * sizeof *server_opts.binds);
1251 if (!tmp) {
1252 ERRMEM;
1253 ret = 1;
1254 goto cleanup;
1255 }
1256 server_opts.binds = tmp;
1257 memset(&server_opts.binds[server_opts.endpt_count], 0, sizeof *server_opts.binds);
1258
1259 server_opts.binds[server_opts.endpt_count].sock = -1;
1260
1261cleanup:
1262 return ret;
1263}
1264
1265static int
roman874fed12023-05-25 10:20:01 +02001266nc_server_config_create_endpoint(const struct lyd_node *node)
romanc1d2b092023-02-02 08:58:27 +01001267{
roman874fed12023-05-25 10:20:01 +02001268 if (nc_server_config_create_bind()) {
romanf02273a2023-05-25 09:44:11 +02001269 return 1;
romanc1d2b092023-02-02 08:58:27 +01001270 }
romanc1d2b092023-02-02 08:58:27 +01001271
1272 node = lyd_child(node);
1273 assert(!strcmp(LYD_NAME(node), "name"));
1274
romanf02273a2023-05-25 09:44:11 +02001275 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 +01001276}
1277
roman5cbb6532023-06-22 12:53:17 +02001278static int
1279nc_server_config_ch_create_endpoint(const struct lyd_node *node, struct nc_ch_client *ch_client)
1280{
1281 node = lyd_child(node);
1282 assert(!strcmp(LYD_NAME(node), "name"));
1283
1284 return nc_server_config_realloc(lyd_get_value(node), (void **)&ch_client->ch_endpts, sizeof *ch_client->ch_endpts, &ch_client->ch_endpt_count);
1285}
1286
romanc1d2b092023-02-02 08:58:27 +01001287/* list */
1288static int
romane028ef92023-02-24 16:33:08 +01001289nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001290{
1291 int ret = 0;
1292 struct nc_endpt *endpt;
1293 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001294 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001295
1296 assert(!strcmp(LYD_NAME(node), "endpoint"));
1297
roman5cbb6532023-06-22 12:53:17 +02001298 if (is_listen(node)) {
1299 /* listen */
1300 if (op == NC_OP_CREATE) {
1301 ret = nc_server_config_create_endpoint(node);
1302 if (ret) {
1303 goto cleanup;
1304 }
1305 } else if (op == NC_OP_DELETE) {
1306 /* free all children */
1307 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1308 ret = 1;
1309 goto cleanup;
1310 }
1311
1312 switch (endpt->ti) {
1313#ifdef NC_ENABLED_SSH_TLS
1314 case NC_TI_LIBSSH:
1315 nc_server_config_del_endpt_ssh(endpt, bind);
1316 break;
1317 case NC_TI_OPENSSL:
1318 nc_server_config_del_endpt_tls(endpt, bind);
1319 break;
1320#endif /* NC_ENABLED_SSH_TLS */
1321 case NC_TI_UNIX:
1322 nc_server_config_del_endpt_unix_socket(endpt, bind);
1323 break;
1324 case NC_TI_NONE:
1325 case NC_TI_FD:
1326 ERRINT;
1327 ret = 1;
1328 goto cleanup;
1329 }
romanc1d2b092023-02-02 08:58:27 +01001330 }
roman5cbb6532023-06-22 12:53:17 +02001331 } else if (is_ch(node)) {
1332 /* ch */
1333 if (nc_server_config_get_ch_client(node, &ch_client)) {
romanc1d2b092023-02-02 08:58:27 +01001334 ret = 1;
1335 goto cleanup;
1336 }
roman3f9b65c2023-06-05 14:26:58 +02001337
roman5cbb6532023-06-22 12:53:17 +02001338 if (op == NC_OP_CREATE) {
1339 ret = nc_server_config_ch_create_endpoint(node, ch_client);
1340 if (ret) {
1341 goto cleanup;
1342 }
1343
1344 /* init ch sock */
1345 ch_client->ch_endpts[ch_client->ch_endpt_count - 1].sock_pending = -1;
roman3f9b65c2023-06-05 14:26:58 +02001346 }
romanc1d2b092023-02-02 08:58:27 +01001347 }
1348
1349cleanup:
1350 return ret;
1351}
1352
roman2eab4742023-06-06 10:00:26 +02001353#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02001354
romanc1d2b092023-02-02 08:58:27 +01001355static int
roman874fed12023-05-25 10:20:01 +02001356nc_server_config_create_ssh(struct nc_endpt *endpt)
romanc1d2b092023-02-02 08:58:27 +01001357{
1358 endpt->ti = NC_TI_LIBSSH;
1359 endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
1360 if (!endpt->opts.ssh) {
1361 ERRMEM;
1362 return 1;
1363 }
1364
1365 return 0;
1366}
1367
roman5cbb6532023-06-22 12:53:17 +02001368static int
1369nc_server_config_ch_create_ssh(struct nc_ch_endpt *ch_endpt)
1370{
1371 ch_endpt->ti = NC_TI_LIBSSH;
1372 ch_endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
1373 if (!ch_endpt->opts.ssh) {
1374 ERRMEM;
1375 return 1;
1376 }
1377
1378 return 0;
1379}
1380
romanc1d2b092023-02-02 08:58:27 +01001381/* NP container */
1382static int
romane028ef92023-02-24 16:33:08 +01001383nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001384{
1385 struct nc_endpt *endpt;
1386 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001387 struct nc_ch_endpt *ch_endpt;
romanc1d2b092023-02-02 08:58:27 +01001388 int ret = 0;
1389
1390 assert(!strcmp(LYD_NAME(node), "ssh"));
1391
roman5cbb6532023-06-22 12:53:17 +02001392 if (is_listen(node)) {
1393 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1394 ret = 1;
romanc1d2b092023-02-02 08:58:27 +01001395 goto cleanup;
1396 }
roman5cbb6532023-06-22 12:53:17 +02001397
1398 if (op == NC_OP_CREATE) {
1399 ret = nc_server_config_create_ssh(endpt);
1400 if (ret) {
1401 goto cleanup;
1402 }
1403 } else if (op == NC_OP_DELETE) {
1404 nc_server_config_del_ssh(bind, endpt->opts.ssh);
1405 }
1406 } else {
roman4cb8bb12023-06-29 09:16:46 +02001407 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001408 ret = 1;
1409 goto cleanup;
1410 }
1411
1412 if (op == NC_OP_CREATE) {
1413 ret = nc_server_config_ch_create_ssh(ch_endpt);
1414 if (ret) {
1415 goto cleanup;
1416 }
romanb6f44032023-06-30 15:07:56 +02001417 } else if (op == NC_OP_DELETE) {
1418 nc_server_config_ch_del_ssh(ch_endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +02001419 }
romanc1d2b092023-02-02 08:58:27 +01001420 }
1421
1422cleanup:
1423 return ret;
1424}
1425
roman3f9b65c2023-06-05 14:26:58 +02001426static int
1427nc_server_config_create_tls(struct nc_endpt *endpt)
1428{
1429 endpt->ti = NC_TI_OPENSSL;
1430 endpt->opts.tls = calloc(1, sizeof *endpt->opts.tls);
1431 if (!endpt->opts.tls) {
1432 ERRMEM;
1433 return 1;
1434 }
1435
1436 return 0;
1437}
1438
1439static int
romanb6f44032023-06-30 15:07:56 +02001440nc_server_config_ch_create_tls(struct nc_ch_endpt *ch_endpt)
1441{
1442 ch_endpt->ti = NC_TI_OPENSSL;
1443 ch_endpt->opts.tls = calloc(1, sizeof(struct nc_server_tls_opts));
1444 if (!ch_endpt->opts.tls) {
1445 ERRMEM;
1446 return 1;
1447 }
1448
1449 return 0;
1450}
1451
1452static int
roman3f9b65c2023-06-05 14:26:58 +02001453nc_server_config_tls(const struct lyd_node *node, NC_OPERATION op)
1454{
1455 struct nc_endpt *endpt;
1456 struct nc_bind *bind;
romanb6f44032023-06-30 15:07:56 +02001457 struct nc_ch_endpt *ch_endpt;
roman3f9b65c2023-06-05 14:26:58 +02001458 int ret = 0;
1459
1460 assert(!strcmp(LYD_NAME(node), "tls"));
1461
romanb6f44032023-06-30 15:07:56 +02001462 if (is_listen(node)) {
1463 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1464 ret = 1;
roman3f9b65c2023-06-05 14:26:58 +02001465 goto cleanup;
1466 }
romanb6f44032023-06-30 15:07:56 +02001467
1468 if (op == NC_OP_CREATE) {
1469 ret = nc_server_config_create_tls(endpt);
1470 if (ret) {
1471 goto cleanup;
1472 }
1473 } else if (op == NC_OP_DELETE) {
1474 nc_server_config_del_tls(bind, endpt->opts.tls);
1475 }
1476 } else {
1477 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
1478 ret = 1;
1479 goto cleanup;
1480 }
1481
1482 if (op == NC_OP_CREATE) {
1483 ret = nc_server_config_ch_create_tls(ch_endpt);
1484 if (ret) {
1485 goto cleanup;
1486 }
1487 }
roman3f9b65c2023-06-05 14:26:58 +02001488 }
1489
1490cleanup:
1491 return ret;
1492}
1493
roman2eab4742023-06-06 10:00:26 +02001494#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02001495
romanc1d2b092023-02-02 08:58:27 +01001496static int
1497nc_server_config_set_address_port(struct nc_endpt *endpt, struct nc_bind *bind, const char *address, uint16_t port)
1498{
1499 int sock = -1, set_addr, ret = 0;
1500
roman83683fb2023-02-24 09:15:23 +01001501 assert((address && !port) || (!address && port) || (endpt->ti == NC_TI_UNIX));
romanc1d2b092023-02-02 08:58:27 +01001502
1503 if (address) {
1504 set_addr = 1;
1505 } else {
1506 set_addr = 0;
1507 }
1508
1509 if (set_addr) {
1510 port = bind->port;
1511 } else {
1512 address = bind->address;
1513 }
1514
romanc1d2b092023-02-02 08:58:27 +01001515 /* we have all the information we need to create a listening socket */
roman83683fb2023-02-24 09:15:23 +01001516 if ((address && port) || (endpt->ti == NC_TI_UNIX)) {
romanc1d2b092023-02-02 08:58:27 +01001517 /* create new socket, close the old one */
roman83683fb2023-02-24 09:15:23 +01001518 if (endpt->ti == NC_TI_UNIX) {
1519 sock = nc_sock_listen_unix(endpt->opts.unixsock);
1520 } else {
1521 sock = nc_sock_listen_inet(address, port, &endpt->ka);
1522 }
1523
romanc1d2b092023-02-02 08:58:27 +01001524 if (sock == -1) {
1525 ret = 1;
1526 goto cleanup;
1527 }
1528
1529 if (bind->sock > -1) {
1530 close(bind->sock);
1531 }
1532 bind->sock = sock;
1533 }
1534
1535 if (sock > -1) {
1536 switch (endpt->ti) {
roman83683fb2023-02-24 09:15:23 +01001537 case NC_TI_UNIX:
1538 VRB(NULL, "Listening on %s for UNIX connections.", endpt->opts.unixsock->address);
1539 break;
roman2eab4742023-06-06 10:00:26 +02001540#ifdef NC_ENABLED_SSH_TLS
romanc1d2b092023-02-02 08:58:27 +01001541 case NC_TI_LIBSSH:
1542 VRB(NULL, "Listening on %s:%u for SSH connections.", address, port);
1543 break;
romanc1d2b092023-02-02 08:58:27 +01001544 case NC_TI_OPENSSL:
1545 VRB(NULL, "Listening on %s:%u for TLS connections.", address, port);
1546 break;
roman2eab4742023-06-06 10:00:26 +02001547#endif /* NC_ENABLED_SSH_TLS */
romanc1d2b092023-02-02 08:58:27 +01001548 default:
1549 ERRINT;
1550 ret = 1;
1551 break;
1552 }
1553 }
1554
1555cleanup:
1556 return ret;
1557}
1558
roman2eab4742023-06-06 10:00:26 +02001559#ifdef NC_ENABLED_SSH_TLS
1560
romanc1d2b092023-02-02 08:58:27 +01001561/* mandatory leaf */
1562static int
romane028ef92023-02-24 16:33:08 +01001563nc_server_config_local_address(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001564{
1565 struct nc_endpt *endpt;
1566 struct nc_bind *bind;
1567 int ret = 0;
1568
1569 (void) op;
1570
1571 assert(!strcmp(LYD_NAME(node), "local-address"));
1572
1573 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001574 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001575 ret = 1;
1576 goto cleanup;
1577 }
1578
roman874fed12023-05-25 10:20:01 +02001579 nc_server_config_del_local_address(bind);
romanc1d2b092023-02-02 08:58:27 +01001580 bind->address = strdup(lyd_get_value(node));
1581 if (!bind->address) {
1582 ERRMEM;
1583 ret = 1;
1584 goto cleanup;
1585 }
1586
1587 ret = nc_server_config_set_address_port(endpt, bind, lyd_get_value(node), 0);
1588 if (ret) {
1589 goto cleanup;
1590 }
1591 }
1592
1593cleanup:
1594 return ret;
1595}
1596
1597/* leaf with default value */
1598static int
romane028ef92023-02-24 16:33:08 +01001599nc_server_config_local_port(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001600{
1601 struct nc_endpt *endpt;
1602 struct nc_bind *bind;
1603 int ret = 0;
1604
1605 assert(!strcmp(LYD_NAME(node), "local-port"));
1606
1607 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001608 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001609 ret = 1;
1610 goto cleanup;
1611 }
1612
1613 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1614 bind->port = strtoul(lyd_get_value(node), NULL, 10);
1615 } else {
1616 /* delete -> set to default */
1617 bind->port = 0;
1618 }
1619
1620 ret = nc_server_config_set_address_port(endpt, bind, NULL, bind->port);
1621 if (ret) {
1622 goto cleanup;
1623 }
1624 }
1625
1626cleanup:
1627 return ret;
1628}
1629
1630/* P container */
1631static int
romane028ef92023-02-24 16:33:08 +01001632nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001633{
roman5cbb6532023-06-22 12:53:17 +02001634 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001635 struct nc_endpt *endpt;
1636 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001637 struct nc_ch_endpt *ch_endpt;
romanc1d2b092023-02-02 08:58:27 +01001638
1639 assert(!strcmp(LYD_NAME(node), "keepalives"));
1640
roman5cbb6532023-06-22 12:53:17 +02001641 if (is_listen(node) && equal_parent_name(node, 1, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001642 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001643 ret = 1;
1644 goto cleanup;
1645 }
1646
1647 if (op == NC_OP_CREATE) {
1648 endpt->ka.enabled = 1;
1649 } else {
1650 endpt->ka.enabled = 0;
1651 }
1652 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1653 if (ret) {
1654 goto cleanup;
1655 }
roman5cbb6532023-06-22 12:53:17 +02001656 } else if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) {
roman4cb8bb12023-06-29 09:16:46 +02001657 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001658 ret = 1;
1659 goto cleanup;
1660 }
1661
1662 if (op == NC_OP_CREATE) {
1663 ch_endpt->ka.enabled = 1;
1664 } else {
1665 ch_endpt->ka.enabled = 0;
1666 }
romanc1d2b092023-02-02 08:58:27 +01001667 }
1668
1669cleanup:
1670 return ret;
1671}
1672
1673/* mandatory leaf */
1674static int
romane028ef92023-02-24 16:33:08 +01001675nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001676{
roman5cbb6532023-06-22 12:53:17 +02001677 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001678 struct nc_endpt *endpt;
1679 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001680 struct nc_ch_endpt *ch_endpt;
romanc1d2b092023-02-02 08:58:27 +01001681
1682 assert(!strcmp(LYD_NAME(node), "idle-time"));
1683
roman5cbb6532023-06-22 12:53:17 +02001684 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001685 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001686 ret = 1;
1687 goto cleanup;
1688 }
1689
1690 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1691 endpt->ka.idle_time = strtoul(lyd_get_value(node), NULL, 10);
1692 } else {
1693 endpt->ka.idle_time = 0;
1694 }
1695 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1696 if (ret) {
1697 goto cleanup;
1698 }
roman5cbb6532023-06-22 12:53:17 +02001699 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
roman4cb8bb12023-06-29 09:16:46 +02001700 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001701 ret = 1;
1702 goto cleanup;
1703 }
1704
1705 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1706 ch_endpt->ka.idle_time = strtoul(lyd_get_value(node), NULL, 10);
1707 } else {
1708 ch_endpt->ka.idle_time = 0;
1709 }
romanc1d2b092023-02-02 08:58:27 +01001710 }
1711
1712cleanup:
1713 return ret;
1714}
1715
1716/* mandatory leaf */
1717static int
romane028ef92023-02-24 16:33:08 +01001718nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001719{
roman5cbb6532023-06-22 12:53:17 +02001720 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001721 struct nc_endpt *endpt;
1722 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001723 struct nc_ch_endpt *ch_endpt;
romanc1d2b092023-02-02 08:58:27 +01001724
1725 assert(!strcmp(LYD_NAME(node), "max-probes"));
1726
roman5cbb6532023-06-22 12:53:17 +02001727 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001728 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001729 ret = 1;
1730 goto cleanup;
1731 }
1732
1733 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1734 endpt->ka.max_probes = strtoul(lyd_get_value(node), NULL, 10);
1735 } else {
1736 endpt->ka.max_probes = 0;
1737 }
1738 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1739 if (ret) {
1740 goto cleanup;
1741 }
roman5cbb6532023-06-22 12:53:17 +02001742 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
roman4cb8bb12023-06-29 09:16:46 +02001743 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001744 ret = 1;
1745 goto cleanup;
1746 }
1747
1748 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1749 ch_endpt->ka.max_probes = strtoul(lyd_get_value(node), NULL, 10);
1750 } else {
1751 ch_endpt->ka.max_probes = 0;
1752 }
romanc1d2b092023-02-02 08:58:27 +01001753 }
1754
1755cleanup:
1756 return ret;
1757}
1758
1759/* mandatory leaf */
1760static int
romane028ef92023-02-24 16:33:08 +01001761nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001762{
roman5cbb6532023-06-22 12:53:17 +02001763 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001764 struct nc_endpt *endpt;
1765 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001766 struct nc_ch_endpt *ch_endpt;
romanc1d2b092023-02-02 08:58:27 +01001767
1768 assert(!strcmp(LYD_NAME(node), "probe-interval"));
1769
roman5cbb6532023-06-22 12:53:17 +02001770 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001771 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001772 ret = 1;
1773 goto cleanup;
1774 }
1775
1776 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1777 endpt->ka.probe_interval = strtoul(lyd_get_value(node), NULL, 10);
1778 } else {
1779 endpt->ka.probe_interval = 0;
1780 }
1781 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1782 if (ret) {
1783 goto cleanup;
1784 }
roman5cbb6532023-06-22 12:53:17 +02001785 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
roman4cb8bb12023-06-29 09:16:46 +02001786 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001787 ret = 1;
1788 goto cleanup;
1789 }
1790
1791 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1792 ch_endpt->ka.probe_interval = strtoul(lyd_get_value(node), NULL, 10);
1793 } else {
1794 ch_endpt->ka.max_probes = 0;
1795 }
romanc1d2b092023-02-02 08:58:27 +01001796 }
1797
1798cleanup:
1799 return ret;
1800}
1801
1802static int
roman874fed12023-05-25 10:20:01 +02001803nc_server_config_create_host_key(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01001804{
romanf02273a2023-05-25 09:44:11 +02001805 node = lyd_child(node);
1806 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01001807
romanf02273a2023-05-25 09:44:11 +02001808 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->hostkeys, sizeof *opts->hostkeys, &opts->hostkey_count);
romanc1d2b092023-02-02 08:58:27 +01001809}
1810
1811/* list */
1812static int
romane028ef92023-02-24 16:33:08 +01001813nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001814{
roman5cbb6532023-06-22 12:53:17 +02001815 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001816 struct nc_hostkey *hostkey;
roman4cb8bb12023-06-29 09:16:46 +02001817 struct nc_server_ssh_opts *opts;
romanc1d2b092023-02-02 08:58:27 +01001818
1819 assert(!strcmp(LYD_NAME(node), "host-key"));
1820
roman4cb8bb12023-06-29 09:16:46 +02001821 if (nc_server_config_get_ssh_opts(node, &opts)) {
1822 ret = 1;
1823 goto cleanup;
1824 }
romanc1d2b092023-02-02 08:58:27 +01001825
roman4cb8bb12023-06-29 09:16:46 +02001826 if (equal_parent_name(node, 1, "server-identity")) {
romanc1d2b092023-02-02 08:58:27 +01001827 if (op == NC_OP_CREATE) {
roman4cb8bb12023-06-29 09:16:46 +02001828 ret = nc_server_config_create_host_key(node, opts);
romanc1d2b092023-02-02 08:58:27 +01001829 if (ret) {
1830 goto cleanup;
1831 }
1832 } else if (op == NC_OP_DELETE) {
roman4cb8bb12023-06-29 09:16:46 +02001833 if (nc_server_config_get_hostkey(node, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001834 ret = 1;
1835 goto cleanup;
1836 }
roman4cb8bb12023-06-29 09:16:46 +02001837 nc_server_config_del_hostkey(opts, hostkey);
roman5cbb6532023-06-22 12:53:17 +02001838 }
romanc1d2b092023-02-02 08:58:27 +01001839 }
1840
1841cleanup:
1842 return ret;
1843}
1844
1845/* mandatory leaf */
romane028ef92023-02-24 16:33:08 +01001846static int
1847nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001848{
roman3f9b65c2023-06-05 14:26:58 +02001849 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02001850 const char *format;
roman3f9b65c2023-06-05 14:26:58 +02001851 NC_PUBKEY_FORMAT pubkey_type;
roman8edee342023-03-31 13:25:48 +02001852 struct nc_public_key *pubkey;
romanc1d2b092023-02-02 08:58:27 +01001853 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02001854 struct nc_server_tls_opts *opts;
romanc1d2b092023-02-02 08:58:27 +01001855
1856 assert(!strcmp(LYD_NAME(node), "public-key-format"));
1857
1858 format = ((struct lyd_node_term *)node)->value.ident->name;
roman3f9b65c2023-06-05 14:26:58 +02001859 if (!strcmp(format, "ssh-public-key-format")) {
1860 pubkey_type = NC_PUBKEY_FORMAT_SSH2;
1861 } else if (!strcmp(format, "subject-public-key-info-format")) {
1862 pubkey_type = NC_PUBKEY_FORMAT_X509;
1863 } else {
1864 ERR(NULL, "Public key format (%s) not supported.", format);
1865 ret = 1;
1866 goto cleanup;
1867 }
romanc1d2b092023-02-02 08:58:27 +01001868
roman4cb8bb12023-06-29 09:16:46 +02001869 if (is_ssh(node) && equal_parent_name(node, 4, "server-identity")) {
roman5cbb6532023-06-22 12:53:17 +02001870 /* SSH hostkey public key fmt */
roman4cb8bb12023-06-29 09:16:46 +02001871 if (nc_server_config_get_hostkey(node, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02001872 ret = 1;
1873 goto cleanup;
1874 }
1875
1876 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1877 hostkey->key.pubkey_type = pubkey_type;
1878 }
roman4cb8bb12023-06-29 09:16:46 +02001879 } else if (is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) {
roman5cbb6532023-06-22 12:53:17 +02001880 /* SSH client auth public key fmt */
roman4cb8bb12023-06-29 09:16:46 +02001881 if (nc_server_config_get_pubkey(node, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001882 ret = 1;
1883 goto cleanup;
1884 }
1885
1886 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman3f9b65c2023-06-05 14:26:58 +02001887 pubkey->type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001888 }
romanb6f44032023-06-30 15:07:56 +02001889 } else if (is_tls(node) && equal_parent_name(node, 3, "server-identity")) {
1890 /* TLS server-identity */
1891 if (nc_server_config_get_tls_opts(node, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02001892 ret = 1;
1893 goto cleanup;
1894 }
1895
roman5cbb6532023-06-22 12:53:17 +02001896 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02001897 opts->pubkey_type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001898 }
romanc1d2b092023-02-02 08:58:27 +01001899 }
1900
1901cleanup:
1902 return ret;
1903}
1904
1905static int
roman874fed12023-05-25 10:20:01 +02001906nc_server_config_create_auth_key_public_key_list(const struct lyd_node *node, struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +01001907{
romanc1d2b092023-02-02 08:58:27 +01001908 assert(!strcmp(LYD_NAME(node), "public-key"));
1909
romanc1d2b092023-02-02 08:58:27 +01001910 node = lyd_child(node);
1911 assert(!strcmp(LYD_NAME(node), "name"));
1912
romanf02273a2023-05-25 09:44:11 +02001913 return nc_server_config_realloc(lyd_get_value(node), (void **)&auth_client->pubkeys, sizeof *auth_client->pubkeys, &auth_client->pubkey_count);
romanc1d2b092023-02-02 08:58:27 +01001914}
1915
1916static int
roman874fed12023-05-25 10:20:01 +02001917nc_server_config_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +01001918{
roman874fed12023-05-25 10:20:01 +02001919 nc_server_config_del_auth_client_pubkey_pub_base64(pubkey);
romanc1d2b092023-02-02 08:58:27 +01001920
roman3f9b65c2023-06-05 14:26:58 +02001921 pubkey->data = strdup(lyd_get_value(node));
1922 if (!pubkey->data) {
romanc1d2b092023-02-02 08:58:27 +01001923 ERRMEM;
1924 return 1;
1925 }
1926
1927 return 0;
1928}
1929
1930static int
roman874fed12023-05-25 10:20:01 +02001931nc_server_config_replace_host_key_public_key(const struct lyd_node *node, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +01001932{
roman874fed12023-05-25 10:20:01 +02001933 nc_server_config_del_public_key(hostkey);
romanc1d2b092023-02-02 08:58:27 +01001934
roman3f9b65c2023-06-05 14:26:58 +02001935 hostkey->key.pubkey_data = strdup(lyd_get_value(node));
1936 if (!hostkey->key.pubkey_data) {
romanc1d2b092023-02-02 08:58:27 +01001937 ERRMEM;
1938 return 1;
1939 }
1940
1941 return 0;
1942}
1943
roman3f9b65c2023-06-05 14:26:58 +02001944static int
1945nc_server_config_tls_replace_server_public_key(const struct lyd_node *node, struct nc_server_tls_opts *opts)
1946{
1947 nc_server_config_tls_del_public_key(opts);
1948
1949 opts->pubkey_data = strdup(lyd_get_value(node));
1950 if (!opts->pubkey_data) {
1951 ERRMEM;
1952 return 1;
1953 }
1954
1955 return 0;
1956}
1957
romanc1d2b092023-02-02 08:58:27 +01001958static int
romane028ef92023-02-24 16:33:08 +01001959nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001960{
roman3f9b65c2023-06-05 14:26:58 +02001961 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001962 struct nc_hostkey *hostkey;
1963 struct nc_client_auth *auth_client;
roman8edee342023-03-31 13:25:48 +02001964 struct nc_public_key *pubkey;
romanb6f44032023-06-30 15:07:56 +02001965 struct nc_server_tls_opts *opts;
romanc1d2b092023-02-02 08:58:27 +01001966
1967 assert(!strcmp(LYD_NAME(node), "public-key"));
1968
roman4cb8bb12023-06-29 09:16:46 +02001969 if (is_ssh(node) && equal_parent_name(node, 3, "host-key")) {
roman3f9b65c2023-06-05 14:26:58 +02001970 /* server's public-key, mandatory leaf */
roman4cb8bb12023-06-29 09:16:46 +02001971 if (nc_server_config_get_hostkey(node, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001972 ret = 1;
1973 goto cleanup;
1974 }
1975
1976 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02001977 /* set to local */
roman874fed12023-05-25 10:20:01 +02001978 hostkey->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02001979
roman874fed12023-05-25 10:20:01 +02001980 ret = nc_server_config_replace_host_key_public_key(node, hostkey);
romanc1d2b092023-02-02 08:58:27 +01001981 if (ret) {
1982 goto cleanup;
1983 }
1984 }
roman4cb8bb12023-06-29 09:16:46 +02001985 } else if (is_ssh(node) && equal_parent_name(node, 5, "client-authentication")) {
romanc1d2b092023-02-02 08:58:27 +01001986 /* client auth pubkeys, list */
roman4cb8bb12023-06-29 09:16:46 +02001987 if (nc_server_config_get_auth_client(node, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001988 ret = 1;
1989 goto cleanup;
1990 }
1991
1992 if (op == NC_OP_CREATE) {
romanf02273a2023-05-25 09:44:11 +02001993 /* set to local */
roman874fed12023-05-25 10:20:01 +02001994 auth_client->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02001995
roman874fed12023-05-25 10:20:01 +02001996 ret = nc_server_config_create_auth_key_public_key_list(node, auth_client);
romanc1d2b092023-02-02 08:58:27 +01001997 if (ret) {
1998 goto cleanup;
1999 }
2000 } else if (op == NC_OP_DELETE) {
roman4cb8bb12023-06-29 09:16:46 +02002001 if (nc_server_config_get_pubkey(node, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01002002 ret = 1;
2003 goto cleanup;
2004 }
2005
roman874fed12023-05-25 10:20:01 +02002006 nc_server_config_del_auth_client_pubkey(auth_client, pubkey);
romanc1d2b092023-02-02 08:58:27 +01002007 }
roman4cb8bb12023-06-29 09:16:46 +02002008 } else if (is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) {
romanc1d2b092023-02-02 08:58:27 +01002009 /* client auth pubkey, leaf */
roman4cb8bb12023-06-29 09:16:46 +02002010 if (nc_server_config_get_pubkey(node, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01002011 ret = 1;
2012 goto cleanup;
2013 }
2014
2015 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02002016 ret = nc_server_config_replace_auth_key_public_key_leaf(node, pubkey);
romanc1d2b092023-02-02 08:58:27 +01002017 if (ret) {
2018 goto cleanup;
2019 }
2020 } else {
roman874fed12023-05-25 10:20:01 +02002021 nc_server_config_del_auth_client_pubkey_pub_base64(pubkey);
romanc1d2b092023-02-02 08:58:27 +01002022 }
romanb6f44032023-06-30 15:07:56 +02002023 } else if (is_tls(node) && equal_parent_name(node, 3, "server-identity")) {
2024 /* TLS server-identity */
2025 if (nc_server_config_get_tls_opts(node, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002026 ret = 1;
2027 goto cleanup;
2028 }
2029
roman3f9b65c2023-06-05 14:26:58 +02002030 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2031 /* set to local */
romanb6f44032023-06-30 15:07:56 +02002032 opts->store = NC_STORE_LOCAL;
roman3f9b65c2023-06-05 14:26:58 +02002033
romanb6f44032023-06-30 15:07:56 +02002034 ret = nc_server_config_tls_replace_server_public_key(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02002035 if (ret) {
2036 goto cleanup;
2037 }
2038 }
roman5cbb6532023-06-22 12:53:17 +02002039 }
2040
2041cleanup:
2042 return ret;
2043}
2044
2045/* leaf */
2046static int
2047nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op)
2048{
2049 int ret = 0;
2050 const char *format;
2051 NC_PRIVKEY_FORMAT privkey_type;
roman5cbb6532023-06-22 12:53:17 +02002052 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02002053 struct nc_server_tls_opts *opts;
roman5cbb6532023-06-22 12:53:17 +02002054
2055 (void) op;
2056
2057 assert(!strcmp(LYD_NAME(node), "private-key-format"));
2058
2059 format = ((struct lyd_node_term *)node)->value.ident->name;
2060 if (!format) {
2061 ret = 1;
2062 goto cleanup;
2063 }
2064
2065 privkey_type = nc_server_config_get_private_key_type(format);
2066 if (privkey_type == NC_PRIVKEY_FORMAT_UNKNOWN) {
2067 ERR(NULL, "Unknown private key format.");
2068 ret = 1;
2069 goto cleanup;
2070 }
2071
roman4cb8bb12023-06-29 09:16:46 +02002072 if (is_ssh(node)) {
2073 /* ssh */
2074 if (nc_server_config_get_hostkey(node, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02002075 ret = 1;
2076 goto cleanup;
2077 }
2078
2079 hostkey->key.privkey_type = privkey_type;
romanb6f44032023-06-30 15:07:56 +02002080 } else if (is_tls(node)) {
2081 /* tls */
2082 if (nc_server_config_get_tls_opts(node, &opts)) {
roman5cbb6532023-06-22 12:53:17 +02002083 ret = 1;
2084 goto cleanup;
2085 }
2086
romanb6f44032023-06-30 15:07:56 +02002087 opts->privkey_type = privkey_type;
roman5cbb6532023-06-22 12:53:17 +02002088 }
2089
2090cleanup:
2091 return ret;
2092}
2093
2094static int
2095nc_server_config_replace_cleartext_private_key(const struct lyd_node *node, struct nc_hostkey *hostkey)
2096{
2097 nc_server_config_del_private_key(hostkey);
2098 hostkey->key.privkey_data = strdup(lyd_get_value(node));
2099 if (!hostkey->key.privkey_data) {
2100 ERRMEM;
2101 return 1;
2102 }
2103
2104 return 0;
2105}
2106
2107static int
2108nc_server_config_tls_replace_cleartext_private_key(const struct lyd_node *node, struct nc_server_tls_opts *opts)
2109{
2110 nc_server_config_tls_del_cleartext_private_key(opts);
2111 opts->privkey_data = strdup(lyd_get_value(node));
2112 if (!opts->privkey_data) {
2113 ERRMEM;
2114 return 1;
2115 }
2116
2117 return 0;
2118}
2119
2120static int
2121nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op)
2122{
2123 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02002124 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02002125 struct nc_server_tls_opts *opts;
roman5cbb6532023-06-22 12:53:17 +02002126
2127 assert(!strcmp(LYD_NAME(node), "cleartext-private-key"));
2128
roman4cb8bb12023-06-29 09:16:46 +02002129 if (is_ssh(node)) {
2130 /* ssh */
2131 if (nc_server_config_get_hostkey(node, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02002132 ret = 1;
2133 goto cleanup;
2134 }
2135
2136 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2137 ret = nc_server_config_replace_cleartext_private_key(node, hostkey);
2138 if (ret) {
2139 goto cleanup;
2140 }
2141 } else {
2142 nc_server_config_del_private_key(hostkey);
2143 }
romanb6f44032023-06-30 15:07:56 +02002144 } else if (is_tls(node)) {
2145 /* tls */
2146 if (nc_server_config_get_tls_opts(node, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002147 ret = 1;
2148 goto cleanup;
2149 }
2150
roman5cbb6532023-06-22 12:53:17 +02002151 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02002152 ret = nc_server_config_tls_replace_cleartext_private_key(node, opts);
roman5cbb6532023-06-22 12:53:17 +02002153 if (ret) {
2154 goto cleanup;
2155 }
2156 } else {
romanb6f44032023-06-30 15:07:56 +02002157 nc_server_config_tls_del_cleartext_private_key(opts);
roman5cbb6532023-06-22 12:53:17 +02002158 }
roman5cbb6532023-06-22 12:53:17 +02002159 }
2160
2161cleanup:
2162 return ret;
2163}
2164
2165static int
2166nc_server_config_create_keystore_reference(const struct lyd_node *node, struct nc_hostkey *hostkey)
2167{
2168 uint16_t i;
2169 struct nc_keystore *ks = &server_opts.keystore;
2170
2171 /* lookup name */
2172 for (i = 0; i < ks->asym_key_count; i++) {
2173 if (!strcmp(lyd_get_value(node), ks->asym_keys[i].name)) {
2174 break;
2175 }
2176 }
2177
2178 if (i == ks->asym_key_count) {
2179 ERR(NULL, "Keystore \"%s\" not found.", lyd_get_value(node));
2180 return 1;
2181 }
2182
2183 hostkey->ks_ref = &ks->asym_keys[i];
2184
2185 return 0;
2186}
2187
2188/* leaf */
2189static int
2190nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op)
2191{
2192 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02002193 struct nc_hostkey *hostkey;
roman5cbb6532023-06-22 12:53:17 +02002194
2195 assert(!strcmp(LYD_NAME(node), "keystore-reference"));
2196
roman4cb8bb12023-06-29 09:16:46 +02002197 if (is_ssh(node) && equal_parent_name(node, 3, "server-identity")) {
2198 if (nc_server_config_get_hostkey(node, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02002199 ret = 1;
2200 goto cleanup;
2201 }
2202
2203 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2204 /* set to keystore */
2205 hostkey->store = NC_STORE_KEYSTORE;
2206
2207 ret = nc_server_config_create_keystore_reference(node, hostkey);
2208 if (ret) {
2209 goto cleanup;
2210 }
2211 } else {
2212 hostkey->ks_ref = NULL;
2213 }
roman3f9b65c2023-06-05 14:26:58 +02002214 }
romanc1d2b092023-02-02 08:58:27 +01002215
2216cleanup:
2217 return ret;
2218}
2219
2220static int
roman874fed12023-05-25 10:20:01 +02002221nc_server_config_create_user(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01002222{
romanf02273a2023-05-25 09:44:11 +02002223 node = lyd_child(node);
2224 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01002225
romanf02273a2023-05-25 09:44:11 +02002226 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 +01002227}
2228
2229/* list */
2230static int
romane028ef92023-02-24 16:33:08 +01002231nc_server_config_user(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002232{
roman5cbb6532023-06-22 12:53:17 +02002233 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002234 struct nc_client_auth *auth_client;
roman4cb8bb12023-06-29 09:16:46 +02002235 struct nc_server_ssh_opts *opts;
romanc1d2b092023-02-02 08:58:27 +01002236
2237 assert(!strcmp(LYD_NAME(node), "user"));
2238
roman4cb8bb12023-06-29 09:16:46 +02002239 if (nc_server_config_get_ssh_opts(node, &opts)) {
2240 ret = 1;
2241 goto cleanup;
2242 }
2243
2244 if (op == NC_OP_CREATE) {
2245 ret = nc_server_config_create_user(node, opts);
2246 if (ret) {
2247 goto cleanup;
2248 }
2249 } else if (op == NC_OP_DELETE) {
2250 if (nc_server_config_get_auth_client(node, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002251 ret = 1;
2252 goto cleanup;
2253 }
2254
roman4cb8bb12023-06-29 09:16:46 +02002255 nc_server_config_del_auth_client(opts, auth_client);
romanc1d2b092023-02-02 08:58:27 +01002256 }
2257
2258cleanup:
2259 return ret;
2260}
2261
2262static int
romane028ef92023-02-24 16:33:08 +01002263nc_server_config_auth_attempts(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002264{
romanc1d2b092023-02-02 08:58:27 +01002265 int ret = 0;
roman4cb8bb12023-06-29 09:16:46 +02002266 struct nc_server_ssh_opts *opts;
romanc1d2b092023-02-02 08:58:27 +01002267
2268 assert(!strcmp(LYD_NAME(node), "auth-attempts"));
2269
roman4cb8bb12023-06-29 09:16:46 +02002270 if (nc_server_config_get_ssh_opts(node, &opts)) {
2271 ret = 1;
2272 goto cleanup;
2273 }
romanc1d2b092023-02-02 08:58:27 +01002274
roman4cb8bb12023-06-29 09:16:46 +02002275 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2276 opts->auth_attempts = strtoul(lyd_get_value(node), NULL, 10);
romanc1d2b092023-02-02 08:58:27 +01002277 }
2278
2279cleanup:
2280 return ret;
2281}
2282
2283static int
romane028ef92023-02-24 16:33:08 +01002284nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002285{
romanc1d2b092023-02-02 08:58:27 +01002286 int ret = 0;
roman4cb8bb12023-06-29 09:16:46 +02002287 struct nc_server_ssh_opts *opts;
romanc1d2b092023-02-02 08:58:27 +01002288
2289 assert(!strcmp(LYD_NAME(node), "auth-timeout"));
2290
roman4cb8bb12023-06-29 09:16:46 +02002291 if (nc_server_config_get_ssh_opts(node, &opts)) {
2292 ret = 1;
2293 goto cleanup;
2294 }
romanc1d2b092023-02-02 08:58:27 +01002295
roman4cb8bb12023-06-29 09:16:46 +02002296 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2297 opts->auth_timeout = strtoul(lyd_get_value(node), NULL, 10);
romanc1d2b092023-02-02 08:58:27 +01002298 }
2299
2300cleanup:
2301 return ret;
2302}
2303
2304static int
roman874fed12023-05-25 10:20:01 +02002305nc_server_config_replace_truststore_reference(const struct lyd_node *node, struct nc_client_auth *client_auth)
romanc1d2b092023-02-02 08:58:27 +01002306{
romand57b3722023-04-05 11:26:25 +02002307 uint16_t i;
2308 struct nc_truststore *ts = &server_opts.truststore;
romanc1d2b092023-02-02 08:58:27 +01002309
romand57b3722023-04-05 11:26:25 +02002310 /* lookup name */
2311 for (i = 0; i < ts->pub_bag_count; i++) {
2312 if (!strcmp(lyd_get_value(node), ts->pub_bags[i].name)) {
2313 break;
2314 }
2315 }
2316
2317 if (i == ts->pub_bag_count) {
roman3f9b65c2023-06-05 14:26:58 +02002318 ERR(NULL, "Public-key bag \"%s\" not found in truststore.", lyd_get_value(node));
romanc1d2b092023-02-02 08:58:27 +01002319 return 1;
2320 }
2321
romand57b3722023-04-05 11:26:25 +02002322 client_auth->ts_ref = &ts->pub_bags[i];
2323
romanc1d2b092023-02-02 08:58:27 +01002324 return 0;
2325}
2326
roman3f9b65c2023-06-05 14:26:58 +02002327static int
2328nc_server_config_tls_replace_truststore_reference(const struct lyd_node *node, struct nc_cert_grouping *auth_client)
2329{
2330 uint16_t i;
2331 struct nc_truststore *ts = &server_opts.truststore;
2332
2333 /* lookup name */
2334 for (i = 0; i < ts->cert_bag_count; i++) {
2335 if (!strcmp(lyd_get_value(node), ts->cert_bags[i].name)) {
2336 break;
2337 }
2338 }
2339
2340 if (i == ts->cert_bag_count) {
2341 ERR(NULL, "Certificate bag \"%s\" not found in truststore.", lyd_get_value(node));
2342 return 1;
2343 }
2344
2345 auth_client->ts_ref = &ts->cert_bags[i];
2346
2347 return 0;
2348}
2349
romanc1d2b092023-02-02 08:58:27 +01002350/* leaf */
2351static int
romane028ef92023-02-24 16:33:08 +01002352nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002353{
romanc1d2b092023-02-02 08:58:27 +01002354 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02002355 struct nc_endpt *endpt;
roman3f9b65c2023-06-05 14:26:58 +02002356 struct nc_client_auth *auth_client;
romanc1d2b092023-02-02 08:58:27 +01002357
2358 assert(!strcmp(LYD_NAME(node), "truststore-reference"));
2359
roman4cb8bb12023-06-29 09:16:46 +02002360 if (is_ssh(node) && equal_parent_name(node, 1, "public-keys")) {
2361 if (nc_server_config_get_auth_client(node, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002362 ret = 1;
2363 goto cleanup;
2364 }
2365
2366 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02002367 /* set to truststore */
roman874fed12023-05-25 10:20:01 +02002368 auth_client->store = NC_STORE_TRUSTSTORE;
romanf02273a2023-05-25 09:44:11 +02002369
roman874fed12023-05-25 10:20:01 +02002370 ret = nc_server_config_replace_truststore_reference(node, auth_client);
romanc1d2b092023-02-02 08:58:27 +01002371 if (ret) {
2372 goto cleanup;
2373 }
2374 } else {
romand57b3722023-04-05 11:26:25 +02002375 auth_client->ts_ref = NULL;
romanc1d2b092023-02-02 08:58:27 +01002376 }
roman5cbb6532023-06-22 12:53:17 +02002377 } else if (is_listen(node) && equal_parent_name(node, 1, "ca-certs")) {
roman4cb8bb12023-06-29 09:16:46 +02002378 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
2379 ret = 1;
2380 goto cleanup;
2381 }
2382
roman3f9b65c2023-06-05 14:26:58 +02002383 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2384 /* set to truststore */
2385 endpt->opts.tls->ca_certs.store = NC_STORE_TRUSTSTORE;
2386
2387 ret = nc_server_config_tls_replace_truststore_reference(node, &endpt->opts.tls->ca_certs);
2388 if (ret) {
2389 goto cleanup;
2390 }
2391 } else {
2392 endpt->opts.tls->ca_certs.ts_ref = NULL;
2393 }
roman5cbb6532023-06-22 12:53:17 +02002394 } else if (is_listen(node) && equal_parent_name(node, 1, "ee-certs")) {
roman4cb8bb12023-06-29 09:16:46 +02002395 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
2396 ret = 1;
2397 goto cleanup;
2398 }
2399
roman3f9b65c2023-06-05 14:26:58 +02002400 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2401 /* set to truststore */
2402 endpt->opts.tls->ee_certs.store = NC_STORE_TRUSTSTORE;
2403
2404 ret = nc_server_config_tls_replace_truststore_reference(node, &endpt->opts.tls->ee_certs);
2405 if (ret) {
2406 goto cleanup;
2407 }
2408 } else {
2409 endpt->opts.tls->ee_certs.ts_ref = NULL;
2410 }
2411 }
romanc1d2b092023-02-02 08:58:27 +01002412
2413cleanup:
2414 return ret;
2415}
2416
2417static int
roman874fed12023-05-25 10:20:01 +02002418nc_server_config_replace_password(const struct lyd_node *node, struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +01002419{
roman874fed12023-05-25 10:20:01 +02002420 nc_server_config_del_auth_client_password(auth_client);
romanc1d2b092023-02-02 08:58:27 +01002421
2422 auth_client->password = strdup(lyd_get_value(node));
2423 if (!auth_client->password) {
2424 ERRMEM;
2425 return 1;
2426 }
2427
2428 return 0;
2429}
2430
2431/* leaf */
2432static int
romane028ef92023-02-24 16:33:08 +01002433nc_server_config_password(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002434{
roman5cbb6532023-06-22 12:53:17 +02002435 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002436 struct nc_client_auth *auth_client;
romanc1d2b092023-02-02 08:58:27 +01002437
2438 assert(!strcmp(LYD_NAME(node), "password"));
2439
roman4cb8bb12023-06-29 09:16:46 +02002440 if (nc_server_config_get_auth_client(node, &auth_client)) {
2441 ret = 1;
2442 goto cleanup;
2443 }
2444
2445 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2446 ret = nc_server_config_replace_password(node, auth_client);
2447 if (ret) {
romanc1d2b092023-02-02 08:58:27 +01002448 goto cleanup;
2449 }
roman4cb8bb12023-06-29 09:16:46 +02002450 } else {
2451 nc_server_config_del_auth_client_password(auth_client);
romanc1d2b092023-02-02 08:58:27 +01002452 }
2453
2454cleanup:
2455 return ret;
2456}
2457
2458static int
romane028ef92023-02-24 16:33:08 +01002459nc_server_config_pam_name(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002460{
roman5cbb6532023-06-22 12:53:17 +02002461 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002462 struct nc_client_auth *auth_client;
romanc1d2b092023-02-02 08:58:27 +01002463
2464 assert(!strcmp(LYD_NAME(node), "pam-config-file-name"));
2465
roman4cb8bb12023-06-29 09:16:46 +02002466 if (nc_server_config_get_auth_client(node, &auth_client)) {
2467 ret = 1;
2468 goto cleanup;
2469 }
2470
2471 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2472 nc_server_config_del_auth_client_pam_name(auth_client);
2473
2474 auth_client->pam_config_name = strdup(lyd_get_value(node));
2475 if (!auth_client->pam_config_name) {
2476 ERRMEM;
romanc1d2b092023-02-02 08:58:27 +01002477 ret = 1;
2478 goto cleanup;
2479 }
roman4cb8bb12023-06-29 09:16:46 +02002480 } else {
2481 nc_server_config_del_auth_client_pam_name(auth_client);
romanc1d2b092023-02-02 08:58:27 +01002482 }
2483
2484cleanup:
2485 return ret;
2486}
2487
2488static int
romane028ef92023-02-24 16:33:08 +01002489nc_server_config_pam_dir(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002490{
roman5cbb6532023-06-22 12:53:17 +02002491 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002492 struct nc_client_auth *auth_client;
romanc1d2b092023-02-02 08:58:27 +01002493
2494 assert(!strcmp(LYD_NAME(node), "pam-config-file-dir"));
2495
roman4cb8bb12023-06-29 09:16:46 +02002496 if (nc_server_config_get_auth_client(node, &auth_client)) {
2497 ret = 1;
2498 goto cleanup;
2499 }
2500
2501 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2502 nc_server_config_del_auth_client_pam_dir(auth_client);
2503 auth_client->pam_config_dir = strdup(lyd_get_value(node));
2504 if (!auth_client->pam_config_dir) {
2505 ERRMEM;
romanc1d2b092023-02-02 08:58:27 +01002506 ret = 1;
2507 goto cleanup;
2508 }
roman4cb8bb12023-06-29 09:16:46 +02002509 } else {
2510 nc_server_config_del_auth_client_pam_dir(auth_client);
romanc1d2b092023-02-02 08:58:27 +01002511 }
2512
2513cleanup:
2514 return ret;
2515}
2516
2517/* leaf */
2518static int
romane028ef92023-02-24 16:33:08 +01002519nc_server_config_none(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002520{
roman5cbb6532023-06-22 12:53:17 +02002521 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002522 struct nc_client_auth *auth_client;
romanc1d2b092023-02-02 08:58:27 +01002523
2524 assert(!strcmp(LYD_NAME(node), "none"));
2525
roman4cb8bb12023-06-29 09:16:46 +02002526 if (nc_server_config_get_auth_client(node, &auth_client)) {
2527 ret = 1;
2528 goto cleanup;
2529 }
romanc1d2b092023-02-02 08:58:27 +01002530
roman4cb8bb12023-06-29 09:16:46 +02002531 if (op == NC_OP_CREATE) {
2532 auth_client->supports_none = 1;
2533 } else {
2534 auth_client->supports_none = 0;
romanc1d2b092023-02-02 08:58:27 +01002535 }
2536
2537cleanup:
2538 return ret;
2539}
2540
2541static int
romana6bf6ab2023-05-26 13:26:02 +02002542nc_server_config_transport_params(const char *algorithm, char **alg_store, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002543{
2544 int ret = 0, alg_found = 0;
romana6bf6ab2023-05-26 13:26:02 +02002545 char *substr, *haystack, *alg = NULL;
2546 size_t alg_len;
2547
2548 if (!strncmp(algorithm, "openssh-", 8)) {
2549 /* if the name starts with openssh, convert it to it's original libssh accepted form */
2550 asprintf(&alg, "%s@openssh.com", algorithm + 8);
2551 if (!alg) {
2552 ERRMEM;
2553 ret = 1;
2554 goto cleanup;
2555 }
2556 } else if (!strncmp(algorithm, "libssh-", 7)) {
2557 /* if the name starts with libssh, convert it to it's original libssh accepted form */
2558 asprintf(&alg, "%s@libssh.org", algorithm + 7);
2559 if (!alg) {
2560 ERRMEM;
2561 ret = 1;
2562 goto cleanup;
2563 }
2564 } else {
2565 alg = strdup(algorithm);
2566 if (!alg) {
2567 ERRMEM;
2568 ret = 1;
2569 goto cleanup;
2570 }
2571 }
2572
2573 alg_len = strlen(alg);
romanc1d2b092023-02-02 08:58:27 +01002574
2575 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2576 if (!*alg_store) {
2577 /* first call */
2578 *alg_store = strdup(alg);
2579 if (!*alg_store) {
2580 ERRMEM;
2581 ret = 1;
2582 goto cleanup;
2583 }
2584 } else {
2585 /* +1 because of ',' between algorithms */
2586 *alg_store = nc_realloc(*alg_store, strlen(*alg_store) + alg_len + 1 + 1);
2587 if (!*alg_store) {
2588 ERRMEM;
2589 ret = 1;
2590 goto cleanup;
2591 }
roman08f67f42023-06-08 13:51:54 +02002592 strcat(*alg_store, ",");
2593 strcat(*alg_store, alg);
romanc1d2b092023-02-02 08:58:27 +01002594 }
2595 } else {
2596 /* delete */
2597 haystack = *alg_store;
2598 while ((substr = strstr(haystack, alg))) {
2599 /* iterate over all the substrings */
2600 if (((substr == haystack) && (*(substr + alg_len) == ',')) ||
2601 ((substr != haystack) && (*(substr - 1) == ',') && (*(substr + alg_len) == ','))) {
2602 /* either the first element of the string or somewhere in the middle */
2603 memmove(substr, substr + alg_len + 1, strlen(substr + alg_len + 1));
2604 alg_found = 1;
2605 break;
2606 } else if ((*(substr - 1) == ',') && (*(substr + alg_len) == '\0')) {
2607 /* the last element of the string */
2608 *(substr - 1) = '\0';
2609 alg_found = 1;
2610 break;
2611 }
2612 haystack++;
2613 }
2614 if (!alg_found) {
2615 ERR(NULL, "Unable to delete an algorithm (%s), which was not previously added.", alg);
2616 ret = 1;
2617 }
2618 }
2619
2620cleanup:
romana6bf6ab2023-05-26 13:26:02 +02002621 free(alg);
romanc1d2b092023-02-02 08:58:27 +01002622 return ret;
2623}
2624
2625/* leaf-list */
2626static int
romane028ef92023-02-24 16:33:08 +01002627nc_server_config_host_key_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002628{
roman5cbb6532023-06-22 12:53:17 +02002629 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002630 const char *alg;
2631 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002632 struct nc_server_ssh_opts *opts;
romanc1d2b092023-02-02 08:58:27 +01002633
roman5cbb6532023-06-22 12:53:17 +02002634 assert(!strcmp(LYD_NAME(node), "host-key-alg"));
romanc1d2b092023-02-02 08:58:27 +01002635
roman4cb8bb12023-06-29 09:16:46 +02002636 if (nc_server_config_get_ssh_opts(node, &opts)) {
2637 ret = 1;
2638 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002639 }
2640
roman5cbb6532023-06-22 12:53:17 +02002641 /* get the algorithm name and compare it with algs supported by libssh */
2642 alg = ((struct lyd_node_term *)node)->value.ident->name;
romanc1d2b092023-02-02 08:58:27 +01002643 i = 0;
2644 while (supported_hostkey_algs[i]) {
2645 if (!strcmp(supported_hostkey_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002646 if (nc_server_config_transport_params(alg, &opts->hostkey_algs, op)) {
2647 ret = 1;
2648 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002649 }
2650 break;
2651 }
2652 i++;
2653 }
2654 if (!supported_hostkey_algs[i]) {
2655 /* algorithm not supported */
2656 ERR(NULL, "Public key algorithm (%s) not supported by libssh.", alg);
2657 ret = 1;
2658 }
2659
2660cleanup:
2661 return ret;
2662}
2663
2664/* leaf-list */
2665static int
romane028ef92023-02-24 16:33:08 +01002666nc_server_config_kex_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002667{
roman5cbb6532023-06-22 12:53:17 +02002668 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002669 const char *alg;
2670 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002671 struct nc_server_ssh_opts *opts;
romanc1d2b092023-02-02 08:58:27 +01002672
roman5cbb6532023-06-22 12:53:17 +02002673 assert(!strcmp(LYD_NAME(node), "key-exchange-alg"));
romanc1d2b092023-02-02 08:58:27 +01002674
roman4cb8bb12023-06-29 09:16:46 +02002675 if (nc_server_config_get_ssh_opts(node, &opts)) {
2676 ret = 1;
2677 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002678 }
2679
roman5cbb6532023-06-22 12:53:17 +02002680 /* get the algorithm name and compare it with algs supported by libssh */
2681 alg = ((struct lyd_node_term *)node)->value.ident->name;
romanc1d2b092023-02-02 08:58:27 +01002682 i = 0;
2683 while (supported_kex_algs[i]) {
2684 if (!strcmp(supported_kex_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002685 if (nc_server_config_transport_params(alg, &opts->kex_algs, op)) {
2686 ret = 1;
2687 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002688 }
2689 break;
2690 }
2691 i++;
2692 }
2693 if (!supported_kex_algs[i]) {
2694 /* algorithm not supported */
2695 ERR(NULL, "Key exchange algorithm (%s) not supported by libssh.", alg);
2696 ret = 1;
2697 }
2698
2699cleanup:
2700 return ret;
2701}
2702
2703/* leaf-list */
2704static int
romane028ef92023-02-24 16:33:08 +01002705nc_server_config_encryption_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002706{
roman5cbb6532023-06-22 12:53:17 +02002707 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002708 const char *alg;
2709 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002710 struct nc_server_ssh_opts *opts;
romanc1d2b092023-02-02 08:58:27 +01002711
roman5cbb6532023-06-22 12:53:17 +02002712 assert(!strcmp(LYD_NAME(node), "encryption-alg"));
romanc1d2b092023-02-02 08:58:27 +01002713
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_encryption_algs[i]) {
2723 if (!strcmp(supported_encryption_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002724 if (nc_server_config_transport_params(alg, &opts->encryption_algs, op)) {
2725 ret = 1;
2726 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002727 }
2728 break;
2729 }
2730 i++;
2731 }
2732 if (!supported_encryption_algs[i]) {
2733 /* algorithm not supported */
2734 ERR(NULL, "Encryption algorithm (%s) not supported by libssh.", alg);
2735 ret = 1;
2736 }
2737
2738cleanup:
2739 return ret;
2740}
2741
2742/* leaf-list */
2743static int
romane028ef92023-02-24 16:33:08 +01002744nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002745{
roman5cbb6532023-06-22 12:53:17 +02002746 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002747 const char *alg;
2748 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002749 struct nc_server_ssh_opts *opts;
romanc1d2b092023-02-02 08:58:27 +01002750
roman5cbb6532023-06-22 12:53:17 +02002751 assert(!strcmp(LYD_NAME(node), "mac-alg"));
romanc1d2b092023-02-02 08:58:27 +01002752
roman4cb8bb12023-06-29 09:16:46 +02002753 if (nc_server_config_get_ssh_opts(node, &opts)) {
2754 ret = 1;
2755 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002756 }
2757
roman5cbb6532023-06-22 12:53:17 +02002758 /* get the algorithm name and compare it with algs supported by libssh */
2759 alg = ((struct lyd_node_term *)node)->value.ident->name;
romanc1d2b092023-02-02 08:58:27 +01002760 i = 0;
2761 while (supported_mac_algs[i]) {
2762 if (!strcmp(supported_mac_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002763 if (nc_server_config_transport_params(alg, &opts->mac_algs, op)) {
2764 ret = 1;
2765 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002766 }
2767 break;
2768 }
2769 i++;
2770 }
2771 if (!supported_mac_algs[i]) {
2772 /* algorithm not supported */
2773 ERR(NULL, "MAC algorithm (%s) not supported by libssh.", alg);
2774 ret = 1;
2775 }
2776
2777cleanup:
2778 return ret;
2779}
2780
roman2eab4742023-06-06 10:00:26 +02002781#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02002782
romanc1d2b092023-02-02 08:58:27 +01002783static int
roman874fed12023-05-25 10:20:01 +02002784nc_server_config_create_unix_socket(struct nc_endpt *endpt)
roman83683fb2023-02-24 09:15:23 +01002785{
2786 endpt->ti = NC_TI_UNIX;
2787 endpt->opts.unixsock = calloc(1, sizeof *endpt->opts.unixsock);
2788 if (!endpt->opts.unixsock) {
2789 ERRMEM;
2790 return 1;
2791 }
2792
2793 /* set default values */
2794 endpt->opts.unixsock->mode = -1;
2795 endpt->opts.unixsock->uid = -1;
2796 endpt->opts.unixsock->gid = -1;
2797
2798 return 0;
2799}
2800
2801static int
romane028ef92023-02-24 16:33:08 +01002802nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op)
roman83683fb2023-02-24 09:15:23 +01002803{
2804 int ret = 0;
2805 uint32_t prev_lo;
2806 struct nc_endpt *endpt;
2807 struct nc_bind *bind;
2808 struct nc_server_unix_opts *opts;
2809 struct lyd_node *data = NULL;
2810
2811 assert(!strcmp(LYD_NAME(node), "unix-socket"));
2812
romanf02273a2023-05-25 09:44:11 +02002813 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
roman83683fb2023-02-24 09:15:23 +01002814 ret = 1;
2815 goto cleanup;
2816 }
2817
2818 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +02002819 if (nc_server_config_create_unix_socket(endpt)) {
roman83683fb2023-02-24 09:15:23 +01002820 ret = 1;
2821 goto cleanup;
2822 }
2823
2824 opts = endpt->opts.unixsock;
2825
2826 lyd_find_path(node, "path", 0, &data);
2827 assert(data);
2828
2829 opts->address = strdup(lyd_get_value(data));
2830 bind->address = strdup(lyd_get_value(data));
2831 if (!opts->address || !bind->address) {
2832 ERRMEM;
2833 ret = 1;
2834 goto cleanup;
2835 }
2836
2837 /* silently search for non-mandatory parameters */
2838 prev_lo = ly_log_options(0);
2839 ret = lyd_find_path(node, "mode", 0, &data);
2840 if (!ret) {
2841 opts->mode = strtol(lyd_get_value(data), NULL, 8);
2842 }
2843
2844 ret = lyd_find_path(node, "uid", 0, &data);
2845 if (!ret) {
2846 opts->uid = strtol(lyd_get_value(data), NULL, 10);
2847 }
2848
2849 ret = lyd_find_path(node, "gid", 0, &data);
2850 if (!ret) {
2851 opts->gid = strtol(lyd_get_value(data), NULL, 10);
2852 }
2853
2854 /* reset the logging options */
2855 ly_log_options(prev_lo);
2856
2857 ret = nc_server_config_set_address_port(endpt, bind, NULL, 0);
2858 if (ret) {
2859 goto cleanup;
2860 }
2861 } else if (op == NC_OP_DELETE) {
roman874fed12023-05-25 10:20:01 +02002862 nc_server_config_del_unix_socket(bind, endpt->opts.unixsock);
roman83683fb2023-02-24 09:15:23 +01002863 }
2864
2865cleanup:
2866 return ret;
2867}
2868
roman2eab4742023-06-06 10:00:26 +02002869#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02002870
roman0bbc19c2023-05-26 09:59:09 +02002871/**
2872 * @brief Set all endpoint client auth references, which couldn't be set beforehand.
2873 *
2874 * The references that could not be set are those, which reference endpoints, which
2875 * lie below the given endpoint in the YANG data (because of DFS tree parsing).
2876 *
2877 * @return 0 on success, 1 on error.
2878 */
2879static int
2880nc_server_config_fill_endpt_client_auth(void)
2881{
2882 uint16_t i, j;
2883
2884 for (i = 0; i < server_opts.endpt_count; i++) {
2885 /* go through all the endpoint */
2886 if (server_opts.endpts[i].referenced_endpt_name) {
2887 /* endpt has a reference, that hasn't been set yet */
2888 for (j = i + 1; j < server_opts.endpt_count; j++) {
2889 /* go through all the remaining endpts */
2890 if (!strcmp(server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[j].name)) {
2891 /* found the endpoint we were looking for */
2892 if (server_opts.endpts[i].ti == NC_TI_LIBSSH) {
2893 server_opts.endpts[i].opts.ssh->endpt_client_ref = &server_opts.endpts[j];
2894 break;
roman2e797ef2023-06-19 10:47:49 +02002895 } else if (server_opts.endpts[i].ti == NC_TI_OPENSSL) {
2896 server_opts.endpts[i].opts.tls->endpt_client_ref = &server_opts.endpts[j];
2897 break;
roman0bbc19c2023-05-26 09:59:09 +02002898 } else {
2899 ERRINT;
2900 return 1;
2901 }
2902 }
2903 }
2904
2905 /* didn't find the endpoint */
2906 if (j == server_opts.endpt_count) {
2907 ERR(NULL, "Endpoint \"%s\" referenced by \"%s\" not found.",
2908 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2909 return 1;
2910 }
2911 }
2912 }
2913
2914 return 0;
2915}
2916
2917static int
roman2e797ef2023-06-19 10:47:49 +02002918nc_server_config_endpoint_client_auth_has_cycle(struct nc_endpt *original, struct nc_endpt *next)
roman0bbc19c2023-05-26 09:59:09 +02002919{
roman2e797ef2023-06-19 10:47:49 +02002920 if (original->ti == NC_TI_LIBSSH) {
2921 if (!next->opts.ssh->endpt_client_ref) {
2922 /* no further reference -> no cycle */
roman0bbc19c2023-05-26 09:59:09 +02002923 return 0;
2924 }
roman2e797ef2023-06-19 10:47:49 +02002925
2926 if (next->opts.ssh->endpt_client_ref == original) {
2927 /* found cycle */
2928 return 1;
2929 } else {
2930 /* continue further */
2931 return nc_server_config_endpoint_client_auth_has_cycle(original, next->opts.ssh->endpt_client_ref);
2932 }
2933 } else if (original->ti == NC_TI_OPENSSL) {
2934 if (!next->opts.tls->endpt_client_ref) {
2935 /* no further reference -> no cycle */
2936 return 0;
2937 }
2938
2939 if (next->opts.tls->endpt_client_ref == original) {
2940 /* found cycle */
2941 return 1;
2942 } else {
2943 /* continue further */
2944 return nc_server_config_endpoint_client_auth_has_cycle(original, next->opts.tls->endpt_client_ref);
2945 }
roman0bbc19c2023-05-26 09:59:09 +02002946 } else {
2947 ERRINT;
2948 return 1;
2949 }
2950}
2951
2952static int
2953nc_server_config_endpoint_client_auth(const struct lyd_node *node, NC_OPERATION op)
2954{
2955 int ret = 0;
2956 uint16_t i;
2957 const char *endpt_name;
2958 struct nc_endpt *endpt;
2959
2960 assert(!strcmp(LYD_NAME(node), "endpoint-client-auth"));
2961
2962 /* get current endpoint */
2963 ret = nc_server_config_get_endpt(node, &endpt, NULL);
2964 if (ret) {
2965 goto cleanup;
2966 }
2967
2968 if (op == NC_OP_DELETE) {
roman2e797ef2023-06-19 10:47:49 +02002969 if (is_ssh(node)) {
2970 endpt->opts.ssh->endpt_client_ref = NULL;
2971 } else {
2972 endpt->opts.tls->endpt_client_ref = NULL;
2973 }
roman0bbc19c2023-05-26 09:59:09 +02002974 goto cleanup;
2975 }
2976
2977 /* find the endpoint leafref is referring to */
2978 endpt_name = lyd_get_value(node);
2979 for (i = 0; i < server_opts.endpt_count; i++) {
2980 if (!strcmp(endpt_name, server_opts.endpts[i].name)) {
2981 break;
2982 }
2983 }
2984
2985 if (i == server_opts.endpt_count) {
2986 /* endpt not found, save the name and try to look it up later */
roman2e797ef2023-06-19 10:47:49 +02002987 nc_server_config_del_endpt_reference(endpt);
roman0bbc19c2023-05-26 09:59:09 +02002988 endpt->referenced_endpt_name = strdup(endpt_name);
2989 if (!endpt->referenced_endpt_name) {
2990 ERRMEM;
2991 ret = 1;
roman0bbc19c2023-05-26 09:59:09 +02002992 }
2993 goto cleanup;
2994 }
2995
2996 /* check for self reference */
2997 if (endpt == &server_opts.endpts[i]) {
2998 ERR(NULL, "Self client authentication reference detected.");
2999 ret = 1;
3000 goto cleanup;
3001 }
3002
3003 /* check for cyclic references */
roman2e797ef2023-06-19 10:47:49 +02003004 ret = nc_server_config_endpoint_client_auth_has_cycle(endpt, &server_opts.endpts[i]);
roman0bbc19c2023-05-26 09:59:09 +02003005 if (ret) {
3006 ERR(NULL, "Cyclic client authentication reference detected.");
3007 goto cleanup;
3008 }
3009
3010 /* assign the current endpt the referrenced endpt */
roman2e797ef2023-06-19 10:47:49 +02003011 if (is_ssh(node)) {
3012 endpt->opts.ssh->endpt_client_ref = &server_opts.endpts[i];
3013 } else {
3014 endpt->opts.tls->endpt_client_ref = &server_opts.endpts[i];
3015 }
roman0bbc19c2023-05-26 09:59:09 +02003016
3017cleanup:
3018 return ret;
3019}
3020
roman3f9b65c2023-06-05 14:26:58 +02003021static int
3022nc_server_config_tls_replace_cert_data(const struct lyd_node *node, struct nc_server_tls_opts *opts)
3023{
3024 nc_server_config_tls_del_cert_data(opts);
3025 opts->cert_data = strdup(lyd_get_value(node));
3026 if (!opts->cert_data) {
3027 ERRMEM;
3028 return 1;
3029 }
3030
3031 return 0;
3032}
3033
3034static int
3035nc_server_config_tls_replace_cert_data_client_auth(const struct lyd_node *node, struct nc_certificate *cert)
3036{
3037 nc_server_config_tls_del_cert_data_certificate(cert);
3038 cert->data = strdup(lyd_get_value(node));
3039 if (!cert->data) {
3040 ERRMEM;
3041 return 1;
3042 }
3043
3044 return 0;
3045}
3046
3047static int
3048nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op)
3049{
3050 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02003051 struct nc_certificate *cert;
romanb6f44032023-06-30 15:07:56 +02003052 struct nc_server_tls_opts *opts;
roman3f9b65c2023-06-05 14:26:58 +02003053
3054 assert(!strcmp(LYD_NAME(node), "cert-data"));
3055
romanb6f44032023-06-30 15:07:56 +02003056 if (equal_parent_name(node, 3, "server-identity")) {
3057 if (nc_server_config_get_tls_opts(node, &opts)) {
3058 ret = 1;
3059 goto cleanup;
3060 }
roman3f9b65c2023-06-05 14:26:58 +02003061
roman3f9b65c2023-06-05 14:26:58 +02003062 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003063 ret = nc_server_config_tls_replace_cert_data(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02003064 if (ret) {
3065 goto cleanup;
3066 }
3067 }
romanb6f44032023-06-30 15:07:56 +02003068 } else if (equal_parent_name(node, 3, "ca-certs")) {
roman4cb8bb12023-06-29 09:16:46 +02003069 if (nc_server_config_get_cert(node, 0, &cert)) {
roman3f9b65c2023-06-05 14:26:58 +02003070 ret = 1;
3071 goto cleanup;
3072 }
3073
3074 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
3075 ret = nc_server_config_tls_replace_cert_data_client_auth(node, cert);
3076 if (ret) {
3077 goto cleanup;
3078 }
3079 } else {
3080 nc_server_config_tls_del_cert_data_certificate(cert);
3081 }
romanb6f44032023-06-30 15:07:56 +02003082 } else if (equal_parent_name(node, 3, "ee-certs")) {
roman4cb8bb12023-06-29 09:16:46 +02003083 if (nc_server_config_get_cert(node, 1, &cert)) {
roman3f9b65c2023-06-05 14:26:58 +02003084 ret = 1;
3085 goto cleanup;
3086 }
3087
3088 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
3089 ret = nc_server_config_tls_replace_cert_data_client_auth(node, cert);
3090 if (ret) {
3091 goto cleanup;
3092 }
3093 } else {
3094 nc_server_config_tls_del_cert_data_certificate(cert);
3095 }
3096 }
3097
3098cleanup:
3099 return ret;
3100}
3101
3102static int
3103nc_server_config_tls_create_asymmetric_key_ref(const struct lyd_node *node, struct nc_endpt *endpt)
3104{
3105 uint16_t i;
3106 struct nc_keystore *ks = &server_opts.keystore;
3107
3108 /* lookup name */
3109 for (i = 0; i < ks->asym_key_count; i++) {
3110 if (!strcmp(lyd_get_value(node), ks->asym_keys[i].name)) {
3111 break;
3112 }
3113 }
3114
3115 if (i == ks->asym_key_count) {
3116 ERR(NULL, "Asymmetric key \"%s\" not found in the keystore.", lyd_get_value(node));
3117 return 1;
3118 }
3119
3120 endpt->opts.tls->key_ref = &ks->asym_keys[i];
3121
3122 return 0;
3123}
3124
3125static int
3126nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op)
3127{
3128 int ret = 0;
3129 struct nc_endpt *endpt;
3130
3131 assert(!strcmp(LYD_NAME(node), "asymmetric-key"));
3132
3133 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
3134 ret = 1;
3135 goto cleanup;
3136 }
3137
3138 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
3139 /* set to keystore */
3140 endpt->opts.tls->store = NC_STORE_KEYSTORE;
3141
3142 ret = nc_server_config_tls_create_asymmetric_key_ref(node, endpt);
3143 if (ret) {
3144 goto cleanup;
3145 }
3146 } else {
3147 endpt->opts.tls->key_ref = NULL;
3148 }
3149
3150cleanup:
3151 return ret;
3152}
3153
3154static int
romanb6f44032023-06-30 15:07:56 +02003155nc_server_config_tls_create_certificate_ref(const struct lyd_node *node, struct nc_server_tls_opts *opts, struct nc_asymmetric_key *key)
roman3f9b65c2023-06-05 14:26:58 +02003156{
3157 uint16_t i;
3158
3159 /* lookup name */
3160 for (i = 0; i < key->cert_count; i++) {
3161 if (!strcmp(lyd_get_value(node), key->certs[i].name)) {
3162 break;
3163 }
3164 }
3165
3166 if (i == key->cert_count) {
3167 ERR(NULL, "Certificate \"%s\" not found in the asymmetric key \"%s\".", lyd_get_value(node), key->name);
3168 return 1;
3169 }
3170
romanb6f44032023-06-30 15:07:56 +02003171 opts->cert_ref = &key->certs[i];
roman3f9b65c2023-06-05 14:26:58 +02003172
3173 return 0;
3174}
3175
3176static struct nc_asymmetric_key *
romanb6f44032023-06-30 15:07:56 +02003177nc_server_config_cert_get_asymmetric_key(const struct lyd_node *node)
roman3f9b65c2023-06-05 14:26:58 +02003178{
3179 uint16_t i;
3180 struct nc_keystore *ks = &server_opts.keystore;
3181
3182 /* starting with certificate node */
3183 assert(!strcmp(LYD_NAME(node), "certificate"));
3184
3185 /* switch to it's only sibling, must be asymmetric-key */
3186 node = node->prev;
3187 assert(!strcmp(LYD_NAME(node), "asymmetric-key"));
3188
3189 /* find the given asymmetric key */
3190 for (i = 0; i < ks->asym_key_count; i++) {
3191 if (!strcmp(lyd_get_value(node), ks->asym_keys[i].name)) {
3192 return &ks->asym_keys[i];
3193 }
3194 }
3195
3196 /* didn't find it */
3197 ERR(NULL, "Asymmetric key \"%s\" not found in the keystore.", lyd_get_value(node));
3198 return NULL;
3199}
3200
3201static int
3202nc_server_config_create_ca_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
3203{
3204 assert(!strcmp(LYD_NAME(node), "certificate"));
3205
3206 node = lyd_child(node);
3207 assert(!strcmp(LYD_NAME(node), "name"));
3208
3209 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ca_certs.certs, sizeof *opts->ca_certs.certs, &opts->ca_certs.cert_count);
3210}
3211
3212static int
3213nc_server_config_create_ee_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
3214{
3215 assert(!strcmp(LYD_NAME(node), "certificate"));
3216
3217 node = lyd_child(node);
3218 assert(!strcmp(LYD_NAME(node), "name"));
3219
3220 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ee_certs.certs, sizeof *opts->ee_certs.certs, &opts->ee_certs.cert_count);
3221}
3222
3223static int
3224nc_server_config_certificate(const struct lyd_node *node, NC_OPERATION op)
3225{
3226 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02003227 struct nc_asymmetric_key *key;
romanb6f44032023-06-30 15:07:56 +02003228 struct nc_server_tls_opts *opts;
roman3f9b65c2023-06-05 14:26:58 +02003229
3230 assert(!strcmp(LYD_NAME(node), "certificate"));
3231
romanb6f44032023-06-30 15:07:56 +02003232 if (nc_server_config_get_tls_opts(node, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02003233 ret = 1;
3234 goto cleanup;
3235 }
3236
romanb6f44032023-06-30 15:07:56 +02003237 if (equal_parent_name(node, 1, "keystore-reference")) {
3238 /* TLS server-identity */
roman3f9b65c2023-06-05 14:26:58 +02003239 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
3240 /* set to keystore */
romanb6f44032023-06-30 15:07:56 +02003241 opts->store = NC_STORE_KEYSTORE;
roman3f9b65c2023-06-05 14:26:58 +02003242
romanb6f44032023-06-30 15:07:56 +02003243 if (!opts->key_ref) {
roman3f9b65c2023-06-05 14:26:58 +02003244 /* we don't have a key from which we need the cert yet */
romanb6f44032023-06-30 15:07:56 +02003245 key = nc_server_config_cert_get_asymmetric_key(node);
roman3f9b65c2023-06-05 14:26:58 +02003246 if (!key) {
3247 ret = 1;
3248 goto cleanup;
3249 }
3250 } else {
3251 /* we have the key */
romanb6f44032023-06-30 15:07:56 +02003252 key = opts->key_ref;
roman3f9b65c2023-06-05 14:26:58 +02003253 }
3254
3255 /* find the given cert in the key and set it */
romanb6f44032023-06-30 15:07:56 +02003256 ret = nc_server_config_tls_create_certificate_ref(node, opts, key);
roman3f9b65c2023-06-05 14:26:58 +02003257 if (ret) {
3258 goto cleanup;
3259 }
3260 } else {
romanb6f44032023-06-30 15:07:56 +02003261 opts->cert_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003262 }
romanb6f44032023-06-30 15:07:56 +02003263 } else if (equal_parent_name(node, 2, "ca-certs")) {
3264 /* TLS client auth certificate authority */
roman3f9b65c2023-06-05 14:26:58 +02003265 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003266 ret = nc_server_config_create_ca_certs_certificate(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02003267 if (ret) {
3268 goto cleanup;
3269 }
3270 } else {
romanb6f44032023-06-30 15:07:56 +02003271 nc_server_config_tls_del_certs(&opts->ca_certs);
roman3f9b65c2023-06-05 14:26:58 +02003272 }
romanb6f44032023-06-30 15:07:56 +02003273 } else if (equal_parent_name(node, 2, "ee-certs")) {
3274 /* TLS client auth end entity */
roman3f9b65c2023-06-05 14:26:58 +02003275 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003276 ret = nc_server_config_create_ee_certs_certificate(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02003277 if (ret) {
3278 goto cleanup;
3279 }
3280 } else {
romanb6f44032023-06-30 15:07:56 +02003281 nc_server_config_tls_del_certs(&opts->ee_certs);
roman3f9b65c2023-06-05 14:26:58 +02003282 }
3283 }
3284
3285cleanup:
3286 return ret;
3287}
3288
3289static int
3290nc_server_config_create_cert_to_name(const struct lyd_node *node, struct nc_server_tls_opts *opts)
3291{
3292 int ret = 0;
3293 struct lyd_node *n;
3294 struct nc_ctn *new, *iter;
3295 const char *map_type, *name;
3296 uint32_t id;
3297 NC_TLS_CTN_MAPTYPE m_type;
3298
3299 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
3300
3301 /* create new ctn */
3302 new = calloc(1, sizeof *new);
3303 if (!new) {
3304 ERRMEM;
3305 ret = 1;
3306 goto cleanup;
3307 }
3308
3309 /* get all the data */
3310 /* find the list's key */
3311 lyd_find_path(node, "id", 0, &n);
3312 assert(n);
3313 id = strtoul(lyd_get_value(n), NULL, 10);
3314
3315 /* find the ctn's name */
3316 lyd_find_path(node, "name", 0, &n);
3317 assert(n);
3318 name = lyd_get_value(n);
3319
3320 /* find the ctn's map-type */
3321 lyd_find_path(node, "map-type", 0, &n);
3322 assert(n);
3323 map_type = ((struct lyd_node_term *)n)->value.ident->name;
3324 if (!strcmp(map_type, "specified")) {
3325 m_type = NC_TLS_CTN_SPECIFIED;
3326 } else if (!strcmp(map_type, "san-rfc822-name")) {
3327 m_type = NC_TLS_CTN_SAN_RFC822_NAME;
3328 } else if (!strcmp(map_type, "san-dns-name")) {
3329 m_type = NC_TLS_CTN_SAN_DNS_NAME;
3330 } else if (!strcmp(map_type, "san-ip-address")) {
3331 m_type = NC_TLS_CTN_SAN_IP_ADDRESS;
3332 } else if (!strcmp(map_type, "san-any")) {
3333 m_type = NC_TLS_CTN_SAN_ANY;
3334 } else if (!strcmp(map_type, "common-name")) {
3335 m_type = NC_TLS_CTN_COMMON_NAME;
3336 } else {
3337 ERR(NULL, "Map-type identity \"%s\" not supported.", map_type);
3338 ret = 1;
3339 goto cleanup;
3340 }
3341
3342 /* find the right place for insertion */
3343 if (!opts->ctn) {
3344 /* inserting the first one */
3345 opts->ctn = new;
3346 } else if (opts->ctn->id > new->id) {
3347 /* insert at the beginning */
3348 new->next = opts->ctn;
3349 opts->ctn = new;
3350 } else {
3351 /* have to find the right place */
3352 for (iter = opts->ctn; iter->next && iter->next->id <= new->id; iter = iter->next) {}
3353 if (iter->id == new->id) {
3354 /* collision */
3355 new = iter;
3356 } else {
3357 new->next = iter->next;
3358 iter->next = new;
3359 }
3360 }
3361
3362 /* insert the right data */
3363 new->id = id;
3364 if (new->name) {
3365 free(new->name);
3366 }
3367 new->name = strdup(name);
3368 if (!new->name) {
3369 ERRMEM;
3370 ret = 1;
3371 goto cleanup;
3372 }
3373 new->map_type = m_type;
3374
3375cleanup:
3376 return ret;
3377}
3378
3379static int
3380nc_server_config_cert_to_name(const struct lyd_node *node, NC_OPERATION op)
3381{
3382 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003383 struct nc_server_tls_opts *opts;
roman3f9b65c2023-06-05 14:26:58 +02003384 struct lyd_node *key;
3385 struct nc_ctn *ctn;
3386
3387 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
3388
romanb6f44032023-06-30 15:07:56 +02003389 if (nc_server_config_get_tls_opts(node, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02003390 ret = 1;
3391 goto cleanup;
3392 }
3393
3394 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003395 ret = nc_server_config_create_cert_to_name(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02003396 if (ret) {
3397 goto cleanup;
3398 }
3399 } else {
3400 /* find the given ctn entry */
3401 lyd_find_path(node, "id", 0, &key);
3402 assert(key);
roman4cb8bb12023-06-29 09:16:46 +02003403 if (nc_server_config_get_ctn(node, &ctn)) {
roman3f9b65c2023-06-05 14:26:58 +02003404 ret = 1;
3405 goto cleanup;
3406 }
romanb6f44032023-06-30 15:07:56 +02003407 nc_server_config_del_ctn(opts, ctn);
roman3f9b65c2023-06-05 14:26:58 +02003408 }
3409
3410cleanup:
3411 return ret;
3412}
3413
3414static int
3415nc_server_config_replace_fingerprint(const struct lyd_node *node, struct nc_ctn *ctn)
3416{
3417 nc_server_config_del_fingerprint(ctn);
3418
3419 ctn->fingerprint = strdup(lyd_get_value(node));
3420 if (!ctn->fingerprint) {
3421 ERRMEM;
3422 return 1;
3423 }
3424
3425 return 0;
3426}
3427
3428static int
3429nc_server_config_fingerprint(const struct lyd_node *node, NC_OPERATION op)
3430{
3431 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02003432 struct nc_ctn *ctn;
3433
roman4cb8bb12023-06-29 09:16:46 +02003434 if (nc_server_config_get_ctn(node, &ctn)) {
roman3f9b65c2023-06-05 14:26:58 +02003435 ret = 1;
3436 goto cleanup;
3437 }
3438
3439 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
3440 ret = nc_server_config_replace_fingerprint(node, ctn);
3441 if (ret) {
3442 goto cleanup;
3443 }
3444 } else {
3445 nc_server_config_del_fingerprint(ctn);
3446 }
3447
3448cleanup:
3449 return ret;
3450}
3451
roman12644fe2023-06-08 11:06:42 +02003452static void
3453nc_server_config_set_tls_version(struct nc_server_tls_opts *opts, NC_TLS_VERSION version, NC_OPERATION op)
3454{
3455 if (op == NC_OP_CREATE) {
3456 /* add the version if it isn't there already */
3457 opts->tls_versions |= version;
3458 } else if ((op == NC_OP_DELETE) && (opts->tls_versions & version)) {
3459 /* delete the version if it is there */
3460 opts->tls_versions -= version;
3461 }
3462}
3463
3464static int
3465nc_server_config_tls_version(const struct lyd_node *node, NC_OPERATION op)
3466{
3467 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003468 struct nc_server_tls_opts *opts;
roman12644fe2023-06-08 11:06:42 +02003469 const char *version = NULL;
3470
3471 assert(!strcmp(LYD_NAME(node), "tls-version"));
3472
romanb6f44032023-06-30 15:07:56 +02003473 if (nc_server_config_get_tls_opts(node, &opts)) {
roman12644fe2023-06-08 11:06:42 +02003474 ret = 1;
3475 goto cleanup;
3476 }
3477
3478 version = ((struct lyd_node_term *)node)->value.ident->name;
3479 if (!strcmp(version, "tls10")) {
romanb6f44032023-06-30 15:07:56 +02003480 nc_server_config_set_tls_version(opts, NC_TLS_VERSION_10, op);
roman12644fe2023-06-08 11:06:42 +02003481 } else if (!strcmp(version, "tls11")) {
romanb6f44032023-06-30 15:07:56 +02003482 nc_server_config_set_tls_version(opts, NC_TLS_VERSION_11, op);
roman12644fe2023-06-08 11:06:42 +02003483 } else if (!strcmp(version, "tls12")) {
romanb6f44032023-06-30 15:07:56 +02003484 nc_server_config_set_tls_version(opts, NC_TLS_VERSION_12, op);
roman12644fe2023-06-08 11:06:42 +02003485 } else if (!strcmp(version, "tls13")) {
romanb6f44032023-06-30 15:07:56 +02003486 nc_server_config_set_tls_version(opts, NC_TLS_VERSION_13, op);
roman12644fe2023-06-08 11:06:42 +02003487 } else {
3488 ERR(NULL, "TLS version \"%s\" not supported.", version);
3489 ret = 1;
3490 goto cleanup;
3491 }
3492
3493cleanup:
3494 return ret;
3495}
3496
3497static int
3498nc_server_config_create_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher)
3499{
3500 int ret = 0;
3501 char *ssl_cipher = NULL;
3502 uint16_t i;
3503
3504 ssl_cipher = malloc(strlen(cipher) + 1);
3505 if (!ssl_cipher) {
3506 ERRMEM;
3507 ret = 1;
3508 goto cleanup;
3509 }
3510
3511 for (i = 0; cipher[i]; i++) {
3512 if (cipher[i] == '-') {
3513 /* OpenSSL requires _ instead of - in cipher names */
3514 ssl_cipher[i] = '_';
3515 } else {
3516 /* and requires uppercase unlike the identities */
3517 ssl_cipher[i] = toupper(cipher[i]);
3518 }
3519 }
3520 ssl_cipher[i] = '\0';
3521
3522 if (!opts->ciphers) {
3523 /* first entry */
3524 opts->ciphers = strdup(ssl_cipher);
3525 if (!opts->ciphers) {
3526 ERRMEM;
3527 ret = 1;
3528 goto cleanup;
3529 }
3530 } else {
3531 /* + 1 because of : between entries */
3532 opts->ciphers = nc_realloc(opts->ciphers, strlen(opts->ciphers) + strlen(ssl_cipher) + 1 + 1);
3533 if (!opts->ciphers) {
3534 ERRMEM;
3535 ret = 1;
3536 goto cleanup;
3537 }
roman08f67f42023-06-08 13:51:54 +02003538 strcat(opts->ciphers, ":");
3539 strcat(opts->ciphers, ssl_cipher);
roman12644fe2023-06-08 11:06:42 +02003540 }
3541
3542cleanup:
3543 free(ssl_cipher);
3544 return ret;
3545}
3546
3547static int
romanb6f44032023-06-30 15:07:56 +02003548nc_server_config_del_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher)
roman12644fe2023-06-08 11:06:42 +02003549{
3550 int cipher_found = 0;
3551 char *haystack, *substr;
3552 size_t cipher_len = strlen(cipher);
3553
3554 /* delete */
3555 haystack = opts->ciphers;
3556 while ((substr = strstr(haystack, cipher))) {
3557 /* iterate over all the substrings */
3558 if (((substr == haystack) && (*(substr + cipher_len) == ':')) ||
3559 ((substr != haystack) && (*(substr - 1) == ':') && (*(substr + cipher_len) == ':'))) {
3560 /* either the first element of the string or somewhere in the middle */
3561 memmove(substr, substr + cipher_len + 1, strlen(substr + cipher_len + 1));
3562 cipher_found = 1;
3563 break;
3564 } else if ((*(substr - 1) == ':') && (*(substr + cipher_len) == '\0')) {
3565 /* the last element of the string */
3566 *(substr - 1) = '\0';
3567 cipher_found = 1;
3568 break;
3569 }
3570 haystack++;
3571 }
3572
3573 if (!cipher_found) {
3574 ERR(NULL, "Unable to delete a cipher (%s), which was not previously added.", cipher);
3575 return 1;
3576 }
3577
3578 return 0;
3579}
3580
3581static int
3582nc_server_config_cipher_suite(const struct lyd_node *node, NC_OPERATION op)
3583{
3584 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003585 struct nc_server_tls_opts *opts;
roman12644fe2023-06-08 11:06:42 +02003586 const char *cipher = NULL;
3587
romanfaecc582023-06-15 16:13:31 +02003588 assert(!strcmp(LYD_NAME(node), "cipher-suite"));
3589
romanb6f44032023-06-30 15:07:56 +02003590 if (nc_server_config_get_tls_opts(node, &opts)) {
roman12644fe2023-06-08 11:06:42 +02003591 ret = 1;
3592 goto cleanup;
3593 }
3594
3595 cipher = ((struct lyd_node_term *)node)->value.ident->name;
3596 if (op == NC_OP_CREATE) {
romanb6f44032023-06-30 15:07:56 +02003597 ret = nc_server_config_create_cipher_suite(opts, cipher);
roman12644fe2023-06-08 11:06:42 +02003598 if (ret) {
3599 goto cleanup;
3600 }
3601 } else if (op == NC_OP_DELETE) {
romanb6f44032023-06-30 15:07:56 +02003602 ret = nc_server_config_del_cipher_suite(opts, cipher);
roman12644fe2023-06-08 11:06:42 +02003603 if (ret) {
3604 goto cleanup;
3605 }
3606 }
3607
3608cleanup:
3609 return ret;
3610}
3611
romanfaecc582023-06-15 16:13:31 +02003612static int
3613nc_server_config_crl_url(const struct lyd_node *node, NC_OPERATION op)
3614{
3615 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003616 struct nc_server_tls_opts *opts;
romanfaecc582023-06-15 16:13:31 +02003617
3618 assert(!strcmp(LYD_NAME(node), "crl-url"));
3619
romanb6f44032023-06-30 15:07:56 +02003620 if (nc_server_config_get_tls_opts(node, &opts)) {
romanfaecc582023-06-15 16:13:31 +02003621 ret = 1;
3622 goto cleanup;
3623 }
3624
3625 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003626 nc_server_config_del_url(opts);
3627 opts->crl_url = strdup(lyd_get_value(node));
3628 if (!opts->crl_url) {
romanfaecc582023-06-15 16:13:31 +02003629 ERRMEM;
3630 ret = 1;
3631 goto cleanup;
3632 }
3633 } else if (op == NC_OP_DELETE) {
romanb6f44032023-06-30 15:07:56 +02003634 nc_server_config_del_url(opts);
romanfaecc582023-06-15 16:13:31 +02003635 }
3636
3637cleanup:
3638 return ret;
3639}
3640
3641static int
3642nc_server_config_crl_path(const struct lyd_node *node, NC_OPERATION op)
3643{
3644 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003645 struct nc_server_tls_opts *opts;
romanfaecc582023-06-15 16:13:31 +02003646
3647 assert(!strcmp(LYD_NAME(node), "crl-path"));
3648
romanb6f44032023-06-30 15:07:56 +02003649 if (nc_server_config_get_tls_opts(node, &opts)) {
romanfaecc582023-06-15 16:13:31 +02003650 ret = 1;
3651 goto cleanup;
3652 }
3653
3654 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003655 nc_server_config_del_path(opts);
3656 opts->crl_path = strdup(lyd_get_value(node));
3657 if (!opts->crl_path) {
romanfaecc582023-06-15 16:13:31 +02003658 ERRMEM;
3659 ret = 1;
3660 goto cleanup;
3661 }
3662 } else if (op == NC_OP_DELETE) {
romanb6f44032023-06-30 15:07:56 +02003663 nc_server_config_del_path(opts);
romanfaecc582023-06-15 16:13:31 +02003664 }
3665
3666cleanup:
3667 return ret;
3668}
3669
3670static int
3671nc_server_config_crl_cert_ext(const struct lyd_node *node, NC_OPERATION op)
3672{
3673 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003674 struct nc_server_tls_opts *opts;
romanfaecc582023-06-15 16:13:31 +02003675
3676 assert(!strcmp(LYD_NAME(node), "crl-cert-ext"));
3677
romanb6f44032023-06-30 15:07:56 +02003678 if (nc_server_config_get_tls_opts(node, &opts)) {
romanfaecc582023-06-15 16:13:31 +02003679 ret = 1;
3680 goto cleanup;
3681 }
3682
3683 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003684 opts->crl_cert_ext = 1;
romanfaecc582023-06-15 16:13:31 +02003685 } else if (op == NC_OP_DELETE) {
romanb6f44032023-06-30 15:07:56 +02003686 opts->crl_cert_ext = 0;
romanfaecc582023-06-15 16:13:31 +02003687 }
3688
3689cleanup:
3690 return ret;
3691}
3692
roman2eab4742023-06-06 10:00:26 +02003693#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02003694
roman83683fb2023-02-24 09:15:23 +01003695static int
roman5cbb6532023-06-22 12:53:17 +02003696nc_server_config_create_netconf_client(const struct lyd_node *node)
3697{
3698 int ret = 0;
3699
3700 node = lyd_child(node);
3701 assert(!strcmp(LYD_NAME(node), "name"));
3702
3703 /* LOCK */
3704 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
3705
3706 ret = nc_server_config_realloc(lyd_get_value(node), (void **)&server_opts.ch_clients, sizeof *server_opts.ch_clients, &server_opts.ch_client_count);
3707 if (ret) {
3708 goto cleanup;
3709 }
3710
3711 server_opts.ch_clients[server_opts.ch_client_count - 1].id = ATOMIC_INC_RELAXED(server_opts.new_client_id);
3712 server_opts.ch_clients[server_opts.ch_client_count - 1].start_with = NC_CH_FIRST_LISTED;
3713 server_opts.ch_clients[server_opts.ch_client_count - 1].max_attempts = 3; // TODO
3714
3715 pthread_mutex_init(&server_opts.ch_clients[server_opts.ch_client_count - 1].lock, NULL);
3716
3717cleanup:
3718 /* UNLOCK */
3719 pthread_rwlock_unlock(&server_opts.ch_client_lock);
3720 return ret;
3721}
3722
3723static int
3724nc_server_config_netconf_client(const struct lyd_node *node, NC_OPERATION op)
3725{
3726 int ret = 0;
3727 struct nc_ch_client *ch_client;
3728
3729 assert(!strcmp(LYD_NAME(node), "netconf-client"));
3730
3731 if (op == NC_OP_CREATE) {
3732 ret = nc_server_config_create_netconf_client(node);
3733 if (ret) {
3734 goto cleanup;
3735 }
3736 } else if (op == NC_OP_DELETE) {
3737 if (nc_server_config_get_ch_client(node, &ch_client)) {
3738 ret = 1;
3739 goto cleanup;
3740 }
3741
3742 nc_server_config_ch_del_client(ch_client);
3743 }
3744
3745cleanup:
3746 return ret;
3747}
3748
3749#ifdef NC_ENABLED_SSH_TLS
3750
3751static int
3752nc_server_config_remote_address(const struct lyd_node *node, NC_OPERATION op)
3753{
3754 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02003755 struct nc_ch_endpt *ch_endpt;
3756
romanb6f44032023-06-30 15:07:56 +02003757 assert(!strcmp(LYD_NAME(node), "remote-address"));
3758
roman4cb8bb12023-06-29 09:16:46 +02003759 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02003760 ret = 1;
3761 goto cleanup;
3762 }
3763
3764 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
3765 nc_server_config_del_remote_address(ch_endpt);
3766
3767 ch_endpt->address = strdup(lyd_get_value(node));
3768 if (!ch_endpt->address) {
3769 ERRMEM;
3770 ret = 1;
3771 goto cleanup;
3772 }
3773 } else {
3774 nc_server_config_del_remote_address(ch_endpt);
3775 }
3776
3777cleanup:
3778 return ret;
3779}
3780
3781static int
3782nc_server_config_remote_port(const struct lyd_node *node, NC_OPERATION op)
3783{
3784 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02003785 struct nc_ch_endpt *ch_endpt;
3786
romanb6f44032023-06-30 15:07:56 +02003787 assert(!strcmp(LYD_NAME(node), "remote-port"));
3788
roman4cb8bb12023-06-29 09:16:46 +02003789 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02003790 ret = 1;
3791 goto cleanup;
3792 }
3793
3794 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
3795 ch_endpt->port = strtoul(lyd_get_value(node), NULL, 10);
3796 } else {
3797 ch_endpt->port = 0;
3798 }
3799
3800cleanup:
3801 return ret;
3802}
3803
3804#endif /* NC_ENABLED_SSH_TLS */
3805
3806static int
romanb6f44032023-06-30 15:07:56 +02003807nc_server_config_persistent(const struct lyd_node *node, NC_OPERATION op)
3808{
3809 int ret = 0;
3810 struct nc_ch_client *ch_client;
3811
3812 assert(!strcmp(LYD_NAME(node), "persistent"));
3813
3814 (void) op;
3815
3816 if (nc_server_config_get_ch_client(node, &ch_client)) {
3817 ret = 1;
3818 goto cleanup;
3819 }
3820
3821 ch_client->conn_type = NC_CH_PERSIST;
3822
3823cleanup:
3824 return ret;
3825}
3826
3827static int
3828nc_server_config_periodic(const struct lyd_node *node, NC_OPERATION op)
3829{
3830 int ret = 0;
3831 struct nc_ch_client *ch_client;
3832
3833 assert(!strcmp(LYD_NAME(node), "periodic"));
3834
3835 (void) op;
3836
3837 if (nc_server_config_get_ch_client(node, &ch_client)) {
3838 ret = 1;
3839 goto cleanup;
3840 }
3841
3842 ch_client->conn_type = NC_CH_PERIOD;
3843 /* set default values */
3844 ch_client->period = 60;
3845 ch_client->anchor_time = 0;
3846 ch_client->idle_timeout = 180;
3847
3848cleanup:
3849 return ret;
3850}
3851
3852static int
3853nc_server_config_period(const struct lyd_node *node, NC_OPERATION op)
3854{
3855 int ret = 0;
3856 struct nc_ch_client *ch_client;
3857
3858 assert(!strcmp(LYD_NAME(node), "period"));
3859
3860 if (nc_server_config_get_ch_client(node, &ch_client)) {
3861 ret = 1;
3862 goto cleanup;
3863 }
3864
3865 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
3866 ch_client->period = strtoul(lyd_get_value(node), NULL, 10);
3867 } else if (op == NC_OP_DELETE) {
3868 ch_client->period = 60;
3869 }
3870
3871cleanup:
3872 return ret;
3873}
3874
3875static int
3876nc_server_config_anchor_time(const struct lyd_node *node, NC_OPERATION op)
3877{
3878 int ret = 0;
3879 struct nc_ch_client *ch_client;
3880 time_t anchor_time = {0};
3881
3882 assert(!strcmp(LYD_NAME(node), "anchor-time"));
3883
3884 if (nc_server_config_get_ch_client(node, &ch_client)) {
3885 ret = 1;
3886 goto cleanup;
3887 }
3888
3889 ret = ly_time_str2time(lyd_get_value(node), &anchor_time, NULL);
3890 if (ret) {
3891 goto cleanup;
3892 }
3893
3894 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
3895 ch_client->anchor_time = anchor_time;
3896 } else if (op == NC_OP_DELETE) {
3897 ch_client->anchor_time = 0;
3898 }
3899
3900cleanup:
3901 return ret;
3902}
3903
3904static int
3905nc_server_config_reconnect_strategy(const struct lyd_node *node, NC_OPERATION op)
3906{
3907 int ret = 0;
3908 struct nc_ch_client *ch_client;
3909
3910 assert(!strcmp(LYD_NAME(node), "reconnect-strategy"));
3911
3912 (void) op;
3913
3914 if (nc_server_config_get_ch_client(node, &ch_client)) {
3915 ret = 1;
3916 goto cleanup;
3917 }
3918
3919 /* set to default values */
3920 ch_client->start_with = NC_CH_FIRST_LISTED;
3921 ch_client->max_wait = 5;
3922 ch_client->max_attempts = 3;
3923
3924cleanup:
3925 return ret;
3926}
3927
3928static int
3929nc_server_config_start_with(const struct lyd_node *node, NC_OPERATION op)
3930{
3931 int ret = 0;
3932 struct nc_ch_client *ch_client;
3933 const char *value;
3934
3935 assert(!strcmp(LYD_NAME(node), "start-with"));
3936
3937 if (nc_server_config_get_ch_client(node, &ch_client)) {
3938 ret = 1;
3939 goto cleanup;
3940 }
3941
3942 if (op == NC_OP_DELETE) {
3943 ch_client->start_with = NC_CH_FIRST_LISTED;
3944 goto cleanup;
3945 }
3946
3947 value = lyd_get_value(node);
3948 if (!strcmp(value, "first-listed")) {
3949 ch_client->start_with = NC_CH_FIRST_LISTED;
3950 } else if (!strcmp(value, "last-connected")) {
3951 ch_client->start_with = NC_CH_LAST_CONNECTED;
3952 } else if (!strcmp(value, "random-selection")) {
3953 ch_client->start_with = NC_CH_RANDOM;
3954 } else {
3955 ERR(NULL, "Unexpected start-with value \"%s\".", value);
3956 ret = 1;
3957 goto cleanup;
3958 }
3959
3960cleanup:
3961 return ret;
3962}
3963
3964static int
3965nc_server_config_max_wait(const struct lyd_node *node, NC_OPERATION op)
3966{
3967 int ret = 0;
3968 struct nc_ch_client *ch_client;
3969
3970 assert(!strcmp(LYD_NAME(node), "max-wait"));
3971
3972 if (nc_server_config_get_ch_client(node, &ch_client)) {
3973 ret = 1;
3974 goto cleanup;
3975 }
3976
3977 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
3978 ch_client->max_wait = strtoul(lyd_get_value(node), NULL, 10);
3979 } else {
3980 ch_client->max_wait = 5;
3981 }
3982
3983cleanup:
3984 return ret;
3985}
3986
3987static int
3988nc_server_config_max_attempts(const struct lyd_node *node, NC_OPERATION op)
3989{
3990 int ret = 0;
3991 struct nc_ch_client *ch_client;
3992
3993 assert(!strcmp(LYD_NAME(node), "max-attempts"));
3994
3995 if (nc_server_config_get_ch_client(node, &ch_client)) {
3996 ret = 1;
3997 goto cleanup;
3998 }
3999
4000 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
4001 ch_client->max_attempts = strtoul(lyd_get_value(node), NULL, 10);
4002 } else {
4003 ch_client->max_attempts = 3;
4004 }
4005
4006cleanup:
4007 return ret;
4008}
4009
4010static int
romanf02273a2023-05-25 09:44:11 +02004011nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01004012{
4013 const char *name = LYD_NAME(node);
4014
4015 if (!strcmp(name, "listen")) {
romanf02273a2023-05-25 09:44:11 +02004016 if (nc_server_config_listen(NULL, op)) {
romanc1d2b092023-02-02 08:58:27 +01004017 goto error;
4018 }
4019 } else if (!strcmp(name, "idle-timeout")) {
romane028ef92023-02-24 16:33:08 +01004020 if (nc_server_config_idle_timeout(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004021 goto error;
4022 }
4023 } else if (!strcmp(name, "endpoint")) {
romane028ef92023-02-24 16:33:08 +01004024 if (nc_server_config_endpoint(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004025 goto error;
4026 }
roman2eab4742023-06-06 10:00:26 +02004027 } else if (!strcmp(name, "unix-socket")) {
4028 if (nc_server_config_unix_socket(node, op)) {
4029 goto error;
4030 }
roman3f9b65c2023-06-05 14:26:58 +02004031 }
roman2eab4742023-06-06 10:00:26 +02004032#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02004033 else if (!strcmp(name, "ssh")) {
romane028ef92023-02-24 16:33:08 +01004034 if (nc_server_config_ssh(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004035 goto error;
4036 }
roman2eab4742023-06-06 10:00:26 +02004037 } else if (!strcmp(name, "local-address")) {
romane028ef92023-02-24 16:33:08 +01004038 if (nc_server_config_local_address(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004039 goto error;
4040 }
4041 } else if (!strcmp(name, "local-port")) {
romane028ef92023-02-24 16:33:08 +01004042 if (nc_server_config_local_port(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004043 goto error;
4044 }
4045 } else if (!strcmp(name, "keepalives")) {
romane028ef92023-02-24 16:33:08 +01004046 if (nc_server_config_keepalives(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004047 goto error;
4048 }
4049 } else if (!strcmp(name, "idle-time")) {
romane028ef92023-02-24 16:33:08 +01004050 if (nc_server_config_idle_time(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004051 goto error;
4052 }
4053 } else if (!strcmp(name, "max-probes")) {
romane028ef92023-02-24 16:33:08 +01004054 if (nc_server_config_max_probes(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004055 goto error;
4056 }
4057 } else if (!strcmp(name, "probe-interval")) {
romane028ef92023-02-24 16:33:08 +01004058 if (nc_server_config_probe_interval(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004059 goto error;
4060 }
roman2eab4742023-06-06 10:00:26 +02004061 } else if (!strcmp(name, "host-key")) {
romane028ef92023-02-24 16:33:08 +01004062 if (nc_server_config_host_key(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004063 goto error;
4064 }
roman2eab4742023-06-06 10:00:26 +02004065 } else if (!strcmp(name, "public-key-format")) {
romane028ef92023-02-24 16:33:08 +01004066 if (nc_server_config_public_key_format(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004067 goto error;
4068 }
4069 } else if (!strcmp(name, "public-key")) {
romane028ef92023-02-24 16:33:08 +01004070 if (nc_server_config_public_key(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004071 goto error;
4072 }
4073 } else if (!strcmp(name, "private-key-format")) {
romane028ef92023-02-24 16:33:08 +01004074 if (nc_server_config_private_key_format(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004075 goto error;
4076 }
4077 } else if (!strcmp(name, "cleartext-private-key")) {
romane028ef92023-02-24 16:33:08 +01004078 if (nc_server_config_cleartext_private_key(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004079 goto error;
4080 }
roman2eab4742023-06-06 10:00:26 +02004081 } else if (!strcmp(name, "keystore-reference")) {
romane028ef92023-02-24 16:33:08 +01004082 if (nc_server_config_keystore_reference(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004083 goto error;
4084 }
4085 } else if (!strcmp(name, "user")) {
romane028ef92023-02-24 16:33:08 +01004086 if (nc_server_config_user(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004087 goto error;
4088 }
4089 } else if (!strcmp(name, "auth-attempts")) {
romane028ef92023-02-24 16:33:08 +01004090 if (nc_server_config_auth_attempts(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004091 goto error;
4092 }
4093 } else if (!strcmp(name, "auth-timeout")) {
romane028ef92023-02-24 16:33:08 +01004094 if (nc_server_config_auth_timeout(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004095 goto error;
4096 }
roman2eab4742023-06-06 10:00:26 +02004097 } else if (!strcmp(name, "truststore-reference")) {
romane028ef92023-02-24 16:33:08 +01004098 if (nc_server_config_truststore_reference(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004099 goto error;
4100 }
roman2eab4742023-06-06 10:00:26 +02004101 } else if (!strcmp(name, "password")) {
romane028ef92023-02-24 16:33:08 +01004102 if (nc_server_config_password(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004103 goto error;
4104 }
4105 } else if (!strcmp(name, "pam-config-file-name")) {
romane028ef92023-02-24 16:33:08 +01004106 if (nc_server_config_pam_name(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004107 goto error;
4108 }
4109 } else if (!strcmp(name, "pam-config-file-dir")) {
romane028ef92023-02-24 16:33:08 +01004110 if (nc_server_config_pam_dir(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004111 goto error;
4112 }
4113 } else if (!strcmp(name, "none")) {
romane028ef92023-02-24 16:33:08 +01004114 if (nc_server_config_none(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004115 goto error;
4116 }
4117 } else if (!strcmp(name, "host-key-alg")) {
romane028ef92023-02-24 16:33:08 +01004118 if (nc_server_config_host_key_alg(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004119 goto error;
4120 }
4121 } else if (!strcmp(name, "key-exchange-alg")) {
romane028ef92023-02-24 16:33:08 +01004122 if (nc_server_config_kex_alg(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004123 goto error;
4124 }
4125 } else if (!strcmp(name, "encryption-alg")) {
romane028ef92023-02-24 16:33:08 +01004126 if (nc_server_config_encryption_alg(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004127 goto error;
4128 }
4129 } else if (!strcmp(name, "mac-alg")) {
romane028ef92023-02-24 16:33:08 +01004130 if (nc_server_config_mac_alg(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01004131 goto error;
4132 }
roman2eab4742023-06-06 10:00:26 +02004133 } else if (!strcmp(name, "endpoint-client-auth")) {
roman0bbc19c2023-05-26 09:59:09 +02004134 if (nc_server_config_endpoint_client_auth(node, op)) {
4135 goto error;
4136 }
roman2eab4742023-06-06 10:00:26 +02004137 } else if (!strcmp(name, "tls")) {
roman3f9b65c2023-06-05 14:26:58 +02004138 if (nc_server_config_tls(node, op)) {
4139 goto error;
4140 }
4141 } else if (!strcmp(name, "cert-data")) {
4142 if (nc_server_config_cert_data(node, op)) {
4143 goto error;
4144 }
4145 } else if (!strcmp(name, "asymmetric-key")) {
4146 if (nc_server_config_asymmetric_key(node, op)) {
4147 goto error;
4148 }
4149 } else if (!strcmp(name, "certificate")) {
4150 if (nc_server_config_certificate(node, op)) {
4151 goto error;
4152 }
4153 } else if (!strcmp(name, "cert-to-name")) {
4154 if (nc_server_config_cert_to_name(node, op)) {
4155 goto error;
4156 }
4157 } else if (!strcmp(name, "fingerprint")) {
4158 if (nc_server_config_fingerprint(node, op)) {
4159 goto error;
4160 }
roman12644fe2023-06-08 11:06:42 +02004161 } else if (!strcmp(name, "tls-version")) {
4162 if (nc_server_config_tls_version(node, op)) {
4163 goto error;
4164 }
4165 } else if (!strcmp(name, "cipher-suite")) {
4166 if (nc_server_config_cipher_suite(node, op)) {
4167 goto error;
4168 }
romanfaecc582023-06-15 16:13:31 +02004169 } else if (!strcmp(name, "crl-url")) {
4170 if (nc_server_config_crl_url(node, op)) {
4171 goto error;
4172 }
4173 } else if (!strcmp(name, "crl-path")) {
4174 if (nc_server_config_crl_path(node, op)) {
4175 goto error;
4176 }
4177 } else if (!strcmp(name, "crl-cert-ext")) {
4178 if (nc_server_config_crl_cert_ext(node, op)) {
4179 goto error;
4180 }
roman3f9b65c2023-06-05 14:26:58 +02004181 }
roman2eab4742023-06-06 10:00:26 +02004182#endif /* NC_ENABLED_SSH_TLS */
roman5cbb6532023-06-22 12:53:17 +02004183 else if (!strcmp(name, "netconf-client")) {
4184 if (nc_server_config_netconf_client(node, op)) {
4185 goto error;
4186 }
4187 }
4188#ifdef NC_ENABLED_SSH_TLS
4189 else if (!strcmp(name, "remote-address")) {
4190 if (nc_server_config_remote_address(node, op)) {
4191 goto error;
4192 }
4193 } else if (!strcmp(name, "remote-port")) {
4194 if (nc_server_config_remote_port(node, op)) {
4195 goto error;
4196 }
4197 }
4198#endif /* NC_ENABLED_SSH_TLS */
romanb6f44032023-06-30 15:07:56 +02004199 else if (!strcmp(name, "persistent")) {
4200 if (nc_server_config_persistent(node, op)) {
4201 goto error;
4202 }
4203 } else if (!strcmp(name, "periodic")) {
4204 if (nc_server_config_periodic(node, op)) {
4205 goto error;
4206 }
4207 } else if (!strcmp(name, "period")) {
4208 if (nc_server_config_period(node, op)) {
4209 goto error;
4210 }
4211 } else if (!strcmp(name, "anchor-time")) {
4212 if (nc_server_config_anchor_time(node, op)) {
4213 goto error;
4214 }
4215 } else if (!strcmp(name, "reconnect-strategy")) {
4216 if (nc_server_config_reconnect_strategy(node, op)) {
4217 goto error;
4218 }
4219 } else if (!strcmp(name, "start-with")) {
4220 if (nc_server_config_start_with(node, op)) {
4221 goto error;
4222 }
4223 } else if (!strcmp(name, "max-wait")) {
4224 if (nc_server_config_max_wait(node, op)) {
4225 goto error;
4226 }
4227 } else if (!strcmp(name, "max-attempts")) {
4228 if (nc_server_config_max_attempts(node, op)) {
4229 goto error;
4230 }
4231 }
romanc1d2b092023-02-02 08:58:27 +01004232
4233 return 0;
4234
4235error:
romanb6f44032023-06-30 15:07:56 +02004236 ERR(NULL, "Configuring node \"%s\" failed.", LYD_NAME(node));
romanc1d2b092023-02-02 08:58:27 +01004237 return 1;
4238}
4239
4240int
roman0bbc19c2023-05-26 09:59:09 +02004241nc_server_config_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, NC_MODULE module)
romanc1d2b092023-02-02 08:58:27 +01004242{
4243 struct lyd_node *child;
4244 struct lyd_meta *m;
romanf9906b42023-05-22 14:04:29 +02004245 NC_OPERATION current_op = NC_OP_UNKNOWN;
romanf02273a2023-05-25 09:44:11 +02004246 int ret;
romanc1d2b092023-02-02 08:58:27 +01004247
4248 assert(node);
4249
romanf9906b42023-05-22 14:04:29 +02004250 /* get current op if there is any */
4251 if ((m = lyd_find_meta(node->meta, NULL, "yang:operation"))) {
4252 if (!strcmp(lyd_get_meta_value(m), "create")) {
4253 current_op = NC_OP_CREATE;
4254 } else if (!strcmp(lyd_get_meta_value(m), "delete")) {
4255 current_op = NC_OP_DELETE;
4256 } else if (!strcmp(lyd_get_meta_value(m), "replace")) {
4257 current_op = NC_OP_REPLACE;
4258 } else if (!strcmp(lyd_get_meta_value(m), "none")) {
4259 current_op = NC_OP_NONE;
romanc1d2b092023-02-02 08:58:27 +01004260 }
4261 }
4262
4263 /* node has no op, inherit from the parent */
romanf9906b42023-05-22 14:04:29 +02004264 if (!current_op) {
4265 if (!parent_op) {
4266 ERR(NULL, "Unknown operation for node \"%s\".", LYD_NAME(node));
4267 return 1;
4268 }
4269
romanc1d2b092023-02-02 08:58:27 +01004270 current_op = parent_op;
4271 }
4272
4273 switch (current_op) {
4274 case NC_OP_NONE:
4275 break;
4276 case NC_OP_CREATE:
4277 case NC_OP_DELETE:
4278 case NC_OP_REPLACE:
roman2eab4742023-06-06 10:00:26 +02004279#ifdef NC_ENABLED_SSH_TLS
4280 if (module == NC_MODULE_KEYSTORE) {
romanf02273a2023-05-25 09:44:11 +02004281 ret = nc_server_config_parse_keystore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02004282 } else if (module == NC_MODULE_TRUSTSTORE) {
romanf02273a2023-05-25 09:44:11 +02004283 ret = nc_server_config_parse_truststore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02004284 } else
4285#endif /* NC_ENABLED_SSH_TLS */
4286 {
4287 ret = nc_server_config_parse_netconf_server(node, current_op);
romanf02273a2023-05-25 09:44:11 +02004288 }
4289 if (ret) {
4290 return ret;
romanc1d2b092023-02-02 08:58:27 +01004291 }
4292 break;
4293 default:
4294 break;
4295 }
4296
4297 if (current_op != NC_OP_DELETE) {
4298 LY_LIST_FOR(lyd_child(node), child) {
roman0bbc19c2023-05-26 09:59:09 +02004299 if (nc_server_config_parse_tree(child, current_op, module)) {
romanc1d2b092023-02-02 08:58:27 +01004300 return 1;
4301 }
4302 }
4303 }
4304 return 0;
4305}
4306
romanc1d2b092023-02-02 08:58:27 +01004307API int
4308nc_server_config_load_modules(struct ly_ctx **ctx)
4309{
4310 int i, new_ctx = 0;
4311
4312 if (!*ctx) {
4313 if (ly_ctx_new(NC_SERVER_SEARCH_DIR, 0, ctx)) {
4314 ERR(NULL, "Couldn't create new libyang context.\n");
4315 goto error;
4316 }
4317 new_ctx = 1;
4318 }
4319
4320 /* all features */
4321 const char *ietf_nectonf_server[] = {"ssh-listen", "tls-listen", "ssh-call-home", "tls-call-home", "central-netconf-server-supported", NULL};
4322 /* all features */
4323 const char *ietf_x509_cert_to_name[] = {NULL};
roman7fdc84d2023-06-06 13:14:53 +02004324 /* no private-key-encryption, csr-generation, p10-csr-format, certificate-expiration-notification,
4325 * encrypted-passwords, hidden-symmetric-keys, encrypted-symmetric-keys, hidden-private-keys, encrypted-private-keys
4326 */
romanc1d2b092023-02-02 08:58:27 +01004327 const char *ietf_crypto_types[] = {
4328 "one-symmetric-key-format", "one-asymmetric-key-format", "symmetrically-encrypted-value-format",
4329 "asymmetrically-encrypted-value-format", "cms-enveloped-data-format", "cms-encrypted-data-format",
roman7fdc84d2023-06-06 13:14:53 +02004330 "cleartext-passwords", "cleartext-symmetric-keys", "cleartext-private-keys", NULL
romanc1d2b092023-02-02 08:58:27 +01004331 };
4332 /* all features */
4333 const char *ietf_tcp_common[] = {"keepalives-supported", NULL};
roman7fdc84d2023-06-06 13:14:53 +02004334 /* all features */
4335 const char *ietf_tcp_server[] = {"tcp-server-keepalives", NULL};
4336 /* all features */
4337 const char *ietf_tcp_client[] = {"local-binding-supported", "tcp-client-keepalives", "proxy-connect", "socks5-gss-api", "socks5-username-password", NULL};
romanc1d2b092023-02-02 08:58:27 +01004338 /* no ssh-x509-certs */
4339 const char *ietf_ssh_common[] = {"transport-params", "public-key-generation", NULL};
roman7fdc84d2023-06-06 13:14:53 +02004340 /* no ssh-server-keepalives and local-user-auth-hostbased */
4341 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 +01004342 /* all features */
4343 const char *iana_ssh_encryption_algs[] = {NULL};
4344 /* all features */
4345 const char *iana_ssh_key_exchange_algs[] = {NULL};
4346 /* all features */
4347 const char *iana_ssh_mac_algs[] = {NULL};
4348 /* all features */
4349 const char *iana_ssh_public_key_algs[] = {NULL};
romanc1d2b092023-02-02 08:58:27 +01004350 /* all features */
roman7fdc84d2023-06-06 13:14:53 +02004351 const char *iana_crypt_hash[] = {"crypt-hash-md5", "crypt-hash-sha-256", "crypt-hash-sha-512", NULL};
4352 /* no symmetric-keys */
4353 const char *ietf_keystore[] = {"central-keystore-supported", "inline-definitions-supported", "asymmetric-keys", NULL};
4354 /* all features */
4355 const char *ietf_truststore[] = {"central-truststore-supported", "inline-definitions-supported", "certificates", "public-keys", NULL};
4356 /* all features */
4357 const char *ietf_tls_common[] = {"tls10", "tls11", "tls12", "tls13", "hello-params", "public-key-generation", NULL};
romanc1d2b092023-02-02 08:58:27 +01004358 /* all features */
4359 const char *ietf_tls_server[] = {
4360 "tls-server-keepalives", "server-ident-x509-cert", "server-ident-raw-public-key", "server-ident-tls12-psk",
4361 "server-ident-tls13-epsk", "client-auth-supported", "client-auth-x509-cert", "client-auth-raw-public-key",
4362 "client-auth-tls12-psk", "client-auth-tls13-epsk", NULL
4363 };
roman12644fe2023-06-08 11:06:42 +02004364 const char *iana_tls_cipher_suite_algs[] = {NULL};
romanc1d2b092023-02-02 08:58:27 +01004365 /* all features */
4366 const char *libnetconf2_netconf_server[] = {NULL};
4367
4368 const char *module_names[] = {
roman7fdc84d2023-06-06 13:14:53 +02004369 "ietf-netconf-server", "ietf-x509-cert-to-name", "ietf-crypto-types", "ietf-tcp-common", "ietf-tcp-server",
4370 "ietf-tcp-client", "ietf-ssh-common", "ietf-ssh-server", "iana-ssh-encryption-algs",
4371 "iana-ssh-key-exchange-algs", "iana-ssh-mac-algs", "iana-ssh-public-key-algs", "iana-crypt-hash",
roman12644fe2023-06-08 11:06:42 +02004372 "ietf-keystore", "ietf-truststore", "ietf-tls-common", "ietf-tls-server", "iana-tls-cipher-suite-algs",
4373 "libnetconf2-netconf-server", NULL
romanc1d2b092023-02-02 08:58:27 +01004374 };
4375
4376 const char **module_features[] = {
roman7fdc84d2023-06-06 13:14:53 +02004377 ietf_nectonf_server, ietf_x509_cert_to_name, ietf_crypto_types, ietf_tcp_common,
4378 ietf_tcp_server, ietf_tcp_client, ietf_ssh_common, ietf_ssh_server, iana_ssh_encryption_algs,
4379 iana_ssh_key_exchange_algs, iana_ssh_mac_algs, iana_ssh_public_key_algs, iana_crypt_hash,
roman12644fe2023-06-08 11:06:42 +02004380 ietf_keystore, ietf_truststore, ietf_tls_common, ietf_tls_server, iana_tls_cipher_suite_algs,
4381 libnetconf2_netconf_server, NULL
romanc1d2b092023-02-02 08:58:27 +01004382 };
4383
4384 for (i = 0; module_names[i] != NULL; i++) {
4385 if (!ly_ctx_load_module(*ctx, module_names[i], NULL, module_features[i])) {
4386 ERR(NULL, "Loading module \"%s\" failed.\n", module_names[i]);
4387 goto error;
4388 }
4389 }
4390
4391 return 0;
4392
4393error:
4394 if (new_ctx) {
4395 ly_ctx_destroy(*ctx);
4396 *ctx = NULL;
4397 }
4398 return 1;
4399}
4400
romanf9906b42023-05-22 14:04:29 +02004401static int
4402nc_server_config_fill_nectonf_server(const struct lyd_node *data, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01004403{
4404 int ret = 0;
4405 struct lyd_node *tree;
romand57b3722023-04-05 11:26:25 +02004406
romanc1d2b092023-02-02 08:58:27 +01004407 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &tree);
4408 if (ret) {
4409 ERR(NULL, "Unable to find the netconf-server container in the YANG data.");
4410 goto cleanup;
4411 }
4412
roman0bbc19c2023-05-26 09:59:09 +02004413 if (nc_server_config_parse_tree(tree, op, NC_MODULE_NETCONF_SERVER)) {
4414 ret = 1;
4415 goto cleanup;
4416 }
4417
roman2eab4742023-06-06 10:00:26 +02004418#ifdef NC_ENABLED_SSH_TLS
4419 /* backward check of client auth reference */
roman0bbc19c2023-05-26 09:59:09 +02004420 if (nc_server_config_fill_endpt_client_auth()) {
romanf9906b42023-05-22 14:04:29 +02004421 ret = 1;
4422 goto cleanup;
4423 }
roman2eab4742023-06-06 10:00:26 +02004424#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004425
4426cleanup:
4427 return ret;
4428}
4429
4430API int
romanf6f37a52023-05-25 14:27:51 +02004431nc_server_config_setup_diff(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02004432{
4433 int ret = 0;
4434
4435 /* LOCK */
4436 pthread_rwlock_wrlock(&server_opts.config_lock);
4437
roman2eab4742023-06-06 10:00:26 +02004438#ifdef NC_ENABLED_SSH_TLS
romanf9906b42023-05-22 14:04:29 +02004439 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02004440 ret = nc_server_config_fill_keystore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02004441 if (ret) {
4442 ERR(NULL, "Filling keystore failed.");
4443 goto cleanup;
4444 }
4445
4446 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02004447 ret = nc_server_config_fill_truststore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02004448 if (ret) {
4449 ERR(NULL, "Filling truststore failed.");
4450 goto cleanup;
4451 }
roman2eab4742023-06-06 10:00:26 +02004452#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004453
4454 /* configure netconf-server */
4455 ret = nc_server_config_fill_nectonf_server(data, NC_OP_UNKNOWN);
4456 if (ret) {
4457 ERR(NULL, "Filling netconf-server failed.");
4458 goto cleanup;
4459 }
4460
4461cleanup:
4462 /* UNLOCK */
4463 pthread_rwlock_unlock(&server_opts.config_lock);
4464 return ret;
4465}
4466
4467API int
romanf6f37a52023-05-25 14:27:51 +02004468nc_server_config_setup_data(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02004469{
4470 int ret = 0;
4471 struct lyd_node *tree, *iter, *root;
4472
4473 /* LOCK */
4474 pthread_rwlock_wrlock(&server_opts.config_lock);
4475
4476 /* find the netconf-server node */
4477 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &root);
4478 if (ret) {
4479 ERR(NULL, "Unable to find the netconf-server container in the YANG data.");
4480 goto cleanup;
4481 }
4482
4483 /* iterate through all the nodes and make sure there is no operation attribute */
4484 LY_LIST_FOR(root, tree) {
4485 LYD_TREE_DFS_BEGIN(tree, iter) {
4486 if (lyd_find_meta(iter->meta, NULL, "yang:operation")) {
4487 ERR(NULL, "Unexpected operation attribute in the YANG data.");
romanc1d2b092023-02-02 08:58:27 +01004488 ret = 1;
4489 goto cleanup;
4490 }
romanf9906b42023-05-22 14:04:29 +02004491 LYD_TREE_DFS_END(tree, iter);
romanc1d2b092023-02-02 08:58:27 +01004492 }
4493 }
4494
romanf9906b42023-05-22 14:04:29 +02004495 /* delete the current configuration */
romanf02273a2023-05-25 09:44:11 +02004496 nc_server_config_listen(NULL, NC_OP_DELETE);
roman4cb8bb12023-06-29 09:16:46 +02004497 nc_server_config_ch(NULL, NC_OP_DELETE);
roman2eab4742023-06-06 10:00:26 +02004498#ifdef NC_ENABLED_SSH_TLS
romanf02273a2023-05-25 09:44:11 +02004499 nc_server_config_ks_keystore(NULL, NC_OP_DELETE);
4500 nc_server_config_ts_truststore(NULL, NC_OP_DELETE);
romanf9906b42023-05-22 14:04:29 +02004501
4502 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02004503 ret = nc_server_config_fill_keystore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02004504 if (ret) {
4505 ERR(NULL, "Filling keystore failed.");
4506 goto cleanup;
4507 }
4508
4509 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02004510 ret = nc_server_config_fill_truststore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02004511 if (ret) {
4512 ERR(NULL, "Filling truststore failed.");
4513 goto cleanup;
4514 }
roman2eab4742023-06-06 10:00:26 +02004515#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004516
4517 /* configure netconf-server */
4518 ret = nc_server_config_fill_nectonf_server(data, NC_OP_CREATE);
4519 if (ret) {
4520 ERR(NULL, "Filling netconf-server failed.");
romanc1d2b092023-02-02 08:58:27 +01004521 goto cleanup;
4522 }
4523
4524cleanup:
4525 /* UNLOCK */
4526 pthread_rwlock_unlock(&server_opts.config_lock);
4527 return ret;
4528}
roman3f9b65c2023-06-05 14:26:58 +02004529
4530API int
4531nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path)
4532{
4533 struct lyd_node *tree = NULL;
4534 int ret = 0;
4535
4536 NC_CHECK_ARG_RET(NULL, path, 1);
4537
4538 ret = lyd_parse_data_path(ctx, path, LYD_UNKNOWN, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree);
4539 if (ret) {
4540 goto cleanup;
4541 }
4542
4543 ret = nc_server_config_setup_data(tree);
4544 if (ret) {
4545 goto cleanup;
4546 }
4547
4548cleanup:
4549 lyd_free_all(tree);
4550 return ret;
4551}