blob: 174b42c4fe1668619f3f1af057a0405d425f00bf [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>
roman3f9b65c2023-06-05 14:26:58 +020019#include <pthread.h>
20#include <stdint.h>
romanc1d2b092023-02-02 08:58:27 +010021#include <stdlib.h>
22#include <string.h>
roman2eab4742023-06-06 10:00:26 +020023#include <unistd.h>
romanc1d2b092023-02-02 08:58:27 +010024
roman3f9b65c2023-06-05 14:26:58 +020025#include <libyang/libyang.h>
26
romanc1d2b092023-02-02 08:58:27 +010027#include "compat.h"
roman3f9b65c2023-06-05 14:26:58 +020028#include "config.h"
29#include "log_p.h"
romane028ef92023-02-24 16:33:08 +010030#include "server_config.h"
romanf02273a2023-05-25 09:44:11 +020031#include "server_config_p.h"
roman3f9b65c2023-06-05 14:26:58 +020032#include "session_p.h"
33
roman2eab4742023-06-06 10:00:26 +020034#ifdef NC_ENABLED_SSH_TLS
romanc1d2b092023-02-02 08:58:27 +010035
36/* All libssh supported host-key, key-exchange, encryption and mac algorithms as of version 0.10.90 */
37
38static const char *supported_hostkey_algs[] = {
romana6bf6ab2023-05-26 13:26:02 +020039 "openssh-ssh-ed25519-cert-v01", "openssh-ecdsa-sha2-nistp521-cert-v01",
40 "openssh-ecdsa-sha2-nistp384-cert-v01", "openssh-ecdsa-sha2-nistp256-cert-v01",
41 "openssh-rsa-sha2-512-cert-v01", "openssh-rsa-sha2-256-cert-v01",
42 "openssh-ssh-rsa-cert-v01", "openssh-ssh-dss-cert-v01",
romanc1d2b092023-02-02 08:58:27 +010043 "ssh-ed25519", "ecdsa-sha2-nistp521", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp256",
44 "rsa-sha2-512", "rsa-sha2-256", "ssh-rsa", "ssh-dss", NULL
45};
46
47static const char *supported_kex_algs[] = {
romana6bf6ab2023-05-26 13:26:02 +020048 "diffie-hellman-group-exchange-sha1", "curve25519-sha256", "libssh-curve25519-sha256",
romanc1d2b092023-02-02 08:58:27 +010049 "ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", "diffie-hellman-group18-sha512",
50 "diffie-hellman-group16-sha512", "diffie-hellman-group-exchange-sha256", "diffie-hellman-group14-sha256", NULL
51};
52
53static const char *supported_encryption_algs[] = {
romana6bf6ab2023-05-26 13:26:02 +020054 "openssh-chacha20-poly1305", "openssh-aes256-gcm", "openssh-aes128-gcm",
romanc1d2b092023-02-02 08:58:27 +010055 "aes256-ctr", "aes192-ctr", "aes128-ctr", "aes256-cbc", "aes192-cbc", "aes128-cbc",
roman27215242023-03-10 14:55:00 +010056 "blowfish-cbc", "triple-des-cbc", "none", NULL
romanc1d2b092023-02-02 08:58:27 +010057};
58
59static const char *supported_mac_algs[] = {
romana6bf6ab2023-05-26 13:26:02 +020060 "openssh-hmac-sha2-256-etm", "openssh-hmac-sha2-512-etm", "openssh-hmac-sha1-etm",
romanc1d2b092023-02-02 08:58:27 +010061 "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1", NULL
62};
63
roman2eab4742023-06-06 10:00:26 +020064#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +020065
romanc1d2b092023-02-02 08:58:27 +010066extern struct nc_server_opts server_opts;
67
romanf02273a2023-05-25 09:44:11 +020068int
69nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, struct nc_bind **bind)
romanc1d2b092023-02-02 08:58:27 +010070{
71 uint16_t i;
72 const char *endpt_name;
73
74 assert(node);
75
76 while (node) {
77 if (!strcmp(LYD_NAME(node), "endpoint")) {
78 break;
79 }
80 node = lyd_parent(node);
81 }
82
83 if (!node) {
84 ERR(NULL, "Node \"%s\" is not contained in an endpoint subtree.", LYD_NAME(node));
85 return 1;
86 }
87
88 node = lyd_child(node);
89 assert(!strcmp(LYD_NAME(node), "name"));
90 endpt_name = lyd_get_value(node);
91
92 for (i = 0; i < server_opts.endpt_count; i++) {
93 if (!strcmp(server_opts.endpts[i].name, endpt_name)) {
94 *endpt = &server_opts.endpts[i];
95 if (bind) {
96 *bind = &server_opts.binds[i];
97 }
98 return 0;
99 }
100 }
101
102 ERR(NULL, "Endpoint \"%s\" was not found.", endpt_name);
103 return 1;
104}
105
roman2eab4742023-06-06 10:00:26 +0200106#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +0200107
romanf02273a2023-05-25 09:44:11 +0200108int
109nc_server_config_get_hostkey(const struct lyd_node *node, const struct nc_server_ssh_opts *opts, struct nc_hostkey **hostkey)
romanc1d2b092023-02-02 08:58:27 +0100110{
111 uint16_t i;
112 const char *hostkey_name;
113
114 assert(node && opts);
115
116 while (node) {
117 if (!strcmp(LYD_NAME(node), "host-key")) {
118 break;
119 }
120 node = lyd_parent(node);
121 }
122
123 if (!node) {
124 ERR(NULL, "Node \"%s\" is not contained in a host-key subtree.", LYD_NAME(node));
125 return 1;
126 }
127
128 node = lyd_child(node);
129 assert(!strcmp(LYD_NAME(node), "name"));
130 hostkey_name = lyd_get_value(node);
131
132 for (i = 0; i < opts->hostkey_count; i++) {
133 if (!strcmp(opts->hostkeys[i].name, hostkey_name)) {
134 *hostkey = &opts->hostkeys[i];
135 return 0;
136 }
137 }
138
139 ERR(NULL, "Host-key \"%s\" was not found.", hostkey_name);
140 return 1;
141}
142
romanf02273a2023-05-25 09:44:11 +0200143int
144nc_server_config_get_auth_client(const struct lyd_node *node, const struct nc_server_ssh_opts *opts, struct nc_client_auth **auth_client)
romanc1d2b092023-02-02 08:58:27 +0100145{
146 uint16_t i;
147 const char *authkey_name;
148
149 assert(node && opts);
150
151 while (node) {
152 if (!strcmp(LYD_NAME(node), "user")) {
153 break;
154 }
155 node = lyd_parent(node);
156 }
157
158 if (!node) {
159 ERR(NULL, "Node \"%s\" is not contained in a client-authentication subtree.", LYD_NAME(node));
160 return 1;
161 }
162
163 node = lyd_child(node);
164 assert(!strcmp(LYD_NAME(node), "name"));
165 authkey_name = lyd_get_value(node);
166
167 for (i = 0; i < opts->client_count; i++) {
168 if (!strcmp(opts->auth_clients[i].username, authkey_name)) {
169 *auth_client = &opts->auth_clients[i];
170 return 0;
171 }
172 }
173
174 ERR(NULL, "Authorized key \"%s\" was not found.", authkey_name);
175 return 1;
176}
177
romanf02273a2023-05-25 09:44:11 +0200178int
179nc_server_config_get_pubkey(const struct lyd_node *node, const struct nc_client_auth *auth_client, struct nc_public_key **pubkey)
romanc1d2b092023-02-02 08:58:27 +0100180{
181 uint16_t i;
182 const char *pubkey_name;
183
184 assert(node && auth_client);
185
186 node = lyd_parent(node);
187 while (node) {
188 if (!strcmp(LYD_NAME(node), "public-key")) {
189 break;
190 }
191 node = lyd_parent(node);
192 }
193
194 if (!node) {
195 ERR(NULL, "Node \"%s\" is not contained in a public-key subtree.", LYD_NAME(node));
196 return 1;
197 }
198
199 node = lyd_child(node);
200 assert(!strcmp(LYD_NAME(node), "name"));
201 pubkey_name = lyd_get_value(node);
202
203 for (i = 0; i < auth_client->pubkey_count; i++) {
204 if (!strcmp(auth_client->pubkeys[i].name, pubkey_name)) {
205 *pubkey = &auth_client->pubkeys[i];
206 return 0;
207 }
208 }
209
210 ERR(NULL, "Public key \"%s\" was not found.", pubkey_name);
211 return 1;
212}
213
roman3f9b65c2023-06-05 14:26:58 +0200214int
215nc_server_config_get_cert(const struct lyd_node *node, struct nc_cert_grouping *auth_client, struct nc_certificate **cert)
216{
217 uint16_t i;
218 const char *cert_name;
219
220 assert(node && auth_client);
221
222 while (node) {
223 if (!strcmp(LYD_NAME(node), "certificate")) {
224 break;
225 }
226 node = lyd_parent(node);
227 }
228
229 if (!node) {
230 ERR(NULL, "Node \"%s\" is not contained in a certificate subtree.", LYD_NAME(node));
231 return 1;
232 }
233
234 node = lyd_child(node);
235 assert(!strcmp(LYD_NAME(node), "name"));
236 cert_name = lyd_get_value(node);
237
238 for (i = 0; i < auth_client->cert_count; i++) {
239 if (!strcmp(auth_client->certs[i].name, cert_name)) {
240 *cert = &auth_client->certs[i];
241 return 0;
242 }
243 }
244
245 ERR(NULL, "Certificate \"%s\" was not found.", cert_name);
246 return 1;
247}
248
249static int
250nc_server_config_get_ctn(const struct lyd_node *node, struct nc_endpt *endpt, struct nc_ctn **ctn)
251{
252 uint32_t id;
253 struct nc_ctn *iter;
254
255 assert(node && endpt);
256
257 node = lyd_parent(node);
258 while (node) {
259 if (!strcmp(LYD_NAME(node), "cert-to-name")) {
260 break;
261 }
262 node = lyd_parent(node);
263 }
264
265 if (!node) {
266 ERR(NULL, "Node \"%s\" is not contained in a cert-to-name subtree.", LYD_NAME(node));
267 return 1;
268 }
269
270 node = lyd_child(node);
271 assert(!strcmp(LYD_NAME(node), "id"));
272 id = strtoul(lyd_get_value(node), NULL, 10);
273
274 iter = endpt->opts.tls->ctn;
275 while (iter) {
276 if (iter->id == id) {
277 *ctn = iter;
278 return 0;
279 }
280
281 iter = iter->next;
282 }
283
284 ERR(NULL, "Cert-to-name entry with id \"%d\" was not found.", id);
285 return 1;
286}
287
roman2eab4742023-06-06 10:00:26 +0200288NC_PRIVKEY_FORMAT
289nc_server_config_get_private_key_type(const char *format)
290{
291 if (!strcmp(format, "rsa-private-key-format")) {
292 return NC_PRIVKEY_FORMAT_RSA;
293 } else if (!strcmp(format, "ec-private-key-format")) {
294 return NC_PRIVKEY_FORMAT_EC;
295 } else if (!strcmp(format, "subject-private-key-info-format")) {
296 return NC_PRIVKEY_FORMAT_X509;
297 } else if (!strcmp(format, "openssh-private-key-format")) {
298 return NC_PRIVKEY_FORMAT_OPENSSH;
299 } else {
300 ERR(NULL, "Private key format (%s) not supported.", format);
301 return NC_PRIVKEY_FORMAT_UNKNOWN;
302 }
303}
304
305#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200306
romanf02273a2023-05-25 09:44:11 +0200307int
romanc1d2b092023-02-02 08:58:27 +0100308equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char *parent_name)
309{
310 uint16_t i;
311
312 assert(node && parent_count > 0 && parent_name);
313
314 node = lyd_parent(node);
315 for (i = 1; i < parent_count; i++) {
316 node = lyd_parent(node);
317 }
318
319 if (!strcmp(LYD_NAME(node), parent_name)) {
320 return 1;
321 }
322
323 return 0;
324}
325
roman3f9b65c2023-06-05 14:26:58 +0200326
romanf02273a2023-05-25 09:44:11 +0200327int
328nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uint16_t *count)
329{
330 int ret = 0;
331 void *tmp;
332 char **name;
333
334 tmp = realloc(*ptr, (*count + 1) * size);
335 if (!tmp) {
336 ERRMEM;
337 ret = 1;
338 goto cleanup;
339 }
340 *ptr = tmp;
341
342 /* set the newly allocated memory to 0 */
343 memset((char *)(*ptr) + (*count * size), 0, size);
344 (*count)++;
345
346 /* access the first member of the supposed structure */
347 name = (char **)((*ptr) + ((*count - 1) * size));
348
349 /* and set it's value */
350 *name = strdup(key_value);
351 if (!*name) {
352 ERRMEM;
353 ret = 1;
354 goto cleanup;
355 }
356
357cleanup:
358 return ret;
359}
360
roman2eab4742023-06-06 10:00:26 +0200361#ifdef NC_ENABLED_SSH_TLS
362
roman3f9b65c2023-06-05 14:26:58 +0200363static int
364is_listen(const struct lyd_node *node)
365{
366 assert(node);
367
368 while (node) {
369 if (!strcmp(LYD_NAME(node), "listen")) {
370 break;
371 }
372 node = lyd_parent(node);
373 }
374
375 return node != NULL;
376}
377
378// static int
379// is_ch(const struct lyd_node *node)
380// {
381// assert(node);
382
383// while (node) {
384// if (!strcmp(LYD_NAME(node), "call-home")) {
385// break;
386// }
387// node = lyd_parent(node);
388// }
389
390// return node != NULL;
391// }
392
roman3f9b65c2023-06-05 14:26:58 +0200393static int
394is_ssh(const struct lyd_node *node)
395{
396 assert(node);
397
398 while (node) {
399 if (!strcmp(LYD_NAME(node), "ssh")) {
400 break;
401 }
402 node = lyd_parent(node);
403 }
404
405 return node != NULL;
406}
407
roman3f9b65c2023-06-05 14:26:58 +0200408static int
409is_tls(const struct lyd_node *node)
410{
411 assert(node);
412
413 while (node) {
414 if (!strcmp(LYD_NAME(node), "tls")) {
415 break;
416 }
417 node = lyd_parent(node);
418 }
419
420 return node != NULL;
421}
422
roman2eab4742023-06-06 10:00:26 +0200423#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200424
425static void
426nc_server_config_del_endpt_name(struct nc_endpt *endpt)
427{
428 free(endpt->name);
429 endpt->name = NULL;
430}
431
roman2eab4742023-06-06 10:00:26 +0200432#ifdef NC_ENABLED_SSH_TLS
433
roman3f9b65c2023-06-05 14:26:58 +0200434static void
435nc_server_config_del_local_address(struct nc_bind *bind)
436{
437 free(bind->address);
438 bind->address = NULL;
439}
440
romanc1d2b092023-02-02 08:58:27 +0100441static void
roman874fed12023-05-25 10:20:01 +0200442nc_server_config_del_auth_client_pam_name(struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100443{
444 free(auth_client->pam_config_name);
445 auth_client->pam_config_name = NULL;
446}
447
448static void
roman874fed12023-05-25 10:20:01 +0200449nc_server_config_del_auth_client_pam_dir(struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100450{
451 free(auth_client->pam_config_dir);
452 auth_client->pam_config_dir = NULL;
453}
454
455static void
roman0bbc19c2023-05-26 09:59:09 +0200456nc_server_config_del_endpt_reference(struct nc_endpt *endpt)
457{
458 free(endpt->referenced_endpt_name);
459 endpt->referenced_endpt_name = NULL;
460}
461
462static void
roman874fed12023-05-25 10:20:01 +0200463nc_server_config_del_hostkey_name(struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100464{
465 free(hostkey->name);
466 hostkey->name = NULL;
467}
468
469static void
roman874fed12023-05-25 10:20:01 +0200470nc_server_config_del_public_key(struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100471{
roman3f9b65c2023-06-05 14:26:58 +0200472 free(hostkey->key.pubkey_data);
473 hostkey->key.pubkey_data = NULL;
romanc1d2b092023-02-02 08:58:27 +0100474}
475
476static void
roman874fed12023-05-25 10:20:01 +0200477nc_server_config_del_private_key(struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100478{
roman3f9b65c2023-06-05 14:26:58 +0200479 free(hostkey->key.privkey_data);
480 hostkey->key.privkey_data = NULL;
romanc1d2b092023-02-02 08:58:27 +0100481}
482
483static void
roman874fed12023-05-25 10:20:01 +0200484nc_server_config_del_auth_client_username(struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100485{
486 free(auth_client->username);
487 auth_client->username = NULL;
488}
489
490static void
roman874fed12023-05-25 10:20:01 +0200491nc_server_config_del_auth_client_pubkey_name(struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +0100492{
493 free(pubkey->name);
494 pubkey->name = NULL;
495}
496
497static void
roman874fed12023-05-25 10:20:01 +0200498nc_server_config_del_auth_client_pubkey_pub_base64(struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +0100499{
roman3f9b65c2023-06-05 14:26:58 +0200500 free(pubkey->data);
501 pubkey->data = NULL;
romanc1d2b092023-02-02 08:58:27 +0100502}
503
504static void
roman874fed12023-05-25 10:20:01 +0200505nc_server_config_del_auth_client_password(struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100506{
507 free(auth_client->password);
508 auth_client->password = NULL;
509}
510
511static void
roman874fed12023-05-25 10:20:01 +0200512nc_server_config_del_hostkey_algs(struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100513{
514 free(opts->hostkey_algs);
515 opts->hostkey_algs = NULL;
516}
517
518static void
roman874fed12023-05-25 10:20:01 +0200519nc_server_config_del_kex_algs(struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100520{
521 free(opts->kex_algs);
522 opts->kex_algs = NULL;
523}
524
525static void
roman874fed12023-05-25 10:20:01 +0200526nc_server_config_del_encryption_algs(struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100527{
528 free(opts->encryption_algs);
529 opts->encryption_algs = NULL;
530}
531
532static void
roman874fed12023-05-25 10:20:01 +0200533nc_server_config_del_mac_algs(struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100534{
535 free(opts->mac_algs);
536 opts->mac_algs = NULL;
537}
538
539static void
roman874fed12023-05-25 10:20:01 +0200540nc_server_config_del_hostkey(struct nc_server_ssh_opts *opts, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100541{
roman874fed12023-05-25 10:20:01 +0200542 assert(hostkey->store == NC_STORE_LOCAL || hostkey->store == NC_STORE_KEYSTORE);
romanc1d2b092023-02-02 08:58:27 +0100543
roman874fed12023-05-25 10:20:01 +0200544 if (hostkey->store == NC_STORE_LOCAL) {
545 nc_server_config_del_public_key(hostkey);
546 nc_server_config_del_private_key(hostkey);
romanc1d2b092023-02-02 08:58:27 +0100547 }
548
roman874fed12023-05-25 10:20:01 +0200549 nc_server_config_del_hostkey_name(hostkey);
romanc1d2b092023-02-02 08:58:27 +0100550 opts->hostkey_count--;
551 if (!opts->hostkey_count) {
552 free(opts->hostkeys);
553 opts->hostkeys = NULL;
554 }
555}
556
557static void
roman874fed12023-05-25 10:20:01 +0200558nc_server_config_del_auth_client_pubkey(struct nc_client_auth *auth_client, struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +0100559{
roman874fed12023-05-25 10:20:01 +0200560 nc_server_config_del_auth_client_pubkey_name(pubkey);
561 nc_server_config_del_auth_client_pubkey_pub_base64(pubkey);
romanc1d2b092023-02-02 08:58:27 +0100562
563 auth_client->pubkey_count--;
564 if (!auth_client->pubkey_count) {
565 free(auth_client->pubkeys);
566 auth_client->pubkeys = NULL;
567 }
568}
569
570static void
roman874fed12023-05-25 10:20:01 +0200571nc_server_config_del_auth_client(struct nc_server_ssh_opts *opts, struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100572{
573 uint16_t i, pubkey_count;
574
roman874fed12023-05-25 10:20:01 +0200575 if (auth_client->store == NC_STORE_LOCAL) {
romanc1d2b092023-02-02 08:58:27 +0100576 pubkey_count = auth_client->pubkey_count;
577 for (i = 0; i < pubkey_count; i++) {
roman874fed12023-05-25 10:20:01 +0200578 nc_server_config_del_auth_client_pubkey(auth_client, &auth_client->pubkeys[i]);
romanc1d2b092023-02-02 08:58:27 +0100579 }
romanc1d2b092023-02-02 08:58:27 +0100580 }
581
roman874fed12023-05-25 10:20:01 +0200582 nc_server_config_del_auth_client_password(auth_client);
583 nc_server_config_del_auth_client_pam_name(auth_client);
584 nc_server_config_del_auth_client_pam_dir(auth_client);
585 nc_server_config_del_auth_client_username(auth_client);
romanc1d2b092023-02-02 08:58:27 +0100586
587 opts->client_count--;
588 if (!opts->client_count) {
589 free(opts->auth_clients);
590 opts->auth_clients = NULL;
591 }
592}
593
594static void
roman874fed12023-05-25 10:20:01 +0200595nc_server_config_del_ssh(struct nc_bind *bind, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100596{
597 uint16_t i, hostkey_count, client_count;
598
roman874fed12023-05-25 10:20:01 +0200599 nc_server_config_del_local_address(bind);
romanc1d2b092023-02-02 08:58:27 +0100600 if (bind->sock > -1) {
601 close(bind->sock);
602 }
603
604 /* store in variable because it gets decremented in the function call */
605 hostkey_count = opts->hostkey_count;
606 for (i = 0; i < hostkey_count; i++) {
roman874fed12023-05-25 10:20:01 +0200607 nc_server_config_del_hostkey(opts, &opts->hostkeys[i]);
romanc1d2b092023-02-02 08:58:27 +0100608 }
609
610 client_count = opts->client_count;
611 for (i = 0; i < client_count; i++) {
roman874fed12023-05-25 10:20:01 +0200612 nc_server_config_del_auth_client(opts, &opts->auth_clients[i]);
romanc1d2b092023-02-02 08:58:27 +0100613 }
614
roman874fed12023-05-25 10:20:01 +0200615 nc_server_config_del_hostkey_algs(opts);
616 nc_server_config_del_kex_algs(opts);
617 nc_server_config_del_encryption_algs(opts);
618 nc_server_config_del_mac_algs(opts);
romanc1d2b092023-02-02 08:58:27 +0100619
620 free(opts);
621 opts = NULL;
622}
623
624void
roman874fed12023-05-25 10:20:01 +0200625nc_server_config_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind)
romanc1d2b092023-02-02 08:58:27 +0100626{
roman874fed12023-05-25 10:20:01 +0200627 nc_server_config_del_endpt_name(endpt);
roman0bbc19c2023-05-26 09:59:09 +0200628 nc_server_config_del_endpt_reference(endpt);
roman874fed12023-05-25 10:20:01 +0200629 nc_server_config_del_ssh(bind, endpt->opts.ssh);
romanc1d2b092023-02-02 08:58:27 +0100630
631 server_opts.endpt_count--;
632 if (!server_opts.endpt_count) {
633 free(server_opts.endpts);
634 free(server_opts.binds);
635 server_opts.endpts = NULL;
636 server_opts.binds = NULL;
637 }
638}
639
roman2eab4742023-06-06 10:00:26 +0200640#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200641
roman45cec4e2023-02-17 10:21:39 +0100642void
roman874fed12023-05-25 10:20:01 +0200643nc_server_config_del_unix_socket(struct nc_bind *bind, struct nc_server_unix_opts *opts)
roman83683fb2023-02-24 09:15:23 +0100644{
645 if (bind->sock > -1) {
646 close(bind->sock);
647 }
648
649 free(bind->address);
650 free(opts->address);
651
652 free(opts);
roman83683fb2023-02-24 09:15:23 +0100653}
654
655void
roman874fed12023-05-25 10:20:01 +0200656nc_server_config_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *bind)
roman83683fb2023-02-24 09:15:23 +0100657{
roman874fed12023-05-25 10:20:01 +0200658 nc_server_config_del_endpt_name(endpt);
659 nc_server_config_del_unix_socket(bind, endpt->opts.unixsock);
roman83683fb2023-02-24 09:15:23 +0100660
661 server_opts.endpt_count--;
662 if (!server_opts.endpt_count) {
663 free(server_opts.endpts);
664 free(server_opts.binds);
665 server_opts.endpts = NULL;
666 server_opts.binds = NULL;
667 }
668}
669
roman2eab4742023-06-06 10:00:26 +0200670#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +0200671
672static void
673nc_server_config_tls_del_public_key(struct nc_server_tls_opts *opts)
674{
675 free(opts->pubkey_data);
676 opts->pubkey_data = NULL;
677}
678
679static void
680nc_server_config_tls_del_cleartext_private_key(struct nc_server_tls_opts *opts)
681{
682 free(opts->privkey_data);
683 opts->privkey_data = NULL;
684}
685
686static void
687nc_server_config_tls_del_cert_data(struct nc_server_tls_opts *opts)
688{
689 free(opts->cert_data);
690 opts->cert_data = NULL;
691}
692
693static void
694nc_server_config_tls_del_cert_data_certificate(struct nc_certificate *cert)
695{
696 free(cert->data);
697 cert->data = NULL;
698}
699
700static void
701nc_server_config_del_fingerprint(struct nc_ctn *ctn)
702{
703 free(ctn->fingerprint);
704 ctn->fingerprint = NULL;
705}
706
707static void
708nc_server_config_del_cert(struct nc_cert_grouping *certs, struct nc_certificate *cert)
709{
710 free(cert->name);
711 cert->name = NULL;
712
713 free(cert->data);
714 cert->data = NULL;
715
716 certs->cert_count--;
717 if (!certs->cert_count) {
718 free(certs->certs);
719 certs->certs = NULL;
720 }
721}
722
723static void
724nc_server_config_tls_del_certs(struct nc_cert_grouping *ca)
725{
726 uint16_t i, cert_count;
727
728 if (ca->store == NC_STORE_LOCAL) {
729 cert_count = ca->cert_count;
730 for (i = 0; i < cert_count; i++) {
731 nc_server_config_del_cert(ca, &ca->certs[i]);
732 }
733 }
734}
735
736static void
737nc_server_config_del_ctn(struct nc_server_tls_opts *opts, struct nc_ctn *ctn)
738{
739 struct nc_ctn *iter;
740
741 free(ctn->fingerprint);
742 ctn->fingerprint = NULL;
743
744 free(ctn->name);
745 ctn->name = NULL;
746
747 if (opts->ctn == ctn) {
748 /* it's the first in the list */
749 opts->ctn = ctn->next;
750 free(ctn);
751 return;
752 }
753
754 iter = opts->ctn;
755 while (iter) {
756 if (iter->next == ctn) {
757 /* found the ctn */
758 break;
759 }
760 iter = iter->next;
761 }
762
763 iter->next = ctn->next;
764 free(ctn);
765}
766
767static void
768nc_server_config_del_ctns(struct nc_server_tls_opts *opts)
769{
770 struct nc_ctn *cur, *next;
771
772 cur = opts->ctn;
773 while (cur) {
774 next = cur->next;
775 free(cur->fingerprint);
776 free(cur->name);
777 free(cur);
778 cur = next;
779 }
780 opts->ctn = NULL;
781}
782
783static void
784nc_server_config_del_tls(struct nc_bind *bind, struct nc_server_tls_opts *opts)
785{
786 nc_server_config_del_local_address(bind);
787 if (bind->sock > -1) {
788 close(bind->sock);
789 }
790
791 if (opts->store == NC_STORE_LOCAL) {
792 nc_server_config_tls_del_public_key(opts);
793 nc_server_config_tls_del_cleartext_private_key(opts);
794 nc_server_config_tls_del_cert_data(opts);
795 }
796
797 nc_server_config_tls_del_certs(&opts->ca_certs);
798 nc_server_config_tls_del_certs(&opts->ee_certs);
799
800 nc_server_config_del_ctns(opts);
801
802 free(opts);
803}
804
805static void
806nc_server_config_del_endpt_tls(struct nc_endpt *endpt, struct nc_bind *bind)
807{
808 nc_server_config_del_endpt_name(endpt);
809 nc_server_config_del_tls(bind, endpt->opts.tls);
810
811 server_opts.endpt_count--;
812 if (!server_opts.endpt_count) {
813 free(server_opts.endpts);
814 free(server_opts.binds);
815 server_opts.endpts = NULL;
816 server_opts.binds = NULL;
817 }
818}
819
roman2eab4742023-06-06 10:00:26 +0200820#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200821
romanc1d2b092023-02-02 08:58:27 +0100822/* presence container */
823int
romanf02273a2023-05-25 09:44:11 +0200824nc_server_config_listen(struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100825{
roman0bbc19c2023-05-26 09:59:09 +0200826 uint16_t i, endpt_count;
romanc1d2b092023-02-02 08:58:27 +0100827
romanf02273a2023-05-25 09:44:11 +0200828 (void) node;
829
romanc1d2b092023-02-02 08:58:27 +0100830 assert(op == NC_OP_CREATE || op == NC_OP_DELETE);
831
832 if (op == NC_OP_DELETE) {
roman0bbc19c2023-05-26 09:59:09 +0200833 endpt_count = server_opts.endpt_count;
834 for (i = 0; i < endpt_count; i++) {
roman456f92d2023-04-28 10:28:12 +0200835 switch (server_opts.endpts[i].ti) {
roman2eab4742023-06-06 10:00:26 +0200836#ifdef NC_ENABLED_SSH_TLS
roman456f92d2023-04-28 10:28:12 +0200837 case NC_TI_LIBSSH:
roman874fed12023-05-25 10:20:01 +0200838 nc_server_config_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]);
roman456f92d2023-04-28 10:28:12 +0200839 break;
roman456f92d2023-04-28 10:28:12 +0200840 case NC_TI_OPENSSL:
roman3f9b65c2023-06-05 14:26:58 +0200841 nc_server_config_del_endpt_tls(&server_opts.endpts[i], &server_opts.binds[i]);
roman456f92d2023-04-28 10:28:12 +0200842 break;
roman2eab4742023-06-06 10:00:26 +0200843#endif /* NC_ENABLED_SSH_TLS */
roman456f92d2023-04-28 10:28:12 +0200844 case NC_TI_UNIX:
roman874fed12023-05-25 10:20:01 +0200845 nc_server_config_del_endpt_unix_socket(&server_opts.endpts[i], &server_opts.binds[i]);
roman456f92d2023-04-28 10:28:12 +0200846 break;
847 case NC_TI_NONE:
848 case NC_TI_FD:
849 ERRINT;
850 return 1;
roman83683fb2023-02-24 09:15:23 +0100851 }
romanc1d2b092023-02-02 08:58:27 +0100852 }
853 }
854
855 return 0;
856}
857
858/* default leaf */
859static int
romane028ef92023-02-24 16:33:08 +0100860nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100861{
862 assert(!strcmp(LYD_NAME(node), "idle-timeout"));
863
864 if (equal_parent_name(node, 1, "listen")) {
865 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
866 server_opts.idle_timeout = strtoul(lyd_get_value(node), NULL, 10);
867 } else {
868 /* default value */
869 server_opts.idle_timeout = 3600;
870 }
871 }
872
873 return 0;
874}
875
876static int
roman874fed12023-05-25 10:20:01 +0200877nc_server_config_create_bind(void)
romanc1d2b092023-02-02 08:58:27 +0100878{
879 int ret = 0;
880 void *tmp;
881
882 tmp = realloc(server_opts.binds, (server_opts.endpt_count + 1) * sizeof *server_opts.binds);
883 if (!tmp) {
884 ERRMEM;
885 ret = 1;
886 goto cleanup;
887 }
888 server_opts.binds = tmp;
889 memset(&server_opts.binds[server_opts.endpt_count], 0, sizeof *server_opts.binds);
890
891 server_opts.binds[server_opts.endpt_count].sock = -1;
892
893cleanup:
894 return ret;
895}
896
897static int
roman874fed12023-05-25 10:20:01 +0200898nc_server_config_create_endpoint(const struct lyd_node *node)
romanc1d2b092023-02-02 08:58:27 +0100899{
roman874fed12023-05-25 10:20:01 +0200900 if (nc_server_config_create_bind()) {
romanf02273a2023-05-25 09:44:11 +0200901 return 1;
romanc1d2b092023-02-02 08:58:27 +0100902 }
romanc1d2b092023-02-02 08:58:27 +0100903
904 node = lyd_child(node);
905 assert(!strcmp(LYD_NAME(node), "name"));
906
romanf02273a2023-05-25 09:44:11 +0200907 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 +0100908}
909
910/* list */
911static int
romane028ef92023-02-24 16:33:08 +0100912nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100913{
914 int ret = 0;
915 struct nc_endpt *endpt;
916 struct nc_bind *bind;
917
918 assert(!strcmp(LYD_NAME(node), "endpoint"));
919
920 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +0200921 ret = nc_server_config_create_endpoint(node);
romanc1d2b092023-02-02 08:58:27 +0100922 if (ret) {
923 goto cleanup;
924 }
925 } else if (op == NC_OP_DELETE) {
926 /* free all children */
romanf02273a2023-05-25 09:44:11 +0200927 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +0100928 ret = 1;
929 goto cleanup;
930 }
roman3f9b65c2023-06-05 14:26:58 +0200931
932 switch (endpt->ti) {
roman2eab4742023-06-06 10:00:26 +0200933#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +0200934 case NC_TI_LIBSSH:
935 nc_server_config_del_endpt_ssh(endpt, bind);
936 break;
roman3f9b65c2023-06-05 14:26:58 +0200937 case NC_TI_OPENSSL:
938 nc_server_config_del_endpt_tls(endpt, bind);
939 break;
roman2eab4742023-06-06 10:00:26 +0200940#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200941 case NC_TI_UNIX:
942 nc_server_config_del_endpt_unix_socket(endpt, bind);
943 break;
944 case NC_TI_NONE:
945 case NC_TI_FD:
946 ERRINT;
947 ret = 1;
948 goto cleanup;
949 }
romanc1d2b092023-02-02 08:58:27 +0100950 }
951
952cleanup:
953 return ret;
954}
955
roman2eab4742023-06-06 10:00:26 +0200956#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +0200957
romanc1d2b092023-02-02 08:58:27 +0100958static int
roman874fed12023-05-25 10:20:01 +0200959nc_server_config_create_ssh(struct nc_endpt *endpt)
romanc1d2b092023-02-02 08:58:27 +0100960{
961 endpt->ti = NC_TI_LIBSSH;
962 endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
963 if (!endpt->opts.ssh) {
964 ERRMEM;
965 return 1;
966 }
967
968 return 0;
969}
970
971/* NP container */
972static int
romane028ef92023-02-24 16:33:08 +0100973nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100974{
975 struct nc_endpt *endpt;
976 struct nc_bind *bind;
977 int ret = 0;
978
979 assert(!strcmp(LYD_NAME(node), "ssh"));
980
romanf02273a2023-05-25 09:44:11 +0200981 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +0100982 ret = 1;
983 goto cleanup;
984 }
985
986 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +0200987 ret = nc_server_config_create_ssh(endpt);
romanc1d2b092023-02-02 08:58:27 +0100988 if (ret) {
989 goto cleanup;
990 }
991 } else if (op == NC_OP_DELETE) {
roman874fed12023-05-25 10:20:01 +0200992 nc_server_config_del_ssh(bind, endpt->opts.ssh);
romanc1d2b092023-02-02 08:58:27 +0100993 }
994
995cleanup:
996 return ret;
997}
998
roman3f9b65c2023-06-05 14:26:58 +0200999static int
1000nc_server_config_create_tls(struct nc_endpt *endpt)
1001{
1002 endpt->ti = NC_TI_OPENSSL;
1003 endpt->opts.tls = calloc(1, sizeof *endpt->opts.tls);
1004 if (!endpt->opts.tls) {
1005 ERRMEM;
1006 return 1;
1007 }
1008
1009 return 0;
1010}
1011
1012static int
1013nc_server_config_tls(const struct lyd_node *node, NC_OPERATION op)
1014{
1015 struct nc_endpt *endpt;
1016 struct nc_bind *bind;
1017 int ret = 0;
1018
1019 assert(!strcmp(LYD_NAME(node), "tls"));
1020
1021 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1022 ret = 1;
1023 goto cleanup;
1024 }
1025
1026 if (op == NC_OP_CREATE) {
1027 ret = nc_server_config_create_tls(endpt);
1028 if (ret) {
1029 goto cleanup;
1030 }
1031 } else if (op == NC_OP_DELETE) {
1032 nc_server_config_del_tls(bind, endpt->opts.tls);
1033 }
1034
1035cleanup:
1036 return ret;
1037}
1038
roman2eab4742023-06-06 10:00:26 +02001039#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02001040
romanc1d2b092023-02-02 08:58:27 +01001041static int
1042nc_server_config_set_address_port(struct nc_endpt *endpt, struct nc_bind *bind, const char *address, uint16_t port)
1043{
1044 int sock = -1, set_addr, ret = 0;
1045
roman83683fb2023-02-24 09:15:23 +01001046 assert((address && !port) || (!address && port) || (endpt->ti == NC_TI_UNIX));
romanc1d2b092023-02-02 08:58:27 +01001047
1048 if (address) {
1049 set_addr = 1;
1050 } else {
1051 set_addr = 0;
1052 }
1053
1054 if (set_addr) {
1055 port = bind->port;
1056 } else {
1057 address = bind->address;
1058 }
1059
romanc1d2b092023-02-02 08:58:27 +01001060 /* we have all the information we need to create a listening socket */
roman83683fb2023-02-24 09:15:23 +01001061 if ((address && port) || (endpt->ti == NC_TI_UNIX)) {
romanc1d2b092023-02-02 08:58:27 +01001062 /* create new socket, close the old one */
roman83683fb2023-02-24 09:15:23 +01001063 if (endpt->ti == NC_TI_UNIX) {
1064 sock = nc_sock_listen_unix(endpt->opts.unixsock);
1065 } else {
1066 sock = nc_sock_listen_inet(address, port, &endpt->ka);
1067 }
1068
romanc1d2b092023-02-02 08:58:27 +01001069 if (sock == -1) {
1070 ret = 1;
1071 goto cleanup;
1072 }
1073
1074 if (bind->sock > -1) {
1075 close(bind->sock);
1076 }
1077 bind->sock = sock;
1078 }
1079
1080 if (sock > -1) {
1081 switch (endpt->ti) {
roman83683fb2023-02-24 09:15:23 +01001082 case NC_TI_UNIX:
1083 VRB(NULL, "Listening on %s for UNIX connections.", endpt->opts.unixsock->address);
1084 break;
roman2eab4742023-06-06 10:00:26 +02001085#ifdef NC_ENABLED_SSH_TLS
romanc1d2b092023-02-02 08:58:27 +01001086 case NC_TI_LIBSSH:
1087 VRB(NULL, "Listening on %s:%u for SSH connections.", address, port);
1088 break;
romanc1d2b092023-02-02 08:58:27 +01001089 case NC_TI_OPENSSL:
1090 VRB(NULL, "Listening on %s:%u for TLS connections.", address, port);
1091 break;
roman2eab4742023-06-06 10:00:26 +02001092#endif /* NC_ENABLED_SSH_TLS */
romanc1d2b092023-02-02 08:58:27 +01001093 default:
1094 ERRINT;
1095 ret = 1;
1096 break;
1097 }
1098 }
1099
1100cleanup:
1101 return ret;
1102}
1103
roman2eab4742023-06-06 10:00:26 +02001104#ifdef NC_ENABLED_SSH_TLS
1105
romanc1d2b092023-02-02 08:58:27 +01001106/* mandatory leaf */
1107static int
romane028ef92023-02-24 16:33:08 +01001108nc_server_config_local_address(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001109{
1110 struct nc_endpt *endpt;
1111 struct nc_bind *bind;
1112 int ret = 0;
1113
1114 (void) op;
1115
1116 assert(!strcmp(LYD_NAME(node), "local-address"));
1117
1118 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001119 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001120 ret = 1;
1121 goto cleanup;
1122 }
1123
roman874fed12023-05-25 10:20:01 +02001124 nc_server_config_del_local_address(bind);
romanc1d2b092023-02-02 08:58:27 +01001125 bind->address = strdup(lyd_get_value(node));
1126 if (!bind->address) {
1127 ERRMEM;
1128 ret = 1;
1129 goto cleanup;
1130 }
1131
1132 ret = nc_server_config_set_address_port(endpt, bind, lyd_get_value(node), 0);
1133 if (ret) {
1134 goto cleanup;
1135 }
1136 }
1137
1138cleanup:
1139 return ret;
1140}
1141
1142/* leaf with default value */
1143static int
romane028ef92023-02-24 16:33:08 +01001144nc_server_config_local_port(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001145{
1146 struct nc_endpt *endpt;
1147 struct nc_bind *bind;
1148 int ret = 0;
1149
1150 assert(!strcmp(LYD_NAME(node), "local-port"));
1151
1152 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001153 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001154 ret = 1;
1155 goto cleanup;
1156 }
1157
1158 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1159 bind->port = strtoul(lyd_get_value(node), NULL, 10);
1160 } else {
1161 /* delete -> set to default */
1162 bind->port = 0;
1163 }
1164
1165 ret = nc_server_config_set_address_port(endpt, bind, NULL, bind->port);
1166 if (ret) {
1167 goto cleanup;
1168 }
1169 }
1170
1171cleanup:
1172 return ret;
1173}
1174
1175/* P container */
1176static int
romane028ef92023-02-24 16:33:08 +01001177nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001178{
1179 struct nc_endpt *endpt;
1180 struct nc_bind *bind;
1181 int ret = 0;
1182
1183 assert(!strcmp(LYD_NAME(node), "keepalives"));
1184
roman3f9b65c2023-06-05 14:26:58 +02001185 if (equal_parent_name(node, 1, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001186 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001187 ret = 1;
1188 goto cleanup;
1189 }
1190
1191 if (op == NC_OP_CREATE) {
1192 endpt->ka.enabled = 1;
1193 } else {
1194 endpt->ka.enabled = 0;
1195 }
1196 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1197 if (ret) {
1198 goto cleanup;
1199 }
1200 }
1201
1202cleanup:
1203 return ret;
1204}
1205
1206/* mandatory leaf */
1207static int
romane028ef92023-02-24 16:33:08 +01001208nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001209{
1210 struct nc_endpt *endpt;
1211 struct nc_bind *bind;
1212 int ret = 0;
1213
1214 assert(!strcmp(LYD_NAME(node), "idle-time"));
1215
1216 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001217 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001218 ret = 1;
1219 goto cleanup;
1220 }
1221
1222 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1223 endpt->ka.idle_time = strtoul(lyd_get_value(node), NULL, 10);
1224 } else {
1225 endpt->ka.idle_time = 0;
1226 }
1227 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1228 if (ret) {
1229 goto cleanup;
1230 }
1231 }
1232
1233cleanup:
1234 return ret;
1235}
1236
1237/* mandatory leaf */
1238static int
romane028ef92023-02-24 16:33:08 +01001239nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001240{
1241 struct nc_endpt *endpt;
1242 struct nc_bind *bind;
1243 int ret = 0;
1244
1245 assert(!strcmp(LYD_NAME(node), "max-probes"));
1246
1247 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001248 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001249 ret = 1;
1250 goto cleanup;
1251 }
1252
1253 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1254 endpt->ka.max_probes = strtoul(lyd_get_value(node), NULL, 10);
1255 } else {
1256 endpt->ka.max_probes = 0;
1257 }
1258 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1259 if (ret) {
1260 goto cleanup;
1261 }
1262 }
1263
1264cleanup:
1265 return ret;
1266}
1267
1268/* mandatory leaf */
1269static int
romane028ef92023-02-24 16:33:08 +01001270nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001271{
1272 struct nc_endpt *endpt;
1273 struct nc_bind *bind;
1274 int ret = 0;
1275
1276 assert(!strcmp(LYD_NAME(node), "probe-interval"));
1277
1278 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001279 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001280 ret = 1;
1281 goto cleanup;
1282 }
1283
1284 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1285 endpt->ka.probe_interval = strtoul(lyd_get_value(node), NULL, 10);
1286 } else {
1287 endpt->ka.probe_interval = 0;
1288 }
1289 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1290 if (ret) {
1291 goto cleanup;
1292 }
1293 }
1294
1295cleanup:
1296 return ret;
1297}
1298
1299static int
roman874fed12023-05-25 10:20:01 +02001300nc_server_config_create_host_key(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01001301{
romanf02273a2023-05-25 09:44:11 +02001302 node = lyd_child(node);
1303 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01001304
romanf02273a2023-05-25 09:44:11 +02001305 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->hostkeys, sizeof *opts->hostkeys, &opts->hostkey_count);
romanc1d2b092023-02-02 08:58:27 +01001306}
1307
1308/* list */
1309static int
romane028ef92023-02-24 16:33:08 +01001310nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001311{
1312 struct nc_endpt *endpt;
1313 struct nc_hostkey *hostkey;
1314 int ret = 0;
1315
1316 assert(!strcmp(LYD_NAME(node), "host-key"));
1317
1318 if ((equal_parent_name(node, 1, "server-identity")) && (equal_parent_name(node, 5, "listen"))) {
romanf02273a2023-05-25 09:44:11 +02001319 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001320 ret = 1;
1321 goto cleanup;
1322 }
1323
1324 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +02001325 ret = nc_server_config_create_host_key(node, endpt->opts.ssh);
romanc1d2b092023-02-02 08:58:27 +01001326 if (ret) {
1327 goto cleanup;
1328 }
1329 } else if (op == NC_OP_DELETE) {
romanf02273a2023-05-25 09:44:11 +02001330 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001331 ret = 1;
1332 goto cleanup;
1333 }
1334
roman874fed12023-05-25 10:20:01 +02001335 nc_server_config_del_hostkey(endpt->opts.ssh, hostkey);
romanc1d2b092023-02-02 08:58:27 +01001336 }
1337 } else if (equal_parent_name(node, 1, "transport-params")) {
1338 /* just a container with the name host-key, nothing to be done */
1339 goto cleanup;
1340 } else {
1341 ERRINT;
1342 ret = 1;
1343 goto cleanup;
1344 }
1345
1346cleanup:
1347 return ret;
1348}
1349
1350/* mandatory leaf */
romane028ef92023-02-24 16:33:08 +01001351static int
1352nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001353{
1354 const char *format;
roman3f9b65c2023-06-05 14:26:58 +02001355 int ret = 0;
1356 NC_PUBKEY_FORMAT pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001357 struct nc_endpt *endpt;
1358 struct nc_client_auth *auth_client;
roman8edee342023-03-31 13:25:48 +02001359 struct nc_public_key *pubkey;
romanc1d2b092023-02-02 08:58:27 +01001360 struct nc_hostkey *hostkey;
romanc1d2b092023-02-02 08:58:27 +01001361
1362 assert(!strcmp(LYD_NAME(node), "public-key-format"));
1363
1364 format = ((struct lyd_node_term *)node)->value.ident->name;
roman3f9b65c2023-06-05 14:26:58 +02001365 if (!strcmp(format, "ssh-public-key-format")) {
1366 pubkey_type = NC_PUBKEY_FORMAT_SSH2;
1367 } else if (!strcmp(format, "subject-public-key-info-format")) {
1368 pubkey_type = NC_PUBKEY_FORMAT_X509;
1369 } else {
1370 ERR(NULL, "Public key format (%s) not supported.", format);
1371 ret = 1;
1372 goto cleanup;
1373 }
romanc1d2b092023-02-02 08:58:27 +01001374
roman3f9b65c2023-06-05 14:26:58 +02001375 if ((equal_parent_name(node, 6, "client-authentication")) && (is_ssh(node)) && (is_listen(node))) {
romanf02273a2023-05-25 09:44:11 +02001376 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001377 ret = 1;
1378 goto cleanup;
1379 }
1380
romanf02273a2023-05-25 09:44:11 +02001381 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001382 ret = 1;
1383 goto cleanup;
1384 }
1385
romanf02273a2023-05-25 09:44:11 +02001386 if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001387 ret = 1;
1388 goto cleanup;
1389 }
1390
1391 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman3f9b65c2023-06-05 14:26:58 +02001392 pubkey->type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001393 }
roman3f9b65c2023-06-05 14:26:58 +02001394 } else if (equal_parent_name(node, 5, "server-identity") && is_ssh(node) && is_listen(node)) {
romanf02273a2023-05-25 09:44:11 +02001395 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001396 ret = 1;
1397 goto cleanup;
1398 }
1399
romanf02273a2023-05-25 09:44:11 +02001400 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001401 ret = 1;
1402 goto cleanup;
1403 }
1404
1405 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman3f9b65c2023-06-05 14:26:58 +02001406 hostkey->key.pubkey_type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001407 }
roman2eab4742023-06-06 10:00:26 +02001408 } else if (equal_parent_name(node, 3, "server-identity") && is_tls(node) && is_listen(node)) {
roman3f9b65c2023-06-05 14:26:58 +02001409 /* TLS listen server-identity */
1410 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
1411 ret = 1;
1412 goto cleanup;
1413 }
1414
1415 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1416 endpt->opts.tls->pubkey_type = pubkey_type;
1417 }
1418 }
romanc1d2b092023-02-02 08:58:27 +01001419
1420cleanup:
1421 return ret;
1422}
1423
1424/* leaf */
romane028ef92023-02-24 16:33:08 +01001425static int
1426nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001427{
roman3f9b65c2023-06-05 14:26:58 +02001428 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001429 const char *format;
1430 struct nc_endpt *endpt;
roman3f9b65c2023-06-05 14:26:58 +02001431 NC_PRIVKEY_FORMAT privkey_type;
romanc1d2b092023-02-02 08:58:27 +01001432 struct nc_hostkey *hostkey;
roman3f9b65c2023-06-05 14:26:58 +02001433
1434 (void) op;
romanc1d2b092023-02-02 08:58:27 +01001435
1436 assert(!strcmp(LYD_NAME(node), "private-key-format"));
1437
romanf02273a2023-05-25 09:44:11 +02001438 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001439 ret = 1;
1440 goto cleanup;
1441 }
1442
roman3f9b65c2023-06-05 14:26:58 +02001443 format = ((struct lyd_node_term *)node)->value.ident->name;
1444 if (!format) {
romanc1d2b092023-02-02 08:58:27 +01001445 ret = 1;
1446 goto cleanup;
1447 }
1448
roman3f9b65c2023-06-05 14:26:58 +02001449 privkey_type = nc_server_config_get_private_key_type(format);
1450 if (privkey_type == NC_PRIVKEY_FORMAT_UNKNOWN) {
1451 ret = 1;
1452 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01001453 }
1454
roman3f9b65c2023-06-05 14:26:58 +02001455 if ((is_ssh(node)) && (is_listen(node))) {
1456 /* listen ssh */
1457 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
1458 ret = 1;
1459 goto cleanup;
1460 }
1461
1462 hostkey->key.privkey_type = privkey_type;
roman2eab4742023-06-06 10:00:26 +02001463 } else if ((is_tls(node)) && (is_listen(node))) {
roman3f9b65c2023-06-05 14:26:58 +02001464 /* listen tls */
roman3f9b65c2023-06-05 14:26:58 +02001465 endpt->opts.tls->privkey_type = privkey_type;
1466 }
roman3f9b65c2023-06-05 14:26:58 +02001467
romanc1d2b092023-02-02 08:58:27 +01001468cleanup:
1469 return ret;
1470}
1471
1472static int
roman874fed12023-05-25 10:20:01 +02001473nc_server_config_replace_cleartext_private_key(const struct lyd_node *node, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +01001474{
roman874fed12023-05-25 10:20:01 +02001475 nc_server_config_del_private_key(hostkey);
roman3f9b65c2023-06-05 14:26:58 +02001476 hostkey->key.privkey_data = strdup(lyd_get_value(node));
1477 if (!hostkey->key.privkey_data) {
romanc1d2b092023-02-02 08:58:27 +01001478 ERRMEM;
1479 return 1;
1480 }
1481
1482 return 0;
1483}
1484
roman3f9b65c2023-06-05 14:26:58 +02001485static int
1486nc_server_config_tls_replace_cleartext_private_key(const struct lyd_node *node, struct nc_server_tls_opts *opts)
1487{
1488 nc_server_config_tls_del_cleartext_private_key(opts);
1489 opts->privkey_data = strdup(lyd_get_value(node));
1490 if (!opts->privkey_data) {
1491 ERRMEM;
1492 return 1;
1493 }
1494
1495 return 0;
1496}
1497
romanc1d2b092023-02-02 08:58:27 +01001498static int
romane028ef92023-02-24 16:33:08 +01001499nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001500{
romanc1d2b092023-02-02 08:58:27 +01001501 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02001502 struct nc_endpt *endpt;
roman3f9b65c2023-06-05 14:26:58 +02001503 struct nc_hostkey *hostkey;
romanc1d2b092023-02-02 08:58:27 +01001504
1505 assert(!strcmp(LYD_NAME(node), "cleartext-private-key"));
1506
roman3f9b65c2023-06-05 14:26:58 +02001507 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
1508 ret = 1;
1509 goto cleanup;
1510 }
1511
roman3f9b65c2023-06-05 14:26:58 +02001512 if ((is_ssh(node)) && (is_listen(node))) {
romanf02273a2023-05-25 09:44:11 +02001513 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001514 ret = 1;
1515 goto cleanup;
1516 }
1517
1518 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02001519 ret = nc_server_config_replace_cleartext_private_key(node, hostkey);
romanc1d2b092023-02-02 08:58:27 +01001520 if (ret) {
1521 goto cleanup;
1522 }
1523 } else {
roman874fed12023-05-25 10:20:01 +02001524 nc_server_config_del_private_key(hostkey);
romanc1d2b092023-02-02 08:58:27 +01001525 }
roman2eab4742023-06-06 10:00:26 +02001526 } else if ((is_tls(node)) && (is_listen(node))) {
roman3f9b65c2023-06-05 14:26:58 +02001527 /* listen tls */
roman3f9b65c2023-06-05 14:26:58 +02001528 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1529 ret = nc_server_config_tls_replace_cleartext_private_key(node, endpt->opts.tls);
1530 if (ret) {
1531 goto cleanup;
1532 }
1533 } else {
1534 nc_server_config_tls_del_cleartext_private_key(endpt->opts.tls);
1535 }
1536 }
romanc1d2b092023-02-02 08:58:27 +01001537
1538cleanup:
1539 return ret;
1540}
1541
1542static int
roman874fed12023-05-25 10:20:01 +02001543nc_server_config_create_keystore_reference(const struct lyd_node *node, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +01001544{
1545 uint16_t i;
roman45cec4e2023-02-17 10:21:39 +01001546 struct nc_keystore *ks = &server_opts.keystore;
romanc1d2b092023-02-02 08:58:27 +01001547
1548 /* lookup name */
roman45cec4e2023-02-17 10:21:39 +01001549 for (i = 0; i < ks->asym_key_count; i++) {
1550 if (!strcmp(lyd_get_value(node), ks->asym_keys[i].name)) {
romanc1d2b092023-02-02 08:58:27 +01001551 break;
1552 }
1553 }
1554
roman45cec4e2023-02-17 10:21:39 +01001555 if (i == ks->asym_key_count) {
1556 ERR(NULL, "Keystore \"%s\" not found.", lyd_get_value(node));
romanc1d2b092023-02-02 08:58:27 +01001557 return 1;
1558 }
1559
roman45cec4e2023-02-17 10:21:39 +01001560 hostkey->ks_ref = &ks->asym_keys[i];
romanc1d2b092023-02-02 08:58:27 +01001561
1562 return 0;
1563}
1564
1565/* leaf */
1566static int
romane028ef92023-02-24 16:33:08 +01001567nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001568{
1569 struct nc_endpt *endpt;
1570 struct nc_hostkey *hostkey;
1571 int ret = 0;
1572
1573 assert(!strcmp(LYD_NAME(node), "keystore-reference"));
1574
roman3f9b65c2023-06-05 14:26:58 +02001575 if ((equal_parent_name(node, 3, "server-identity")) && (is_ssh(node)) && (is_listen(node))) {
romanf02273a2023-05-25 09:44:11 +02001576 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001577 ret = 1;
1578 goto cleanup;
1579 }
romanf02273a2023-05-25 09:44:11 +02001580 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001581 ret = 1;
1582 goto cleanup;
1583 }
1584
1585 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02001586 /* set to keystore */
roman874fed12023-05-25 10:20:01 +02001587 hostkey->store = NC_STORE_KEYSTORE;
romanf02273a2023-05-25 09:44:11 +02001588
roman874fed12023-05-25 10:20:01 +02001589 ret = nc_server_config_create_keystore_reference(node, hostkey);
romanc1d2b092023-02-02 08:58:27 +01001590 if (ret) {
1591 goto cleanup;
1592 }
1593 } else {
roman45cec4e2023-02-17 10:21:39 +01001594 hostkey->ks_ref = NULL;
romanc1d2b092023-02-02 08:58:27 +01001595 }
1596 }
1597
1598cleanup:
1599 return ret;
1600}
1601
1602static int
roman874fed12023-05-25 10:20:01 +02001603nc_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 +01001604{
romanc1d2b092023-02-02 08:58:27 +01001605 assert(!strcmp(LYD_NAME(node), "public-key"));
1606
romanc1d2b092023-02-02 08:58:27 +01001607 node = lyd_child(node);
1608 assert(!strcmp(LYD_NAME(node), "name"));
1609
romanf02273a2023-05-25 09:44:11 +02001610 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 +01001611}
1612
1613static int
roman874fed12023-05-25 10:20:01 +02001614nc_server_config_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +01001615{
roman874fed12023-05-25 10:20:01 +02001616 nc_server_config_del_auth_client_pubkey_pub_base64(pubkey);
romanc1d2b092023-02-02 08:58:27 +01001617
roman3f9b65c2023-06-05 14:26:58 +02001618 pubkey->data = strdup(lyd_get_value(node));
1619 if (!pubkey->data) {
romanc1d2b092023-02-02 08:58:27 +01001620 ERRMEM;
1621 return 1;
1622 }
1623
1624 return 0;
1625}
1626
1627static int
roman874fed12023-05-25 10:20:01 +02001628nc_server_config_replace_host_key_public_key(const struct lyd_node *node, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +01001629{
roman874fed12023-05-25 10:20:01 +02001630 nc_server_config_del_public_key(hostkey);
romanc1d2b092023-02-02 08:58:27 +01001631
roman3f9b65c2023-06-05 14:26:58 +02001632 hostkey->key.pubkey_data = strdup(lyd_get_value(node));
1633 if (!hostkey->key.pubkey_data) {
romanc1d2b092023-02-02 08:58:27 +01001634 ERRMEM;
1635 return 1;
1636 }
1637
1638 return 0;
1639}
1640
roman3f9b65c2023-06-05 14:26:58 +02001641static int
1642nc_server_config_tls_replace_server_public_key(const struct lyd_node *node, struct nc_server_tls_opts *opts)
1643{
1644 nc_server_config_tls_del_public_key(opts);
1645
1646 opts->pubkey_data = strdup(lyd_get_value(node));
1647 if (!opts->pubkey_data) {
1648 ERRMEM;
1649 return 1;
1650 }
1651
1652 return 0;
1653}
1654
romanc1d2b092023-02-02 08:58:27 +01001655static int
romane028ef92023-02-24 16:33:08 +01001656nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001657{
roman3f9b65c2023-06-05 14:26:58 +02001658 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001659 struct nc_endpt *endpt;
1660 struct nc_hostkey *hostkey;
1661 struct nc_client_auth *auth_client;
roman8edee342023-03-31 13:25:48 +02001662 struct nc_public_key *pubkey;
romanc1d2b092023-02-02 08:58:27 +01001663
1664 assert(!strcmp(LYD_NAME(node), "public-key"));
1665
roman3f9b65c2023-06-05 14:26:58 +02001666 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
1667 ret = 1;
1668 goto cleanup;
1669 }
romanc1d2b092023-02-02 08:58:27 +01001670
roman3f9b65c2023-06-05 14:26:58 +02001671 if ((equal_parent_name(node, 3, "host-key")) && (is_ssh(node)) && (is_listen(node))) {
1672 /* server's public-key, mandatory leaf */
romanf02273a2023-05-25 09:44:11 +02001673 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001674 ret = 1;
1675 goto cleanup;
1676 }
1677
1678 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02001679 /* set to local */
roman874fed12023-05-25 10:20:01 +02001680 hostkey->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02001681
roman874fed12023-05-25 10:20:01 +02001682 ret = nc_server_config_replace_host_key_public_key(node, hostkey);
romanc1d2b092023-02-02 08:58:27 +01001683 if (ret) {
1684 goto cleanup;
1685 }
1686 }
roman3f9b65c2023-06-05 14:26:58 +02001687 } else if ((equal_parent_name(node, 5, "client-authentication")) && (is_ssh(node)) && (is_listen(node))) {
romanc1d2b092023-02-02 08:58:27 +01001688 /* client auth pubkeys, list */
romanf02273a2023-05-25 09:44:11 +02001689 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001690 ret = 1;
1691 goto cleanup;
1692 }
1693
1694 if (op == NC_OP_CREATE) {
romanf02273a2023-05-25 09:44:11 +02001695 /* set to local */
roman874fed12023-05-25 10:20:01 +02001696 auth_client->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02001697
roman874fed12023-05-25 10:20:01 +02001698 ret = nc_server_config_create_auth_key_public_key_list(node, auth_client);
romanc1d2b092023-02-02 08:58:27 +01001699 if (ret) {
1700 goto cleanup;
1701 }
1702 } else if (op == NC_OP_DELETE) {
romanf02273a2023-05-25 09:44:11 +02001703 if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001704 ret = 1;
1705 goto cleanup;
1706 }
1707
roman874fed12023-05-25 10:20:01 +02001708 nc_server_config_del_auth_client_pubkey(auth_client, pubkey);
romanc1d2b092023-02-02 08:58:27 +01001709 }
roman3f9b65c2023-06-05 14:26:58 +02001710 } else if ((equal_parent_name(node, 6, "client-authentication")) && (is_ssh(node)) && (is_listen(node))) {
romanc1d2b092023-02-02 08:58:27 +01001711 /* client auth pubkey, leaf */
romanf02273a2023-05-25 09:44:11 +02001712 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001713 ret = 1;
1714 goto cleanup;
1715 }
1716
romanf02273a2023-05-25 09:44:11 +02001717 if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001718 ret = 1;
1719 goto cleanup;
1720 }
1721
1722 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02001723 ret = nc_server_config_replace_auth_key_public_key_leaf(node, pubkey);
romanc1d2b092023-02-02 08:58:27 +01001724 if (ret) {
1725 goto cleanup;
1726 }
1727 } else {
roman874fed12023-05-25 10:20:01 +02001728 nc_server_config_del_auth_client_pubkey_pub_base64(pubkey);
romanc1d2b092023-02-02 08:58:27 +01001729 }
roman2eab4742023-06-06 10:00:26 +02001730 } else if ((equal_parent_name(node, 3, "server-identity")) && (is_tls(node)) && (is_listen(node))) {
roman3f9b65c2023-06-05 14:26:58 +02001731 /* tls listen server-identity */
roman3f9b65c2023-06-05 14:26:58 +02001732 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1733 /* set to local */
1734 endpt->opts.tls->store = NC_STORE_LOCAL;
1735
1736 ret = nc_server_config_tls_replace_server_public_key(node, endpt->opts.tls);
1737 if (ret) {
1738 goto cleanup;
1739 }
1740 }
1741 }
romanc1d2b092023-02-02 08:58:27 +01001742
1743cleanup:
1744 return ret;
1745}
1746
1747static int
roman874fed12023-05-25 10:20:01 +02001748nc_server_config_create_user(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01001749{
romanf02273a2023-05-25 09:44:11 +02001750 node = lyd_child(node);
1751 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01001752
romanf02273a2023-05-25 09:44:11 +02001753 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 +01001754}
1755
1756/* list */
1757static int
romane028ef92023-02-24 16:33:08 +01001758nc_server_config_user(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001759{
1760 struct nc_endpt *endpt;
1761 struct nc_client_auth *auth_client;
1762 int ret = 0;
1763
1764 assert(!strcmp(LYD_NAME(node), "user"));
1765
1766 if (equal_parent_name(node, 6, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001767 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001768 ret = 1;
1769 goto cleanup;
1770 }
1771
1772 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +02001773 ret = nc_server_config_create_user(node, endpt->opts.ssh);
romanc1d2b092023-02-02 08:58:27 +01001774 if (ret) {
1775 goto cleanup;
1776 }
1777 } else if (op == NC_OP_DELETE) {
romanf02273a2023-05-25 09:44:11 +02001778 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001779 ret = 1;
1780 goto cleanup;
1781 }
1782
roman874fed12023-05-25 10:20:01 +02001783 nc_server_config_del_auth_client(endpt->opts.ssh, auth_client);
romanc1d2b092023-02-02 08:58:27 +01001784 }
1785 }
1786
1787cleanup:
1788 return ret;
1789}
1790
1791static int
romane028ef92023-02-24 16:33:08 +01001792nc_server_config_auth_attempts(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001793{
1794 struct nc_endpt *endpt;
1795 int ret = 0;
1796
1797 assert(!strcmp(LYD_NAME(node), "auth-attempts"));
1798
1799 if (equal_parent_name(node, 5, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001800 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001801 ret = 1;
1802 goto cleanup;
1803 }
1804
1805 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1806 endpt->opts.ssh->auth_attempts = strtoul(lyd_get_value(node), NULL, 10);
1807 }
1808 }
1809
1810cleanup:
1811 return ret;
1812}
1813
1814static int
romane028ef92023-02-24 16:33:08 +01001815nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001816{
1817 struct nc_endpt *endpt;
1818 int ret = 0;
1819
1820 assert(!strcmp(LYD_NAME(node), "auth-timeout"));
1821
1822 if (equal_parent_name(node, 5, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001823 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001824 ret = 1;
1825 goto cleanup;
1826 }
1827
1828 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1829 endpt->opts.ssh->auth_timeout = strtoul(lyd_get_value(node), NULL, 10);
1830 }
1831 }
1832
1833cleanup:
1834 return ret;
1835}
1836
1837static int
roman874fed12023-05-25 10:20:01 +02001838nc_server_config_replace_truststore_reference(const struct lyd_node *node, struct nc_client_auth *client_auth)
romanc1d2b092023-02-02 08:58:27 +01001839{
romand57b3722023-04-05 11:26:25 +02001840 uint16_t i;
1841 struct nc_truststore *ts = &server_opts.truststore;
romanc1d2b092023-02-02 08:58:27 +01001842
romand57b3722023-04-05 11:26:25 +02001843 /* lookup name */
1844 for (i = 0; i < ts->pub_bag_count; i++) {
1845 if (!strcmp(lyd_get_value(node), ts->pub_bags[i].name)) {
1846 break;
1847 }
1848 }
1849
1850 if (i == ts->pub_bag_count) {
roman3f9b65c2023-06-05 14:26:58 +02001851 ERR(NULL, "Public-key bag \"%s\" not found in truststore.", lyd_get_value(node));
romanc1d2b092023-02-02 08:58:27 +01001852 return 1;
1853 }
1854
romand57b3722023-04-05 11:26:25 +02001855 client_auth->ts_ref = &ts->pub_bags[i];
1856
romanc1d2b092023-02-02 08:58:27 +01001857 return 0;
1858}
1859
roman3f9b65c2023-06-05 14:26:58 +02001860static int
1861nc_server_config_tls_replace_truststore_reference(const struct lyd_node *node, struct nc_cert_grouping *auth_client)
1862{
1863 uint16_t i;
1864 struct nc_truststore *ts = &server_opts.truststore;
1865
1866 /* lookup name */
1867 for (i = 0; i < ts->cert_bag_count; i++) {
1868 if (!strcmp(lyd_get_value(node), ts->cert_bags[i].name)) {
1869 break;
1870 }
1871 }
1872
1873 if (i == ts->cert_bag_count) {
1874 ERR(NULL, "Certificate bag \"%s\" not found in truststore.", lyd_get_value(node));
1875 return 1;
1876 }
1877
1878 auth_client->ts_ref = &ts->cert_bags[i];
1879
1880 return 0;
1881}
1882
romanc1d2b092023-02-02 08:58:27 +01001883/* leaf */
1884static int
romane028ef92023-02-24 16:33:08 +01001885nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001886{
romanc1d2b092023-02-02 08:58:27 +01001887 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02001888 struct nc_endpt *endpt;
roman3f9b65c2023-06-05 14:26:58 +02001889 struct nc_client_auth *auth_client;
romanc1d2b092023-02-02 08:58:27 +01001890
1891 assert(!strcmp(LYD_NAME(node), "truststore-reference"));
1892
roman3f9b65c2023-06-05 14:26:58 +02001893 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
1894 ret = 1;
1895 goto cleanup;
1896 }
romanc1d2b092023-02-02 08:58:27 +01001897
roman3f9b65c2023-06-05 14:26:58 +02001898 if ((equal_parent_name(node, 1, "public-keys")) && (is_ssh(node)) && (is_listen(node))) {
romanf02273a2023-05-25 09:44:11 +02001899 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001900 ret = 1;
1901 goto cleanup;
1902 }
1903
1904 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02001905 /* set to truststore */
roman874fed12023-05-25 10:20:01 +02001906 auth_client->store = NC_STORE_TRUSTSTORE;
romanf02273a2023-05-25 09:44:11 +02001907
roman874fed12023-05-25 10:20:01 +02001908 ret = nc_server_config_replace_truststore_reference(node, auth_client);
romanc1d2b092023-02-02 08:58:27 +01001909 if (ret) {
1910 goto cleanup;
1911 }
1912 } else {
romand57b3722023-04-05 11:26:25 +02001913 auth_client->ts_ref = NULL;
romanc1d2b092023-02-02 08:58:27 +01001914 }
roman2eab4742023-06-06 10:00:26 +02001915 } else if ((equal_parent_name(node, 1, "ca-certs")) && (is_listen(node))) {
roman3f9b65c2023-06-05 14:26:58 +02001916 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1917 /* set to truststore */
1918 endpt->opts.tls->ca_certs.store = NC_STORE_TRUSTSTORE;
1919
1920 ret = nc_server_config_tls_replace_truststore_reference(node, &endpt->opts.tls->ca_certs);
1921 if (ret) {
1922 goto cleanup;
1923 }
1924 } else {
1925 endpt->opts.tls->ca_certs.ts_ref = NULL;
1926 }
1927 } else if ((equal_parent_name(node, 1, "ee-certs")) && (is_listen(node))) {
1928 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1929 /* set to truststore */
1930 endpt->opts.tls->ee_certs.store = NC_STORE_TRUSTSTORE;
1931
1932 ret = nc_server_config_tls_replace_truststore_reference(node, &endpt->opts.tls->ee_certs);
1933 if (ret) {
1934 goto cleanup;
1935 }
1936 } else {
1937 endpt->opts.tls->ee_certs.ts_ref = NULL;
1938 }
1939 }
romanc1d2b092023-02-02 08:58:27 +01001940
1941cleanup:
1942 return ret;
1943}
1944
1945static int
roman874fed12023-05-25 10:20:01 +02001946nc_server_config_replace_password(const struct lyd_node *node, struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +01001947{
roman874fed12023-05-25 10:20:01 +02001948 nc_server_config_del_auth_client_password(auth_client);
romanc1d2b092023-02-02 08:58:27 +01001949
1950 auth_client->password = strdup(lyd_get_value(node));
1951 if (!auth_client->password) {
1952 ERRMEM;
1953 return 1;
1954 }
1955
1956 return 0;
1957}
1958
1959/* leaf */
1960static int
romane028ef92023-02-24 16:33:08 +01001961nc_server_config_password(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001962{
1963 struct nc_endpt *endpt;
1964 struct nc_client_auth *auth_client;
1965 int ret = 0;
1966
1967 assert(!strcmp(LYD_NAME(node), "password"));
1968
1969 if (equal_parent_name(node, 7, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001970 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001971 ret = 1;
1972 goto cleanup;
1973 }
1974
romanf02273a2023-05-25 09:44:11 +02001975 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001976 ret = 1;
1977 goto cleanup;
1978 }
1979
1980 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02001981 ret = nc_server_config_replace_password(node, auth_client);
romanc1d2b092023-02-02 08:58:27 +01001982 if (ret) {
1983 goto cleanup;
1984 }
1985 } else {
roman874fed12023-05-25 10:20:01 +02001986 nc_server_config_del_auth_client_password(auth_client);
romanc1d2b092023-02-02 08:58:27 +01001987 }
1988 }
1989
1990cleanup:
1991 return ret;
1992}
1993
1994static int
romane028ef92023-02-24 16:33:08 +01001995nc_server_config_pam_name(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001996{
1997 struct nc_endpt *endpt;
1998 struct nc_client_auth *auth_client;
1999 int ret = 0;
2000
2001 assert(!strcmp(LYD_NAME(node), "pam-config-file-name"));
2002
2003 if (equal_parent_name(node, 8, "listen")) {
romanf02273a2023-05-25 09:44:11 +02002004 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01002005 ret = 1;
2006 goto cleanup;
2007 }
2008
romanf02273a2023-05-25 09:44:11 +02002009 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002010 ret = 1;
2011 goto cleanup;
2012 }
2013
2014 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02002015 nc_server_config_del_auth_client_pam_name(auth_client);
romanc1d2b092023-02-02 08:58:27 +01002016
2017 auth_client->pam_config_name = strdup(lyd_get_value(node));
2018 if (!auth_client->pam_config_name) {
2019 ERRMEM;
2020 ret = 1;
2021 goto cleanup;
2022 }
2023 }
2024 }
2025
2026cleanup:
2027 return ret;
2028}
2029
2030static int
romane028ef92023-02-24 16:33:08 +01002031nc_server_config_pam_dir(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002032{
2033 struct nc_endpt *endpt;
2034 struct nc_client_auth *auth_client;
2035 int ret = 0;
2036
2037 assert(!strcmp(LYD_NAME(node), "pam-config-file-dir"));
2038
2039 if (equal_parent_name(node, 8, "listen")) {
romanf02273a2023-05-25 09:44:11 +02002040 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01002041 ret = 1;
2042 goto cleanup;
2043 }
2044
romanf02273a2023-05-25 09:44:11 +02002045 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002046 ret = 1;
2047 goto cleanup;
2048 }
2049
2050 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02002051 nc_server_config_del_auth_client_pam_dir(auth_client);
romanc1d2b092023-02-02 08:58:27 +01002052 auth_client->pam_config_dir = strdup(lyd_get_value(node));
2053 if (!auth_client->pam_config_dir) {
2054 ERRMEM;
2055 ret = 1;
2056 goto cleanup;
2057 }
2058 }
2059 }
2060
2061cleanup:
2062 return ret;
2063}
2064
2065/* leaf */
2066static int
romane028ef92023-02-24 16:33:08 +01002067nc_server_config_none(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002068{
2069 struct nc_endpt *endpt;
2070 struct nc_client_auth *auth_client;
2071 int ret = 0;
2072
2073 assert(!strcmp(LYD_NAME(node), "none"));
2074
2075 if (equal_parent_name(node, 7, "listen")) {
romanf02273a2023-05-25 09:44:11 +02002076 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01002077 ret = 1;
2078 goto cleanup;
2079 }
2080
romanf02273a2023-05-25 09:44:11 +02002081 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002082 ret = 1;
2083 goto cleanup;
2084 }
2085
2086 if (op == NC_OP_CREATE) {
2087 auth_client->supports_none = 1;
2088 } else {
2089 auth_client->supports_none = 0;
2090 }
2091 }
2092
2093cleanup:
2094 return ret;
2095}
2096
2097static int
romana6bf6ab2023-05-26 13:26:02 +02002098nc_server_config_transport_params(const char *algorithm, char **alg_store, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002099{
2100 int ret = 0, alg_found = 0;
romana6bf6ab2023-05-26 13:26:02 +02002101 char *substr, *haystack, *alg = NULL;
2102 size_t alg_len;
2103
2104 if (!strncmp(algorithm, "openssh-", 8)) {
2105 /* if the name starts with openssh, convert it to it's original libssh accepted form */
2106 asprintf(&alg, "%s@openssh.com", algorithm + 8);
2107 if (!alg) {
2108 ERRMEM;
2109 ret = 1;
2110 goto cleanup;
2111 }
2112 } else if (!strncmp(algorithm, "libssh-", 7)) {
2113 /* if the name starts with libssh, convert it to it's original libssh accepted form */
2114 asprintf(&alg, "%s@libssh.org", algorithm + 7);
2115 if (!alg) {
2116 ERRMEM;
2117 ret = 1;
2118 goto cleanup;
2119 }
2120 } else {
2121 alg = strdup(algorithm);
2122 if (!alg) {
2123 ERRMEM;
2124 ret = 1;
2125 goto cleanup;
2126 }
2127 }
2128
2129 alg_len = strlen(alg);
romanc1d2b092023-02-02 08:58:27 +01002130
2131 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2132 if (!*alg_store) {
2133 /* first call */
2134 *alg_store = strdup(alg);
2135 if (!*alg_store) {
2136 ERRMEM;
2137 ret = 1;
2138 goto cleanup;
2139 }
2140 } else {
2141 /* +1 because of ',' between algorithms */
2142 *alg_store = nc_realloc(*alg_store, strlen(*alg_store) + alg_len + 1 + 1);
2143 if (!*alg_store) {
2144 ERRMEM;
2145 ret = 1;
2146 goto cleanup;
2147 }
2148 sprintf(*alg_store, "%s,%s", *alg_store, alg);
2149 }
2150 } else {
2151 /* delete */
2152 haystack = *alg_store;
2153 while ((substr = strstr(haystack, alg))) {
2154 /* iterate over all the substrings */
2155 if (((substr == haystack) && (*(substr + alg_len) == ',')) ||
2156 ((substr != haystack) && (*(substr - 1) == ',') && (*(substr + alg_len) == ','))) {
2157 /* either the first element of the string or somewhere in the middle */
2158 memmove(substr, substr + alg_len + 1, strlen(substr + alg_len + 1));
2159 alg_found = 1;
2160 break;
2161 } else if ((*(substr - 1) == ',') && (*(substr + alg_len) == '\0')) {
2162 /* the last element of the string */
2163 *(substr - 1) = '\0';
2164 alg_found = 1;
2165 break;
2166 }
2167 haystack++;
2168 }
2169 if (!alg_found) {
2170 ERR(NULL, "Unable to delete an algorithm (%s), which was not previously added.", alg);
2171 ret = 1;
2172 }
2173 }
2174
2175cleanup:
romana6bf6ab2023-05-26 13:26:02 +02002176 free(alg);
romanc1d2b092023-02-02 08:58:27 +01002177 return ret;
2178}
2179
2180/* leaf-list */
2181static int
romane028ef92023-02-24 16:33:08 +01002182nc_server_config_host_key_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002183{
2184 struct nc_endpt *endpt;
2185 int ret = 0, listen = 0;
2186 const char *alg;
2187 uint8_t i;
2188
2189 /* get the algorithm name and compare it with algs supported by libssh */
2190 alg = ((struct lyd_node_term *)node)->value.ident->name;
2191
2192 if (equal_parent_name(node, 6, "listen")) {
2193 listen = 1;
romanf02273a2023-05-25 09:44:11 +02002194 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01002195 ret = 1;
2196 goto cleanup;
2197 }
2198 }
2199
2200 i = 0;
2201 while (supported_hostkey_algs[i]) {
2202 if (!strcmp(supported_hostkey_algs[i], alg)) {
2203 if (listen) {
romane028ef92023-02-24 16:33:08 +01002204 if (nc_server_config_transport_params(alg, &endpt->opts.ssh->hostkey_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002205 ret = 1;
2206 goto cleanup;
2207 }
2208 }
2209 break;
2210 }
2211 i++;
2212 }
2213 if (!supported_hostkey_algs[i]) {
2214 /* algorithm not supported */
2215 ERR(NULL, "Public key algorithm (%s) not supported by libssh.", alg);
2216 ret = 1;
2217 }
2218
2219cleanup:
2220 return ret;
2221}
2222
2223/* leaf-list */
2224static int
romane028ef92023-02-24 16:33:08 +01002225nc_server_config_kex_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002226{
2227 struct nc_endpt *endpt;
2228 int ret = 0, listen = 0;
2229 const char *alg;
2230 uint8_t i;
2231
2232 /* get the algorithm name and compare it with algs supported by libssh */
2233 alg = ((struct lyd_node_term *)node)->value.ident->name;
2234
2235 if (equal_parent_name(node, 6, "listen")) {
2236 listen = 1;
romanf02273a2023-05-25 09:44:11 +02002237 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01002238 ret = 1;
2239 goto cleanup;
2240 }
2241 }
2242
2243 i = 0;
2244 while (supported_kex_algs[i]) {
2245 if (!strcmp(supported_kex_algs[i], alg)) {
2246 if (listen) {
romane028ef92023-02-24 16:33:08 +01002247 if (nc_server_config_transport_params(alg, &endpt->opts.ssh->kex_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002248 ret = 1;
2249 goto cleanup;
2250 }
2251 }
2252 break;
2253 }
2254 i++;
2255 }
2256 if (!supported_kex_algs[i]) {
2257 /* algorithm not supported */
2258 ERR(NULL, "Key exchange algorithm (%s) not supported by libssh.", alg);
2259 ret = 1;
2260 }
2261
2262cleanup:
2263 return ret;
2264}
2265
2266/* leaf-list */
2267static int
romane028ef92023-02-24 16:33:08 +01002268nc_server_config_encryption_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002269{
2270 struct nc_endpt *endpt;
2271 int ret = 0, listen = 0;
2272 const char *alg;
2273 uint8_t i;
2274
2275 /* get the algorithm name and compare it with algs supported by libssh */
2276 alg = ((struct lyd_node_term *)node)->value.ident->name;
2277
2278 if (equal_parent_name(node, 6, "listen")) {
2279 listen = 1;
romanf02273a2023-05-25 09:44:11 +02002280 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01002281 ret = 1;
2282 goto cleanup;
2283 }
2284 }
2285
2286 i = 0;
2287 while (supported_encryption_algs[i]) {
2288 if (!strcmp(supported_encryption_algs[i], alg)) {
2289 if (listen) {
romane028ef92023-02-24 16:33:08 +01002290 if (nc_server_config_transport_params(alg, &endpt->opts.ssh->encryption_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002291 ret = 1;
2292 goto cleanup;
2293 }
2294 }
2295 break;
2296 }
2297 i++;
2298 }
2299 if (!supported_encryption_algs[i]) {
2300 /* algorithm not supported */
2301 ERR(NULL, "Encryption algorithm (%s) not supported by libssh.", alg);
2302 ret = 1;
2303 }
2304
2305cleanup:
2306 return ret;
2307}
2308
2309/* leaf-list */
2310static int
romane028ef92023-02-24 16:33:08 +01002311nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002312{
2313 struct nc_endpt *endpt;
2314 int ret = 0, listen = 0;
2315 const char *alg;
2316 uint8_t i;
2317
2318 /* get the algorithm name and compare it with algs supported by libssh */
2319 alg = ((struct lyd_node_term *)node)->value.ident->name;
2320
2321 if (equal_parent_name(node, 6, "listen")) {
2322 listen = 1;
romanf02273a2023-05-25 09:44:11 +02002323 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01002324 ret = 1;
2325 goto cleanup;
2326 }
2327 }
2328
2329 i = 0;
2330 while (supported_mac_algs[i]) {
2331 if (!strcmp(supported_mac_algs[i], alg)) {
2332 if (listen) {
romane028ef92023-02-24 16:33:08 +01002333 if (nc_server_config_transport_params(alg, &endpt->opts.ssh->mac_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002334 ret = 1;
2335 goto cleanup;
2336 }
2337 }
2338 break;
2339 }
2340 i++;
2341 }
2342 if (!supported_mac_algs[i]) {
2343 /* algorithm not supported */
2344 ERR(NULL, "MAC algorithm (%s) not supported by libssh.", alg);
2345 ret = 1;
2346 }
2347
2348cleanup:
2349 return ret;
2350}
2351
roman2eab4742023-06-06 10:00:26 +02002352#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02002353
romanc1d2b092023-02-02 08:58:27 +01002354static int
roman874fed12023-05-25 10:20:01 +02002355nc_server_config_create_unix_socket(struct nc_endpt *endpt)
roman83683fb2023-02-24 09:15:23 +01002356{
2357 endpt->ti = NC_TI_UNIX;
2358 endpt->opts.unixsock = calloc(1, sizeof *endpt->opts.unixsock);
2359 if (!endpt->opts.unixsock) {
2360 ERRMEM;
2361 return 1;
2362 }
2363
2364 /* set default values */
2365 endpt->opts.unixsock->mode = -1;
2366 endpt->opts.unixsock->uid = -1;
2367 endpt->opts.unixsock->gid = -1;
2368
2369 return 0;
2370}
2371
2372static int
romane028ef92023-02-24 16:33:08 +01002373nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op)
roman83683fb2023-02-24 09:15:23 +01002374{
2375 int ret = 0;
2376 uint32_t prev_lo;
2377 struct nc_endpt *endpt;
2378 struct nc_bind *bind;
2379 struct nc_server_unix_opts *opts;
2380 struct lyd_node *data = NULL;
2381
2382 assert(!strcmp(LYD_NAME(node), "unix-socket"));
2383
romanf02273a2023-05-25 09:44:11 +02002384 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
roman83683fb2023-02-24 09:15:23 +01002385 ret = 1;
2386 goto cleanup;
2387 }
2388
2389 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +02002390 if (nc_server_config_create_unix_socket(endpt)) {
roman83683fb2023-02-24 09:15:23 +01002391 ret = 1;
2392 goto cleanup;
2393 }
2394
2395 opts = endpt->opts.unixsock;
2396
2397 lyd_find_path(node, "path", 0, &data);
2398 assert(data);
2399
2400 opts->address = strdup(lyd_get_value(data));
2401 bind->address = strdup(lyd_get_value(data));
2402 if (!opts->address || !bind->address) {
2403 ERRMEM;
2404 ret = 1;
2405 goto cleanup;
2406 }
2407
2408 /* silently search for non-mandatory parameters */
2409 prev_lo = ly_log_options(0);
2410 ret = lyd_find_path(node, "mode", 0, &data);
2411 if (!ret) {
2412 opts->mode = strtol(lyd_get_value(data), NULL, 8);
2413 }
2414
2415 ret = lyd_find_path(node, "uid", 0, &data);
2416 if (!ret) {
2417 opts->uid = strtol(lyd_get_value(data), NULL, 10);
2418 }
2419
2420 ret = lyd_find_path(node, "gid", 0, &data);
2421 if (!ret) {
2422 opts->gid = strtol(lyd_get_value(data), NULL, 10);
2423 }
2424
2425 /* reset the logging options */
2426 ly_log_options(prev_lo);
2427
2428 ret = nc_server_config_set_address_port(endpt, bind, NULL, 0);
2429 if (ret) {
2430 goto cleanup;
2431 }
2432 } else if (op == NC_OP_DELETE) {
roman874fed12023-05-25 10:20:01 +02002433 nc_server_config_del_unix_socket(bind, endpt->opts.unixsock);
roman83683fb2023-02-24 09:15:23 +01002434 }
2435
2436cleanup:
2437 return ret;
2438}
2439
roman2eab4742023-06-06 10:00:26 +02002440#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02002441
roman0bbc19c2023-05-26 09:59:09 +02002442/**
2443 * @brief Set all endpoint client auth references, which couldn't be set beforehand.
2444 *
2445 * The references that could not be set are those, which reference endpoints, which
2446 * lie below the given endpoint in the YANG data (because of DFS tree parsing).
2447 *
2448 * @return 0 on success, 1 on error.
2449 */
2450static int
2451nc_server_config_fill_endpt_client_auth(void)
2452{
2453 uint16_t i, j;
2454
2455 for (i = 0; i < server_opts.endpt_count; i++) {
2456 /* go through all the endpoint */
2457 if (server_opts.endpts[i].referenced_endpt_name) {
2458 /* endpt has a reference, that hasn't been set yet */
2459 for (j = i + 1; j < server_opts.endpt_count; j++) {
2460 /* go through all the remaining endpts */
2461 if (!strcmp(server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[j].name)) {
2462 /* found the endpoint we were looking for */
2463 if (server_opts.endpts[i].ti == NC_TI_LIBSSH) {
2464 server_opts.endpts[i].opts.ssh->endpt_client_ref = &server_opts.endpts[j];
2465 break;
2466 } else {
2467 ERRINT;
2468 return 1;
2469 }
2470 }
2471 }
2472
2473 /* didn't find the endpoint */
2474 if (j == server_opts.endpt_count) {
2475 ERR(NULL, "Endpoint \"%s\" referenced by \"%s\" not found.",
2476 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2477 return 1;
2478 }
2479 }
2480 }
2481
2482 return 0;
2483}
2484
2485static int
2486nc_server_config_endpoint_client_auth_has_cycle(struct nc_endpt *original, struct nc_endpt *next, NC_TRANSPORT_IMPL transport)
2487{
2488 if (transport == NC_TI_LIBSSH) {
2489 if (next->opts.ssh->endpt_client_ref) {
2490 if (next->opts.ssh->endpt_client_ref == original) {
2491 return 1;
2492 } else {
2493 return nc_server_config_endpoint_client_auth_has_cycle(original, next->opts.ssh->endpt_client_ref, NC_TI_LIBSSH);
2494 }
2495 } else {
2496 return 0;
2497 }
2498 } else {
2499 ERRINT;
2500 return 1;
2501 }
2502}
2503
2504static int
2505nc_server_config_endpoint_client_auth(const struct lyd_node *node, NC_OPERATION op)
2506{
2507 int ret = 0;
2508 uint16_t i;
2509 const char *endpt_name;
2510 struct nc_endpt *endpt;
2511
2512 assert(!strcmp(LYD_NAME(node), "endpoint-client-auth"));
2513
2514 /* get current endpoint */
2515 ret = nc_server_config_get_endpt(node, &endpt, NULL);
2516 if (ret) {
2517 goto cleanup;
2518 }
2519
2520 if (op == NC_OP_DELETE) {
2521 endpt->opts.ssh->endpt_client_ref = NULL;
2522 goto cleanup;
2523 }
2524
2525 /* find the endpoint leafref is referring to */
2526 endpt_name = lyd_get_value(node);
2527 for (i = 0; i < server_opts.endpt_count; i++) {
2528 if (!strcmp(endpt_name, server_opts.endpts[i].name)) {
2529 break;
2530 }
2531 }
2532
2533 if (i == server_opts.endpt_count) {
2534 /* endpt not found, save the name and try to look it up later */
2535 endpt->referenced_endpt_name = strdup(endpt_name);
2536 if (!endpt->referenced_endpt_name) {
2537 ERRMEM;
2538 ret = 1;
2539 goto cleanup;
2540 }
2541 goto cleanup;
2542 }
2543
2544 /* check for self reference */
2545 if (endpt == &server_opts.endpts[i]) {
2546 ERR(NULL, "Self client authentication reference detected.");
2547 ret = 1;
2548 goto cleanup;
2549 }
2550
2551 /* check for cyclic references */
2552 ret = nc_server_config_endpoint_client_auth_has_cycle(endpt, &server_opts.endpts[i], endpt->ti);
2553 if (ret) {
2554 ERR(NULL, "Cyclic client authentication reference detected.");
2555 goto cleanup;
2556 }
2557
2558 /* assign the current endpt the referrenced endpt */
2559 endpt->opts.ssh->endpt_client_ref = &server_opts.endpts[i];
2560
2561cleanup:
2562 return ret;
2563}
2564
roman3f9b65c2023-06-05 14:26:58 +02002565static int
2566nc_server_config_tls_replace_cert_data(const struct lyd_node *node, struct nc_server_tls_opts *opts)
2567{
2568 nc_server_config_tls_del_cert_data(opts);
2569 opts->cert_data = strdup(lyd_get_value(node));
2570 if (!opts->cert_data) {
2571 ERRMEM;
2572 return 1;
2573 }
2574
2575 return 0;
2576}
2577
2578static int
2579nc_server_config_tls_replace_cert_data_client_auth(const struct lyd_node *node, struct nc_certificate *cert)
2580{
2581 nc_server_config_tls_del_cert_data_certificate(cert);
2582 cert->data = strdup(lyd_get_value(node));
2583 if (!cert->data) {
2584 ERRMEM;
2585 return 1;
2586 }
2587
2588 return 0;
2589}
2590
2591static int
2592nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op)
2593{
2594 int ret = 0;
2595 struct nc_endpt *endpt;
2596 struct nc_certificate *cert;
2597
2598 assert(!strcmp(LYD_NAME(node), "cert-data"));
2599
2600 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
2601 ret = 1;
2602 goto cleanup;
2603 }
2604
2605 if ((equal_parent_name(node, 3, "server-identity")) && (is_listen(node))) {
2606 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2607 ret = nc_server_config_tls_replace_cert_data(node, endpt->opts.tls);
2608 if (ret) {
2609 goto cleanup;
2610 }
2611 }
2612 } else if ((equal_parent_name(node, 3, "ca-certs")) && (is_listen(node))) {
2613 if (nc_server_config_get_cert(node, &endpt->opts.tls->ca_certs, &cert)) {
2614 ret = 1;
2615 goto cleanup;
2616 }
2617
2618 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2619 ret = nc_server_config_tls_replace_cert_data_client_auth(node, cert);
2620 if (ret) {
2621 goto cleanup;
2622 }
2623 } else {
2624 nc_server_config_tls_del_cert_data_certificate(cert);
2625 }
2626 } else if ((equal_parent_name(node, 3, "ee-certs")) && (is_listen(node))) {
2627 if (nc_server_config_get_cert(node, &endpt->opts.tls->ee_certs, &cert)) {
2628 ret = 1;
2629 goto cleanup;
2630 }
2631
2632 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2633 ret = nc_server_config_tls_replace_cert_data_client_auth(node, cert);
2634 if (ret) {
2635 goto cleanup;
2636 }
2637 } else {
2638 nc_server_config_tls_del_cert_data_certificate(cert);
2639 }
2640 }
2641
2642cleanup:
2643 return ret;
2644}
2645
2646static int
2647nc_server_config_tls_create_asymmetric_key_ref(const struct lyd_node *node, struct nc_endpt *endpt)
2648{
2649 uint16_t i;
2650 struct nc_keystore *ks = &server_opts.keystore;
2651
2652 /* lookup name */
2653 for (i = 0; i < ks->asym_key_count; i++) {
2654 if (!strcmp(lyd_get_value(node), ks->asym_keys[i].name)) {
2655 break;
2656 }
2657 }
2658
2659 if (i == ks->asym_key_count) {
2660 ERR(NULL, "Asymmetric key \"%s\" not found in the keystore.", lyd_get_value(node));
2661 return 1;
2662 }
2663
2664 endpt->opts.tls->key_ref = &ks->asym_keys[i];
2665
2666 return 0;
2667}
2668
2669static int
2670nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op)
2671{
2672 int ret = 0;
2673 struct nc_endpt *endpt;
2674
2675 assert(!strcmp(LYD_NAME(node), "asymmetric-key"));
2676
2677 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
2678 ret = 1;
2679 goto cleanup;
2680 }
2681
2682 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2683 /* set to keystore */
2684 endpt->opts.tls->store = NC_STORE_KEYSTORE;
2685
2686 ret = nc_server_config_tls_create_asymmetric_key_ref(node, endpt);
2687 if (ret) {
2688 goto cleanup;
2689 }
2690 } else {
2691 endpt->opts.tls->key_ref = NULL;
2692 }
2693
2694cleanup:
2695 return ret;
2696}
2697
2698static int
2699nc_server_config_tls_create_certificate_ref(const struct lyd_node *node, struct nc_endpt *endpt, struct nc_asymmetric_key *key)
2700{
2701 uint16_t i;
2702
2703 /* lookup name */
2704 for (i = 0; i < key->cert_count; i++) {
2705 if (!strcmp(lyd_get_value(node), key->certs[i].name)) {
2706 break;
2707 }
2708 }
2709
2710 if (i == key->cert_count) {
2711 ERR(NULL, "Certificate \"%s\" not found in the asymmetric key \"%s\".", lyd_get_value(node), key->name);
2712 return 1;
2713 }
2714
2715 endpt->opts.tls->cert_ref = &key->certs[i];
2716
2717 return 0;
2718}
2719
2720static struct nc_asymmetric_key *
2721cert_get_asymmetric_key(const struct lyd_node *node)
2722{
2723 uint16_t i;
2724 struct nc_keystore *ks = &server_opts.keystore;
2725
2726 /* starting with certificate node */
2727 assert(!strcmp(LYD_NAME(node), "certificate"));
2728
2729 /* switch to it's only sibling, must be asymmetric-key */
2730 node = node->prev;
2731 assert(!strcmp(LYD_NAME(node), "asymmetric-key"));
2732
2733 /* find the given asymmetric key */
2734 for (i = 0; i < ks->asym_key_count; i++) {
2735 if (!strcmp(lyd_get_value(node), ks->asym_keys[i].name)) {
2736 return &ks->asym_keys[i];
2737 }
2738 }
2739
2740 /* didn't find it */
2741 ERR(NULL, "Asymmetric key \"%s\" not found in the keystore.", lyd_get_value(node));
2742 return NULL;
2743}
2744
2745static int
2746nc_server_config_create_ca_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
2747{
2748 assert(!strcmp(LYD_NAME(node), "certificate"));
2749
2750 node = lyd_child(node);
2751 assert(!strcmp(LYD_NAME(node), "name"));
2752
2753 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ca_certs.certs, sizeof *opts->ca_certs.certs, &opts->ca_certs.cert_count);
2754}
2755
2756static int
2757nc_server_config_create_ee_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
2758{
2759 assert(!strcmp(LYD_NAME(node), "certificate"));
2760
2761 node = lyd_child(node);
2762 assert(!strcmp(LYD_NAME(node), "name"));
2763
2764 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ee_certs.certs, sizeof *opts->ee_certs.certs, &opts->ee_certs.cert_count);
2765}
2766
2767static int
2768nc_server_config_certificate(const struct lyd_node *node, NC_OPERATION op)
2769{
2770 int ret = 0;
2771 struct nc_endpt *endpt;
2772 struct nc_asymmetric_key *key;
2773
2774 assert(!strcmp(LYD_NAME(node), "certificate"));
2775
2776 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
2777 ret = 1;
2778 goto cleanup;
2779 }
2780
2781 if ((equal_parent_name(node, 1, "keystore-reference")) && (is_listen(node))) {
2782 /* server-identity TLS listen */
2783
2784 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2785 /* set to keystore */
2786 endpt->opts.tls->store = NC_STORE_KEYSTORE;
2787
2788 if (!endpt->opts.tls->key_ref) {
2789 /* we don't have a key from which we need the cert yet */
2790 key = cert_get_asymmetric_key(node);
2791 if (!key) {
2792 ret = 1;
2793 goto cleanup;
2794 }
2795 } else {
2796 /* we have the key */
2797 key = endpt->opts.tls->key_ref;
2798 }
2799
2800 /* find the given cert in the key and set it */
2801 ret = nc_server_config_tls_create_certificate_ref(node, endpt, key);
2802 if (ret) {
2803 goto cleanup;
2804 }
2805 } else {
2806 endpt->opts.tls->cert_ref = NULL;
2807 }
2808 } else if ((equal_parent_name(node, 2, "ca-certs")) && (is_listen(node))) {
2809 /* client auth TLS listen */
2810 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2811 ret = nc_server_config_create_ca_certs_certificate(node, endpt->opts.tls);
2812 if (ret) {
2813 goto cleanup;
2814 }
2815 } else {
2816 nc_server_config_tls_del_certs(&endpt->opts.tls->ca_certs);
2817 }
2818 } else if ((equal_parent_name(node, 2, "ee-certs")) && (is_listen(node))) {
2819 /* client auth TLS listen */
2820 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2821 ret = nc_server_config_create_ee_certs_certificate(node, endpt->opts.tls);
2822 if (ret) {
2823 goto cleanup;
2824 }
2825 } else {
2826 nc_server_config_tls_del_certs(&endpt->opts.tls->ee_certs);
2827 }
2828 }
2829
2830cleanup:
2831 return ret;
2832}
2833
2834static int
2835nc_server_config_create_cert_to_name(const struct lyd_node *node, struct nc_server_tls_opts *opts)
2836{
2837 int ret = 0;
2838 struct lyd_node *n;
2839 struct nc_ctn *new, *iter;
2840 const char *map_type, *name;
2841 uint32_t id;
2842 NC_TLS_CTN_MAPTYPE m_type;
2843
2844 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
2845
2846 /* create new ctn */
2847 new = calloc(1, sizeof *new);
2848 if (!new) {
2849 ERRMEM;
2850 ret = 1;
2851 goto cleanup;
2852 }
2853
2854 /* get all the data */
2855 /* find the list's key */
2856 lyd_find_path(node, "id", 0, &n);
2857 assert(n);
2858 id = strtoul(lyd_get_value(n), NULL, 10);
2859
2860 /* find the ctn's name */
2861 lyd_find_path(node, "name", 0, &n);
2862 assert(n);
2863 name = lyd_get_value(n);
2864
2865 /* find the ctn's map-type */
2866 lyd_find_path(node, "map-type", 0, &n);
2867 assert(n);
2868 map_type = ((struct lyd_node_term *)n)->value.ident->name;
2869 if (!strcmp(map_type, "specified")) {
2870 m_type = NC_TLS_CTN_SPECIFIED;
2871 } else if (!strcmp(map_type, "san-rfc822-name")) {
2872 m_type = NC_TLS_CTN_SAN_RFC822_NAME;
2873 } else if (!strcmp(map_type, "san-dns-name")) {
2874 m_type = NC_TLS_CTN_SAN_DNS_NAME;
2875 } else if (!strcmp(map_type, "san-ip-address")) {
2876 m_type = NC_TLS_CTN_SAN_IP_ADDRESS;
2877 } else if (!strcmp(map_type, "san-any")) {
2878 m_type = NC_TLS_CTN_SAN_ANY;
2879 } else if (!strcmp(map_type, "common-name")) {
2880 m_type = NC_TLS_CTN_COMMON_NAME;
2881 } else {
2882 ERR(NULL, "Map-type identity \"%s\" not supported.", map_type);
2883 ret = 1;
2884 goto cleanup;
2885 }
2886
2887 /* find the right place for insertion */
2888 if (!opts->ctn) {
2889 /* inserting the first one */
2890 opts->ctn = new;
2891 } else if (opts->ctn->id > new->id) {
2892 /* insert at the beginning */
2893 new->next = opts->ctn;
2894 opts->ctn = new;
2895 } else {
2896 /* have to find the right place */
2897 for (iter = opts->ctn; iter->next && iter->next->id <= new->id; iter = iter->next) {}
2898 if (iter->id == new->id) {
2899 /* collision */
2900 new = iter;
2901 } else {
2902 new->next = iter->next;
2903 iter->next = new;
2904 }
2905 }
2906
2907 /* insert the right data */
2908 new->id = id;
2909 if (new->name) {
2910 free(new->name);
2911 }
2912 new->name = strdup(name);
2913 if (!new->name) {
2914 ERRMEM;
2915 ret = 1;
2916 goto cleanup;
2917 }
2918 new->map_type = m_type;
2919
2920cleanup:
2921 return ret;
2922}
2923
2924static int
2925nc_server_config_cert_to_name(const struct lyd_node *node, NC_OPERATION op)
2926{
2927 int ret = 0;
2928 struct nc_endpt *endpt;
2929 struct lyd_node *key;
2930 struct nc_ctn *ctn;
2931
2932 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
2933
2934 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
2935 ret = 1;
2936 goto cleanup;
2937 }
2938
2939 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2940 ret = nc_server_config_create_cert_to_name(node, endpt->opts.tls);
2941 if (ret) {
2942 goto cleanup;
2943 }
2944 } else {
2945 /* find the given ctn entry */
2946 lyd_find_path(node, "id", 0, &key);
2947 assert(key);
2948 if (nc_server_config_get_ctn(node, endpt, &ctn)) {
2949 ret = 1;
2950 goto cleanup;
2951 }
2952 nc_server_config_del_ctn(endpt->opts.tls, ctn);
2953 }
2954
2955cleanup:
2956 return ret;
2957}
2958
2959static int
2960nc_server_config_replace_fingerprint(const struct lyd_node *node, struct nc_ctn *ctn)
2961{
2962 nc_server_config_del_fingerprint(ctn);
2963
2964 ctn->fingerprint = strdup(lyd_get_value(node));
2965 if (!ctn->fingerprint) {
2966 ERRMEM;
2967 return 1;
2968 }
2969
2970 return 0;
2971}
2972
2973static int
2974nc_server_config_fingerprint(const struct lyd_node *node, NC_OPERATION op)
2975{
2976 int ret = 0;
2977 struct nc_endpt *endpt;
2978 struct nc_ctn *ctn;
2979
2980 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
2981 ret = 1;
2982 goto cleanup;
2983 }
2984
2985 if (nc_server_config_get_ctn(node, endpt, &ctn)) {
2986 ret = 1;
2987 goto cleanup;
2988 }
2989
2990 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2991 ret = nc_server_config_replace_fingerprint(node, ctn);
2992 if (ret) {
2993 goto cleanup;
2994 }
2995 } else {
2996 nc_server_config_del_fingerprint(ctn);
2997 }
2998
2999cleanup:
3000 return ret;
3001}
3002
roman2eab4742023-06-06 10:00:26 +02003003#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02003004
roman83683fb2023-02-24 09:15:23 +01003005static int
romanf02273a2023-05-25 09:44:11 +02003006nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01003007{
3008 const char *name = LYD_NAME(node);
3009
3010 if (!strcmp(name, "listen")) {
romanf02273a2023-05-25 09:44:11 +02003011 if (nc_server_config_listen(NULL, op)) {
romanc1d2b092023-02-02 08:58:27 +01003012 goto error;
3013 }
3014 } else if (!strcmp(name, "idle-timeout")) {
romane028ef92023-02-24 16:33:08 +01003015 if (nc_server_config_idle_timeout(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003016 goto error;
3017 }
3018 } else if (!strcmp(name, "endpoint")) {
romane028ef92023-02-24 16:33:08 +01003019 if (nc_server_config_endpoint(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003020 goto error;
3021 }
roman2eab4742023-06-06 10:00:26 +02003022 } else if (!strcmp(name, "unix-socket")) {
3023 if (nc_server_config_unix_socket(node, op)) {
3024 goto error;
3025 }
roman3f9b65c2023-06-05 14:26:58 +02003026 }
roman2eab4742023-06-06 10:00:26 +02003027#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02003028 else if (!strcmp(name, "ssh")) {
romane028ef92023-02-24 16:33:08 +01003029 if (nc_server_config_ssh(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003030 goto error;
3031 }
roman2eab4742023-06-06 10:00:26 +02003032 } else if (!strcmp(name, "local-address")) {
romane028ef92023-02-24 16:33:08 +01003033 if (nc_server_config_local_address(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003034 goto error;
3035 }
3036 } else if (!strcmp(name, "local-port")) {
romane028ef92023-02-24 16:33:08 +01003037 if (nc_server_config_local_port(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003038 goto error;
3039 }
3040 } else if (!strcmp(name, "keepalives")) {
romane028ef92023-02-24 16:33:08 +01003041 if (nc_server_config_keepalives(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003042 goto error;
3043 }
3044 } else if (!strcmp(name, "idle-time")) {
romane028ef92023-02-24 16:33:08 +01003045 if (nc_server_config_idle_time(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003046 goto error;
3047 }
3048 } else if (!strcmp(name, "max-probes")) {
romane028ef92023-02-24 16:33:08 +01003049 if (nc_server_config_max_probes(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003050 goto error;
3051 }
3052 } else if (!strcmp(name, "probe-interval")) {
romane028ef92023-02-24 16:33:08 +01003053 if (nc_server_config_probe_interval(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003054 goto error;
3055 }
roman2eab4742023-06-06 10:00:26 +02003056 } else if (!strcmp(name, "host-key")) {
romane028ef92023-02-24 16:33:08 +01003057 if (nc_server_config_host_key(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003058 goto error;
3059 }
roman2eab4742023-06-06 10:00:26 +02003060 } else if (!strcmp(name, "public-key-format")) {
romane028ef92023-02-24 16:33:08 +01003061 if (nc_server_config_public_key_format(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003062 goto error;
3063 }
3064 } else if (!strcmp(name, "public-key")) {
romane028ef92023-02-24 16:33:08 +01003065 if (nc_server_config_public_key(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003066 goto error;
3067 }
3068 } else if (!strcmp(name, "private-key-format")) {
romane028ef92023-02-24 16:33:08 +01003069 if (nc_server_config_private_key_format(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003070 goto error;
3071 }
3072 } else if (!strcmp(name, "cleartext-private-key")) {
romane028ef92023-02-24 16:33:08 +01003073 if (nc_server_config_cleartext_private_key(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003074 goto error;
3075 }
roman2eab4742023-06-06 10:00:26 +02003076 } else if (!strcmp(name, "keystore-reference")) {
romane028ef92023-02-24 16:33:08 +01003077 if (nc_server_config_keystore_reference(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003078 goto error;
3079 }
3080 } else if (!strcmp(name, "user")) {
romane028ef92023-02-24 16:33:08 +01003081 if (nc_server_config_user(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003082 goto error;
3083 }
3084 } else if (!strcmp(name, "auth-attempts")) {
romane028ef92023-02-24 16:33:08 +01003085 if (nc_server_config_auth_attempts(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003086 goto error;
3087 }
3088 } else if (!strcmp(name, "auth-timeout")) {
romane028ef92023-02-24 16:33:08 +01003089 if (nc_server_config_auth_timeout(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003090 goto error;
3091 }
roman2eab4742023-06-06 10:00:26 +02003092 } else if (!strcmp(name, "truststore-reference")) {
romane028ef92023-02-24 16:33:08 +01003093 if (nc_server_config_truststore_reference(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003094 goto error;
3095 }
roman2eab4742023-06-06 10:00:26 +02003096 } else if (!strcmp(name, "password")) {
romane028ef92023-02-24 16:33:08 +01003097 if (nc_server_config_password(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003098 goto error;
3099 }
3100 } else if (!strcmp(name, "pam-config-file-name")) {
romane028ef92023-02-24 16:33:08 +01003101 if (nc_server_config_pam_name(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003102 goto error;
3103 }
3104 } else if (!strcmp(name, "pam-config-file-dir")) {
romane028ef92023-02-24 16:33:08 +01003105 if (nc_server_config_pam_dir(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003106 goto error;
3107 }
3108 } else if (!strcmp(name, "none")) {
romane028ef92023-02-24 16:33:08 +01003109 if (nc_server_config_none(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003110 goto error;
3111 }
3112 } else if (!strcmp(name, "host-key-alg")) {
romane028ef92023-02-24 16:33:08 +01003113 if (nc_server_config_host_key_alg(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003114 goto error;
3115 }
3116 } else if (!strcmp(name, "key-exchange-alg")) {
romane028ef92023-02-24 16:33:08 +01003117 if (nc_server_config_kex_alg(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003118 goto error;
3119 }
3120 } else if (!strcmp(name, "encryption-alg")) {
romane028ef92023-02-24 16:33:08 +01003121 if (nc_server_config_encryption_alg(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003122 goto error;
3123 }
3124 } else if (!strcmp(name, "mac-alg")) {
romane028ef92023-02-24 16:33:08 +01003125 if (nc_server_config_mac_alg(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003126 goto error;
3127 }
roman2eab4742023-06-06 10:00:26 +02003128 } else if (!strcmp(name, "endpoint-client-auth")) {
roman0bbc19c2023-05-26 09:59:09 +02003129 if (nc_server_config_endpoint_client_auth(node, op)) {
3130 goto error;
3131 }
roman2eab4742023-06-06 10:00:26 +02003132 } else if (!strcmp(name, "tls")) {
roman3f9b65c2023-06-05 14:26:58 +02003133 if (nc_server_config_tls(node, op)) {
3134 goto error;
3135 }
3136 } else if (!strcmp(name, "cert-data")) {
3137 if (nc_server_config_cert_data(node, op)) {
3138 goto error;
3139 }
3140 } else if (!strcmp(name, "asymmetric-key")) {
3141 if (nc_server_config_asymmetric_key(node, op)) {
3142 goto error;
3143 }
3144 } else if (!strcmp(name, "certificate")) {
3145 if (nc_server_config_certificate(node, op)) {
3146 goto error;
3147 }
3148 } else if (!strcmp(name, "cert-to-name")) {
3149 if (nc_server_config_cert_to_name(node, op)) {
3150 goto error;
3151 }
3152 } else if (!strcmp(name, "fingerprint")) {
3153 if (nc_server_config_fingerprint(node, op)) {
3154 goto error;
3155 }
3156 }
roman2eab4742023-06-06 10:00:26 +02003157#endif /* NC_ENABLED_SSH_TLS */
romanc1d2b092023-02-02 08:58:27 +01003158
3159 return 0;
3160
3161error:
3162 ERR(NULL, "Configuring (%s) failed.", LYD_NAME(node));
3163 return 1;
3164}
3165
3166int
roman0bbc19c2023-05-26 09:59:09 +02003167nc_server_config_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, NC_MODULE module)
romanc1d2b092023-02-02 08:58:27 +01003168{
3169 struct lyd_node *child;
3170 struct lyd_meta *m;
romanf9906b42023-05-22 14:04:29 +02003171 NC_OPERATION current_op = NC_OP_UNKNOWN;
romanf02273a2023-05-25 09:44:11 +02003172 int ret;
romanc1d2b092023-02-02 08:58:27 +01003173
3174 assert(node);
3175
romanf9906b42023-05-22 14:04:29 +02003176 /* get current op if there is any */
3177 if ((m = lyd_find_meta(node->meta, NULL, "yang:operation"))) {
3178 if (!strcmp(lyd_get_meta_value(m), "create")) {
3179 current_op = NC_OP_CREATE;
3180 } else if (!strcmp(lyd_get_meta_value(m), "delete")) {
3181 current_op = NC_OP_DELETE;
3182 } else if (!strcmp(lyd_get_meta_value(m), "replace")) {
3183 current_op = NC_OP_REPLACE;
3184 } else if (!strcmp(lyd_get_meta_value(m), "none")) {
3185 current_op = NC_OP_NONE;
romanc1d2b092023-02-02 08:58:27 +01003186 }
3187 }
3188
3189 /* node has no op, inherit from the parent */
romanf9906b42023-05-22 14:04:29 +02003190 if (!current_op) {
3191 if (!parent_op) {
3192 ERR(NULL, "Unknown operation for node \"%s\".", LYD_NAME(node));
3193 return 1;
3194 }
3195
romanc1d2b092023-02-02 08:58:27 +01003196 current_op = parent_op;
3197 }
3198
3199 switch (current_op) {
3200 case NC_OP_NONE:
3201 break;
3202 case NC_OP_CREATE:
3203 case NC_OP_DELETE:
3204 case NC_OP_REPLACE:
roman2eab4742023-06-06 10:00:26 +02003205#ifdef NC_ENABLED_SSH_TLS
3206 if (module == NC_MODULE_KEYSTORE) {
romanf02273a2023-05-25 09:44:11 +02003207 ret = nc_server_config_parse_keystore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02003208 } else if (module == NC_MODULE_TRUSTSTORE) {
romanf02273a2023-05-25 09:44:11 +02003209 ret = nc_server_config_parse_truststore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02003210 } else
3211#endif /* NC_ENABLED_SSH_TLS */
3212 {
3213 ret = nc_server_config_parse_netconf_server(node, current_op);
romanf02273a2023-05-25 09:44:11 +02003214 }
3215 if (ret) {
3216 return ret;
romanc1d2b092023-02-02 08:58:27 +01003217 }
3218 break;
3219 default:
3220 break;
3221 }
3222
3223 if (current_op != NC_OP_DELETE) {
3224 LY_LIST_FOR(lyd_child(node), child) {
roman0bbc19c2023-05-26 09:59:09 +02003225 if (nc_server_config_parse_tree(child, current_op, module)) {
romanc1d2b092023-02-02 08:58:27 +01003226 return 1;
3227 }
3228 }
3229 }
3230 return 0;
3231}
3232
romanc1d2b092023-02-02 08:58:27 +01003233API int
3234nc_server_config_load_modules(struct ly_ctx **ctx)
3235{
3236 int i, new_ctx = 0;
3237
3238 if (!*ctx) {
3239 if (ly_ctx_new(NC_SERVER_SEARCH_DIR, 0, ctx)) {
3240 ERR(NULL, "Couldn't create new libyang context.\n");
3241 goto error;
3242 }
3243 new_ctx = 1;
3244 }
3245
3246 /* all features */
3247 const char *ietf_nectonf_server[] = {"ssh-listen", "tls-listen", "ssh-call-home", "tls-call-home", "central-netconf-server-supported", NULL};
3248 /* all features */
3249 const char *ietf_x509_cert_to_name[] = {NULL};
3250 /* no private-key-encryption and csr-generation */
3251 const char *ietf_crypto_types[] = {
3252 "one-symmetric-key-format", "one-asymmetric-key-format", "symmetrically-encrypted-value-format",
3253 "asymmetrically-encrypted-value-format", "cms-enveloped-data-format", "cms-encrypted-data-format",
3254 "p10-based-csrs", "certificate-expiration-notification", "hidden-keys", "password-encryption",
3255 "symmetric-key-encryption", NULL
3256 };
3257 /* all features */
3258 const char *ietf_tcp_common[] = {"keepalives-supported", NULL};
3259 /* no ssh-x509-certs */
3260 const char *ietf_ssh_common[] = {"transport-params", "public-key-generation", NULL};
3261 /* all features */
3262 const char *iana_ssh_encryption_algs[] = {NULL};
3263 /* all features */
3264 const char *iana_ssh_key_exchange_algs[] = {NULL};
3265 /* all features */
3266 const char *iana_ssh_mac_algs[] = {NULL};
3267 /* all features */
3268 const char *iana_ssh_public_key_algs[] = {NULL};
romanf02273a2023-05-25 09:44:11 +02003269 /* no symmetric-keys */
3270 const char *ietf_keystore[] = {"central-keystore-supported", "local-definitions-supported", "asymmetric-keys", NULL};
romanc1d2b092023-02-02 08:58:27 +01003271 /* no ssh-server-keepalives and local-user-auth-hostbased */
3272 const char *ietf_ssh_server[] = {"local-users-supported", "local-user-auth-publickey", "local-user-auth-password", "local-user-auth-none", NULL};
3273 /* all features */
3274 const char *ietf_truststore[] = {"central-truststore-supported", "local-definitions-supported", "certificates", "public-keys", NULL};
3275 /* all features */
3276 const char *ietf_tls_server[] = {
3277 "tls-server-keepalives", "server-ident-x509-cert", "server-ident-raw-public-key", "server-ident-tls12-psk",
3278 "server-ident-tls13-epsk", "client-auth-supported", "client-auth-x509-cert", "client-auth-raw-public-key",
3279 "client-auth-tls12-psk", "client-auth-tls13-epsk", NULL
3280 };
3281 /* all features */
3282 const char *libnetconf2_netconf_server[] = {NULL};
3283
3284 const char *module_names[] = {
3285 "ietf-netconf-server", "ietf-x509-cert-to-name", "ietf-crypto-types",
3286 "ietf-tcp-common", "ietf-ssh-common", "iana-ssh-encryption-algs",
3287 "iana-ssh-key-exchange-algs", "iana-ssh-mac-algs", "iana-ssh-public-key-algs",
3288 "ietf-keystore", "ietf-ssh-server", "ietf-truststore",
3289 "ietf-tls-server", "libnetconf2-netconf-server", NULL
3290 };
3291
3292 const char **module_features[] = {
3293 ietf_nectonf_server, ietf_x509_cert_to_name, ietf_crypto_types,
3294 ietf_tcp_common, ietf_ssh_common, iana_ssh_encryption_algs,
3295 iana_ssh_key_exchange_algs, iana_ssh_mac_algs, iana_ssh_public_key_algs,
3296 ietf_keystore, ietf_ssh_server, ietf_truststore,
3297 ietf_tls_server, libnetconf2_netconf_server, NULL
3298 };
3299
3300 for (i = 0; module_names[i] != NULL; i++) {
3301 if (!ly_ctx_load_module(*ctx, module_names[i], NULL, module_features[i])) {
3302 ERR(NULL, "Loading module \"%s\" failed.\n", module_names[i]);
3303 goto error;
3304 }
3305 }
3306
3307 return 0;
3308
3309error:
3310 if (new_ctx) {
3311 ly_ctx_destroy(*ctx);
3312 *ctx = NULL;
3313 }
3314 return 1;
3315}
3316
romanf9906b42023-05-22 14:04:29 +02003317static int
3318nc_server_config_fill_nectonf_server(const struct lyd_node *data, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01003319{
3320 int ret = 0;
3321 struct lyd_node *tree;
romand57b3722023-04-05 11:26:25 +02003322
romanc1d2b092023-02-02 08:58:27 +01003323 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &tree);
3324 if (ret) {
3325 ERR(NULL, "Unable to find the netconf-server container in the YANG data.");
3326 goto cleanup;
3327 }
3328
roman0bbc19c2023-05-26 09:59:09 +02003329 if (nc_server_config_parse_tree(tree, op, NC_MODULE_NETCONF_SERVER)) {
3330 ret = 1;
3331 goto cleanup;
3332 }
3333
roman2eab4742023-06-06 10:00:26 +02003334#ifdef NC_ENABLED_SSH_TLS
3335 /* backward check of client auth reference */
roman0bbc19c2023-05-26 09:59:09 +02003336 if (nc_server_config_fill_endpt_client_auth()) {
romanf9906b42023-05-22 14:04:29 +02003337 ret = 1;
3338 goto cleanup;
3339 }
roman2eab4742023-06-06 10:00:26 +02003340#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02003341
3342cleanup:
3343 return ret;
3344}
3345
3346API int
romanf6f37a52023-05-25 14:27:51 +02003347nc_server_config_setup_diff(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02003348{
3349 int ret = 0;
3350
3351 /* LOCK */
3352 pthread_rwlock_wrlock(&server_opts.config_lock);
3353
roman2eab4742023-06-06 10:00:26 +02003354#ifdef NC_ENABLED_SSH_TLS
romanf9906b42023-05-22 14:04:29 +02003355 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02003356 ret = nc_server_config_fill_keystore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02003357 if (ret) {
3358 ERR(NULL, "Filling keystore failed.");
3359 goto cleanup;
3360 }
3361
3362 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02003363 ret = nc_server_config_fill_truststore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02003364 if (ret) {
3365 ERR(NULL, "Filling truststore failed.");
3366 goto cleanup;
3367 }
roman2eab4742023-06-06 10:00:26 +02003368#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02003369
3370 /* configure netconf-server */
3371 ret = nc_server_config_fill_nectonf_server(data, NC_OP_UNKNOWN);
3372 if (ret) {
3373 ERR(NULL, "Filling netconf-server failed.");
3374 goto cleanup;
3375 }
3376
3377cleanup:
3378 /* UNLOCK */
3379 pthread_rwlock_unlock(&server_opts.config_lock);
3380 return ret;
3381}
3382
3383API int
romanf6f37a52023-05-25 14:27:51 +02003384nc_server_config_setup_data(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02003385{
3386 int ret = 0;
3387 struct lyd_node *tree, *iter, *root;
3388
3389 /* LOCK */
3390 pthread_rwlock_wrlock(&server_opts.config_lock);
3391
3392 /* find the netconf-server node */
3393 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &root);
3394 if (ret) {
3395 ERR(NULL, "Unable to find the netconf-server container in the YANG data.");
3396 goto cleanup;
3397 }
3398
3399 /* iterate through all the nodes and make sure there is no operation attribute */
3400 LY_LIST_FOR(root, tree) {
3401 LYD_TREE_DFS_BEGIN(tree, iter) {
3402 if (lyd_find_meta(iter->meta, NULL, "yang:operation")) {
3403 ERR(NULL, "Unexpected operation attribute in the YANG data.");
romanc1d2b092023-02-02 08:58:27 +01003404 ret = 1;
3405 goto cleanup;
3406 }
romanf9906b42023-05-22 14:04:29 +02003407 LYD_TREE_DFS_END(tree, iter);
romanc1d2b092023-02-02 08:58:27 +01003408 }
3409 }
3410
romanf9906b42023-05-22 14:04:29 +02003411 /* delete the current configuration */
romanf02273a2023-05-25 09:44:11 +02003412 nc_server_config_listen(NULL, NC_OP_DELETE);
roman2eab4742023-06-06 10:00:26 +02003413#ifdef NC_ENABLED_SSH_TLS
romanf02273a2023-05-25 09:44:11 +02003414 nc_server_config_ks_keystore(NULL, NC_OP_DELETE);
3415 nc_server_config_ts_truststore(NULL, NC_OP_DELETE);
romanf9906b42023-05-22 14:04:29 +02003416
3417 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02003418 ret = nc_server_config_fill_keystore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02003419 if (ret) {
3420 ERR(NULL, "Filling keystore failed.");
3421 goto cleanup;
3422 }
3423
3424 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02003425 ret = nc_server_config_fill_truststore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02003426 if (ret) {
3427 ERR(NULL, "Filling truststore failed.");
3428 goto cleanup;
3429 }
roman2eab4742023-06-06 10:00:26 +02003430#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02003431
3432 /* configure netconf-server */
3433 ret = nc_server_config_fill_nectonf_server(data, NC_OP_CREATE);
3434 if (ret) {
3435 ERR(NULL, "Filling netconf-server failed.");
romanc1d2b092023-02-02 08:58:27 +01003436 goto cleanup;
3437 }
3438
3439cleanup:
3440 /* UNLOCK */
3441 pthread_rwlock_unlock(&server_opts.config_lock);
3442 return ret;
3443}
roman3f9b65c2023-06-05 14:26:58 +02003444
3445API int
3446nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path)
3447{
3448 struct lyd_node *tree = NULL;
3449 int ret = 0;
3450
3451 NC_CHECK_ARG_RET(NULL, path, 1);
3452
3453 ret = lyd_parse_data_path(ctx, path, LYD_UNKNOWN, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree);
3454 if (ret) {
3455 goto cleanup;
3456 }
3457
3458 ret = nc_server_config_setup_data(tree);
3459 if (ret) {
3460 goto cleanup;
3461 }
3462
3463cleanup:
3464 lyd_free_all(tree);
3465 return ret;
3466}