blob: 4182cbd727d6cb80fa56cc340c6c2ba14c662f50 [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
romanf02273a2023-05-25 09:44:11 +0200326int
327nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uint16_t *count)
328{
329 int ret = 0;
330 void *tmp;
331 char **name;
332
333 tmp = realloc(*ptr, (*count + 1) * size);
334 if (!tmp) {
335 ERRMEM;
336 ret = 1;
337 goto cleanup;
338 }
339 *ptr = tmp;
340
341 /* set the newly allocated memory to 0 */
342 memset((char *)(*ptr) + (*count * size), 0, size);
343 (*count)++;
344
345 /* access the first member of the supposed structure */
346 name = (char **)((*ptr) + ((*count - 1) * size));
347
348 /* and set it's value */
349 *name = strdup(key_value);
350 if (!*name) {
351 ERRMEM;
352 ret = 1;
353 goto cleanup;
354 }
355
356cleanup:
357 return ret;
358}
359
roman2eab4742023-06-06 10:00:26 +0200360#ifdef NC_ENABLED_SSH_TLS
361
roman3f9b65c2023-06-05 14:26:58 +0200362static int
363is_listen(const struct lyd_node *node)
364{
365 assert(node);
366
367 while (node) {
368 if (!strcmp(LYD_NAME(node), "listen")) {
369 break;
370 }
371 node = lyd_parent(node);
372 }
373
374 return node != NULL;
375}
376
377// static int
378// is_ch(const struct lyd_node *node)
379// {
380// assert(node);
381
382// while (node) {
383// if (!strcmp(LYD_NAME(node), "call-home")) {
384// break;
385// }
386// node = lyd_parent(node);
387// }
388
389// return node != NULL;
390// }
391
roman3f9b65c2023-06-05 14:26:58 +0200392static int
393is_ssh(const struct lyd_node *node)
394{
395 assert(node);
396
397 while (node) {
398 if (!strcmp(LYD_NAME(node), "ssh")) {
399 break;
400 }
401 node = lyd_parent(node);
402 }
403
404 return node != NULL;
405}
406
roman3f9b65c2023-06-05 14:26:58 +0200407static int
408is_tls(const struct lyd_node *node)
409{
410 assert(node);
411
412 while (node) {
413 if (!strcmp(LYD_NAME(node), "tls")) {
414 break;
415 }
416 node = lyd_parent(node);
417 }
418
419 return node != NULL;
420}
421
roman2eab4742023-06-06 10:00:26 +0200422#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200423
424static void
425nc_server_config_del_endpt_name(struct nc_endpt *endpt)
426{
427 free(endpt->name);
428 endpt->name = NULL;
429}
430
roman2eab4742023-06-06 10:00:26 +0200431#ifdef NC_ENABLED_SSH_TLS
432
roman3f9b65c2023-06-05 14:26:58 +0200433static void
434nc_server_config_del_local_address(struct nc_bind *bind)
435{
436 free(bind->address);
437 bind->address = NULL;
438}
439
romanc1d2b092023-02-02 08:58:27 +0100440static void
roman874fed12023-05-25 10:20:01 +0200441nc_server_config_del_auth_client_pam_name(struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100442{
443 free(auth_client->pam_config_name);
444 auth_client->pam_config_name = NULL;
445}
446
447static void
roman874fed12023-05-25 10:20:01 +0200448nc_server_config_del_auth_client_pam_dir(struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100449{
450 free(auth_client->pam_config_dir);
451 auth_client->pam_config_dir = NULL;
452}
453
454static void
roman0bbc19c2023-05-26 09:59:09 +0200455nc_server_config_del_endpt_reference(struct nc_endpt *endpt)
456{
457 free(endpt->referenced_endpt_name);
458 endpt->referenced_endpt_name = NULL;
459}
460
461static void
roman874fed12023-05-25 10:20:01 +0200462nc_server_config_del_hostkey_name(struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100463{
464 free(hostkey->name);
465 hostkey->name = NULL;
466}
467
468static void
roman874fed12023-05-25 10:20:01 +0200469nc_server_config_del_public_key(struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100470{
roman3f9b65c2023-06-05 14:26:58 +0200471 free(hostkey->key.pubkey_data);
472 hostkey->key.pubkey_data = NULL;
romanc1d2b092023-02-02 08:58:27 +0100473}
474
475static void
roman874fed12023-05-25 10:20:01 +0200476nc_server_config_del_private_key(struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100477{
roman3f9b65c2023-06-05 14:26:58 +0200478 free(hostkey->key.privkey_data);
479 hostkey->key.privkey_data = NULL;
romanc1d2b092023-02-02 08:58:27 +0100480}
481
482static void
roman874fed12023-05-25 10:20:01 +0200483nc_server_config_del_auth_client_username(struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100484{
485 free(auth_client->username);
486 auth_client->username = NULL;
487}
488
489static void
roman874fed12023-05-25 10:20:01 +0200490nc_server_config_del_auth_client_pubkey_name(struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +0100491{
492 free(pubkey->name);
493 pubkey->name = NULL;
494}
495
496static void
roman874fed12023-05-25 10:20:01 +0200497nc_server_config_del_auth_client_pubkey_pub_base64(struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +0100498{
roman3f9b65c2023-06-05 14:26:58 +0200499 free(pubkey->data);
500 pubkey->data = NULL;
romanc1d2b092023-02-02 08:58:27 +0100501}
502
503static void
roman874fed12023-05-25 10:20:01 +0200504nc_server_config_del_auth_client_password(struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100505{
506 free(auth_client->password);
507 auth_client->password = NULL;
508}
509
510static void
roman874fed12023-05-25 10:20:01 +0200511nc_server_config_del_hostkey_algs(struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100512{
513 free(opts->hostkey_algs);
514 opts->hostkey_algs = NULL;
515}
516
517static void
roman874fed12023-05-25 10:20:01 +0200518nc_server_config_del_kex_algs(struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100519{
520 free(opts->kex_algs);
521 opts->kex_algs = NULL;
522}
523
524static void
roman874fed12023-05-25 10:20:01 +0200525nc_server_config_del_encryption_algs(struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100526{
527 free(opts->encryption_algs);
528 opts->encryption_algs = NULL;
529}
530
531static void
roman874fed12023-05-25 10:20:01 +0200532nc_server_config_del_mac_algs(struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100533{
534 free(opts->mac_algs);
535 opts->mac_algs = NULL;
536}
537
538static void
roman874fed12023-05-25 10:20:01 +0200539nc_server_config_del_hostkey(struct nc_server_ssh_opts *opts, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100540{
roman874fed12023-05-25 10:20:01 +0200541 assert(hostkey->store == NC_STORE_LOCAL || hostkey->store == NC_STORE_KEYSTORE);
romanc1d2b092023-02-02 08:58:27 +0100542
roman874fed12023-05-25 10:20:01 +0200543 if (hostkey->store == NC_STORE_LOCAL) {
544 nc_server_config_del_public_key(hostkey);
545 nc_server_config_del_private_key(hostkey);
romanc1d2b092023-02-02 08:58:27 +0100546 }
547
roman874fed12023-05-25 10:20:01 +0200548 nc_server_config_del_hostkey_name(hostkey);
romanc1d2b092023-02-02 08:58:27 +0100549 opts->hostkey_count--;
550 if (!opts->hostkey_count) {
551 free(opts->hostkeys);
552 opts->hostkeys = NULL;
553 }
554}
555
556static void
roman874fed12023-05-25 10:20:01 +0200557nc_server_config_del_auth_client_pubkey(struct nc_client_auth *auth_client, struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +0100558{
roman874fed12023-05-25 10:20:01 +0200559 nc_server_config_del_auth_client_pubkey_name(pubkey);
560 nc_server_config_del_auth_client_pubkey_pub_base64(pubkey);
romanc1d2b092023-02-02 08:58:27 +0100561
562 auth_client->pubkey_count--;
563 if (!auth_client->pubkey_count) {
564 free(auth_client->pubkeys);
565 auth_client->pubkeys = NULL;
566 }
567}
568
569static void
roman874fed12023-05-25 10:20:01 +0200570nc_server_config_del_auth_client(struct nc_server_ssh_opts *opts, struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100571{
572 uint16_t i, pubkey_count;
573
roman874fed12023-05-25 10:20:01 +0200574 if (auth_client->store == NC_STORE_LOCAL) {
romanc1d2b092023-02-02 08:58:27 +0100575 pubkey_count = auth_client->pubkey_count;
576 for (i = 0; i < pubkey_count; i++) {
roman874fed12023-05-25 10:20:01 +0200577 nc_server_config_del_auth_client_pubkey(auth_client, &auth_client->pubkeys[i]);
romanc1d2b092023-02-02 08:58:27 +0100578 }
romanc1d2b092023-02-02 08:58:27 +0100579 }
580
roman874fed12023-05-25 10:20:01 +0200581 nc_server_config_del_auth_client_password(auth_client);
582 nc_server_config_del_auth_client_pam_name(auth_client);
583 nc_server_config_del_auth_client_pam_dir(auth_client);
584 nc_server_config_del_auth_client_username(auth_client);
romanc1d2b092023-02-02 08:58:27 +0100585
586 opts->client_count--;
587 if (!opts->client_count) {
588 free(opts->auth_clients);
589 opts->auth_clients = NULL;
590 }
591}
592
593static void
roman874fed12023-05-25 10:20:01 +0200594nc_server_config_del_ssh(struct nc_bind *bind, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100595{
596 uint16_t i, hostkey_count, client_count;
597
roman874fed12023-05-25 10:20:01 +0200598 nc_server_config_del_local_address(bind);
romanc1d2b092023-02-02 08:58:27 +0100599 if (bind->sock > -1) {
600 close(bind->sock);
601 }
602
603 /* store in variable because it gets decremented in the function call */
604 hostkey_count = opts->hostkey_count;
605 for (i = 0; i < hostkey_count; i++) {
roman874fed12023-05-25 10:20:01 +0200606 nc_server_config_del_hostkey(opts, &opts->hostkeys[i]);
romanc1d2b092023-02-02 08:58:27 +0100607 }
608
609 client_count = opts->client_count;
610 for (i = 0; i < client_count; i++) {
roman874fed12023-05-25 10:20:01 +0200611 nc_server_config_del_auth_client(opts, &opts->auth_clients[i]);
romanc1d2b092023-02-02 08:58:27 +0100612 }
613
roman874fed12023-05-25 10:20:01 +0200614 nc_server_config_del_hostkey_algs(opts);
615 nc_server_config_del_kex_algs(opts);
616 nc_server_config_del_encryption_algs(opts);
617 nc_server_config_del_mac_algs(opts);
romanc1d2b092023-02-02 08:58:27 +0100618
619 free(opts);
620 opts = NULL;
621}
622
623void
roman874fed12023-05-25 10:20:01 +0200624nc_server_config_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind)
romanc1d2b092023-02-02 08:58:27 +0100625{
roman874fed12023-05-25 10:20:01 +0200626 nc_server_config_del_endpt_name(endpt);
roman0bbc19c2023-05-26 09:59:09 +0200627 nc_server_config_del_endpt_reference(endpt);
roman874fed12023-05-25 10:20:01 +0200628 nc_server_config_del_ssh(bind, endpt->opts.ssh);
romanc1d2b092023-02-02 08:58:27 +0100629
630 server_opts.endpt_count--;
631 if (!server_opts.endpt_count) {
632 free(server_opts.endpts);
633 free(server_opts.binds);
634 server_opts.endpts = NULL;
635 server_opts.binds = NULL;
636 }
637}
638
roman2eab4742023-06-06 10:00:26 +0200639#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200640
roman45cec4e2023-02-17 10:21:39 +0100641void
roman874fed12023-05-25 10:20:01 +0200642nc_server_config_del_unix_socket(struct nc_bind *bind, struct nc_server_unix_opts *opts)
roman83683fb2023-02-24 09:15:23 +0100643{
644 if (bind->sock > -1) {
645 close(bind->sock);
646 }
647
648 free(bind->address);
649 free(opts->address);
650
651 free(opts);
roman83683fb2023-02-24 09:15:23 +0100652}
653
654void
roman874fed12023-05-25 10:20:01 +0200655nc_server_config_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *bind)
roman83683fb2023-02-24 09:15:23 +0100656{
roman874fed12023-05-25 10:20:01 +0200657 nc_server_config_del_endpt_name(endpt);
658 nc_server_config_del_unix_socket(bind, endpt->opts.unixsock);
roman83683fb2023-02-24 09:15:23 +0100659
660 server_opts.endpt_count--;
661 if (!server_opts.endpt_count) {
662 free(server_opts.endpts);
663 free(server_opts.binds);
664 server_opts.endpts = NULL;
665 server_opts.binds = NULL;
666 }
667}
668
roman2eab4742023-06-06 10:00:26 +0200669#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +0200670
671static void
672nc_server_config_tls_del_public_key(struct nc_server_tls_opts *opts)
673{
674 free(opts->pubkey_data);
675 opts->pubkey_data = NULL;
676}
677
678static void
679nc_server_config_tls_del_cleartext_private_key(struct nc_server_tls_opts *opts)
680{
681 free(opts->privkey_data);
682 opts->privkey_data = NULL;
683}
684
685static void
686nc_server_config_tls_del_cert_data(struct nc_server_tls_opts *opts)
687{
688 free(opts->cert_data);
689 opts->cert_data = NULL;
690}
691
692static void
693nc_server_config_tls_del_cert_data_certificate(struct nc_certificate *cert)
694{
695 free(cert->data);
696 cert->data = NULL;
697}
698
699static void
700nc_server_config_del_fingerprint(struct nc_ctn *ctn)
701{
702 free(ctn->fingerprint);
703 ctn->fingerprint = NULL;
704}
705
706static void
707nc_server_config_del_cert(struct nc_cert_grouping *certs, struct nc_certificate *cert)
708{
709 free(cert->name);
710 cert->name = NULL;
711
712 free(cert->data);
713 cert->data = NULL;
714
715 certs->cert_count--;
716 if (!certs->cert_count) {
717 free(certs->certs);
718 certs->certs = NULL;
719 }
720}
721
722static void
723nc_server_config_tls_del_certs(struct nc_cert_grouping *ca)
724{
725 uint16_t i, cert_count;
726
727 if (ca->store == NC_STORE_LOCAL) {
728 cert_count = ca->cert_count;
729 for (i = 0; i < cert_count; i++) {
730 nc_server_config_del_cert(ca, &ca->certs[i]);
731 }
732 }
733}
734
735static void
736nc_server_config_del_ctn(struct nc_server_tls_opts *opts, struct nc_ctn *ctn)
737{
738 struct nc_ctn *iter;
739
740 free(ctn->fingerprint);
741 ctn->fingerprint = NULL;
742
743 free(ctn->name);
744 ctn->name = NULL;
745
746 if (opts->ctn == ctn) {
747 /* it's the first in the list */
748 opts->ctn = ctn->next;
749 free(ctn);
750 return;
751 }
752
753 iter = opts->ctn;
754 while (iter) {
755 if (iter->next == ctn) {
756 /* found the ctn */
757 break;
758 }
759 iter = iter->next;
760 }
761
762 iter->next = ctn->next;
763 free(ctn);
764}
765
766static void
767nc_server_config_del_ctns(struct nc_server_tls_opts *opts)
768{
769 struct nc_ctn *cur, *next;
770
771 cur = opts->ctn;
772 while (cur) {
773 next = cur->next;
774 free(cur->fingerprint);
775 free(cur->name);
776 free(cur);
777 cur = next;
778 }
779 opts->ctn = NULL;
780}
781
782static void
783nc_server_config_del_tls(struct nc_bind *bind, struct nc_server_tls_opts *opts)
784{
785 nc_server_config_del_local_address(bind);
786 if (bind->sock > -1) {
787 close(bind->sock);
788 }
789
790 if (opts->store == NC_STORE_LOCAL) {
791 nc_server_config_tls_del_public_key(opts);
792 nc_server_config_tls_del_cleartext_private_key(opts);
793 nc_server_config_tls_del_cert_data(opts);
794 }
795
796 nc_server_config_tls_del_certs(&opts->ca_certs);
797 nc_server_config_tls_del_certs(&opts->ee_certs);
798
799 nc_server_config_del_ctns(opts);
800
801 free(opts);
802}
803
804static void
805nc_server_config_del_endpt_tls(struct nc_endpt *endpt, struct nc_bind *bind)
806{
807 nc_server_config_del_endpt_name(endpt);
808 nc_server_config_del_tls(bind, endpt->opts.tls);
809
810 server_opts.endpt_count--;
811 if (!server_opts.endpt_count) {
812 free(server_opts.endpts);
813 free(server_opts.binds);
814 server_opts.endpts = NULL;
815 server_opts.binds = NULL;
816 }
817}
818
roman2eab4742023-06-06 10:00:26 +0200819#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200820
romanc1d2b092023-02-02 08:58:27 +0100821/* presence container */
822int
romanf02273a2023-05-25 09:44:11 +0200823nc_server_config_listen(struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100824{
roman0bbc19c2023-05-26 09:59:09 +0200825 uint16_t i, endpt_count;
romanc1d2b092023-02-02 08:58:27 +0100826
romanf02273a2023-05-25 09:44:11 +0200827 (void) node;
828
romanc1d2b092023-02-02 08:58:27 +0100829 assert(op == NC_OP_CREATE || op == NC_OP_DELETE);
830
831 if (op == NC_OP_DELETE) {
roman0bbc19c2023-05-26 09:59:09 +0200832 endpt_count = server_opts.endpt_count;
833 for (i = 0; i < endpt_count; i++) {
roman456f92d2023-04-28 10:28:12 +0200834 switch (server_opts.endpts[i].ti) {
roman2eab4742023-06-06 10:00:26 +0200835#ifdef NC_ENABLED_SSH_TLS
roman456f92d2023-04-28 10:28:12 +0200836 case NC_TI_LIBSSH:
roman874fed12023-05-25 10:20:01 +0200837 nc_server_config_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]);
roman456f92d2023-04-28 10:28:12 +0200838 break;
roman456f92d2023-04-28 10:28:12 +0200839 case NC_TI_OPENSSL:
roman3f9b65c2023-06-05 14:26:58 +0200840 nc_server_config_del_endpt_tls(&server_opts.endpts[i], &server_opts.binds[i]);
roman456f92d2023-04-28 10:28:12 +0200841 break;
roman2eab4742023-06-06 10:00:26 +0200842#endif /* NC_ENABLED_SSH_TLS */
roman456f92d2023-04-28 10:28:12 +0200843 case NC_TI_UNIX:
roman874fed12023-05-25 10:20:01 +0200844 nc_server_config_del_endpt_unix_socket(&server_opts.endpts[i], &server_opts.binds[i]);
roman456f92d2023-04-28 10:28:12 +0200845 break;
846 case NC_TI_NONE:
847 case NC_TI_FD:
848 ERRINT;
849 return 1;
roman83683fb2023-02-24 09:15:23 +0100850 }
romanc1d2b092023-02-02 08:58:27 +0100851 }
852 }
853
854 return 0;
855}
856
857/* default leaf */
858static int
romane028ef92023-02-24 16:33:08 +0100859nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100860{
861 assert(!strcmp(LYD_NAME(node), "idle-timeout"));
862
863 if (equal_parent_name(node, 1, "listen")) {
864 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
865 server_opts.idle_timeout = strtoul(lyd_get_value(node), NULL, 10);
866 } else {
867 /* default value */
868 server_opts.idle_timeout = 3600;
869 }
870 }
871
872 return 0;
873}
874
875static int
roman874fed12023-05-25 10:20:01 +0200876nc_server_config_create_bind(void)
romanc1d2b092023-02-02 08:58:27 +0100877{
878 int ret = 0;
879 void *tmp;
880
881 tmp = realloc(server_opts.binds, (server_opts.endpt_count + 1) * sizeof *server_opts.binds);
882 if (!tmp) {
883 ERRMEM;
884 ret = 1;
885 goto cleanup;
886 }
887 server_opts.binds = tmp;
888 memset(&server_opts.binds[server_opts.endpt_count], 0, sizeof *server_opts.binds);
889
890 server_opts.binds[server_opts.endpt_count].sock = -1;
891
892cleanup:
893 return ret;
894}
895
896static int
roman874fed12023-05-25 10:20:01 +0200897nc_server_config_create_endpoint(const struct lyd_node *node)
romanc1d2b092023-02-02 08:58:27 +0100898{
roman874fed12023-05-25 10:20:01 +0200899 if (nc_server_config_create_bind()) {
romanf02273a2023-05-25 09:44:11 +0200900 return 1;
romanc1d2b092023-02-02 08:58:27 +0100901 }
romanc1d2b092023-02-02 08:58:27 +0100902
903 node = lyd_child(node);
904 assert(!strcmp(LYD_NAME(node), "name"));
905
romanf02273a2023-05-25 09:44:11 +0200906 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 +0100907}
908
909/* list */
910static int
romane028ef92023-02-24 16:33:08 +0100911nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100912{
913 int ret = 0;
914 struct nc_endpt *endpt;
915 struct nc_bind *bind;
916
917 assert(!strcmp(LYD_NAME(node), "endpoint"));
918
919 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +0200920 ret = nc_server_config_create_endpoint(node);
romanc1d2b092023-02-02 08:58:27 +0100921 if (ret) {
922 goto cleanup;
923 }
924 } else if (op == NC_OP_DELETE) {
925 /* free all children */
romanf02273a2023-05-25 09:44:11 +0200926 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +0100927 ret = 1;
928 goto cleanup;
929 }
roman3f9b65c2023-06-05 14:26:58 +0200930
931 switch (endpt->ti) {
roman2eab4742023-06-06 10:00:26 +0200932#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +0200933 case NC_TI_LIBSSH:
934 nc_server_config_del_endpt_ssh(endpt, bind);
935 break;
roman3f9b65c2023-06-05 14:26:58 +0200936 case NC_TI_OPENSSL:
937 nc_server_config_del_endpt_tls(endpt, bind);
938 break;
roman2eab4742023-06-06 10:00:26 +0200939#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200940 case NC_TI_UNIX:
941 nc_server_config_del_endpt_unix_socket(endpt, bind);
942 break;
943 case NC_TI_NONE:
944 case NC_TI_FD:
945 ERRINT;
946 ret = 1;
947 goto cleanup;
948 }
romanc1d2b092023-02-02 08:58:27 +0100949 }
950
951cleanup:
952 return ret;
953}
954
roman2eab4742023-06-06 10:00:26 +0200955#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +0200956
romanc1d2b092023-02-02 08:58:27 +0100957static int
roman874fed12023-05-25 10:20:01 +0200958nc_server_config_create_ssh(struct nc_endpt *endpt)
romanc1d2b092023-02-02 08:58:27 +0100959{
960 endpt->ti = NC_TI_LIBSSH;
961 endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
962 if (!endpt->opts.ssh) {
963 ERRMEM;
964 return 1;
965 }
966
967 return 0;
968}
969
970/* NP container */
971static int
romane028ef92023-02-24 16:33:08 +0100972nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100973{
974 struct nc_endpt *endpt;
975 struct nc_bind *bind;
976 int ret = 0;
977
978 assert(!strcmp(LYD_NAME(node), "ssh"));
979
romanf02273a2023-05-25 09:44:11 +0200980 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +0100981 ret = 1;
982 goto cleanup;
983 }
984
985 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +0200986 ret = nc_server_config_create_ssh(endpt);
romanc1d2b092023-02-02 08:58:27 +0100987 if (ret) {
988 goto cleanup;
989 }
990 } else if (op == NC_OP_DELETE) {
roman874fed12023-05-25 10:20:01 +0200991 nc_server_config_del_ssh(bind, endpt->opts.ssh);
romanc1d2b092023-02-02 08:58:27 +0100992 }
993
994cleanup:
995 return ret;
996}
997
roman3f9b65c2023-06-05 14:26:58 +0200998static int
999nc_server_config_create_tls(struct nc_endpt *endpt)
1000{
1001 endpt->ti = NC_TI_OPENSSL;
1002 endpt->opts.tls = calloc(1, sizeof *endpt->opts.tls);
1003 if (!endpt->opts.tls) {
1004 ERRMEM;
1005 return 1;
1006 }
1007
1008 return 0;
1009}
1010
1011static int
1012nc_server_config_tls(const struct lyd_node *node, NC_OPERATION op)
1013{
1014 struct nc_endpt *endpt;
1015 struct nc_bind *bind;
1016 int ret = 0;
1017
1018 assert(!strcmp(LYD_NAME(node), "tls"));
1019
1020 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1021 ret = 1;
1022 goto cleanup;
1023 }
1024
1025 if (op == NC_OP_CREATE) {
1026 ret = nc_server_config_create_tls(endpt);
1027 if (ret) {
1028 goto cleanup;
1029 }
1030 } else if (op == NC_OP_DELETE) {
1031 nc_server_config_del_tls(bind, endpt->opts.tls);
1032 }
1033
1034cleanup:
1035 return ret;
1036}
1037
roman2eab4742023-06-06 10:00:26 +02001038#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02001039
romanc1d2b092023-02-02 08:58:27 +01001040static int
1041nc_server_config_set_address_port(struct nc_endpt *endpt, struct nc_bind *bind, const char *address, uint16_t port)
1042{
1043 int sock = -1, set_addr, ret = 0;
1044
roman83683fb2023-02-24 09:15:23 +01001045 assert((address && !port) || (!address && port) || (endpt->ti == NC_TI_UNIX));
romanc1d2b092023-02-02 08:58:27 +01001046
1047 if (address) {
1048 set_addr = 1;
1049 } else {
1050 set_addr = 0;
1051 }
1052
1053 if (set_addr) {
1054 port = bind->port;
1055 } else {
1056 address = bind->address;
1057 }
1058
romanc1d2b092023-02-02 08:58:27 +01001059 /* we have all the information we need to create a listening socket */
roman83683fb2023-02-24 09:15:23 +01001060 if ((address && port) || (endpt->ti == NC_TI_UNIX)) {
romanc1d2b092023-02-02 08:58:27 +01001061 /* create new socket, close the old one */
roman83683fb2023-02-24 09:15:23 +01001062 if (endpt->ti == NC_TI_UNIX) {
1063 sock = nc_sock_listen_unix(endpt->opts.unixsock);
1064 } else {
1065 sock = nc_sock_listen_inet(address, port, &endpt->ka);
1066 }
1067
romanc1d2b092023-02-02 08:58:27 +01001068 if (sock == -1) {
1069 ret = 1;
1070 goto cleanup;
1071 }
1072
1073 if (bind->sock > -1) {
1074 close(bind->sock);
1075 }
1076 bind->sock = sock;
1077 }
1078
1079 if (sock > -1) {
1080 switch (endpt->ti) {
roman83683fb2023-02-24 09:15:23 +01001081 case NC_TI_UNIX:
1082 VRB(NULL, "Listening on %s for UNIX connections.", endpt->opts.unixsock->address);
1083 break;
roman2eab4742023-06-06 10:00:26 +02001084#ifdef NC_ENABLED_SSH_TLS
romanc1d2b092023-02-02 08:58:27 +01001085 case NC_TI_LIBSSH:
1086 VRB(NULL, "Listening on %s:%u for SSH connections.", address, port);
1087 break;
romanc1d2b092023-02-02 08:58:27 +01001088 case NC_TI_OPENSSL:
1089 VRB(NULL, "Listening on %s:%u for TLS connections.", address, port);
1090 break;
roman2eab4742023-06-06 10:00:26 +02001091#endif /* NC_ENABLED_SSH_TLS */
romanc1d2b092023-02-02 08:58:27 +01001092 default:
1093 ERRINT;
1094 ret = 1;
1095 break;
1096 }
1097 }
1098
1099cleanup:
1100 return ret;
1101}
1102
roman2eab4742023-06-06 10:00:26 +02001103#ifdef NC_ENABLED_SSH_TLS
1104
romanc1d2b092023-02-02 08:58:27 +01001105/* mandatory leaf */
1106static int
romane028ef92023-02-24 16:33:08 +01001107nc_server_config_local_address(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001108{
1109 struct nc_endpt *endpt;
1110 struct nc_bind *bind;
1111 int ret = 0;
1112
1113 (void) op;
1114
1115 assert(!strcmp(LYD_NAME(node), "local-address"));
1116
1117 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001118 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001119 ret = 1;
1120 goto cleanup;
1121 }
1122
roman874fed12023-05-25 10:20:01 +02001123 nc_server_config_del_local_address(bind);
romanc1d2b092023-02-02 08:58:27 +01001124 bind->address = strdup(lyd_get_value(node));
1125 if (!bind->address) {
1126 ERRMEM;
1127 ret = 1;
1128 goto cleanup;
1129 }
1130
1131 ret = nc_server_config_set_address_port(endpt, bind, lyd_get_value(node), 0);
1132 if (ret) {
1133 goto cleanup;
1134 }
1135 }
1136
1137cleanup:
1138 return ret;
1139}
1140
1141/* leaf with default value */
1142static int
romane028ef92023-02-24 16:33:08 +01001143nc_server_config_local_port(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001144{
1145 struct nc_endpt *endpt;
1146 struct nc_bind *bind;
1147 int ret = 0;
1148
1149 assert(!strcmp(LYD_NAME(node), "local-port"));
1150
1151 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001152 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001153 ret = 1;
1154 goto cleanup;
1155 }
1156
1157 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1158 bind->port = strtoul(lyd_get_value(node), NULL, 10);
1159 } else {
1160 /* delete -> set to default */
1161 bind->port = 0;
1162 }
1163
1164 ret = nc_server_config_set_address_port(endpt, bind, NULL, bind->port);
1165 if (ret) {
1166 goto cleanup;
1167 }
1168 }
1169
1170cleanup:
1171 return ret;
1172}
1173
1174/* P container */
1175static int
romane028ef92023-02-24 16:33:08 +01001176nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001177{
1178 struct nc_endpt *endpt;
1179 struct nc_bind *bind;
1180 int ret = 0;
1181
1182 assert(!strcmp(LYD_NAME(node), "keepalives"));
1183
roman3f9b65c2023-06-05 14:26:58 +02001184 if (equal_parent_name(node, 1, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001185 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001186 ret = 1;
1187 goto cleanup;
1188 }
1189
1190 if (op == NC_OP_CREATE) {
1191 endpt->ka.enabled = 1;
1192 } else {
1193 endpt->ka.enabled = 0;
1194 }
1195 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1196 if (ret) {
1197 goto cleanup;
1198 }
1199 }
1200
1201cleanup:
1202 return ret;
1203}
1204
1205/* mandatory leaf */
1206static int
romane028ef92023-02-24 16:33:08 +01001207nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001208{
1209 struct nc_endpt *endpt;
1210 struct nc_bind *bind;
1211 int ret = 0;
1212
1213 assert(!strcmp(LYD_NAME(node), "idle-time"));
1214
1215 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001216 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001217 ret = 1;
1218 goto cleanup;
1219 }
1220
1221 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1222 endpt->ka.idle_time = strtoul(lyd_get_value(node), NULL, 10);
1223 } else {
1224 endpt->ka.idle_time = 0;
1225 }
1226 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1227 if (ret) {
1228 goto cleanup;
1229 }
1230 }
1231
1232cleanup:
1233 return ret;
1234}
1235
1236/* mandatory leaf */
1237static int
romane028ef92023-02-24 16:33:08 +01001238nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001239{
1240 struct nc_endpt *endpt;
1241 struct nc_bind *bind;
1242 int ret = 0;
1243
1244 assert(!strcmp(LYD_NAME(node), "max-probes"));
1245
1246 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001247 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001248 ret = 1;
1249 goto cleanup;
1250 }
1251
1252 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1253 endpt->ka.max_probes = strtoul(lyd_get_value(node), NULL, 10);
1254 } else {
1255 endpt->ka.max_probes = 0;
1256 }
1257 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1258 if (ret) {
1259 goto cleanup;
1260 }
1261 }
1262
1263cleanup:
1264 return ret;
1265}
1266
1267/* mandatory leaf */
1268static int
romane028ef92023-02-24 16:33:08 +01001269nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001270{
1271 struct nc_endpt *endpt;
1272 struct nc_bind *bind;
1273 int ret = 0;
1274
1275 assert(!strcmp(LYD_NAME(node), "probe-interval"));
1276
1277 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001278 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001279 ret = 1;
1280 goto cleanup;
1281 }
1282
1283 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1284 endpt->ka.probe_interval = strtoul(lyd_get_value(node), NULL, 10);
1285 } else {
1286 endpt->ka.probe_interval = 0;
1287 }
1288 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1289 if (ret) {
1290 goto cleanup;
1291 }
1292 }
1293
1294cleanup:
1295 return ret;
1296}
1297
1298static int
roman874fed12023-05-25 10:20:01 +02001299nc_server_config_create_host_key(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01001300{
romanf02273a2023-05-25 09:44:11 +02001301 node = lyd_child(node);
1302 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01001303
romanf02273a2023-05-25 09:44:11 +02001304 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->hostkeys, sizeof *opts->hostkeys, &opts->hostkey_count);
romanc1d2b092023-02-02 08:58:27 +01001305}
1306
1307/* list */
1308static int
romane028ef92023-02-24 16:33:08 +01001309nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001310{
1311 struct nc_endpt *endpt;
1312 struct nc_hostkey *hostkey;
1313 int ret = 0;
1314
1315 assert(!strcmp(LYD_NAME(node), "host-key"));
1316
1317 if ((equal_parent_name(node, 1, "server-identity")) && (equal_parent_name(node, 5, "listen"))) {
romanf02273a2023-05-25 09:44:11 +02001318 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001319 ret = 1;
1320 goto cleanup;
1321 }
1322
1323 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +02001324 ret = nc_server_config_create_host_key(node, endpt->opts.ssh);
romanc1d2b092023-02-02 08:58:27 +01001325 if (ret) {
1326 goto cleanup;
1327 }
1328 } else if (op == NC_OP_DELETE) {
romanf02273a2023-05-25 09:44:11 +02001329 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001330 ret = 1;
1331 goto cleanup;
1332 }
1333
roman874fed12023-05-25 10:20:01 +02001334 nc_server_config_del_hostkey(endpt->opts.ssh, hostkey);
romanc1d2b092023-02-02 08:58:27 +01001335 }
1336 } else if (equal_parent_name(node, 1, "transport-params")) {
1337 /* just a container with the name host-key, nothing to be done */
1338 goto cleanup;
1339 } else {
1340 ERRINT;
1341 ret = 1;
1342 goto cleanup;
1343 }
1344
1345cleanup:
1346 return ret;
1347}
1348
1349/* mandatory leaf */
romane028ef92023-02-24 16:33:08 +01001350static int
1351nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001352{
1353 const char *format;
roman3f9b65c2023-06-05 14:26:58 +02001354 int ret = 0;
1355 NC_PUBKEY_FORMAT pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001356 struct nc_endpt *endpt;
1357 struct nc_client_auth *auth_client;
roman8edee342023-03-31 13:25:48 +02001358 struct nc_public_key *pubkey;
romanc1d2b092023-02-02 08:58:27 +01001359 struct nc_hostkey *hostkey;
romanc1d2b092023-02-02 08:58:27 +01001360
1361 assert(!strcmp(LYD_NAME(node), "public-key-format"));
1362
1363 format = ((struct lyd_node_term *)node)->value.ident->name;
roman3f9b65c2023-06-05 14:26:58 +02001364 if (!strcmp(format, "ssh-public-key-format")) {
1365 pubkey_type = NC_PUBKEY_FORMAT_SSH2;
1366 } else if (!strcmp(format, "subject-public-key-info-format")) {
1367 pubkey_type = NC_PUBKEY_FORMAT_X509;
1368 } else {
1369 ERR(NULL, "Public key format (%s) not supported.", format);
1370 ret = 1;
1371 goto cleanup;
1372 }
romanc1d2b092023-02-02 08:58:27 +01001373
roman3f9b65c2023-06-05 14:26:58 +02001374 if ((equal_parent_name(node, 6, "client-authentication")) && (is_ssh(node)) && (is_listen(node))) {
romanf02273a2023-05-25 09:44:11 +02001375 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001376 ret = 1;
1377 goto cleanup;
1378 }
1379
romanf02273a2023-05-25 09:44:11 +02001380 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001381 ret = 1;
1382 goto cleanup;
1383 }
1384
romanf02273a2023-05-25 09:44:11 +02001385 if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001386 ret = 1;
1387 goto cleanup;
1388 }
1389
1390 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman3f9b65c2023-06-05 14:26:58 +02001391 pubkey->type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001392 }
roman3f9b65c2023-06-05 14:26:58 +02001393 } else if (equal_parent_name(node, 5, "server-identity") && is_ssh(node) && is_listen(node)) {
romanf02273a2023-05-25 09:44:11 +02001394 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001395 ret = 1;
1396 goto cleanup;
1397 }
1398
romanf02273a2023-05-25 09:44:11 +02001399 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001400 ret = 1;
1401 goto cleanup;
1402 }
1403
1404 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman3f9b65c2023-06-05 14:26:58 +02001405 hostkey->key.pubkey_type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001406 }
roman2eab4742023-06-06 10:00:26 +02001407 } else if (equal_parent_name(node, 3, "server-identity") && is_tls(node) && is_listen(node)) {
roman3f9b65c2023-06-05 14:26:58 +02001408 /* TLS listen server-identity */
1409 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
1410 ret = 1;
1411 goto cleanup;
1412 }
1413
1414 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1415 endpt->opts.tls->pubkey_type = pubkey_type;
1416 }
1417 }
romanc1d2b092023-02-02 08:58:27 +01001418
1419cleanup:
1420 return ret;
1421}
1422
1423/* leaf */
romane028ef92023-02-24 16:33:08 +01001424static int
1425nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001426{
roman3f9b65c2023-06-05 14:26:58 +02001427 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001428 const char *format;
1429 struct nc_endpt *endpt;
roman3f9b65c2023-06-05 14:26:58 +02001430 NC_PRIVKEY_FORMAT privkey_type;
romanc1d2b092023-02-02 08:58:27 +01001431 struct nc_hostkey *hostkey;
roman3f9b65c2023-06-05 14:26:58 +02001432
1433 (void) op;
romanc1d2b092023-02-02 08:58:27 +01001434
1435 assert(!strcmp(LYD_NAME(node), "private-key-format"));
1436
romanf02273a2023-05-25 09:44:11 +02001437 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001438 ret = 1;
1439 goto cleanup;
1440 }
1441
roman3f9b65c2023-06-05 14:26:58 +02001442 format = ((struct lyd_node_term *)node)->value.ident->name;
1443 if (!format) {
romanc1d2b092023-02-02 08:58:27 +01001444 ret = 1;
1445 goto cleanup;
1446 }
1447
roman3f9b65c2023-06-05 14:26:58 +02001448 privkey_type = nc_server_config_get_private_key_type(format);
1449 if (privkey_type == NC_PRIVKEY_FORMAT_UNKNOWN) {
1450 ret = 1;
1451 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01001452 }
1453
roman3f9b65c2023-06-05 14:26:58 +02001454 if ((is_ssh(node)) && (is_listen(node))) {
1455 /* listen ssh */
1456 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
1457 ret = 1;
1458 goto cleanup;
1459 }
1460
1461 hostkey->key.privkey_type = privkey_type;
roman2eab4742023-06-06 10:00:26 +02001462 } else if ((is_tls(node)) && (is_listen(node))) {
roman3f9b65c2023-06-05 14:26:58 +02001463 /* listen tls */
roman3f9b65c2023-06-05 14:26:58 +02001464 endpt->opts.tls->privkey_type = privkey_type;
1465 }
roman3f9b65c2023-06-05 14:26:58 +02001466
romanc1d2b092023-02-02 08:58:27 +01001467cleanup:
1468 return ret;
1469}
1470
1471static int
roman874fed12023-05-25 10:20:01 +02001472nc_server_config_replace_cleartext_private_key(const struct lyd_node *node, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +01001473{
roman874fed12023-05-25 10:20:01 +02001474 nc_server_config_del_private_key(hostkey);
roman3f9b65c2023-06-05 14:26:58 +02001475 hostkey->key.privkey_data = strdup(lyd_get_value(node));
1476 if (!hostkey->key.privkey_data) {
romanc1d2b092023-02-02 08:58:27 +01001477 ERRMEM;
1478 return 1;
1479 }
1480
1481 return 0;
1482}
1483
roman3f9b65c2023-06-05 14:26:58 +02001484static int
1485nc_server_config_tls_replace_cleartext_private_key(const struct lyd_node *node, struct nc_server_tls_opts *opts)
1486{
1487 nc_server_config_tls_del_cleartext_private_key(opts);
1488 opts->privkey_data = strdup(lyd_get_value(node));
1489 if (!opts->privkey_data) {
1490 ERRMEM;
1491 return 1;
1492 }
1493
1494 return 0;
1495}
1496
romanc1d2b092023-02-02 08:58:27 +01001497static int
romane028ef92023-02-24 16:33:08 +01001498nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001499{
romanc1d2b092023-02-02 08:58:27 +01001500 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02001501 struct nc_endpt *endpt;
roman3f9b65c2023-06-05 14:26:58 +02001502 struct nc_hostkey *hostkey;
romanc1d2b092023-02-02 08:58:27 +01001503
1504 assert(!strcmp(LYD_NAME(node), "cleartext-private-key"));
1505
roman3f9b65c2023-06-05 14:26:58 +02001506 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
1507 ret = 1;
1508 goto cleanup;
1509 }
1510
roman3f9b65c2023-06-05 14:26:58 +02001511 if ((is_ssh(node)) && (is_listen(node))) {
romanf02273a2023-05-25 09:44:11 +02001512 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001513 ret = 1;
1514 goto cleanup;
1515 }
1516
1517 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02001518 ret = nc_server_config_replace_cleartext_private_key(node, hostkey);
romanc1d2b092023-02-02 08:58:27 +01001519 if (ret) {
1520 goto cleanup;
1521 }
1522 } else {
roman874fed12023-05-25 10:20:01 +02001523 nc_server_config_del_private_key(hostkey);
romanc1d2b092023-02-02 08:58:27 +01001524 }
roman2eab4742023-06-06 10:00:26 +02001525 } else if ((is_tls(node)) && (is_listen(node))) {
roman3f9b65c2023-06-05 14:26:58 +02001526 /* listen tls */
roman3f9b65c2023-06-05 14:26:58 +02001527 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1528 ret = nc_server_config_tls_replace_cleartext_private_key(node, endpt->opts.tls);
1529 if (ret) {
1530 goto cleanup;
1531 }
1532 } else {
1533 nc_server_config_tls_del_cleartext_private_key(endpt->opts.tls);
1534 }
1535 }
romanc1d2b092023-02-02 08:58:27 +01001536
1537cleanup:
1538 return ret;
1539}
1540
1541static int
roman874fed12023-05-25 10:20:01 +02001542nc_server_config_create_keystore_reference(const struct lyd_node *node, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +01001543{
1544 uint16_t i;
roman45cec4e2023-02-17 10:21:39 +01001545 struct nc_keystore *ks = &server_opts.keystore;
romanc1d2b092023-02-02 08:58:27 +01001546
1547 /* lookup name */
roman45cec4e2023-02-17 10:21:39 +01001548 for (i = 0; i < ks->asym_key_count; i++) {
1549 if (!strcmp(lyd_get_value(node), ks->asym_keys[i].name)) {
romanc1d2b092023-02-02 08:58:27 +01001550 break;
1551 }
1552 }
1553
roman45cec4e2023-02-17 10:21:39 +01001554 if (i == ks->asym_key_count) {
1555 ERR(NULL, "Keystore \"%s\" not found.", lyd_get_value(node));
romanc1d2b092023-02-02 08:58:27 +01001556 return 1;
1557 }
1558
roman45cec4e2023-02-17 10:21:39 +01001559 hostkey->ks_ref = &ks->asym_keys[i];
romanc1d2b092023-02-02 08:58:27 +01001560
1561 return 0;
1562}
1563
1564/* leaf */
1565static int
romane028ef92023-02-24 16:33:08 +01001566nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001567{
1568 struct nc_endpt *endpt;
1569 struct nc_hostkey *hostkey;
1570 int ret = 0;
1571
1572 assert(!strcmp(LYD_NAME(node), "keystore-reference"));
1573
roman3f9b65c2023-06-05 14:26:58 +02001574 if ((equal_parent_name(node, 3, "server-identity")) && (is_ssh(node)) && (is_listen(node))) {
romanf02273a2023-05-25 09:44:11 +02001575 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001576 ret = 1;
1577 goto cleanup;
1578 }
romanf02273a2023-05-25 09:44:11 +02001579 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001580 ret = 1;
1581 goto cleanup;
1582 }
1583
1584 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02001585 /* set to keystore */
roman874fed12023-05-25 10:20:01 +02001586 hostkey->store = NC_STORE_KEYSTORE;
romanf02273a2023-05-25 09:44:11 +02001587
roman874fed12023-05-25 10:20:01 +02001588 ret = nc_server_config_create_keystore_reference(node, hostkey);
romanc1d2b092023-02-02 08:58:27 +01001589 if (ret) {
1590 goto cleanup;
1591 }
1592 } else {
roman45cec4e2023-02-17 10:21:39 +01001593 hostkey->ks_ref = NULL;
romanc1d2b092023-02-02 08:58:27 +01001594 }
1595 }
1596
1597cleanup:
1598 return ret;
1599}
1600
1601static int
roman874fed12023-05-25 10:20:01 +02001602nc_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 +01001603{
romanc1d2b092023-02-02 08:58:27 +01001604 assert(!strcmp(LYD_NAME(node), "public-key"));
1605
romanc1d2b092023-02-02 08:58:27 +01001606 node = lyd_child(node);
1607 assert(!strcmp(LYD_NAME(node), "name"));
1608
romanf02273a2023-05-25 09:44:11 +02001609 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 +01001610}
1611
1612static int
roman874fed12023-05-25 10:20:01 +02001613nc_server_config_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +01001614{
roman874fed12023-05-25 10:20:01 +02001615 nc_server_config_del_auth_client_pubkey_pub_base64(pubkey);
romanc1d2b092023-02-02 08:58:27 +01001616
roman3f9b65c2023-06-05 14:26:58 +02001617 pubkey->data = strdup(lyd_get_value(node));
1618 if (!pubkey->data) {
romanc1d2b092023-02-02 08:58:27 +01001619 ERRMEM;
1620 return 1;
1621 }
1622
1623 return 0;
1624}
1625
1626static int
roman874fed12023-05-25 10:20:01 +02001627nc_server_config_replace_host_key_public_key(const struct lyd_node *node, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +01001628{
roman874fed12023-05-25 10:20:01 +02001629 nc_server_config_del_public_key(hostkey);
romanc1d2b092023-02-02 08:58:27 +01001630
roman3f9b65c2023-06-05 14:26:58 +02001631 hostkey->key.pubkey_data = strdup(lyd_get_value(node));
1632 if (!hostkey->key.pubkey_data) {
romanc1d2b092023-02-02 08:58:27 +01001633 ERRMEM;
1634 return 1;
1635 }
1636
1637 return 0;
1638}
1639
roman3f9b65c2023-06-05 14:26:58 +02001640static int
1641nc_server_config_tls_replace_server_public_key(const struct lyd_node *node, struct nc_server_tls_opts *opts)
1642{
1643 nc_server_config_tls_del_public_key(opts);
1644
1645 opts->pubkey_data = strdup(lyd_get_value(node));
1646 if (!opts->pubkey_data) {
1647 ERRMEM;
1648 return 1;
1649 }
1650
1651 return 0;
1652}
1653
romanc1d2b092023-02-02 08:58:27 +01001654static int
romane028ef92023-02-24 16:33:08 +01001655nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001656{
roman3f9b65c2023-06-05 14:26:58 +02001657 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001658 struct nc_endpt *endpt;
1659 struct nc_hostkey *hostkey;
1660 struct nc_client_auth *auth_client;
roman8edee342023-03-31 13:25:48 +02001661 struct nc_public_key *pubkey;
romanc1d2b092023-02-02 08:58:27 +01001662
1663 assert(!strcmp(LYD_NAME(node), "public-key"));
1664
roman3f9b65c2023-06-05 14:26:58 +02001665 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
1666 ret = 1;
1667 goto cleanup;
1668 }
romanc1d2b092023-02-02 08:58:27 +01001669
roman3f9b65c2023-06-05 14:26:58 +02001670 if ((equal_parent_name(node, 3, "host-key")) && (is_ssh(node)) && (is_listen(node))) {
1671 /* server's public-key, mandatory leaf */
romanf02273a2023-05-25 09:44:11 +02001672 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001673 ret = 1;
1674 goto cleanup;
1675 }
1676
1677 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02001678 /* set to local */
roman874fed12023-05-25 10:20:01 +02001679 hostkey->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02001680
roman874fed12023-05-25 10:20:01 +02001681 ret = nc_server_config_replace_host_key_public_key(node, hostkey);
romanc1d2b092023-02-02 08:58:27 +01001682 if (ret) {
1683 goto cleanup;
1684 }
1685 }
roman3f9b65c2023-06-05 14:26:58 +02001686 } else if ((equal_parent_name(node, 5, "client-authentication")) && (is_ssh(node)) && (is_listen(node))) {
romanc1d2b092023-02-02 08:58:27 +01001687 /* client auth pubkeys, list */
romanf02273a2023-05-25 09:44:11 +02001688 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001689 ret = 1;
1690 goto cleanup;
1691 }
1692
1693 if (op == NC_OP_CREATE) {
romanf02273a2023-05-25 09:44:11 +02001694 /* set to local */
roman874fed12023-05-25 10:20:01 +02001695 auth_client->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02001696
roman874fed12023-05-25 10:20:01 +02001697 ret = nc_server_config_create_auth_key_public_key_list(node, auth_client);
romanc1d2b092023-02-02 08:58:27 +01001698 if (ret) {
1699 goto cleanup;
1700 }
1701 } else if (op == NC_OP_DELETE) {
romanf02273a2023-05-25 09:44:11 +02001702 if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001703 ret = 1;
1704 goto cleanup;
1705 }
1706
roman874fed12023-05-25 10:20:01 +02001707 nc_server_config_del_auth_client_pubkey(auth_client, pubkey);
romanc1d2b092023-02-02 08:58:27 +01001708 }
roman3f9b65c2023-06-05 14:26:58 +02001709 } else if ((equal_parent_name(node, 6, "client-authentication")) && (is_ssh(node)) && (is_listen(node))) {
romanc1d2b092023-02-02 08:58:27 +01001710 /* client auth pubkey, leaf */
romanf02273a2023-05-25 09:44:11 +02001711 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001712 ret = 1;
1713 goto cleanup;
1714 }
1715
romanf02273a2023-05-25 09:44:11 +02001716 if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001717 ret = 1;
1718 goto cleanup;
1719 }
1720
1721 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02001722 ret = nc_server_config_replace_auth_key_public_key_leaf(node, pubkey);
romanc1d2b092023-02-02 08:58:27 +01001723 if (ret) {
1724 goto cleanup;
1725 }
1726 } else {
roman874fed12023-05-25 10:20:01 +02001727 nc_server_config_del_auth_client_pubkey_pub_base64(pubkey);
romanc1d2b092023-02-02 08:58:27 +01001728 }
roman2eab4742023-06-06 10:00:26 +02001729 } else if ((equal_parent_name(node, 3, "server-identity")) && (is_tls(node)) && (is_listen(node))) {
roman3f9b65c2023-06-05 14:26:58 +02001730 /* tls listen server-identity */
roman3f9b65c2023-06-05 14:26:58 +02001731 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1732 /* set to local */
1733 endpt->opts.tls->store = NC_STORE_LOCAL;
1734
1735 ret = nc_server_config_tls_replace_server_public_key(node, endpt->opts.tls);
1736 if (ret) {
1737 goto cleanup;
1738 }
1739 }
1740 }
romanc1d2b092023-02-02 08:58:27 +01001741
1742cleanup:
1743 return ret;
1744}
1745
1746static int
roman874fed12023-05-25 10:20:01 +02001747nc_server_config_create_user(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01001748{
romanf02273a2023-05-25 09:44:11 +02001749 node = lyd_child(node);
1750 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01001751
romanf02273a2023-05-25 09:44:11 +02001752 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 +01001753}
1754
1755/* list */
1756static int
romane028ef92023-02-24 16:33:08 +01001757nc_server_config_user(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001758{
1759 struct nc_endpt *endpt;
1760 struct nc_client_auth *auth_client;
1761 int ret = 0;
1762
1763 assert(!strcmp(LYD_NAME(node), "user"));
1764
1765 if (equal_parent_name(node, 6, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001766 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001767 ret = 1;
1768 goto cleanup;
1769 }
1770
1771 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +02001772 ret = nc_server_config_create_user(node, endpt->opts.ssh);
romanc1d2b092023-02-02 08:58:27 +01001773 if (ret) {
1774 goto cleanup;
1775 }
1776 } else if (op == NC_OP_DELETE) {
romanf02273a2023-05-25 09:44:11 +02001777 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001778 ret = 1;
1779 goto cleanup;
1780 }
1781
roman874fed12023-05-25 10:20:01 +02001782 nc_server_config_del_auth_client(endpt->opts.ssh, auth_client);
romanc1d2b092023-02-02 08:58:27 +01001783 }
1784 }
1785
1786cleanup:
1787 return ret;
1788}
1789
1790static int
romane028ef92023-02-24 16:33:08 +01001791nc_server_config_auth_attempts(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001792{
1793 struct nc_endpt *endpt;
1794 int ret = 0;
1795
1796 assert(!strcmp(LYD_NAME(node), "auth-attempts"));
1797
1798 if (equal_parent_name(node, 5, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001799 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001800 ret = 1;
1801 goto cleanup;
1802 }
1803
1804 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1805 endpt->opts.ssh->auth_attempts = strtoul(lyd_get_value(node), NULL, 10);
1806 }
1807 }
1808
1809cleanup:
1810 return ret;
1811}
1812
1813static int
romane028ef92023-02-24 16:33:08 +01001814nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001815{
1816 struct nc_endpt *endpt;
1817 int ret = 0;
1818
1819 assert(!strcmp(LYD_NAME(node), "auth-timeout"));
1820
1821 if (equal_parent_name(node, 5, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001822 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001823 ret = 1;
1824 goto cleanup;
1825 }
1826
1827 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1828 endpt->opts.ssh->auth_timeout = strtoul(lyd_get_value(node), NULL, 10);
1829 }
1830 }
1831
1832cleanup:
1833 return ret;
1834}
1835
1836static int
roman874fed12023-05-25 10:20:01 +02001837nc_server_config_replace_truststore_reference(const struct lyd_node *node, struct nc_client_auth *client_auth)
romanc1d2b092023-02-02 08:58:27 +01001838{
romand57b3722023-04-05 11:26:25 +02001839 uint16_t i;
1840 struct nc_truststore *ts = &server_opts.truststore;
romanc1d2b092023-02-02 08:58:27 +01001841
romand57b3722023-04-05 11:26:25 +02001842 /* lookup name */
1843 for (i = 0; i < ts->pub_bag_count; i++) {
1844 if (!strcmp(lyd_get_value(node), ts->pub_bags[i].name)) {
1845 break;
1846 }
1847 }
1848
1849 if (i == ts->pub_bag_count) {
roman3f9b65c2023-06-05 14:26:58 +02001850 ERR(NULL, "Public-key bag \"%s\" not found in truststore.", lyd_get_value(node));
romanc1d2b092023-02-02 08:58:27 +01001851 return 1;
1852 }
1853
romand57b3722023-04-05 11:26:25 +02001854 client_auth->ts_ref = &ts->pub_bags[i];
1855
romanc1d2b092023-02-02 08:58:27 +01001856 return 0;
1857}
1858
roman3f9b65c2023-06-05 14:26:58 +02001859static int
1860nc_server_config_tls_replace_truststore_reference(const struct lyd_node *node, struct nc_cert_grouping *auth_client)
1861{
1862 uint16_t i;
1863 struct nc_truststore *ts = &server_opts.truststore;
1864
1865 /* lookup name */
1866 for (i = 0; i < ts->cert_bag_count; i++) {
1867 if (!strcmp(lyd_get_value(node), ts->cert_bags[i].name)) {
1868 break;
1869 }
1870 }
1871
1872 if (i == ts->cert_bag_count) {
1873 ERR(NULL, "Certificate bag \"%s\" not found in truststore.", lyd_get_value(node));
1874 return 1;
1875 }
1876
1877 auth_client->ts_ref = &ts->cert_bags[i];
1878
1879 return 0;
1880}
1881
romanc1d2b092023-02-02 08:58:27 +01001882/* leaf */
1883static int
romane028ef92023-02-24 16:33:08 +01001884nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001885{
romanc1d2b092023-02-02 08:58:27 +01001886 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02001887 struct nc_endpt *endpt;
roman3f9b65c2023-06-05 14:26:58 +02001888 struct nc_client_auth *auth_client;
romanc1d2b092023-02-02 08:58:27 +01001889
1890 assert(!strcmp(LYD_NAME(node), "truststore-reference"));
1891
roman3f9b65c2023-06-05 14:26:58 +02001892 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
1893 ret = 1;
1894 goto cleanup;
1895 }
romanc1d2b092023-02-02 08:58:27 +01001896
roman3f9b65c2023-06-05 14:26:58 +02001897 if ((equal_parent_name(node, 1, "public-keys")) && (is_ssh(node)) && (is_listen(node))) {
romanf02273a2023-05-25 09:44:11 +02001898 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001899 ret = 1;
1900 goto cleanup;
1901 }
1902
1903 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02001904 /* set to truststore */
roman874fed12023-05-25 10:20:01 +02001905 auth_client->store = NC_STORE_TRUSTSTORE;
romanf02273a2023-05-25 09:44:11 +02001906
roman874fed12023-05-25 10:20:01 +02001907 ret = nc_server_config_replace_truststore_reference(node, auth_client);
romanc1d2b092023-02-02 08:58:27 +01001908 if (ret) {
1909 goto cleanup;
1910 }
1911 } else {
romand57b3722023-04-05 11:26:25 +02001912 auth_client->ts_ref = NULL;
romanc1d2b092023-02-02 08:58:27 +01001913 }
roman2eab4742023-06-06 10:00:26 +02001914 } else if ((equal_parent_name(node, 1, "ca-certs")) && (is_listen(node))) {
roman3f9b65c2023-06-05 14:26:58 +02001915 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1916 /* set to truststore */
1917 endpt->opts.tls->ca_certs.store = NC_STORE_TRUSTSTORE;
1918
1919 ret = nc_server_config_tls_replace_truststore_reference(node, &endpt->opts.tls->ca_certs);
1920 if (ret) {
1921 goto cleanup;
1922 }
1923 } else {
1924 endpt->opts.tls->ca_certs.ts_ref = NULL;
1925 }
1926 } else if ((equal_parent_name(node, 1, "ee-certs")) && (is_listen(node))) {
1927 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1928 /* set to truststore */
1929 endpt->opts.tls->ee_certs.store = NC_STORE_TRUSTSTORE;
1930
1931 ret = nc_server_config_tls_replace_truststore_reference(node, &endpt->opts.tls->ee_certs);
1932 if (ret) {
1933 goto cleanup;
1934 }
1935 } else {
1936 endpt->opts.tls->ee_certs.ts_ref = NULL;
1937 }
1938 }
romanc1d2b092023-02-02 08:58:27 +01001939
1940cleanup:
1941 return ret;
1942}
1943
1944static int
roman874fed12023-05-25 10:20:01 +02001945nc_server_config_replace_password(const struct lyd_node *node, struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +01001946{
roman874fed12023-05-25 10:20:01 +02001947 nc_server_config_del_auth_client_password(auth_client);
romanc1d2b092023-02-02 08:58:27 +01001948
1949 auth_client->password = strdup(lyd_get_value(node));
1950 if (!auth_client->password) {
1951 ERRMEM;
1952 return 1;
1953 }
1954
1955 return 0;
1956}
1957
1958/* leaf */
1959static int
romane028ef92023-02-24 16:33:08 +01001960nc_server_config_password(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001961{
1962 struct nc_endpt *endpt;
1963 struct nc_client_auth *auth_client;
1964 int ret = 0;
1965
1966 assert(!strcmp(LYD_NAME(node), "password"));
1967
1968 if (equal_parent_name(node, 7, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001969 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001970 ret = 1;
1971 goto cleanup;
1972 }
1973
romanf02273a2023-05-25 09:44:11 +02001974 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001975 ret = 1;
1976 goto cleanup;
1977 }
1978
1979 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02001980 ret = nc_server_config_replace_password(node, auth_client);
romanc1d2b092023-02-02 08:58:27 +01001981 if (ret) {
1982 goto cleanup;
1983 }
1984 } else {
roman874fed12023-05-25 10:20:01 +02001985 nc_server_config_del_auth_client_password(auth_client);
romanc1d2b092023-02-02 08:58:27 +01001986 }
1987 }
1988
1989cleanup:
1990 return ret;
1991}
1992
1993static int
romane028ef92023-02-24 16:33:08 +01001994nc_server_config_pam_name(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001995{
1996 struct nc_endpt *endpt;
1997 struct nc_client_auth *auth_client;
1998 int ret = 0;
1999
2000 assert(!strcmp(LYD_NAME(node), "pam-config-file-name"));
2001
2002 if (equal_parent_name(node, 8, "listen")) {
romanf02273a2023-05-25 09:44:11 +02002003 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01002004 ret = 1;
2005 goto cleanup;
2006 }
2007
romanf02273a2023-05-25 09:44:11 +02002008 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002009 ret = 1;
2010 goto cleanup;
2011 }
2012
2013 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02002014 nc_server_config_del_auth_client_pam_name(auth_client);
romanc1d2b092023-02-02 08:58:27 +01002015
2016 auth_client->pam_config_name = strdup(lyd_get_value(node));
2017 if (!auth_client->pam_config_name) {
2018 ERRMEM;
2019 ret = 1;
2020 goto cleanup;
2021 }
2022 }
2023 }
2024
2025cleanup:
2026 return ret;
2027}
2028
2029static int
romane028ef92023-02-24 16:33:08 +01002030nc_server_config_pam_dir(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002031{
2032 struct nc_endpt *endpt;
2033 struct nc_client_auth *auth_client;
2034 int ret = 0;
2035
2036 assert(!strcmp(LYD_NAME(node), "pam-config-file-dir"));
2037
2038 if (equal_parent_name(node, 8, "listen")) {
romanf02273a2023-05-25 09:44:11 +02002039 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01002040 ret = 1;
2041 goto cleanup;
2042 }
2043
romanf02273a2023-05-25 09:44:11 +02002044 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002045 ret = 1;
2046 goto cleanup;
2047 }
2048
2049 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02002050 nc_server_config_del_auth_client_pam_dir(auth_client);
romanc1d2b092023-02-02 08:58:27 +01002051 auth_client->pam_config_dir = strdup(lyd_get_value(node));
2052 if (!auth_client->pam_config_dir) {
2053 ERRMEM;
2054 ret = 1;
2055 goto cleanup;
2056 }
2057 }
2058 }
2059
2060cleanup:
2061 return ret;
2062}
2063
2064/* leaf */
2065static int
romane028ef92023-02-24 16:33:08 +01002066nc_server_config_none(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002067{
2068 struct nc_endpt *endpt;
2069 struct nc_client_auth *auth_client;
2070 int ret = 0;
2071
2072 assert(!strcmp(LYD_NAME(node), "none"));
2073
2074 if (equal_parent_name(node, 7, "listen")) {
romanf02273a2023-05-25 09:44:11 +02002075 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01002076 ret = 1;
2077 goto cleanup;
2078 }
2079
romanf02273a2023-05-25 09:44:11 +02002080 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002081 ret = 1;
2082 goto cleanup;
2083 }
2084
2085 if (op == NC_OP_CREATE) {
2086 auth_client->supports_none = 1;
2087 } else {
2088 auth_client->supports_none = 0;
2089 }
2090 }
2091
2092cleanup:
2093 return ret;
2094}
2095
2096static int
romana6bf6ab2023-05-26 13:26:02 +02002097nc_server_config_transport_params(const char *algorithm, char **alg_store, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002098{
2099 int ret = 0, alg_found = 0;
romana6bf6ab2023-05-26 13:26:02 +02002100 char *substr, *haystack, *alg = NULL;
2101 size_t alg_len;
2102
2103 if (!strncmp(algorithm, "openssh-", 8)) {
2104 /* if the name starts with openssh, convert it to it's original libssh accepted form */
2105 asprintf(&alg, "%s@openssh.com", algorithm + 8);
2106 if (!alg) {
2107 ERRMEM;
2108 ret = 1;
2109 goto cleanup;
2110 }
2111 } else if (!strncmp(algorithm, "libssh-", 7)) {
2112 /* if the name starts with libssh, convert it to it's original libssh accepted form */
2113 asprintf(&alg, "%s@libssh.org", algorithm + 7);
2114 if (!alg) {
2115 ERRMEM;
2116 ret = 1;
2117 goto cleanup;
2118 }
2119 } else {
2120 alg = strdup(algorithm);
2121 if (!alg) {
2122 ERRMEM;
2123 ret = 1;
2124 goto cleanup;
2125 }
2126 }
2127
2128 alg_len = strlen(alg);
romanc1d2b092023-02-02 08:58:27 +01002129
2130 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2131 if (!*alg_store) {
2132 /* first call */
2133 *alg_store = strdup(alg);
2134 if (!*alg_store) {
2135 ERRMEM;
2136 ret = 1;
2137 goto cleanup;
2138 }
2139 } else {
2140 /* +1 because of ',' between algorithms */
2141 *alg_store = nc_realloc(*alg_store, strlen(*alg_store) + alg_len + 1 + 1);
2142 if (!*alg_store) {
2143 ERRMEM;
2144 ret = 1;
2145 goto cleanup;
2146 }
2147 sprintf(*alg_store, "%s,%s", *alg_store, alg);
2148 }
2149 } else {
2150 /* delete */
2151 haystack = *alg_store;
2152 while ((substr = strstr(haystack, alg))) {
2153 /* iterate over all the substrings */
2154 if (((substr == haystack) && (*(substr + alg_len) == ',')) ||
2155 ((substr != haystack) && (*(substr - 1) == ',') && (*(substr + alg_len) == ','))) {
2156 /* either the first element of the string or somewhere in the middle */
2157 memmove(substr, substr + alg_len + 1, strlen(substr + alg_len + 1));
2158 alg_found = 1;
2159 break;
2160 } else if ((*(substr - 1) == ',') && (*(substr + alg_len) == '\0')) {
2161 /* the last element of the string */
2162 *(substr - 1) = '\0';
2163 alg_found = 1;
2164 break;
2165 }
2166 haystack++;
2167 }
2168 if (!alg_found) {
2169 ERR(NULL, "Unable to delete an algorithm (%s), which was not previously added.", alg);
2170 ret = 1;
2171 }
2172 }
2173
2174cleanup:
romana6bf6ab2023-05-26 13:26:02 +02002175 free(alg);
romanc1d2b092023-02-02 08:58:27 +01002176 return ret;
2177}
2178
2179/* leaf-list */
2180static int
romane028ef92023-02-24 16:33:08 +01002181nc_server_config_host_key_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002182{
2183 struct nc_endpt *endpt;
2184 int ret = 0, listen = 0;
2185 const char *alg;
2186 uint8_t i;
2187
2188 /* get the algorithm name and compare it with algs supported by libssh */
2189 alg = ((struct lyd_node_term *)node)->value.ident->name;
2190
2191 if (equal_parent_name(node, 6, "listen")) {
2192 listen = 1;
romanf02273a2023-05-25 09:44:11 +02002193 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01002194 ret = 1;
2195 goto cleanup;
2196 }
2197 }
2198
2199 i = 0;
2200 while (supported_hostkey_algs[i]) {
2201 if (!strcmp(supported_hostkey_algs[i], alg)) {
2202 if (listen) {
romane028ef92023-02-24 16:33:08 +01002203 if (nc_server_config_transport_params(alg, &endpt->opts.ssh->hostkey_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002204 ret = 1;
2205 goto cleanup;
2206 }
2207 }
2208 break;
2209 }
2210 i++;
2211 }
2212 if (!supported_hostkey_algs[i]) {
2213 /* algorithm not supported */
2214 ERR(NULL, "Public key algorithm (%s) not supported by libssh.", alg);
2215 ret = 1;
2216 }
2217
2218cleanup:
2219 return ret;
2220}
2221
2222/* leaf-list */
2223static int
romane028ef92023-02-24 16:33:08 +01002224nc_server_config_kex_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002225{
2226 struct nc_endpt *endpt;
2227 int ret = 0, listen = 0;
2228 const char *alg;
2229 uint8_t i;
2230
2231 /* get the algorithm name and compare it with algs supported by libssh */
2232 alg = ((struct lyd_node_term *)node)->value.ident->name;
2233
2234 if (equal_parent_name(node, 6, "listen")) {
2235 listen = 1;
romanf02273a2023-05-25 09:44:11 +02002236 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01002237 ret = 1;
2238 goto cleanup;
2239 }
2240 }
2241
2242 i = 0;
2243 while (supported_kex_algs[i]) {
2244 if (!strcmp(supported_kex_algs[i], alg)) {
2245 if (listen) {
romane028ef92023-02-24 16:33:08 +01002246 if (nc_server_config_transport_params(alg, &endpt->opts.ssh->kex_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002247 ret = 1;
2248 goto cleanup;
2249 }
2250 }
2251 break;
2252 }
2253 i++;
2254 }
2255 if (!supported_kex_algs[i]) {
2256 /* algorithm not supported */
2257 ERR(NULL, "Key exchange algorithm (%s) not supported by libssh.", alg);
2258 ret = 1;
2259 }
2260
2261cleanup:
2262 return ret;
2263}
2264
2265/* leaf-list */
2266static int
romane028ef92023-02-24 16:33:08 +01002267nc_server_config_encryption_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002268{
2269 struct nc_endpt *endpt;
2270 int ret = 0, listen = 0;
2271 const char *alg;
2272 uint8_t i;
2273
2274 /* get the algorithm name and compare it with algs supported by libssh */
2275 alg = ((struct lyd_node_term *)node)->value.ident->name;
2276
2277 if (equal_parent_name(node, 6, "listen")) {
2278 listen = 1;
romanf02273a2023-05-25 09:44:11 +02002279 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01002280 ret = 1;
2281 goto cleanup;
2282 }
2283 }
2284
2285 i = 0;
2286 while (supported_encryption_algs[i]) {
2287 if (!strcmp(supported_encryption_algs[i], alg)) {
2288 if (listen) {
romane028ef92023-02-24 16:33:08 +01002289 if (nc_server_config_transport_params(alg, &endpt->opts.ssh->encryption_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002290 ret = 1;
2291 goto cleanup;
2292 }
2293 }
2294 break;
2295 }
2296 i++;
2297 }
2298 if (!supported_encryption_algs[i]) {
2299 /* algorithm not supported */
2300 ERR(NULL, "Encryption algorithm (%s) not supported by libssh.", alg);
2301 ret = 1;
2302 }
2303
2304cleanup:
2305 return ret;
2306}
2307
2308/* leaf-list */
2309static int
romane028ef92023-02-24 16:33:08 +01002310nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002311{
2312 struct nc_endpt *endpt;
2313 int ret = 0, listen = 0;
2314 const char *alg;
2315 uint8_t i;
2316
2317 /* get the algorithm name and compare it with algs supported by libssh */
2318 alg = ((struct lyd_node_term *)node)->value.ident->name;
2319
2320 if (equal_parent_name(node, 6, "listen")) {
2321 listen = 1;
romanf02273a2023-05-25 09:44:11 +02002322 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01002323 ret = 1;
2324 goto cleanup;
2325 }
2326 }
2327
2328 i = 0;
2329 while (supported_mac_algs[i]) {
2330 if (!strcmp(supported_mac_algs[i], alg)) {
2331 if (listen) {
romane028ef92023-02-24 16:33:08 +01002332 if (nc_server_config_transport_params(alg, &endpt->opts.ssh->mac_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002333 ret = 1;
2334 goto cleanup;
2335 }
2336 }
2337 break;
2338 }
2339 i++;
2340 }
2341 if (!supported_mac_algs[i]) {
2342 /* algorithm not supported */
2343 ERR(NULL, "MAC algorithm (%s) not supported by libssh.", alg);
2344 ret = 1;
2345 }
2346
2347cleanup:
2348 return ret;
2349}
2350
roman2eab4742023-06-06 10:00:26 +02002351#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02002352
romanc1d2b092023-02-02 08:58:27 +01002353static int
roman874fed12023-05-25 10:20:01 +02002354nc_server_config_create_unix_socket(struct nc_endpt *endpt)
roman83683fb2023-02-24 09:15:23 +01002355{
2356 endpt->ti = NC_TI_UNIX;
2357 endpt->opts.unixsock = calloc(1, sizeof *endpt->opts.unixsock);
2358 if (!endpt->opts.unixsock) {
2359 ERRMEM;
2360 return 1;
2361 }
2362
2363 /* set default values */
2364 endpt->opts.unixsock->mode = -1;
2365 endpt->opts.unixsock->uid = -1;
2366 endpt->opts.unixsock->gid = -1;
2367
2368 return 0;
2369}
2370
2371static int
romane028ef92023-02-24 16:33:08 +01002372nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op)
roman83683fb2023-02-24 09:15:23 +01002373{
2374 int ret = 0;
2375 uint32_t prev_lo;
2376 struct nc_endpt *endpt;
2377 struct nc_bind *bind;
2378 struct nc_server_unix_opts *opts;
2379 struct lyd_node *data = NULL;
2380
2381 assert(!strcmp(LYD_NAME(node), "unix-socket"));
2382
romanf02273a2023-05-25 09:44:11 +02002383 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
roman83683fb2023-02-24 09:15:23 +01002384 ret = 1;
2385 goto cleanup;
2386 }
2387
2388 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +02002389 if (nc_server_config_create_unix_socket(endpt)) {
roman83683fb2023-02-24 09:15:23 +01002390 ret = 1;
2391 goto cleanup;
2392 }
2393
2394 opts = endpt->opts.unixsock;
2395
2396 lyd_find_path(node, "path", 0, &data);
2397 assert(data);
2398
2399 opts->address = strdup(lyd_get_value(data));
2400 bind->address = strdup(lyd_get_value(data));
2401 if (!opts->address || !bind->address) {
2402 ERRMEM;
2403 ret = 1;
2404 goto cleanup;
2405 }
2406
2407 /* silently search for non-mandatory parameters */
2408 prev_lo = ly_log_options(0);
2409 ret = lyd_find_path(node, "mode", 0, &data);
2410 if (!ret) {
2411 opts->mode = strtol(lyd_get_value(data), NULL, 8);
2412 }
2413
2414 ret = lyd_find_path(node, "uid", 0, &data);
2415 if (!ret) {
2416 opts->uid = strtol(lyd_get_value(data), NULL, 10);
2417 }
2418
2419 ret = lyd_find_path(node, "gid", 0, &data);
2420 if (!ret) {
2421 opts->gid = strtol(lyd_get_value(data), NULL, 10);
2422 }
2423
2424 /* reset the logging options */
2425 ly_log_options(prev_lo);
2426
2427 ret = nc_server_config_set_address_port(endpt, bind, NULL, 0);
2428 if (ret) {
2429 goto cleanup;
2430 }
2431 } else if (op == NC_OP_DELETE) {
roman874fed12023-05-25 10:20:01 +02002432 nc_server_config_del_unix_socket(bind, endpt->opts.unixsock);
roman83683fb2023-02-24 09:15:23 +01002433 }
2434
2435cleanup:
2436 return ret;
2437}
2438
roman2eab4742023-06-06 10:00:26 +02002439#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02002440
roman0bbc19c2023-05-26 09:59:09 +02002441/**
2442 * @brief Set all endpoint client auth references, which couldn't be set beforehand.
2443 *
2444 * The references that could not be set are those, which reference endpoints, which
2445 * lie below the given endpoint in the YANG data (because of DFS tree parsing).
2446 *
2447 * @return 0 on success, 1 on error.
2448 */
2449static int
2450nc_server_config_fill_endpt_client_auth(void)
2451{
2452 uint16_t i, j;
2453
2454 for (i = 0; i < server_opts.endpt_count; i++) {
2455 /* go through all the endpoint */
2456 if (server_opts.endpts[i].referenced_endpt_name) {
2457 /* endpt has a reference, that hasn't been set yet */
2458 for (j = i + 1; j < server_opts.endpt_count; j++) {
2459 /* go through all the remaining endpts */
2460 if (!strcmp(server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[j].name)) {
2461 /* found the endpoint we were looking for */
2462 if (server_opts.endpts[i].ti == NC_TI_LIBSSH) {
2463 server_opts.endpts[i].opts.ssh->endpt_client_ref = &server_opts.endpts[j];
2464 break;
2465 } else {
2466 ERRINT;
2467 return 1;
2468 }
2469 }
2470 }
2471
2472 /* didn't find the endpoint */
2473 if (j == server_opts.endpt_count) {
2474 ERR(NULL, "Endpoint \"%s\" referenced by \"%s\" not found.",
2475 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2476 return 1;
2477 }
2478 }
2479 }
2480
2481 return 0;
2482}
2483
2484static int
2485nc_server_config_endpoint_client_auth_has_cycle(struct nc_endpt *original, struct nc_endpt *next, NC_TRANSPORT_IMPL transport)
2486{
2487 if (transport == NC_TI_LIBSSH) {
2488 if (next->opts.ssh->endpt_client_ref) {
2489 if (next->opts.ssh->endpt_client_ref == original) {
2490 return 1;
2491 } else {
2492 return nc_server_config_endpoint_client_auth_has_cycle(original, next->opts.ssh->endpt_client_ref, NC_TI_LIBSSH);
2493 }
2494 } else {
2495 return 0;
2496 }
2497 } else {
2498 ERRINT;
2499 return 1;
2500 }
2501}
2502
2503static int
2504nc_server_config_endpoint_client_auth(const struct lyd_node *node, NC_OPERATION op)
2505{
2506 int ret = 0;
2507 uint16_t i;
2508 const char *endpt_name;
2509 struct nc_endpt *endpt;
2510
2511 assert(!strcmp(LYD_NAME(node), "endpoint-client-auth"));
2512
2513 /* get current endpoint */
2514 ret = nc_server_config_get_endpt(node, &endpt, NULL);
2515 if (ret) {
2516 goto cleanup;
2517 }
2518
2519 if (op == NC_OP_DELETE) {
2520 endpt->opts.ssh->endpt_client_ref = NULL;
2521 goto cleanup;
2522 }
2523
2524 /* find the endpoint leafref is referring to */
2525 endpt_name = lyd_get_value(node);
2526 for (i = 0; i < server_opts.endpt_count; i++) {
2527 if (!strcmp(endpt_name, server_opts.endpts[i].name)) {
2528 break;
2529 }
2530 }
2531
2532 if (i == server_opts.endpt_count) {
2533 /* endpt not found, save the name and try to look it up later */
2534 endpt->referenced_endpt_name = strdup(endpt_name);
2535 if (!endpt->referenced_endpt_name) {
2536 ERRMEM;
2537 ret = 1;
2538 goto cleanup;
2539 }
2540 goto cleanup;
2541 }
2542
2543 /* check for self reference */
2544 if (endpt == &server_opts.endpts[i]) {
2545 ERR(NULL, "Self client authentication reference detected.");
2546 ret = 1;
2547 goto cleanup;
2548 }
2549
2550 /* check for cyclic references */
2551 ret = nc_server_config_endpoint_client_auth_has_cycle(endpt, &server_opts.endpts[i], endpt->ti);
2552 if (ret) {
2553 ERR(NULL, "Cyclic client authentication reference detected.");
2554 goto cleanup;
2555 }
2556
2557 /* assign the current endpt the referrenced endpt */
2558 endpt->opts.ssh->endpt_client_ref = &server_opts.endpts[i];
2559
2560cleanup:
2561 return ret;
2562}
2563
roman3f9b65c2023-06-05 14:26:58 +02002564static int
2565nc_server_config_tls_replace_cert_data(const struct lyd_node *node, struct nc_server_tls_opts *opts)
2566{
2567 nc_server_config_tls_del_cert_data(opts);
2568 opts->cert_data = strdup(lyd_get_value(node));
2569 if (!opts->cert_data) {
2570 ERRMEM;
2571 return 1;
2572 }
2573
2574 return 0;
2575}
2576
2577static int
2578nc_server_config_tls_replace_cert_data_client_auth(const struct lyd_node *node, struct nc_certificate *cert)
2579{
2580 nc_server_config_tls_del_cert_data_certificate(cert);
2581 cert->data = strdup(lyd_get_value(node));
2582 if (!cert->data) {
2583 ERRMEM;
2584 return 1;
2585 }
2586
2587 return 0;
2588}
2589
2590static int
2591nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op)
2592{
2593 int ret = 0;
2594 struct nc_endpt *endpt;
2595 struct nc_certificate *cert;
2596
2597 assert(!strcmp(LYD_NAME(node), "cert-data"));
2598
2599 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
2600 ret = 1;
2601 goto cleanup;
2602 }
2603
2604 if ((equal_parent_name(node, 3, "server-identity")) && (is_listen(node))) {
2605 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2606 ret = nc_server_config_tls_replace_cert_data(node, endpt->opts.tls);
2607 if (ret) {
2608 goto cleanup;
2609 }
2610 }
2611 } else if ((equal_parent_name(node, 3, "ca-certs")) && (is_listen(node))) {
2612 if (nc_server_config_get_cert(node, &endpt->opts.tls->ca_certs, &cert)) {
2613 ret = 1;
2614 goto cleanup;
2615 }
2616
2617 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2618 ret = nc_server_config_tls_replace_cert_data_client_auth(node, cert);
2619 if (ret) {
2620 goto cleanup;
2621 }
2622 } else {
2623 nc_server_config_tls_del_cert_data_certificate(cert);
2624 }
2625 } else if ((equal_parent_name(node, 3, "ee-certs")) && (is_listen(node))) {
2626 if (nc_server_config_get_cert(node, &endpt->opts.tls->ee_certs, &cert)) {
2627 ret = 1;
2628 goto cleanup;
2629 }
2630
2631 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2632 ret = nc_server_config_tls_replace_cert_data_client_auth(node, cert);
2633 if (ret) {
2634 goto cleanup;
2635 }
2636 } else {
2637 nc_server_config_tls_del_cert_data_certificate(cert);
2638 }
2639 }
2640
2641cleanup:
2642 return ret;
2643}
2644
2645static int
2646nc_server_config_tls_create_asymmetric_key_ref(const struct lyd_node *node, struct nc_endpt *endpt)
2647{
2648 uint16_t i;
2649 struct nc_keystore *ks = &server_opts.keystore;
2650
2651 /* lookup name */
2652 for (i = 0; i < ks->asym_key_count; i++) {
2653 if (!strcmp(lyd_get_value(node), ks->asym_keys[i].name)) {
2654 break;
2655 }
2656 }
2657
2658 if (i == ks->asym_key_count) {
2659 ERR(NULL, "Asymmetric key \"%s\" not found in the keystore.", lyd_get_value(node));
2660 return 1;
2661 }
2662
2663 endpt->opts.tls->key_ref = &ks->asym_keys[i];
2664
2665 return 0;
2666}
2667
2668static int
2669nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op)
2670{
2671 int ret = 0;
2672 struct nc_endpt *endpt;
2673
2674 assert(!strcmp(LYD_NAME(node), "asymmetric-key"));
2675
2676 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
2677 ret = 1;
2678 goto cleanup;
2679 }
2680
2681 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2682 /* set to keystore */
2683 endpt->opts.tls->store = NC_STORE_KEYSTORE;
2684
2685 ret = nc_server_config_tls_create_asymmetric_key_ref(node, endpt);
2686 if (ret) {
2687 goto cleanup;
2688 }
2689 } else {
2690 endpt->opts.tls->key_ref = NULL;
2691 }
2692
2693cleanup:
2694 return ret;
2695}
2696
2697static int
2698nc_server_config_tls_create_certificate_ref(const struct lyd_node *node, struct nc_endpt *endpt, struct nc_asymmetric_key *key)
2699{
2700 uint16_t i;
2701
2702 /* lookup name */
2703 for (i = 0; i < key->cert_count; i++) {
2704 if (!strcmp(lyd_get_value(node), key->certs[i].name)) {
2705 break;
2706 }
2707 }
2708
2709 if (i == key->cert_count) {
2710 ERR(NULL, "Certificate \"%s\" not found in the asymmetric key \"%s\".", lyd_get_value(node), key->name);
2711 return 1;
2712 }
2713
2714 endpt->opts.tls->cert_ref = &key->certs[i];
2715
2716 return 0;
2717}
2718
2719static struct nc_asymmetric_key *
2720cert_get_asymmetric_key(const struct lyd_node *node)
2721{
2722 uint16_t i;
2723 struct nc_keystore *ks = &server_opts.keystore;
2724
2725 /* starting with certificate node */
2726 assert(!strcmp(LYD_NAME(node), "certificate"));
2727
2728 /* switch to it's only sibling, must be asymmetric-key */
2729 node = node->prev;
2730 assert(!strcmp(LYD_NAME(node), "asymmetric-key"));
2731
2732 /* find the given asymmetric key */
2733 for (i = 0; i < ks->asym_key_count; i++) {
2734 if (!strcmp(lyd_get_value(node), ks->asym_keys[i].name)) {
2735 return &ks->asym_keys[i];
2736 }
2737 }
2738
2739 /* didn't find it */
2740 ERR(NULL, "Asymmetric key \"%s\" not found in the keystore.", lyd_get_value(node));
2741 return NULL;
2742}
2743
2744static int
2745nc_server_config_create_ca_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
2746{
2747 assert(!strcmp(LYD_NAME(node), "certificate"));
2748
2749 node = lyd_child(node);
2750 assert(!strcmp(LYD_NAME(node), "name"));
2751
2752 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ca_certs.certs, sizeof *opts->ca_certs.certs, &opts->ca_certs.cert_count);
2753}
2754
2755static int
2756nc_server_config_create_ee_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
2757{
2758 assert(!strcmp(LYD_NAME(node), "certificate"));
2759
2760 node = lyd_child(node);
2761 assert(!strcmp(LYD_NAME(node), "name"));
2762
2763 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ee_certs.certs, sizeof *opts->ee_certs.certs, &opts->ee_certs.cert_count);
2764}
2765
2766static int
2767nc_server_config_certificate(const struct lyd_node *node, NC_OPERATION op)
2768{
2769 int ret = 0;
2770 struct nc_endpt *endpt;
2771 struct nc_asymmetric_key *key;
2772
2773 assert(!strcmp(LYD_NAME(node), "certificate"));
2774
2775 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
2776 ret = 1;
2777 goto cleanup;
2778 }
2779
2780 if ((equal_parent_name(node, 1, "keystore-reference")) && (is_listen(node))) {
2781 /* server-identity TLS listen */
2782
2783 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2784 /* set to keystore */
2785 endpt->opts.tls->store = NC_STORE_KEYSTORE;
2786
2787 if (!endpt->opts.tls->key_ref) {
2788 /* we don't have a key from which we need the cert yet */
2789 key = cert_get_asymmetric_key(node);
2790 if (!key) {
2791 ret = 1;
2792 goto cleanup;
2793 }
2794 } else {
2795 /* we have the key */
2796 key = endpt->opts.tls->key_ref;
2797 }
2798
2799 /* find the given cert in the key and set it */
2800 ret = nc_server_config_tls_create_certificate_ref(node, endpt, key);
2801 if (ret) {
2802 goto cleanup;
2803 }
2804 } else {
2805 endpt->opts.tls->cert_ref = NULL;
2806 }
2807 } else if ((equal_parent_name(node, 2, "ca-certs")) && (is_listen(node))) {
2808 /* client auth TLS listen */
2809 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2810 ret = nc_server_config_create_ca_certs_certificate(node, endpt->opts.tls);
2811 if (ret) {
2812 goto cleanup;
2813 }
2814 } else {
2815 nc_server_config_tls_del_certs(&endpt->opts.tls->ca_certs);
2816 }
2817 } else if ((equal_parent_name(node, 2, "ee-certs")) && (is_listen(node))) {
2818 /* client auth TLS listen */
2819 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2820 ret = nc_server_config_create_ee_certs_certificate(node, endpt->opts.tls);
2821 if (ret) {
2822 goto cleanup;
2823 }
2824 } else {
2825 nc_server_config_tls_del_certs(&endpt->opts.tls->ee_certs);
2826 }
2827 }
2828
2829cleanup:
2830 return ret;
2831}
2832
2833static int
2834nc_server_config_create_cert_to_name(const struct lyd_node *node, struct nc_server_tls_opts *opts)
2835{
2836 int ret = 0;
2837 struct lyd_node *n;
2838 struct nc_ctn *new, *iter;
2839 const char *map_type, *name;
2840 uint32_t id;
2841 NC_TLS_CTN_MAPTYPE m_type;
2842
2843 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
2844
2845 /* create new ctn */
2846 new = calloc(1, sizeof *new);
2847 if (!new) {
2848 ERRMEM;
2849 ret = 1;
2850 goto cleanup;
2851 }
2852
2853 /* get all the data */
2854 /* find the list's key */
2855 lyd_find_path(node, "id", 0, &n);
2856 assert(n);
2857 id = strtoul(lyd_get_value(n), NULL, 10);
2858
2859 /* find the ctn's name */
2860 lyd_find_path(node, "name", 0, &n);
2861 assert(n);
2862 name = lyd_get_value(n);
2863
2864 /* find the ctn's map-type */
2865 lyd_find_path(node, "map-type", 0, &n);
2866 assert(n);
2867 map_type = ((struct lyd_node_term *)n)->value.ident->name;
2868 if (!strcmp(map_type, "specified")) {
2869 m_type = NC_TLS_CTN_SPECIFIED;
2870 } else if (!strcmp(map_type, "san-rfc822-name")) {
2871 m_type = NC_TLS_CTN_SAN_RFC822_NAME;
2872 } else if (!strcmp(map_type, "san-dns-name")) {
2873 m_type = NC_TLS_CTN_SAN_DNS_NAME;
2874 } else if (!strcmp(map_type, "san-ip-address")) {
2875 m_type = NC_TLS_CTN_SAN_IP_ADDRESS;
2876 } else if (!strcmp(map_type, "san-any")) {
2877 m_type = NC_TLS_CTN_SAN_ANY;
2878 } else if (!strcmp(map_type, "common-name")) {
2879 m_type = NC_TLS_CTN_COMMON_NAME;
2880 } else {
2881 ERR(NULL, "Map-type identity \"%s\" not supported.", map_type);
2882 ret = 1;
2883 goto cleanup;
2884 }
2885
2886 /* find the right place for insertion */
2887 if (!opts->ctn) {
2888 /* inserting the first one */
2889 opts->ctn = new;
2890 } else if (opts->ctn->id > new->id) {
2891 /* insert at the beginning */
2892 new->next = opts->ctn;
2893 opts->ctn = new;
2894 } else {
2895 /* have to find the right place */
2896 for (iter = opts->ctn; iter->next && iter->next->id <= new->id; iter = iter->next) {}
2897 if (iter->id == new->id) {
2898 /* collision */
2899 new = iter;
2900 } else {
2901 new->next = iter->next;
2902 iter->next = new;
2903 }
2904 }
2905
2906 /* insert the right data */
2907 new->id = id;
2908 if (new->name) {
2909 free(new->name);
2910 }
2911 new->name = strdup(name);
2912 if (!new->name) {
2913 ERRMEM;
2914 ret = 1;
2915 goto cleanup;
2916 }
2917 new->map_type = m_type;
2918
2919cleanup:
2920 return ret;
2921}
2922
2923static int
2924nc_server_config_cert_to_name(const struct lyd_node *node, NC_OPERATION op)
2925{
2926 int ret = 0;
2927 struct nc_endpt *endpt;
2928 struct lyd_node *key;
2929 struct nc_ctn *ctn;
2930
2931 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
2932
2933 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
2934 ret = 1;
2935 goto cleanup;
2936 }
2937
2938 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2939 ret = nc_server_config_create_cert_to_name(node, endpt->opts.tls);
2940 if (ret) {
2941 goto cleanup;
2942 }
2943 } else {
2944 /* find the given ctn entry */
2945 lyd_find_path(node, "id", 0, &key);
2946 assert(key);
2947 if (nc_server_config_get_ctn(node, endpt, &ctn)) {
2948 ret = 1;
2949 goto cleanup;
2950 }
2951 nc_server_config_del_ctn(endpt->opts.tls, ctn);
2952 }
2953
2954cleanup:
2955 return ret;
2956}
2957
2958static int
2959nc_server_config_replace_fingerprint(const struct lyd_node *node, struct nc_ctn *ctn)
2960{
2961 nc_server_config_del_fingerprint(ctn);
2962
2963 ctn->fingerprint = strdup(lyd_get_value(node));
2964 if (!ctn->fingerprint) {
2965 ERRMEM;
2966 return 1;
2967 }
2968
2969 return 0;
2970}
2971
2972static int
2973nc_server_config_fingerprint(const struct lyd_node *node, NC_OPERATION op)
2974{
2975 int ret = 0;
2976 struct nc_endpt *endpt;
2977 struct nc_ctn *ctn;
2978
2979 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
2980 ret = 1;
2981 goto cleanup;
2982 }
2983
2984 if (nc_server_config_get_ctn(node, endpt, &ctn)) {
2985 ret = 1;
2986 goto cleanup;
2987 }
2988
2989 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2990 ret = nc_server_config_replace_fingerprint(node, ctn);
2991 if (ret) {
2992 goto cleanup;
2993 }
2994 } else {
2995 nc_server_config_del_fingerprint(ctn);
2996 }
2997
2998cleanup:
2999 return ret;
3000}
3001
roman2eab4742023-06-06 10:00:26 +02003002#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02003003
roman83683fb2023-02-24 09:15:23 +01003004static int
romanf02273a2023-05-25 09:44:11 +02003005nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01003006{
3007 const char *name = LYD_NAME(node);
3008
3009 if (!strcmp(name, "listen")) {
romanf02273a2023-05-25 09:44:11 +02003010 if (nc_server_config_listen(NULL, op)) {
romanc1d2b092023-02-02 08:58:27 +01003011 goto error;
3012 }
3013 } else if (!strcmp(name, "idle-timeout")) {
romane028ef92023-02-24 16:33:08 +01003014 if (nc_server_config_idle_timeout(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003015 goto error;
3016 }
3017 } else if (!strcmp(name, "endpoint")) {
romane028ef92023-02-24 16:33:08 +01003018 if (nc_server_config_endpoint(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003019 goto error;
3020 }
roman2eab4742023-06-06 10:00:26 +02003021 } else if (!strcmp(name, "unix-socket")) {
3022 if (nc_server_config_unix_socket(node, op)) {
3023 goto error;
3024 }
roman3f9b65c2023-06-05 14:26:58 +02003025 }
roman2eab4742023-06-06 10:00:26 +02003026#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02003027 else if (!strcmp(name, "ssh")) {
romane028ef92023-02-24 16:33:08 +01003028 if (nc_server_config_ssh(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003029 goto error;
3030 }
roman2eab4742023-06-06 10:00:26 +02003031 } else if (!strcmp(name, "local-address")) {
romane028ef92023-02-24 16:33:08 +01003032 if (nc_server_config_local_address(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003033 goto error;
3034 }
3035 } else if (!strcmp(name, "local-port")) {
romane028ef92023-02-24 16:33:08 +01003036 if (nc_server_config_local_port(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003037 goto error;
3038 }
3039 } else if (!strcmp(name, "keepalives")) {
romane028ef92023-02-24 16:33:08 +01003040 if (nc_server_config_keepalives(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003041 goto error;
3042 }
3043 } else if (!strcmp(name, "idle-time")) {
romane028ef92023-02-24 16:33:08 +01003044 if (nc_server_config_idle_time(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003045 goto error;
3046 }
3047 } else if (!strcmp(name, "max-probes")) {
romane028ef92023-02-24 16:33:08 +01003048 if (nc_server_config_max_probes(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003049 goto error;
3050 }
3051 } else if (!strcmp(name, "probe-interval")) {
romane028ef92023-02-24 16:33:08 +01003052 if (nc_server_config_probe_interval(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003053 goto error;
3054 }
roman2eab4742023-06-06 10:00:26 +02003055 } else if (!strcmp(name, "host-key")) {
romane028ef92023-02-24 16:33:08 +01003056 if (nc_server_config_host_key(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003057 goto error;
3058 }
roman2eab4742023-06-06 10:00:26 +02003059 } else if (!strcmp(name, "public-key-format")) {
romane028ef92023-02-24 16:33:08 +01003060 if (nc_server_config_public_key_format(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003061 goto error;
3062 }
3063 } else if (!strcmp(name, "public-key")) {
romane028ef92023-02-24 16:33:08 +01003064 if (nc_server_config_public_key(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003065 goto error;
3066 }
3067 } else if (!strcmp(name, "private-key-format")) {
romane028ef92023-02-24 16:33:08 +01003068 if (nc_server_config_private_key_format(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003069 goto error;
3070 }
3071 } else if (!strcmp(name, "cleartext-private-key")) {
romane028ef92023-02-24 16:33:08 +01003072 if (nc_server_config_cleartext_private_key(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003073 goto error;
3074 }
roman2eab4742023-06-06 10:00:26 +02003075 } else if (!strcmp(name, "keystore-reference")) {
romane028ef92023-02-24 16:33:08 +01003076 if (nc_server_config_keystore_reference(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003077 goto error;
3078 }
3079 } else if (!strcmp(name, "user")) {
romane028ef92023-02-24 16:33:08 +01003080 if (nc_server_config_user(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003081 goto error;
3082 }
3083 } else if (!strcmp(name, "auth-attempts")) {
romane028ef92023-02-24 16:33:08 +01003084 if (nc_server_config_auth_attempts(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003085 goto error;
3086 }
3087 } else if (!strcmp(name, "auth-timeout")) {
romane028ef92023-02-24 16:33:08 +01003088 if (nc_server_config_auth_timeout(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003089 goto error;
3090 }
roman2eab4742023-06-06 10:00:26 +02003091 } else if (!strcmp(name, "truststore-reference")) {
romane028ef92023-02-24 16:33:08 +01003092 if (nc_server_config_truststore_reference(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003093 goto error;
3094 }
roman2eab4742023-06-06 10:00:26 +02003095 } else if (!strcmp(name, "password")) {
romane028ef92023-02-24 16:33:08 +01003096 if (nc_server_config_password(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003097 goto error;
3098 }
3099 } else if (!strcmp(name, "pam-config-file-name")) {
romane028ef92023-02-24 16:33:08 +01003100 if (nc_server_config_pam_name(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003101 goto error;
3102 }
3103 } else if (!strcmp(name, "pam-config-file-dir")) {
romane028ef92023-02-24 16:33:08 +01003104 if (nc_server_config_pam_dir(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003105 goto error;
3106 }
3107 } else if (!strcmp(name, "none")) {
romane028ef92023-02-24 16:33:08 +01003108 if (nc_server_config_none(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003109 goto error;
3110 }
3111 } else if (!strcmp(name, "host-key-alg")) {
romane028ef92023-02-24 16:33:08 +01003112 if (nc_server_config_host_key_alg(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003113 goto error;
3114 }
3115 } else if (!strcmp(name, "key-exchange-alg")) {
romane028ef92023-02-24 16:33:08 +01003116 if (nc_server_config_kex_alg(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003117 goto error;
3118 }
3119 } else if (!strcmp(name, "encryption-alg")) {
romane028ef92023-02-24 16:33:08 +01003120 if (nc_server_config_encryption_alg(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003121 goto error;
3122 }
3123 } else if (!strcmp(name, "mac-alg")) {
romane028ef92023-02-24 16:33:08 +01003124 if (nc_server_config_mac_alg(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003125 goto error;
3126 }
roman2eab4742023-06-06 10:00:26 +02003127 } else if (!strcmp(name, "endpoint-client-auth")) {
roman0bbc19c2023-05-26 09:59:09 +02003128 if (nc_server_config_endpoint_client_auth(node, op)) {
3129 goto error;
3130 }
roman2eab4742023-06-06 10:00:26 +02003131 } else if (!strcmp(name, "tls")) {
roman3f9b65c2023-06-05 14:26:58 +02003132 if (nc_server_config_tls(node, op)) {
3133 goto error;
3134 }
3135 } else if (!strcmp(name, "cert-data")) {
3136 if (nc_server_config_cert_data(node, op)) {
3137 goto error;
3138 }
3139 } else if (!strcmp(name, "asymmetric-key")) {
3140 if (nc_server_config_asymmetric_key(node, op)) {
3141 goto error;
3142 }
3143 } else if (!strcmp(name, "certificate")) {
3144 if (nc_server_config_certificate(node, op)) {
3145 goto error;
3146 }
3147 } else if (!strcmp(name, "cert-to-name")) {
3148 if (nc_server_config_cert_to_name(node, op)) {
3149 goto error;
3150 }
3151 } else if (!strcmp(name, "fingerprint")) {
3152 if (nc_server_config_fingerprint(node, op)) {
3153 goto error;
3154 }
3155 }
roman2eab4742023-06-06 10:00:26 +02003156#endif /* NC_ENABLED_SSH_TLS */
romanc1d2b092023-02-02 08:58:27 +01003157
3158 return 0;
3159
3160error:
3161 ERR(NULL, "Configuring (%s) failed.", LYD_NAME(node));
3162 return 1;
3163}
3164
3165int
roman0bbc19c2023-05-26 09:59:09 +02003166nc_server_config_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, NC_MODULE module)
romanc1d2b092023-02-02 08:58:27 +01003167{
3168 struct lyd_node *child;
3169 struct lyd_meta *m;
romanf9906b42023-05-22 14:04:29 +02003170 NC_OPERATION current_op = NC_OP_UNKNOWN;
romanf02273a2023-05-25 09:44:11 +02003171 int ret;
romanc1d2b092023-02-02 08:58:27 +01003172
3173 assert(node);
3174
romanf9906b42023-05-22 14:04:29 +02003175 /* get current op if there is any */
3176 if ((m = lyd_find_meta(node->meta, NULL, "yang:operation"))) {
3177 if (!strcmp(lyd_get_meta_value(m), "create")) {
3178 current_op = NC_OP_CREATE;
3179 } else if (!strcmp(lyd_get_meta_value(m), "delete")) {
3180 current_op = NC_OP_DELETE;
3181 } else if (!strcmp(lyd_get_meta_value(m), "replace")) {
3182 current_op = NC_OP_REPLACE;
3183 } else if (!strcmp(lyd_get_meta_value(m), "none")) {
3184 current_op = NC_OP_NONE;
romanc1d2b092023-02-02 08:58:27 +01003185 }
3186 }
3187
3188 /* node has no op, inherit from the parent */
romanf9906b42023-05-22 14:04:29 +02003189 if (!current_op) {
3190 if (!parent_op) {
3191 ERR(NULL, "Unknown operation for node \"%s\".", LYD_NAME(node));
3192 return 1;
3193 }
3194
romanc1d2b092023-02-02 08:58:27 +01003195 current_op = parent_op;
3196 }
3197
3198 switch (current_op) {
3199 case NC_OP_NONE:
3200 break;
3201 case NC_OP_CREATE:
3202 case NC_OP_DELETE:
3203 case NC_OP_REPLACE:
roman2eab4742023-06-06 10:00:26 +02003204#ifdef NC_ENABLED_SSH_TLS
3205 if (module == NC_MODULE_KEYSTORE) {
romanf02273a2023-05-25 09:44:11 +02003206 ret = nc_server_config_parse_keystore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02003207 } else if (module == NC_MODULE_TRUSTSTORE) {
romanf02273a2023-05-25 09:44:11 +02003208 ret = nc_server_config_parse_truststore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02003209 } else
3210#endif /* NC_ENABLED_SSH_TLS */
3211 {
3212 ret = nc_server_config_parse_netconf_server(node, current_op);
romanf02273a2023-05-25 09:44:11 +02003213 }
3214 if (ret) {
3215 return ret;
romanc1d2b092023-02-02 08:58:27 +01003216 }
3217 break;
3218 default:
3219 break;
3220 }
3221
3222 if (current_op != NC_OP_DELETE) {
3223 LY_LIST_FOR(lyd_child(node), child) {
roman0bbc19c2023-05-26 09:59:09 +02003224 if (nc_server_config_parse_tree(child, current_op, module)) {
romanc1d2b092023-02-02 08:58:27 +01003225 return 1;
3226 }
3227 }
3228 }
3229 return 0;
3230}
3231
romanc1d2b092023-02-02 08:58:27 +01003232API int
3233nc_server_config_load_modules(struct ly_ctx **ctx)
3234{
3235 int i, new_ctx = 0;
3236
3237 if (!*ctx) {
3238 if (ly_ctx_new(NC_SERVER_SEARCH_DIR, 0, ctx)) {
3239 ERR(NULL, "Couldn't create new libyang context.\n");
3240 goto error;
3241 }
3242 new_ctx = 1;
3243 }
3244
3245 /* all features */
3246 const char *ietf_nectonf_server[] = {"ssh-listen", "tls-listen", "ssh-call-home", "tls-call-home", "central-netconf-server-supported", NULL};
3247 /* all features */
3248 const char *ietf_x509_cert_to_name[] = {NULL};
roman7fdc84d2023-06-06 13:14:53 +02003249 /* no private-key-encryption, csr-generation, p10-csr-format, certificate-expiration-notification,
3250 * encrypted-passwords, hidden-symmetric-keys, encrypted-symmetric-keys, hidden-private-keys, encrypted-private-keys
3251 */
romanc1d2b092023-02-02 08:58:27 +01003252 const char *ietf_crypto_types[] = {
3253 "one-symmetric-key-format", "one-asymmetric-key-format", "symmetrically-encrypted-value-format",
3254 "asymmetrically-encrypted-value-format", "cms-enveloped-data-format", "cms-encrypted-data-format",
roman7fdc84d2023-06-06 13:14:53 +02003255 "cleartext-passwords", "cleartext-symmetric-keys", "cleartext-private-keys", NULL
romanc1d2b092023-02-02 08:58:27 +01003256 };
3257 /* all features */
3258 const char *ietf_tcp_common[] = {"keepalives-supported", NULL};
roman7fdc84d2023-06-06 13:14:53 +02003259 /* all features */
3260 const char *ietf_tcp_server[] = {"tcp-server-keepalives", NULL};
3261 /* all features */
3262 const char *ietf_tcp_client[] = {"local-binding-supported", "tcp-client-keepalives", "proxy-connect", "socks5-gss-api", "socks5-username-password", NULL};
romanc1d2b092023-02-02 08:58:27 +01003263 /* no ssh-x509-certs */
3264 const char *ietf_ssh_common[] = {"transport-params", "public-key-generation", NULL};
roman7fdc84d2023-06-06 13:14:53 +02003265 /* no ssh-server-keepalives and local-user-auth-hostbased */
3266 const char *ietf_ssh_server[] = {"local-users-supported", "local-user-auth-publickey", "local-user-auth-password", "local-user-auth-none", NULL};
romanc1d2b092023-02-02 08:58:27 +01003267 /* all features */
3268 const char *iana_ssh_encryption_algs[] = {NULL};
3269 /* all features */
3270 const char *iana_ssh_key_exchange_algs[] = {NULL};
3271 /* all features */
3272 const char *iana_ssh_mac_algs[] = {NULL};
3273 /* all features */
3274 const char *iana_ssh_public_key_algs[] = {NULL};
romanc1d2b092023-02-02 08:58:27 +01003275 /* all features */
roman7fdc84d2023-06-06 13:14:53 +02003276 const char *iana_crypt_hash[] = {"crypt-hash-md5", "crypt-hash-sha-256", "crypt-hash-sha-512", NULL};
3277 /* no symmetric-keys */
3278 const char *ietf_keystore[] = {"central-keystore-supported", "inline-definitions-supported", "asymmetric-keys", NULL};
3279 /* all features */
3280 const char *ietf_truststore[] = {"central-truststore-supported", "inline-definitions-supported", "certificates", "public-keys", NULL};
3281 /* all features */
3282 const char *ietf_tls_common[] = {"tls10", "tls11", "tls12", "tls13", "hello-params", "public-key-generation", NULL};
romanc1d2b092023-02-02 08:58:27 +01003283 /* all features */
3284 const char *ietf_tls_server[] = {
3285 "tls-server-keepalives", "server-ident-x509-cert", "server-ident-raw-public-key", "server-ident-tls12-psk",
3286 "server-ident-tls13-epsk", "client-auth-supported", "client-auth-x509-cert", "client-auth-raw-public-key",
3287 "client-auth-tls12-psk", "client-auth-tls13-epsk", NULL
3288 };
3289 /* all features */
3290 const char *libnetconf2_netconf_server[] = {NULL};
3291
3292 const char *module_names[] = {
roman7fdc84d2023-06-06 13:14:53 +02003293 "ietf-netconf-server", "ietf-x509-cert-to-name", "ietf-crypto-types", "ietf-tcp-common", "ietf-tcp-server",
3294 "ietf-tcp-client", "ietf-ssh-common", "ietf-ssh-server", "iana-ssh-encryption-algs",
3295 "iana-ssh-key-exchange-algs", "iana-ssh-mac-algs", "iana-ssh-public-key-algs", "iana-crypt-hash",
3296 "ietf-keystore", "ietf-truststore", "ietf-tls-common", "ietf-tls-server", "libnetconf2-netconf-server", NULL
romanc1d2b092023-02-02 08:58:27 +01003297 };
3298
3299 const char **module_features[] = {
roman7fdc84d2023-06-06 13:14:53 +02003300 ietf_nectonf_server, ietf_x509_cert_to_name, ietf_crypto_types, ietf_tcp_common,
3301 ietf_tcp_server, ietf_tcp_client, ietf_ssh_common, ietf_ssh_server, iana_ssh_encryption_algs,
3302 iana_ssh_key_exchange_algs, iana_ssh_mac_algs, iana_ssh_public_key_algs, iana_crypt_hash,
3303 ietf_keystore, ietf_truststore, ietf_tls_common, ietf_tls_server, libnetconf2_netconf_server, NULL
romanc1d2b092023-02-02 08:58:27 +01003304 };
3305
3306 for (i = 0; module_names[i] != NULL; i++) {
3307 if (!ly_ctx_load_module(*ctx, module_names[i], NULL, module_features[i])) {
3308 ERR(NULL, "Loading module \"%s\" failed.\n", module_names[i]);
3309 goto error;
3310 }
3311 }
3312
3313 return 0;
3314
3315error:
3316 if (new_ctx) {
3317 ly_ctx_destroy(*ctx);
3318 *ctx = NULL;
3319 }
3320 return 1;
3321}
3322
romanf9906b42023-05-22 14:04:29 +02003323static int
3324nc_server_config_fill_nectonf_server(const struct lyd_node *data, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01003325{
3326 int ret = 0;
3327 struct lyd_node *tree;
romand57b3722023-04-05 11:26:25 +02003328
romanc1d2b092023-02-02 08:58:27 +01003329 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &tree);
3330 if (ret) {
3331 ERR(NULL, "Unable to find the netconf-server container in the YANG data.");
3332 goto cleanup;
3333 }
3334
roman0bbc19c2023-05-26 09:59:09 +02003335 if (nc_server_config_parse_tree(tree, op, NC_MODULE_NETCONF_SERVER)) {
3336 ret = 1;
3337 goto cleanup;
3338 }
3339
roman2eab4742023-06-06 10:00:26 +02003340#ifdef NC_ENABLED_SSH_TLS
3341 /* backward check of client auth reference */
roman0bbc19c2023-05-26 09:59:09 +02003342 if (nc_server_config_fill_endpt_client_auth()) {
romanf9906b42023-05-22 14:04:29 +02003343 ret = 1;
3344 goto cleanup;
3345 }
roman2eab4742023-06-06 10:00:26 +02003346#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02003347
3348cleanup:
3349 return ret;
3350}
3351
3352API int
romanf6f37a52023-05-25 14:27:51 +02003353nc_server_config_setup_diff(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02003354{
3355 int ret = 0;
3356
3357 /* LOCK */
3358 pthread_rwlock_wrlock(&server_opts.config_lock);
3359
roman2eab4742023-06-06 10:00:26 +02003360#ifdef NC_ENABLED_SSH_TLS
romanf9906b42023-05-22 14:04:29 +02003361 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02003362 ret = nc_server_config_fill_keystore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02003363 if (ret) {
3364 ERR(NULL, "Filling keystore failed.");
3365 goto cleanup;
3366 }
3367
3368 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02003369 ret = nc_server_config_fill_truststore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02003370 if (ret) {
3371 ERR(NULL, "Filling truststore failed.");
3372 goto cleanup;
3373 }
roman2eab4742023-06-06 10:00:26 +02003374#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02003375
3376 /* configure netconf-server */
3377 ret = nc_server_config_fill_nectonf_server(data, NC_OP_UNKNOWN);
3378 if (ret) {
3379 ERR(NULL, "Filling netconf-server failed.");
3380 goto cleanup;
3381 }
3382
3383cleanup:
3384 /* UNLOCK */
3385 pthread_rwlock_unlock(&server_opts.config_lock);
3386 return ret;
3387}
3388
3389API int
romanf6f37a52023-05-25 14:27:51 +02003390nc_server_config_setup_data(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02003391{
3392 int ret = 0;
3393 struct lyd_node *tree, *iter, *root;
3394
3395 /* LOCK */
3396 pthread_rwlock_wrlock(&server_opts.config_lock);
3397
3398 /* find the netconf-server node */
3399 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &root);
3400 if (ret) {
3401 ERR(NULL, "Unable to find the netconf-server container in the YANG data.");
3402 goto cleanup;
3403 }
3404
3405 /* iterate through all the nodes and make sure there is no operation attribute */
3406 LY_LIST_FOR(root, tree) {
3407 LYD_TREE_DFS_BEGIN(tree, iter) {
3408 if (lyd_find_meta(iter->meta, NULL, "yang:operation")) {
3409 ERR(NULL, "Unexpected operation attribute in the YANG data.");
romanc1d2b092023-02-02 08:58:27 +01003410 ret = 1;
3411 goto cleanup;
3412 }
romanf9906b42023-05-22 14:04:29 +02003413 LYD_TREE_DFS_END(tree, iter);
romanc1d2b092023-02-02 08:58:27 +01003414 }
3415 }
3416
romanf9906b42023-05-22 14:04:29 +02003417 /* delete the current configuration */
romanf02273a2023-05-25 09:44:11 +02003418 nc_server_config_listen(NULL, NC_OP_DELETE);
roman2eab4742023-06-06 10:00:26 +02003419#ifdef NC_ENABLED_SSH_TLS
romanf02273a2023-05-25 09:44:11 +02003420 nc_server_config_ks_keystore(NULL, NC_OP_DELETE);
3421 nc_server_config_ts_truststore(NULL, NC_OP_DELETE);
romanf9906b42023-05-22 14:04:29 +02003422
3423 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02003424 ret = nc_server_config_fill_keystore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02003425 if (ret) {
3426 ERR(NULL, "Filling keystore failed.");
3427 goto cleanup;
3428 }
3429
3430 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02003431 ret = nc_server_config_fill_truststore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02003432 if (ret) {
3433 ERR(NULL, "Filling truststore failed.");
3434 goto cleanup;
3435 }
roman2eab4742023-06-06 10:00:26 +02003436#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02003437
3438 /* configure netconf-server */
3439 ret = nc_server_config_fill_nectonf_server(data, NC_OP_CREATE);
3440 if (ret) {
3441 ERR(NULL, "Filling netconf-server failed.");
romanc1d2b092023-02-02 08:58:27 +01003442 goto cleanup;
3443 }
3444
3445cleanup:
3446 /* UNLOCK */
3447 pthread_rwlock_unlock(&server_opts.config_lock);
3448 return ret;
3449}
roman3f9b65c2023-06-05 14:26:58 +02003450
3451API int
3452nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path)
3453{
3454 struct lyd_node *tree = NULL;
3455 int ret = 0;
3456
3457 NC_CHECK_ARG_RET(NULL, path, 1);
3458
3459 ret = lyd_parse_data_path(ctx, path, LYD_UNKNOWN, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree);
3460 if (ret) {
3461 goto cleanup;
3462 }
3463
3464 ret = nc_server_config_setup_data(tree);
3465 if (ret) {
3466 goto cleanup;
3467 }
3468
3469cleanup:
3470 lyd_free_all(tree);
3471 return ret;
3472}