blob: a143839eb12ec9c0f062b99a0d3e3b3f85b7fd90 [file] [log] [blame]
romanc1d2b092023-02-02 08:58:27 +01001/**
romane028ef92023-02-24 16:33:08 +01002 * @file server_config.c
romanc1d2b092023-02-02 08:58:27 +01003 * @author Roman Janota <janota@cesnet.cz>
4 * @brief libnetconf2 server configuration functions
5 *
6 * @copyright
romanf02273a2023-05-25 09:44:11 +02007 * Copyright (c) 2022-2023 CESNET, z.s.p.o.
romanc1d2b092023-02-02 08:58:27 +01008 *
9 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * https://opensource.org/licenses/BSD-3-Clause
14 */
roman27215242023-03-10 14:55:00 +010015
16#define _GNU_SOURCE
17
romanc1d2b092023-02-02 08:58:27 +010018#include <assert.h>
roman12644fe2023-06-08 11:06:42 +020019#include <ctype.h>
roman3f9b65c2023-06-05 14:26:58 +020020#include <pthread.h>
21#include <stdint.h>
romanc1d2b092023-02-02 08:58:27 +010022#include <stdlib.h>
23#include <string.h>
roman2eab4742023-06-06 10:00:26 +020024#include <unistd.h>
romanc1d2b092023-02-02 08:58:27 +010025
roman3f9b65c2023-06-05 14:26:58 +020026#include <libyang/libyang.h>
27
romanc1d2b092023-02-02 08:58:27 +010028#include "compat.h"
roman3f9b65c2023-06-05 14:26:58 +020029#include "config.h"
30#include "log_p.h"
romane028ef92023-02-24 16:33:08 +010031#include "server_config.h"
romanf02273a2023-05-25 09:44:11 +020032#include "server_config_p.h"
roman3f9b65c2023-06-05 14:26:58 +020033#include "session_p.h"
34
roman2eab4742023-06-06 10:00:26 +020035#ifdef NC_ENABLED_SSH_TLS
romanc1d2b092023-02-02 08:58:27 +010036
37/* All libssh supported host-key, key-exchange, encryption and mac algorithms as of version 0.10.90 */
38
39static const char *supported_hostkey_algs[] = {
romana6bf6ab2023-05-26 13:26:02 +020040 "openssh-ssh-ed25519-cert-v01", "openssh-ecdsa-sha2-nistp521-cert-v01",
41 "openssh-ecdsa-sha2-nistp384-cert-v01", "openssh-ecdsa-sha2-nistp256-cert-v01",
42 "openssh-rsa-sha2-512-cert-v01", "openssh-rsa-sha2-256-cert-v01",
43 "openssh-ssh-rsa-cert-v01", "openssh-ssh-dss-cert-v01",
romanc1d2b092023-02-02 08:58:27 +010044 "ssh-ed25519", "ecdsa-sha2-nistp521", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp256",
45 "rsa-sha2-512", "rsa-sha2-256", "ssh-rsa", "ssh-dss", NULL
46};
47
48static const char *supported_kex_algs[] = {
romana6bf6ab2023-05-26 13:26:02 +020049 "diffie-hellman-group-exchange-sha1", "curve25519-sha256", "libssh-curve25519-sha256",
romanc1d2b092023-02-02 08:58:27 +010050 "ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", "diffie-hellman-group18-sha512",
51 "diffie-hellman-group16-sha512", "diffie-hellman-group-exchange-sha256", "diffie-hellman-group14-sha256", NULL
52};
53
54static const char *supported_encryption_algs[] = {
romana6bf6ab2023-05-26 13:26:02 +020055 "openssh-chacha20-poly1305", "openssh-aes256-gcm", "openssh-aes128-gcm",
romanc1d2b092023-02-02 08:58:27 +010056 "aes256-ctr", "aes192-ctr", "aes128-ctr", "aes256-cbc", "aes192-cbc", "aes128-cbc",
roman27215242023-03-10 14:55:00 +010057 "blowfish-cbc", "triple-des-cbc", "none", NULL
romanc1d2b092023-02-02 08:58:27 +010058};
59
60static const char *supported_mac_algs[] = {
romana6bf6ab2023-05-26 13:26:02 +020061 "openssh-hmac-sha2-256-etm", "openssh-hmac-sha2-512-etm", "openssh-hmac-sha1-etm",
romanc1d2b092023-02-02 08:58:27 +010062 "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1", NULL
63};
64
roman2eab4742023-06-06 10:00:26 +020065#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +020066
romanc1d2b092023-02-02 08:58:27 +010067extern struct nc_server_opts server_opts;
68
romanf02273a2023-05-25 09:44:11 +020069int
70nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, struct nc_bind **bind)
romanc1d2b092023-02-02 08:58:27 +010071{
72 uint16_t i;
73 const char *endpt_name;
74
75 assert(node);
76
77 while (node) {
78 if (!strcmp(LYD_NAME(node), "endpoint")) {
79 break;
80 }
81 node = lyd_parent(node);
82 }
83
84 if (!node) {
85 ERR(NULL, "Node \"%s\" is not contained in an endpoint subtree.", LYD_NAME(node));
86 return 1;
87 }
88
89 node = lyd_child(node);
90 assert(!strcmp(LYD_NAME(node), "name"));
91 endpt_name = lyd_get_value(node);
92
93 for (i = 0; i < server_opts.endpt_count; i++) {
94 if (!strcmp(server_opts.endpts[i].name, endpt_name)) {
95 *endpt = &server_opts.endpts[i];
96 if (bind) {
97 *bind = &server_opts.binds[i];
98 }
99 return 0;
100 }
101 }
102
103 ERR(NULL, "Endpoint \"%s\" was not found.", endpt_name);
104 return 1;
105}
106
roman2eab4742023-06-06 10:00:26 +0200107#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +0200108
romanf02273a2023-05-25 09:44:11 +0200109int
110nc_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 +0100111{
112 uint16_t i;
113 const char *hostkey_name;
114
115 assert(node && opts);
116
117 while (node) {
118 if (!strcmp(LYD_NAME(node), "host-key")) {
119 break;
120 }
121 node = lyd_parent(node);
122 }
123
124 if (!node) {
125 ERR(NULL, "Node \"%s\" is not contained in a host-key subtree.", LYD_NAME(node));
126 return 1;
127 }
128
129 node = lyd_child(node);
130 assert(!strcmp(LYD_NAME(node), "name"));
131 hostkey_name = lyd_get_value(node);
132
133 for (i = 0; i < opts->hostkey_count; i++) {
134 if (!strcmp(opts->hostkeys[i].name, hostkey_name)) {
135 *hostkey = &opts->hostkeys[i];
136 return 0;
137 }
138 }
139
140 ERR(NULL, "Host-key \"%s\" was not found.", hostkey_name);
141 return 1;
142}
143
romanf02273a2023-05-25 09:44:11 +0200144int
145nc_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 +0100146{
147 uint16_t i;
148 const char *authkey_name;
149
150 assert(node && opts);
151
152 while (node) {
153 if (!strcmp(LYD_NAME(node), "user")) {
154 break;
155 }
156 node = lyd_parent(node);
157 }
158
159 if (!node) {
160 ERR(NULL, "Node \"%s\" is not contained in a client-authentication subtree.", LYD_NAME(node));
161 return 1;
162 }
163
164 node = lyd_child(node);
165 assert(!strcmp(LYD_NAME(node), "name"));
166 authkey_name = lyd_get_value(node);
167
168 for (i = 0; i < opts->client_count; i++) {
169 if (!strcmp(opts->auth_clients[i].username, authkey_name)) {
170 *auth_client = &opts->auth_clients[i];
171 return 0;
172 }
173 }
174
175 ERR(NULL, "Authorized key \"%s\" was not found.", authkey_name);
176 return 1;
177}
178
romanf02273a2023-05-25 09:44:11 +0200179int
180nc_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 +0100181{
182 uint16_t i;
183 const char *pubkey_name;
184
185 assert(node && auth_client);
186
187 node = lyd_parent(node);
188 while (node) {
189 if (!strcmp(LYD_NAME(node), "public-key")) {
190 break;
191 }
192 node = lyd_parent(node);
193 }
194
195 if (!node) {
196 ERR(NULL, "Node \"%s\" is not contained in a public-key subtree.", LYD_NAME(node));
197 return 1;
198 }
199
200 node = lyd_child(node);
201 assert(!strcmp(LYD_NAME(node), "name"));
202 pubkey_name = lyd_get_value(node);
203
204 for (i = 0; i < auth_client->pubkey_count; i++) {
205 if (!strcmp(auth_client->pubkeys[i].name, pubkey_name)) {
206 *pubkey = &auth_client->pubkeys[i];
207 return 0;
208 }
209 }
210
211 ERR(NULL, "Public key \"%s\" was not found.", pubkey_name);
212 return 1;
213}
214
roman3f9b65c2023-06-05 14:26:58 +0200215int
216nc_server_config_get_cert(const struct lyd_node *node, struct nc_cert_grouping *auth_client, struct nc_certificate **cert)
217{
218 uint16_t i;
219 const char *cert_name;
220
221 assert(node && auth_client);
222
223 while (node) {
224 if (!strcmp(LYD_NAME(node), "certificate")) {
225 break;
226 }
227 node = lyd_parent(node);
228 }
229
230 if (!node) {
231 ERR(NULL, "Node \"%s\" is not contained in a certificate subtree.", LYD_NAME(node));
232 return 1;
233 }
234
235 node = lyd_child(node);
236 assert(!strcmp(LYD_NAME(node), "name"));
237 cert_name = lyd_get_value(node);
238
239 for (i = 0; i < auth_client->cert_count; i++) {
240 if (!strcmp(auth_client->certs[i].name, cert_name)) {
241 *cert = &auth_client->certs[i];
242 return 0;
243 }
244 }
245
246 ERR(NULL, "Certificate \"%s\" was not found.", cert_name);
247 return 1;
248}
249
250static int
251nc_server_config_get_ctn(const struct lyd_node *node, struct nc_endpt *endpt, struct nc_ctn **ctn)
252{
253 uint32_t id;
254 struct nc_ctn *iter;
255
256 assert(node && endpt);
257
258 node = lyd_parent(node);
259 while (node) {
260 if (!strcmp(LYD_NAME(node), "cert-to-name")) {
261 break;
262 }
263 node = lyd_parent(node);
264 }
265
266 if (!node) {
267 ERR(NULL, "Node \"%s\" is not contained in a cert-to-name subtree.", LYD_NAME(node));
268 return 1;
269 }
270
271 node = lyd_child(node);
272 assert(!strcmp(LYD_NAME(node), "id"));
273 id = strtoul(lyd_get_value(node), NULL, 10);
274
275 iter = endpt->opts.tls->ctn;
276 while (iter) {
277 if (iter->id == id) {
278 *ctn = iter;
279 return 0;
280 }
281
282 iter = iter->next;
283 }
284
285 ERR(NULL, "Cert-to-name entry with id \"%d\" was not found.", id);
286 return 1;
287}
288
roman2eab4742023-06-06 10:00:26 +0200289NC_PRIVKEY_FORMAT
290nc_server_config_get_private_key_type(const char *format)
291{
292 if (!strcmp(format, "rsa-private-key-format")) {
293 return NC_PRIVKEY_FORMAT_RSA;
294 } else if (!strcmp(format, "ec-private-key-format")) {
295 return NC_PRIVKEY_FORMAT_EC;
296 } else if (!strcmp(format, "subject-private-key-info-format")) {
297 return NC_PRIVKEY_FORMAT_X509;
298 } else if (!strcmp(format, "openssh-private-key-format")) {
299 return NC_PRIVKEY_FORMAT_OPENSSH;
300 } else {
301 ERR(NULL, "Private key format (%s) not supported.", format);
302 return NC_PRIVKEY_FORMAT_UNKNOWN;
303 }
304}
305
306#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200307
romanf02273a2023-05-25 09:44:11 +0200308int
romanc1d2b092023-02-02 08:58:27 +0100309equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char *parent_name)
310{
311 uint16_t i;
312
313 assert(node && parent_count > 0 && parent_name);
314
315 node = lyd_parent(node);
316 for (i = 1; i < parent_count; i++) {
317 node = lyd_parent(node);
318 }
319
320 if (!strcmp(LYD_NAME(node), parent_name)) {
321 return 1;
322 }
323
324 return 0;
325}
326
romanf02273a2023-05-25 09:44:11 +0200327int
328nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uint16_t *count)
329{
330 int ret = 0;
331 void *tmp;
332 char **name;
333
334 tmp = realloc(*ptr, (*count + 1) * size);
335 if (!tmp) {
336 ERRMEM;
337 ret = 1;
338 goto cleanup;
339 }
340 *ptr = tmp;
341
342 /* set the newly allocated memory to 0 */
343 memset((char *)(*ptr) + (*count * size), 0, size);
344 (*count)++;
345
346 /* access the first member of the supposed structure */
347 name = (char **)((*ptr) + ((*count - 1) * size));
348
349 /* and set it's value */
350 *name = strdup(key_value);
351 if (!*name) {
352 ERRMEM;
353 ret = 1;
354 goto cleanup;
355 }
356
357cleanup:
358 return ret;
359}
360
roman2eab4742023-06-06 10:00:26 +0200361#ifdef NC_ENABLED_SSH_TLS
362
roman3f9b65c2023-06-05 14:26:58 +0200363static int
364is_listen(const struct lyd_node *node)
365{
366 assert(node);
367
368 while (node) {
369 if (!strcmp(LYD_NAME(node), "listen")) {
370 break;
371 }
372 node = lyd_parent(node);
373 }
374
375 return node != NULL;
376}
377
378// static int
379// is_ch(const struct lyd_node *node)
380// {
381// assert(node);
382
383// while (node) {
384// if (!strcmp(LYD_NAME(node), "call-home")) {
385// break;
386// }
387// node = lyd_parent(node);
388// }
389
390// return node != NULL;
391// }
392
roman3f9b65c2023-06-05 14:26:58 +0200393static int
394is_ssh(const struct lyd_node *node)
395{
396 assert(node);
397
398 while (node) {
399 if (!strcmp(LYD_NAME(node), "ssh")) {
400 break;
401 }
402 node = lyd_parent(node);
403 }
404
405 return node != NULL;
406}
407
roman3f9b65c2023-06-05 14:26:58 +0200408static int
409is_tls(const struct lyd_node *node)
410{
411 assert(node);
412
413 while (node) {
414 if (!strcmp(LYD_NAME(node), "tls")) {
415 break;
416 }
417 node = lyd_parent(node);
418 }
419
420 return node != NULL;
421}
422
roman2eab4742023-06-06 10:00:26 +0200423#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200424
425static void
426nc_server_config_del_endpt_name(struct nc_endpt *endpt)
427{
428 free(endpt->name);
429 endpt->name = NULL;
430}
431
roman2eab4742023-06-06 10:00:26 +0200432#ifdef NC_ENABLED_SSH_TLS
433
roman3f9b65c2023-06-05 14:26:58 +0200434static void
435nc_server_config_del_local_address(struct nc_bind *bind)
436{
437 free(bind->address);
438 bind->address = NULL;
439}
440
romanc1d2b092023-02-02 08:58:27 +0100441static void
roman874fed12023-05-25 10:20:01 +0200442nc_server_config_del_auth_client_pam_name(struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100443{
444 free(auth_client->pam_config_name);
445 auth_client->pam_config_name = NULL;
446}
447
448static void
roman874fed12023-05-25 10:20:01 +0200449nc_server_config_del_auth_client_pam_dir(struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100450{
451 free(auth_client->pam_config_dir);
452 auth_client->pam_config_dir = NULL;
453}
454
455static void
roman0bbc19c2023-05-26 09:59:09 +0200456nc_server_config_del_endpt_reference(struct nc_endpt *endpt)
457{
458 free(endpt->referenced_endpt_name);
459 endpt->referenced_endpt_name = NULL;
460}
461
462static void
roman874fed12023-05-25 10:20:01 +0200463nc_server_config_del_hostkey_name(struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100464{
465 free(hostkey->name);
466 hostkey->name = NULL;
467}
468
469static void
roman874fed12023-05-25 10:20:01 +0200470nc_server_config_del_public_key(struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100471{
roman3f9b65c2023-06-05 14:26:58 +0200472 free(hostkey->key.pubkey_data);
473 hostkey->key.pubkey_data = NULL;
romanc1d2b092023-02-02 08:58:27 +0100474}
475
476static void
roman874fed12023-05-25 10:20:01 +0200477nc_server_config_del_private_key(struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100478{
roman3f9b65c2023-06-05 14:26:58 +0200479 free(hostkey->key.privkey_data);
480 hostkey->key.privkey_data = NULL;
romanc1d2b092023-02-02 08:58:27 +0100481}
482
483static void
roman874fed12023-05-25 10:20:01 +0200484nc_server_config_del_auth_client_username(struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100485{
486 free(auth_client->username);
487 auth_client->username = NULL;
488}
489
490static void
roman874fed12023-05-25 10:20:01 +0200491nc_server_config_del_auth_client_pubkey_name(struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +0100492{
493 free(pubkey->name);
494 pubkey->name = NULL;
495}
496
497static void
roman874fed12023-05-25 10:20:01 +0200498nc_server_config_del_auth_client_pubkey_pub_base64(struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +0100499{
roman3f9b65c2023-06-05 14:26:58 +0200500 free(pubkey->data);
501 pubkey->data = NULL;
romanc1d2b092023-02-02 08:58:27 +0100502}
503
504static void
roman874fed12023-05-25 10:20:01 +0200505nc_server_config_del_auth_client_password(struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100506{
507 free(auth_client->password);
508 auth_client->password = NULL;
509}
510
511static void
roman874fed12023-05-25 10:20:01 +0200512nc_server_config_del_hostkey_algs(struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100513{
514 free(opts->hostkey_algs);
515 opts->hostkey_algs = NULL;
516}
517
518static void
roman874fed12023-05-25 10:20:01 +0200519nc_server_config_del_kex_algs(struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100520{
521 free(opts->kex_algs);
522 opts->kex_algs = NULL;
523}
524
525static void
roman874fed12023-05-25 10:20:01 +0200526nc_server_config_del_encryption_algs(struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100527{
528 free(opts->encryption_algs);
529 opts->encryption_algs = NULL;
530}
531
532static void
roman874fed12023-05-25 10:20:01 +0200533nc_server_config_del_mac_algs(struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100534{
535 free(opts->mac_algs);
536 opts->mac_algs = NULL;
537}
538
539static void
roman874fed12023-05-25 10:20:01 +0200540nc_server_config_del_hostkey(struct nc_server_ssh_opts *opts, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100541{
roman874fed12023-05-25 10:20:01 +0200542 assert(hostkey->store == NC_STORE_LOCAL || hostkey->store == NC_STORE_KEYSTORE);
romanc1d2b092023-02-02 08:58:27 +0100543
roman874fed12023-05-25 10:20:01 +0200544 if (hostkey->store == NC_STORE_LOCAL) {
545 nc_server_config_del_public_key(hostkey);
546 nc_server_config_del_private_key(hostkey);
romanc1d2b092023-02-02 08:58:27 +0100547 }
548
roman874fed12023-05-25 10:20:01 +0200549 nc_server_config_del_hostkey_name(hostkey);
romanc1d2b092023-02-02 08:58:27 +0100550 opts->hostkey_count--;
551 if (!opts->hostkey_count) {
552 free(opts->hostkeys);
553 opts->hostkeys = NULL;
554 }
555}
556
557static void
roman874fed12023-05-25 10:20:01 +0200558nc_server_config_del_auth_client_pubkey(struct nc_client_auth *auth_client, struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +0100559{
roman874fed12023-05-25 10:20:01 +0200560 nc_server_config_del_auth_client_pubkey_name(pubkey);
561 nc_server_config_del_auth_client_pubkey_pub_base64(pubkey);
romanc1d2b092023-02-02 08:58:27 +0100562
563 auth_client->pubkey_count--;
564 if (!auth_client->pubkey_count) {
565 free(auth_client->pubkeys);
566 auth_client->pubkeys = NULL;
567 }
568}
569
570static void
roman874fed12023-05-25 10:20:01 +0200571nc_server_config_del_auth_client(struct nc_server_ssh_opts *opts, struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100572{
573 uint16_t i, pubkey_count;
574
roman874fed12023-05-25 10:20:01 +0200575 if (auth_client->store == NC_STORE_LOCAL) {
romanc1d2b092023-02-02 08:58:27 +0100576 pubkey_count = auth_client->pubkey_count;
577 for (i = 0; i < pubkey_count; i++) {
roman874fed12023-05-25 10:20:01 +0200578 nc_server_config_del_auth_client_pubkey(auth_client, &auth_client->pubkeys[i]);
romanc1d2b092023-02-02 08:58:27 +0100579 }
romanc1d2b092023-02-02 08:58:27 +0100580 }
581
roman874fed12023-05-25 10:20:01 +0200582 nc_server_config_del_auth_client_password(auth_client);
583 nc_server_config_del_auth_client_pam_name(auth_client);
584 nc_server_config_del_auth_client_pam_dir(auth_client);
585 nc_server_config_del_auth_client_username(auth_client);
romanc1d2b092023-02-02 08:58:27 +0100586
587 opts->client_count--;
588 if (!opts->client_count) {
589 free(opts->auth_clients);
590 opts->auth_clients = NULL;
591 }
592}
593
594static void
roman874fed12023-05-25 10:20:01 +0200595nc_server_config_del_ssh(struct nc_bind *bind, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100596{
597 uint16_t i, hostkey_count, client_count;
598
roman874fed12023-05-25 10:20:01 +0200599 nc_server_config_del_local_address(bind);
romanc1d2b092023-02-02 08:58:27 +0100600 if (bind->sock > -1) {
601 close(bind->sock);
602 }
603
604 /* store in variable because it gets decremented in the function call */
605 hostkey_count = opts->hostkey_count;
606 for (i = 0; i < hostkey_count; i++) {
roman874fed12023-05-25 10:20:01 +0200607 nc_server_config_del_hostkey(opts, &opts->hostkeys[i]);
romanc1d2b092023-02-02 08:58:27 +0100608 }
609
610 client_count = opts->client_count;
611 for (i = 0; i < client_count; i++) {
roman874fed12023-05-25 10:20:01 +0200612 nc_server_config_del_auth_client(opts, &opts->auth_clients[i]);
romanc1d2b092023-02-02 08:58:27 +0100613 }
614
roman874fed12023-05-25 10:20:01 +0200615 nc_server_config_del_hostkey_algs(opts);
616 nc_server_config_del_kex_algs(opts);
617 nc_server_config_del_encryption_algs(opts);
618 nc_server_config_del_mac_algs(opts);
romanc1d2b092023-02-02 08:58:27 +0100619
620 free(opts);
621 opts = NULL;
622}
623
624void
roman874fed12023-05-25 10:20:01 +0200625nc_server_config_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind)
romanc1d2b092023-02-02 08:58:27 +0100626{
roman874fed12023-05-25 10:20:01 +0200627 nc_server_config_del_endpt_name(endpt);
roman0bbc19c2023-05-26 09:59:09 +0200628 nc_server_config_del_endpt_reference(endpt);
roman874fed12023-05-25 10:20:01 +0200629 nc_server_config_del_ssh(bind, endpt->opts.ssh);
romanc1d2b092023-02-02 08:58:27 +0100630
631 server_opts.endpt_count--;
632 if (!server_opts.endpt_count) {
633 free(server_opts.endpts);
634 free(server_opts.binds);
635 server_opts.endpts = NULL;
636 server_opts.binds = NULL;
637 }
638}
639
roman2eab4742023-06-06 10:00:26 +0200640#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200641
roman45cec4e2023-02-17 10:21:39 +0100642void
roman874fed12023-05-25 10:20:01 +0200643nc_server_config_del_unix_socket(struct nc_bind *bind, struct nc_server_unix_opts *opts)
roman83683fb2023-02-24 09:15:23 +0100644{
645 if (bind->sock > -1) {
646 close(bind->sock);
647 }
648
649 free(bind->address);
650 free(opts->address);
651
652 free(opts);
roman83683fb2023-02-24 09:15:23 +0100653}
654
655void
roman874fed12023-05-25 10:20:01 +0200656nc_server_config_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *bind)
roman83683fb2023-02-24 09:15:23 +0100657{
roman874fed12023-05-25 10:20:01 +0200658 nc_server_config_del_endpt_name(endpt);
659 nc_server_config_del_unix_socket(bind, endpt->opts.unixsock);
roman83683fb2023-02-24 09:15:23 +0100660
661 server_opts.endpt_count--;
662 if (!server_opts.endpt_count) {
663 free(server_opts.endpts);
664 free(server_opts.binds);
665 server_opts.endpts = NULL;
666 server_opts.binds = NULL;
667 }
668}
669
roman2eab4742023-06-06 10:00:26 +0200670#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +0200671
672static void
roman12644fe2023-06-08 11:06:42 +0200673nc_server_config_tls_del_ciphers(struct nc_server_tls_opts *opts)
674{
675 free(opts->ciphers);
676 opts->ciphers = NULL;
677}
678
679static void
roman3f9b65c2023-06-05 14:26:58 +0200680nc_server_config_tls_del_public_key(struct nc_server_tls_opts *opts)
681{
682 free(opts->pubkey_data);
683 opts->pubkey_data = NULL;
684}
685
686static void
687nc_server_config_tls_del_cleartext_private_key(struct nc_server_tls_opts *opts)
688{
689 free(opts->privkey_data);
690 opts->privkey_data = NULL;
691}
692
693static void
694nc_server_config_tls_del_cert_data(struct nc_server_tls_opts *opts)
695{
696 free(opts->cert_data);
697 opts->cert_data = NULL;
698}
699
700static void
701nc_server_config_tls_del_cert_data_certificate(struct nc_certificate *cert)
702{
703 free(cert->data);
704 cert->data = NULL;
705}
706
707static void
708nc_server_config_del_fingerprint(struct nc_ctn *ctn)
709{
710 free(ctn->fingerprint);
711 ctn->fingerprint = NULL;
712}
713
714static void
715nc_server_config_del_cert(struct nc_cert_grouping *certs, struct nc_certificate *cert)
716{
717 free(cert->name);
718 cert->name = NULL;
719
720 free(cert->data);
721 cert->data = NULL;
722
723 certs->cert_count--;
724 if (!certs->cert_count) {
725 free(certs->certs);
726 certs->certs = NULL;
727 }
728}
729
730static void
731nc_server_config_tls_del_certs(struct nc_cert_grouping *ca)
732{
733 uint16_t i, cert_count;
734
735 if (ca->store == NC_STORE_LOCAL) {
736 cert_count = ca->cert_count;
737 for (i = 0; i < cert_count; i++) {
738 nc_server_config_del_cert(ca, &ca->certs[i]);
739 }
740 }
741}
742
743static void
744nc_server_config_del_ctn(struct nc_server_tls_opts *opts, struct nc_ctn *ctn)
745{
746 struct nc_ctn *iter;
747
748 free(ctn->fingerprint);
749 ctn->fingerprint = NULL;
750
751 free(ctn->name);
752 ctn->name = NULL;
753
754 if (opts->ctn == ctn) {
755 /* it's the first in the list */
756 opts->ctn = ctn->next;
757 free(ctn);
758 return;
759 }
760
761 iter = opts->ctn;
762 while (iter) {
763 if (iter->next == ctn) {
764 /* found the ctn */
765 break;
766 }
767 iter = iter->next;
768 }
769
770 iter->next = ctn->next;
771 free(ctn);
772}
773
774static void
roman12644fe2023-06-08 11:06:42 +0200775nc_server_config_tls_del_ctns(struct nc_server_tls_opts *opts)
roman3f9b65c2023-06-05 14:26:58 +0200776{
777 struct nc_ctn *cur, *next;
778
779 cur = opts->ctn;
780 while (cur) {
781 next = cur->next;
782 free(cur->fingerprint);
783 free(cur->name);
784 free(cur);
785 cur = next;
786 }
787 opts->ctn = NULL;
788}
789
790static void
791nc_server_config_del_tls(struct nc_bind *bind, struct nc_server_tls_opts *opts)
792{
793 nc_server_config_del_local_address(bind);
794 if (bind->sock > -1) {
795 close(bind->sock);
796 }
797
798 if (opts->store == NC_STORE_LOCAL) {
799 nc_server_config_tls_del_public_key(opts);
800 nc_server_config_tls_del_cleartext_private_key(opts);
801 nc_server_config_tls_del_cert_data(opts);
802 }
803
804 nc_server_config_tls_del_certs(&opts->ca_certs);
805 nc_server_config_tls_del_certs(&opts->ee_certs);
806
roman12644fe2023-06-08 11:06:42 +0200807 nc_server_config_tls_del_ctns(opts);
808 nc_server_config_tls_del_ciphers(opts);
roman3f9b65c2023-06-05 14:26:58 +0200809
810 free(opts);
811}
812
813static void
814nc_server_config_del_endpt_tls(struct nc_endpt *endpt, struct nc_bind *bind)
815{
816 nc_server_config_del_endpt_name(endpt);
817 nc_server_config_del_tls(bind, endpt->opts.tls);
818
819 server_opts.endpt_count--;
820 if (!server_opts.endpt_count) {
821 free(server_opts.endpts);
822 free(server_opts.binds);
823 server_opts.endpts = NULL;
824 server_opts.binds = NULL;
825 }
826}
827
roman2eab4742023-06-06 10:00:26 +0200828#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200829
romanc1d2b092023-02-02 08:58:27 +0100830/* presence container */
831int
romanf02273a2023-05-25 09:44:11 +0200832nc_server_config_listen(struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100833{
roman0bbc19c2023-05-26 09:59:09 +0200834 uint16_t i, endpt_count;
romanc1d2b092023-02-02 08:58:27 +0100835
romanf02273a2023-05-25 09:44:11 +0200836 (void) node;
837
romanc1d2b092023-02-02 08:58:27 +0100838 assert(op == NC_OP_CREATE || op == NC_OP_DELETE);
839
840 if (op == NC_OP_DELETE) {
roman0bbc19c2023-05-26 09:59:09 +0200841 endpt_count = server_opts.endpt_count;
842 for (i = 0; i < endpt_count; i++) {
roman456f92d2023-04-28 10:28:12 +0200843 switch (server_opts.endpts[i].ti) {
roman2eab4742023-06-06 10:00:26 +0200844#ifdef NC_ENABLED_SSH_TLS
roman456f92d2023-04-28 10:28:12 +0200845 case NC_TI_LIBSSH:
roman874fed12023-05-25 10:20:01 +0200846 nc_server_config_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]);
roman456f92d2023-04-28 10:28:12 +0200847 break;
roman456f92d2023-04-28 10:28:12 +0200848 case NC_TI_OPENSSL:
roman3f9b65c2023-06-05 14:26:58 +0200849 nc_server_config_del_endpt_tls(&server_opts.endpts[i], &server_opts.binds[i]);
roman456f92d2023-04-28 10:28:12 +0200850 break;
roman2eab4742023-06-06 10:00:26 +0200851#endif /* NC_ENABLED_SSH_TLS */
roman456f92d2023-04-28 10:28:12 +0200852 case NC_TI_UNIX:
roman874fed12023-05-25 10:20:01 +0200853 nc_server_config_del_endpt_unix_socket(&server_opts.endpts[i], &server_opts.binds[i]);
roman456f92d2023-04-28 10:28:12 +0200854 break;
855 case NC_TI_NONE:
856 case NC_TI_FD:
857 ERRINT;
858 return 1;
roman83683fb2023-02-24 09:15:23 +0100859 }
romanc1d2b092023-02-02 08:58:27 +0100860 }
861 }
862
863 return 0;
864}
865
866/* default leaf */
867static int
romane028ef92023-02-24 16:33:08 +0100868nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100869{
870 assert(!strcmp(LYD_NAME(node), "idle-timeout"));
871
872 if (equal_parent_name(node, 1, "listen")) {
873 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
874 server_opts.idle_timeout = strtoul(lyd_get_value(node), NULL, 10);
875 } else {
876 /* default value */
877 server_opts.idle_timeout = 3600;
878 }
879 }
880
881 return 0;
882}
883
884static int
roman874fed12023-05-25 10:20:01 +0200885nc_server_config_create_bind(void)
romanc1d2b092023-02-02 08:58:27 +0100886{
887 int ret = 0;
888 void *tmp;
889
890 tmp = realloc(server_opts.binds, (server_opts.endpt_count + 1) * sizeof *server_opts.binds);
891 if (!tmp) {
892 ERRMEM;
893 ret = 1;
894 goto cleanup;
895 }
896 server_opts.binds = tmp;
897 memset(&server_opts.binds[server_opts.endpt_count], 0, sizeof *server_opts.binds);
898
899 server_opts.binds[server_opts.endpt_count].sock = -1;
900
901cleanup:
902 return ret;
903}
904
905static int
roman874fed12023-05-25 10:20:01 +0200906nc_server_config_create_endpoint(const struct lyd_node *node)
romanc1d2b092023-02-02 08:58:27 +0100907{
roman874fed12023-05-25 10:20:01 +0200908 if (nc_server_config_create_bind()) {
romanf02273a2023-05-25 09:44:11 +0200909 return 1;
romanc1d2b092023-02-02 08:58:27 +0100910 }
romanc1d2b092023-02-02 08:58:27 +0100911
912 node = lyd_child(node);
913 assert(!strcmp(LYD_NAME(node), "name"));
914
romanf02273a2023-05-25 09:44:11 +0200915 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 +0100916}
917
918/* list */
919static int
romane028ef92023-02-24 16:33:08 +0100920nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100921{
922 int ret = 0;
923 struct nc_endpt *endpt;
924 struct nc_bind *bind;
925
926 assert(!strcmp(LYD_NAME(node), "endpoint"));
927
928 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +0200929 ret = nc_server_config_create_endpoint(node);
romanc1d2b092023-02-02 08:58:27 +0100930 if (ret) {
931 goto cleanup;
932 }
933 } else if (op == NC_OP_DELETE) {
934 /* free all children */
romanf02273a2023-05-25 09:44:11 +0200935 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +0100936 ret = 1;
937 goto cleanup;
938 }
roman3f9b65c2023-06-05 14:26:58 +0200939
940 switch (endpt->ti) {
roman2eab4742023-06-06 10:00:26 +0200941#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +0200942 case NC_TI_LIBSSH:
943 nc_server_config_del_endpt_ssh(endpt, bind);
944 break;
roman3f9b65c2023-06-05 14:26:58 +0200945 case NC_TI_OPENSSL:
946 nc_server_config_del_endpt_tls(endpt, bind);
947 break;
roman2eab4742023-06-06 10:00:26 +0200948#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200949 case NC_TI_UNIX:
950 nc_server_config_del_endpt_unix_socket(endpt, bind);
951 break;
952 case NC_TI_NONE:
953 case NC_TI_FD:
954 ERRINT;
955 ret = 1;
956 goto cleanup;
957 }
romanc1d2b092023-02-02 08:58:27 +0100958 }
959
960cleanup:
961 return ret;
962}
963
roman2eab4742023-06-06 10:00:26 +0200964#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +0200965
romanc1d2b092023-02-02 08:58:27 +0100966static int
roman874fed12023-05-25 10:20:01 +0200967nc_server_config_create_ssh(struct nc_endpt *endpt)
romanc1d2b092023-02-02 08:58:27 +0100968{
969 endpt->ti = NC_TI_LIBSSH;
970 endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
971 if (!endpt->opts.ssh) {
972 ERRMEM;
973 return 1;
974 }
975
976 return 0;
977}
978
979/* NP container */
980static int
romane028ef92023-02-24 16:33:08 +0100981nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100982{
983 struct nc_endpt *endpt;
984 struct nc_bind *bind;
985 int ret = 0;
986
987 assert(!strcmp(LYD_NAME(node), "ssh"));
988
romanf02273a2023-05-25 09:44:11 +0200989 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +0100990 ret = 1;
991 goto cleanup;
992 }
993
994 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +0200995 ret = nc_server_config_create_ssh(endpt);
romanc1d2b092023-02-02 08:58:27 +0100996 if (ret) {
997 goto cleanup;
998 }
999 } else if (op == NC_OP_DELETE) {
roman874fed12023-05-25 10:20:01 +02001000 nc_server_config_del_ssh(bind, endpt->opts.ssh);
romanc1d2b092023-02-02 08:58:27 +01001001 }
1002
1003cleanup:
1004 return ret;
1005}
1006
roman3f9b65c2023-06-05 14:26:58 +02001007static int
1008nc_server_config_create_tls(struct nc_endpt *endpt)
1009{
1010 endpt->ti = NC_TI_OPENSSL;
1011 endpt->opts.tls = calloc(1, sizeof *endpt->opts.tls);
1012 if (!endpt->opts.tls) {
1013 ERRMEM;
1014 return 1;
1015 }
1016
1017 return 0;
1018}
1019
1020static int
1021nc_server_config_tls(const struct lyd_node *node, NC_OPERATION op)
1022{
1023 struct nc_endpt *endpt;
1024 struct nc_bind *bind;
1025 int ret = 0;
1026
1027 assert(!strcmp(LYD_NAME(node), "tls"));
1028
1029 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1030 ret = 1;
1031 goto cleanup;
1032 }
1033
1034 if (op == NC_OP_CREATE) {
1035 ret = nc_server_config_create_tls(endpt);
1036 if (ret) {
1037 goto cleanup;
1038 }
1039 } else if (op == NC_OP_DELETE) {
1040 nc_server_config_del_tls(bind, endpt->opts.tls);
1041 }
1042
1043cleanup:
1044 return ret;
1045}
1046
roman2eab4742023-06-06 10:00:26 +02001047#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02001048
romanc1d2b092023-02-02 08:58:27 +01001049static int
1050nc_server_config_set_address_port(struct nc_endpt *endpt, struct nc_bind *bind, const char *address, uint16_t port)
1051{
1052 int sock = -1, set_addr, ret = 0;
1053
roman83683fb2023-02-24 09:15:23 +01001054 assert((address && !port) || (!address && port) || (endpt->ti == NC_TI_UNIX));
romanc1d2b092023-02-02 08:58:27 +01001055
1056 if (address) {
1057 set_addr = 1;
1058 } else {
1059 set_addr = 0;
1060 }
1061
1062 if (set_addr) {
1063 port = bind->port;
1064 } else {
1065 address = bind->address;
1066 }
1067
romanc1d2b092023-02-02 08:58:27 +01001068 /* we have all the information we need to create a listening socket */
roman83683fb2023-02-24 09:15:23 +01001069 if ((address && port) || (endpt->ti == NC_TI_UNIX)) {
romanc1d2b092023-02-02 08:58:27 +01001070 /* create new socket, close the old one */
roman83683fb2023-02-24 09:15:23 +01001071 if (endpt->ti == NC_TI_UNIX) {
1072 sock = nc_sock_listen_unix(endpt->opts.unixsock);
1073 } else {
1074 sock = nc_sock_listen_inet(address, port, &endpt->ka);
1075 }
1076
romanc1d2b092023-02-02 08:58:27 +01001077 if (sock == -1) {
1078 ret = 1;
1079 goto cleanup;
1080 }
1081
1082 if (bind->sock > -1) {
1083 close(bind->sock);
1084 }
1085 bind->sock = sock;
1086 }
1087
1088 if (sock > -1) {
1089 switch (endpt->ti) {
roman83683fb2023-02-24 09:15:23 +01001090 case NC_TI_UNIX:
1091 VRB(NULL, "Listening on %s for UNIX connections.", endpt->opts.unixsock->address);
1092 break;
roman2eab4742023-06-06 10:00:26 +02001093#ifdef NC_ENABLED_SSH_TLS
romanc1d2b092023-02-02 08:58:27 +01001094 case NC_TI_LIBSSH:
1095 VRB(NULL, "Listening on %s:%u for SSH connections.", address, port);
1096 break;
romanc1d2b092023-02-02 08:58:27 +01001097 case NC_TI_OPENSSL:
1098 VRB(NULL, "Listening on %s:%u for TLS connections.", address, port);
1099 break;
roman2eab4742023-06-06 10:00:26 +02001100#endif /* NC_ENABLED_SSH_TLS */
romanc1d2b092023-02-02 08:58:27 +01001101 default:
1102 ERRINT;
1103 ret = 1;
1104 break;
1105 }
1106 }
1107
1108cleanup:
1109 return ret;
1110}
1111
roman2eab4742023-06-06 10:00:26 +02001112#ifdef NC_ENABLED_SSH_TLS
1113
romanc1d2b092023-02-02 08:58:27 +01001114/* mandatory leaf */
1115static int
romane028ef92023-02-24 16:33:08 +01001116nc_server_config_local_address(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001117{
1118 struct nc_endpt *endpt;
1119 struct nc_bind *bind;
1120 int ret = 0;
1121
1122 (void) op;
1123
1124 assert(!strcmp(LYD_NAME(node), "local-address"));
1125
1126 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001127 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001128 ret = 1;
1129 goto cleanup;
1130 }
1131
roman874fed12023-05-25 10:20:01 +02001132 nc_server_config_del_local_address(bind);
romanc1d2b092023-02-02 08:58:27 +01001133 bind->address = strdup(lyd_get_value(node));
1134 if (!bind->address) {
1135 ERRMEM;
1136 ret = 1;
1137 goto cleanup;
1138 }
1139
1140 ret = nc_server_config_set_address_port(endpt, bind, lyd_get_value(node), 0);
1141 if (ret) {
1142 goto cleanup;
1143 }
1144 }
1145
1146cleanup:
1147 return ret;
1148}
1149
1150/* leaf with default value */
1151static int
romane028ef92023-02-24 16:33:08 +01001152nc_server_config_local_port(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001153{
1154 struct nc_endpt *endpt;
1155 struct nc_bind *bind;
1156 int ret = 0;
1157
1158 assert(!strcmp(LYD_NAME(node), "local-port"));
1159
1160 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001161 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001162 ret = 1;
1163 goto cleanup;
1164 }
1165
1166 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1167 bind->port = strtoul(lyd_get_value(node), NULL, 10);
1168 } else {
1169 /* delete -> set to default */
1170 bind->port = 0;
1171 }
1172
1173 ret = nc_server_config_set_address_port(endpt, bind, NULL, bind->port);
1174 if (ret) {
1175 goto cleanup;
1176 }
1177 }
1178
1179cleanup:
1180 return ret;
1181}
1182
1183/* P container */
1184static int
romane028ef92023-02-24 16:33:08 +01001185nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001186{
1187 struct nc_endpt *endpt;
1188 struct nc_bind *bind;
1189 int ret = 0;
1190
1191 assert(!strcmp(LYD_NAME(node), "keepalives"));
1192
roman3f9b65c2023-06-05 14:26:58 +02001193 if (equal_parent_name(node, 1, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001194 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001195 ret = 1;
1196 goto cleanup;
1197 }
1198
1199 if (op == NC_OP_CREATE) {
1200 endpt->ka.enabled = 1;
1201 } else {
1202 endpt->ka.enabled = 0;
1203 }
1204 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1205 if (ret) {
1206 goto cleanup;
1207 }
1208 }
1209
1210cleanup:
1211 return ret;
1212}
1213
1214/* mandatory leaf */
1215static int
romane028ef92023-02-24 16:33:08 +01001216nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001217{
1218 struct nc_endpt *endpt;
1219 struct nc_bind *bind;
1220 int ret = 0;
1221
1222 assert(!strcmp(LYD_NAME(node), "idle-time"));
1223
1224 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001225 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001226 ret = 1;
1227 goto cleanup;
1228 }
1229
1230 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1231 endpt->ka.idle_time = strtoul(lyd_get_value(node), NULL, 10);
1232 } else {
1233 endpt->ka.idle_time = 0;
1234 }
1235 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1236 if (ret) {
1237 goto cleanup;
1238 }
1239 }
1240
1241cleanup:
1242 return ret;
1243}
1244
1245/* mandatory leaf */
1246static int
romane028ef92023-02-24 16:33:08 +01001247nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001248{
1249 struct nc_endpt *endpt;
1250 struct nc_bind *bind;
1251 int ret = 0;
1252
1253 assert(!strcmp(LYD_NAME(node), "max-probes"));
1254
1255 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001256 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001257 ret = 1;
1258 goto cleanup;
1259 }
1260
1261 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1262 endpt->ka.max_probes = strtoul(lyd_get_value(node), NULL, 10);
1263 } else {
1264 endpt->ka.max_probes = 0;
1265 }
1266 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1267 if (ret) {
1268 goto cleanup;
1269 }
1270 }
1271
1272cleanup:
1273 return ret;
1274}
1275
1276/* mandatory leaf */
1277static int
romane028ef92023-02-24 16:33:08 +01001278nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001279{
1280 struct nc_endpt *endpt;
1281 struct nc_bind *bind;
1282 int ret = 0;
1283
1284 assert(!strcmp(LYD_NAME(node), "probe-interval"));
1285
1286 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001287 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001288 ret = 1;
1289 goto cleanup;
1290 }
1291
1292 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1293 endpt->ka.probe_interval = strtoul(lyd_get_value(node), NULL, 10);
1294 } else {
1295 endpt->ka.probe_interval = 0;
1296 }
1297 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1298 if (ret) {
1299 goto cleanup;
1300 }
1301 }
1302
1303cleanup:
1304 return ret;
1305}
1306
1307static int
roman874fed12023-05-25 10:20:01 +02001308nc_server_config_create_host_key(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01001309{
romanf02273a2023-05-25 09:44:11 +02001310 node = lyd_child(node);
1311 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01001312
romanf02273a2023-05-25 09:44:11 +02001313 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->hostkeys, sizeof *opts->hostkeys, &opts->hostkey_count);
romanc1d2b092023-02-02 08:58:27 +01001314}
1315
1316/* list */
1317static int
romane028ef92023-02-24 16:33:08 +01001318nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001319{
1320 struct nc_endpt *endpt;
1321 struct nc_hostkey *hostkey;
1322 int ret = 0;
1323
1324 assert(!strcmp(LYD_NAME(node), "host-key"));
1325
1326 if ((equal_parent_name(node, 1, "server-identity")) && (equal_parent_name(node, 5, "listen"))) {
romanf02273a2023-05-25 09:44:11 +02001327 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001328 ret = 1;
1329 goto cleanup;
1330 }
1331
1332 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +02001333 ret = nc_server_config_create_host_key(node, endpt->opts.ssh);
romanc1d2b092023-02-02 08:58:27 +01001334 if (ret) {
1335 goto cleanup;
1336 }
1337 } else if (op == NC_OP_DELETE) {
romanf02273a2023-05-25 09:44:11 +02001338 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001339 ret = 1;
1340 goto cleanup;
1341 }
1342
roman874fed12023-05-25 10:20:01 +02001343 nc_server_config_del_hostkey(endpt->opts.ssh, hostkey);
romanc1d2b092023-02-02 08:58:27 +01001344 }
1345 } else if (equal_parent_name(node, 1, "transport-params")) {
1346 /* just a container with the name host-key, nothing to be done */
1347 goto cleanup;
1348 } else {
1349 ERRINT;
1350 ret = 1;
1351 goto cleanup;
1352 }
1353
1354cleanup:
1355 return ret;
1356}
1357
1358/* mandatory leaf */
romane028ef92023-02-24 16:33:08 +01001359static int
1360nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001361{
1362 const char *format;
roman3f9b65c2023-06-05 14:26:58 +02001363 int ret = 0;
1364 NC_PUBKEY_FORMAT pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001365 struct nc_endpt *endpt;
1366 struct nc_client_auth *auth_client;
roman8edee342023-03-31 13:25:48 +02001367 struct nc_public_key *pubkey;
romanc1d2b092023-02-02 08:58:27 +01001368 struct nc_hostkey *hostkey;
romanc1d2b092023-02-02 08:58:27 +01001369
1370 assert(!strcmp(LYD_NAME(node), "public-key-format"));
1371
1372 format = ((struct lyd_node_term *)node)->value.ident->name;
roman3f9b65c2023-06-05 14:26:58 +02001373 if (!strcmp(format, "ssh-public-key-format")) {
1374 pubkey_type = NC_PUBKEY_FORMAT_SSH2;
1375 } else if (!strcmp(format, "subject-public-key-info-format")) {
1376 pubkey_type = NC_PUBKEY_FORMAT_X509;
1377 } else {
1378 ERR(NULL, "Public key format (%s) not supported.", format);
1379 ret = 1;
1380 goto cleanup;
1381 }
romanc1d2b092023-02-02 08:58:27 +01001382
roman3f9b65c2023-06-05 14:26:58 +02001383 if ((equal_parent_name(node, 6, "client-authentication")) && (is_ssh(node)) && (is_listen(node))) {
romanf02273a2023-05-25 09:44:11 +02001384 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001385 ret = 1;
1386 goto cleanup;
1387 }
1388
romanf02273a2023-05-25 09:44:11 +02001389 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001390 ret = 1;
1391 goto cleanup;
1392 }
1393
romanf02273a2023-05-25 09:44:11 +02001394 if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001395 ret = 1;
1396 goto cleanup;
1397 }
1398
1399 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman3f9b65c2023-06-05 14:26:58 +02001400 pubkey->type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001401 }
roman3f9b65c2023-06-05 14:26:58 +02001402 } else if (equal_parent_name(node, 5, "server-identity") && is_ssh(node) && is_listen(node)) {
romanf02273a2023-05-25 09:44:11 +02001403 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001404 ret = 1;
1405 goto cleanup;
1406 }
1407
romanf02273a2023-05-25 09:44:11 +02001408 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001409 ret = 1;
1410 goto cleanup;
1411 }
1412
1413 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman3f9b65c2023-06-05 14:26:58 +02001414 hostkey->key.pubkey_type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001415 }
roman2eab4742023-06-06 10:00:26 +02001416 } else if (equal_parent_name(node, 3, "server-identity") && is_tls(node) && is_listen(node)) {
roman3f9b65c2023-06-05 14:26:58 +02001417 /* TLS listen server-identity */
1418 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
1419 ret = 1;
1420 goto cleanup;
1421 }
1422
1423 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1424 endpt->opts.tls->pubkey_type = pubkey_type;
1425 }
1426 }
romanc1d2b092023-02-02 08:58:27 +01001427
1428cleanup:
1429 return ret;
1430}
1431
1432/* leaf */
romane028ef92023-02-24 16:33:08 +01001433static int
1434nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001435{
roman3f9b65c2023-06-05 14:26:58 +02001436 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001437 const char *format;
1438 struct nc_endpt *endpt;
roman3f9b65c2023-06-05 14:26:58 +02001439 NC_PRIVKEY_FORMAT privkey_type;
romanc1d2b092023-02-02 08:58:27 +01001440 struct nc_hostkey *hostkey;
roman3f9b65c2023-06-05 14:26:58 +02001441
1442 (void) op;
romanc1d2b092023-02-02 08:58:27 +01001443
1444 assert(!strcmp(LYD_NAME(node), "private-key-format"));
1445
romanf02273a2023-05-25 09:44:11 +02001446 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001447 ret = 1;
1448 goto cleanup;
1449 }
1450
roman3f9b65c2023-06-05 14:26:58 +02001451 format = ((struct lyd_node_term *)node)->value.ident->name;
1452 if (!format) {
romanc1d2b092023-02-02 08:58:27 +01001453 ret = 1;
1454 goto cleanup;
1455 }
1456
roman3f9b65c2023-06-05 14:26:58 +02001457 privkey_type = nc_server_config_get_private_key_type(format);
1458 if (privkey_type == NC_PRIVKEY_FORMAT_UNKNOWN) {
1459 ret = 1;
1460 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01001461 }
1462
roman3f9b65c2023-06-05 14:26:58 +02001463 if ((is_ssh(node)) && (is_listen(node))) {
1464 /* listen ssh */
1465 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
1466 ret = 1;
1467 goto cleanup;
1468 }
1469
1470 hostkey->key.privkey_type = privkey_type;
roman2eab4742023-06-06 10:00:26 +02001471 } else if ((is_tls(node)) && (is_listen(node))) {
roman3f9b65c2023-06-05 14:26:58 +02001472 /* listen tls */
roman3f9b65c2023-06-05 14:26:58 +02001473 endpt->opts.tls->privkey_type = privkey_type;
1474 }
roman3f9b65c2023-06-05 14:26:58 +02001475
romanc1d2b092023-02-02 08:58:27 +01001476cleanup:
1477 return ret;
1478}
1479
1480static int
roman874fed12023-05-25 10:20:01 +02001481nc_server_config_replace_cleartext_private_key(const struct lyd_node *node, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +01001482{
roman874fed12023-05-25 10:20:01 +02001483 nc_server_config_del_private_key(hostkey);
roman3f9b65c2023-06-05 14:26:58 +02001484 hostkey->key.privkey_data = strdup(lyd_get_value(node));
1485 if (!hostkey->key.privkey_data) {
romanc1d2b092023-02-02 08:58:27 +01001486 ERRMEM;
1487 return 1;
1488 }
1489
1490 return 0;
1491}
1492
roman3f9b65c2023-06-05 14:26:58 +02001493static int
1494nc_server_config_tls_replace_cleartext_private_key(const struct lyd_node *node, struct nc_server_tls_opts *opts)
1495{
1496 nc_server_config_tls_del_cleartext_private_key(opts);
1497 opts->privkey_data = strdup(lyd_get_value(node));
1498 if (!opts->privkey_data) {
1499 ERRMEM;
1500 return 1;
1501 }
1502
1503 return 0;
1504}
1505
romanc1d2b092023-02-02 08:58:27 +01001506static int
romane028ef92023-02-24 16:33:08 +01001507nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001508{
romanc1d2b092023-02-02 08:58:27 +01001509 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02001510 struct nc_endpt *endpt;
roman3f9b65c2023-06-05 14:26:58 +02001511 struct nc_hostkey *hostkey;
romanc1d2b092023-02-02 08:58:27 +01001512
1513 assert(!strcmp(LYD_NAME(node), "cleartext-private-key"));
1514
roman3f9b65c2023-06-05 14:26:58 +02001515 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
1516 ret = 1;
1517 goto cleanup;
1518 }
1519
roman3f9b65c2023-06-05 14:26:58 +02001520 if ((is_ssh(node)) && (is_listen(node))) {
romanf02273a2023-05-25 09:44:11 +02001521 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001522 ret = 1;
1523 goto cleanup;
1524 }
1525
1526 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02001527 ret = nc_server_config_replace_cleartext_private_key(node, hostkey);
romanc1d2b092023-02-02 08:58:27 +01001528 if (ret) {
1529 goto cleanup;
1530 }
1531 } else {
roman874fed12023-05-25 10:20:01 +02001532 nc_server_config_del_private_key(hostkey);
romanc1d2b092023-02-02 08:58:27 +01001533 }
roman2eab4742023-06-06 10:00:26 +02001534 } else if ((is_tls(node)) && (is_listen(node))) {
roman3f9b65c2023-06-05 14:26:58 +02001535 /* listen tls */
roman3f9b65c2023-06-05 14:26:58 +02001536 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1537 ret = nc_server_config_tls_replace_cleartext_private_key(node, endpt->opts.tls);
1538 if (ret) {
1539 goto cleanup;
1540 }
1541 } else {
1542 nc_server_config_tls_del_cleartext_private_key(endpt->opts.tls);
1543 }
1544 }
romanc1d2b092023-02-02 08:58:27 +01001545
1546cleanup:
1547 return ret;
1548}
1549
1550static int
roman874fed12023-05-25 10:20:01 +02001551nc_server_config_create_keystore_reference(const struct lyd_node *node, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +01001552{
1553 uint16_t i;
roman45cec4e2023-02-17 10:21:39 +01001554 struct nc_keystore *ks = &server_opts.keystore;
romanc1d2b092023-02-02 08:58:27 +01001555
1556 /* lookup name */
roman45cec4e2023-02-17 10:21:39 +01001557 for (i = 0; i < ks->asym_key_count; i++) {
1558 if (!strcmp(lyd_get_value(node), ks->asym_keys[i].name)) {
romanc1d2b092023-02-02 08:58:27 +01001559 break;
1560 }
1561 }
1562
roman45cec4e2023-02-17 10:21:39 +01001563 if (i == ks->asym_key_count) {
1564 ERR(NULL, "Keystore \"%s\" not found.", lyd_get_value(node));
romanc1d2b092023-02-02 08:58:27 +01001565 return 1;
1566 }
1567
roman45cec4e2023-02-17 10:21:39 +01001568 hostkey->ks_ref = &ks->asym_keys[i];
romanc1d2b092023-02-02 08:58:27 +01001569
1570 return 0;
1571}
1572
1573/* leaf */
1574static int
romane028ef92023-02-24 16:33:08 +01001575nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001576{
1577 struct nc_endpt *endpt;
1578 struct nc_hostkey *hostkey;
1579 int ret = 0;
1580
1581 assert(!strcmp(LYD_NAME(node), "keystore-reference"));
1582
roman3f9b65c2023-06-05 14:26:58 +02001583 if ((equal_parent_name(node, 3, "server-identity")) && (is_ssh(node)) && (is_listen(node))) {
romanf02273a2023-05-25 09:44:11 +02001584 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001585 ret = 1;
1586 goto cleanup;
1587 }
romanf02273a2023-05-25 09:44:11 +02001588 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001589 ret = 1;
1590 goto cleanup;
1591 }
1592
1593 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02001594 /* set to keystore */
roman874fed12023-05-25 10:20:01 +02001595 hostkey->store = NC_STORE_KEYSTORE;
romanf02273a2023-05-25 09:44:11 +02001596
roman874fed12023-05-25 10:20:01 +02001597 ret = nc_server_config_create_keystore_reference(node, hostkey);
romanc1d2b092023-02-02 08:58:27 +01001598 if (ret) {
1599 goto cleanup;
1600 }
1601 } else {
roman45cec4e2023-02-17 10:21:39 +01001602 hostkey->ks_ref = NULL;
romanc1d2b092023-02-02 08:58:27 +01001603 }
1604 }
1605
1606cleanup:
1607 return ret;
1608}
1609
1610static int
roman874fed12023-05-25 10:20:01 +02001611nc_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 +01001612{
romanc1d2b092023-02-02 08:58:27 +01001613 assert(!strcmp(LYD_NAME(node), "public-key"));
1614
romanc1d2b092023-02-02 08:58:27 +01001615 node = lyd_child(node);
1616 assert(!strcmp(LYD_NAME(node), "name"));
1617
romanf02273a2023-05-25 09:44:11 +02001618 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 +01001619}
1620
1621static int
roman874fed12023-05-25 10:20:01 +02001622nc_server_config_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +01001623{
roman874fed12023-05-25 10:20:01 +02001624 nc_server_config_del_auth_client_pubkey_pub_base64(pubkey);
romanc1d2b092023-02-02 08:58:27 +01001625
roman3f9b65c2023-06-05 14:26:58 +02001626 pubkey->data = strdup(lyd_get_value(node));
1627 if (!pubkey->data) {
romanc1d2b092023-02-02 08:58:27 +01001628 ERRMEM;
1629 return 1;
1630 }
1631
1632 return 0;
1633}
1634
1635static int
roman874fed12023-05-25 10:20:01 +02001636nc_server_config_replace_host_key_public_key(const struct lyd_node *node, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +01001637{
roman874fed12023-05-25 10:20:01 +02001638 nc_server_config_del_public_key(hostkey);
romanc1d2b092023-02-02 08:58:27 +01001639
roman3f9b65c2023-06-05 14:26:58 +02001640 hostkey->key.pubkey_data = strdup(lyd_get_value(node));
1641 if (!hostkey->key.pubkey_data) {
romanc1d2b092023-02-02 08:58:27 +01001642 ERRMEM;
1643 return 1;
1644 }
1645
1646 return 0;
1647}
1648
roman3f9b65c2023-06-05 14:26:58 +02001649static int
1650nc_server_config_tls_replace_server_public_key(const struct lyd_node *node, struct nc_server_tls_opts *opts)
1651{
1652 nc_server_config_tls_del_public_key(opts);
1653
1654 opts->pubkey_data = strdup(lyd_get_value(node));
1655 if (!opts->pubkey_data) {
1656 ERRMEM;
1657 return 1;
1658 }
1659
1660 return 0;
1661}
1662
romanc1d2b092023-02-02 08:58:27 +01001663static int
romane028ef92023-02-24 16:33:08 +01001664nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001665{
roman3f9b65c2023-06-05 14:26:58 +02001666 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001667 struct nc_endpt *endpt;
1668 struct nc_hostkey *hostkey;
1669 struct nc_client_auth *auth_client;
roman8edee342023-03-31 13:25:48 +02001670 struct nc_public_key *pubkey;
romanc1d2b092023-02-02 08:58:27 +01001671
1672 assert(!strcmp(LYD_NAME(node), "public-key"));
1673
roman3f9b65c2023-06-05 14:26:58 +02001674 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
1675 ret = 1;
1676 goto cleanup;
1677 }
romanc1d2b092023-02-02 08:58:27 +01001678
roman3f9b65c2023-06-05 14:26:58 +02001679 if ((equal_parent_name(node, 3, "host-key")) && (is_ssh(node)) && (is_listen(node))) {
1680 /* server's public-key, mandatory leaf */
romanf02273a2023-05-25 09:44:11 +02001681 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001682 ret = 1;
1683 goto cleanup;
1684 }
1685
1686 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02001687 /* set to local */
roman874fed12023-05-25 10:20:01 +02001688 hostkey->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02001689
roman874fed12023-05-25 10:20:01 +02001690 ret = nc_server_config_replace_host_key_public_key(node, hostkey);
romanc1d2b092023-02-02 08:58:27 +01001691 if (ret) {
1692 goto cleanup;
1693 }
1694 }
roman3f9b65c2023-06-05 14:26:58 +02001695 } else if ((equal_parent_name(node, 5, "client-authentication")) && (is_ssh(node)) && (is_listen(node))) {
romanc1d2b092023-02-02 08:58:27 +01001696 /* client auth pubkeys, list */
romanf02273a2023-05-25 09:44:11 +02001697 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001698 ret = 1;
1699 goto cleanup;
1700 }
1701
1702 if (op == NC_OP_CREATE) {
romanf02273a2023-05-25 09:44:11 +02001703 /* set to local */
roman874fed12023-05-25 10:20:01 +02001704 auth_client->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02001705
roman874fed12023-05-25 10:20:01 +02001706 ret = nc_server_config_create_auth_key_public_key_list(node, auth_client);
romanc1d2b092023-02-02 08:58:27 +01001707 if (ret) {
1708 goto cleanup;
1709 }
1710 } else if (op == NC_OP_DELETE) {
romanf02273a2023-05-25 09:44:11 +02001711 if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001712 ret = 1;
1713 goto cleanup;
1714 }
1715
roman874fed12023-05-25 10:20:01 +02001716 nc_server_config_del_auth_client_pubkey(auth_client, pubkey);
romanc1d2b092023-02-02 08:58:27 +01001717 }
roman3f9b65c2023-06-05 14:26:58 +02001718 } else if ((equal_parent_name(node, 6, "client-authentication")) && (is_ssh(node)) && (is_listen(node))) {
romanc1d2b092023-02-02 08:58:27 +01001719 /* client auth pubkey, leaf */
romanf02273a2023-05-25 09:44:11 +02001720 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001721 ret = 1;
1722 goto cleanup;
1723 }
1724
romanf02273a2023-05-25 09:44:11 +02001725 if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001726 ret = 1;
1727 goto cleanup;
1728 }
1729
1730 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02001731 ret = nc_server_config_replace_auth_key_public_key_leaf(node, pubkey);
romanc1d2b092023-02-02 08:58:27 +01001732 if (ret) {
1733 goto cleanup;
1734 }
1735 } else {
roman874fed12023-05-25 10:20:01 +02001736 nc_server_config_del_auth_client_pubkey_pub_base64(pubkey);
romanc1d2b092023-02-02 08:58:27 +01001737 }
roman2eab4742023-06-06 10:00:26 +02001738 } else if ((equal_parent_name(node, 3, "server-identity")) && (is_tls(node)) && (is_listen(node))) {
roman3f9b65c2023-06-05 14:26:58 +02001739 /* tls listen server-identity */
roman3f9b65c2023-06-05 14:26:58 +02001740 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1741 /* set to local */
1742 endpt->opts.tls->store = NC_STORE_LOCAL;
1743
1744 ret = nc_server_config_tls_replace_server_public_key(node, endpt->opts.tls);
1745 if (ret) {
1746 goto cleanup;
1747 }
1748 }
1749 }
romanc1d2b092023-02-02 08:58:27 +01001750
1751cleanup:
1752 return ret;
1753}
1754
1755static int
roman874fed12023-05-25 10:20:01 +02001756nc_server_config_create_user(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01001757{
romanf02273a2023-05-25 09:44:11 +02001758 node = lyd_child(node);
1759 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01001760
romanf02273a2023-05-25 09:44:11 +02001761 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 +01001762}
1763
1764/* list */
1765static int
romane028ef92023-02-24 16:33:08 +01001766nc_server_config_user(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001767{
1768 struct nc_endpt *endpt;
1769 struct nc_client_auth *auth_client;
1770 int ret = 0;
1771
1772 assert(!strcmp(LYD_NAME(node), "user"));
1773
1774 if (equal_parent_name(node, 6, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001775 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001776 ret = 1;
1777 goto cleanup;
1778 }
1779
1780 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +02001781 ret = nc_server_config_create_user(node, endpt->opts.ssh);
romanc1d2b092023-02-02 08:58:27 +01001782 if (ret) {
1783 goto cleanup;
1784 }
1785 } else if (op == NC_OP_DELETE) {
romanf02273a2023-05-25 09:44:11 +02001786 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001787 ret = 1;
1788 goto cleanup;
1789 }
1790
roman874fed12023-05-25 10:20:01 +02001791 nc_server_config_del_auth_client(endpt->opts.ssh, auth_client);
romanc1d2b092023-02-02 08:58:27 +01001792 }
1793 }
1794
1795cleanup:
1796 return ret;
1797}
1798
1799static int
romane028ef92023-02-24 16:33:08 +01001800nc_server_config_auth_attempts(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001801{
1802 struct nc_endpt *endpt;
1803 int ret = 0;
1804
1805 assert(!strcmp(LYD_NAME(node), "auth-attempts"));
1806
1807 if (equal_parent_name(node, 5, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001808 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001809 ret = 1;
1810 goto cleanup;
1811 }
1812
1813 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1814 endpt->opts.ssh->auth_attempts = strtoul(lyd_get_value(node), NULL, 10);
1815 }
1816 }
1817
1818cleanup:
1819 return ret;
1820}
1821
1822static int
romane028ef92023-02-24 16:33:08 +01001823nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001824{
1825 struct nc_endpt *endpt;
1826 int ret = 0;
1827
1828 assert(!strcmp(LYD_NAME(node), "auth-timeout"));
1829
1830 if (equal_parent_name(node, 5, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001831 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001832 ret = 1;
1833 goto cleanup;
1834 }
1835
1836 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1837 endpt->opts.ssh->auth_timeout = strtoul(lyd_get_value(node), NULL, 10);
1838 }
1839 }
1840
1841cleanup:
1842 return ret;
1843}
1844
1845static int
roman874fed12023-05-25 10:20:01 +02001846nc_server_config_replace_truststore_reference(const struct lyd_node *node, struct nc_client_auth *client_auth)
romanc1d2b092023-02-02 08:58:27 +01001847{
romand57b3722023-04-05 11:26:25 +02001848 uint16_t i;
1849 struct nc_truststore *ts = &server_opts.truststore;
romanc1d2b092023-02-02 08:58:27 +01001850
romand57b3722023-04-05 11:26:25 +02001851 /* lookup name */
1852 for (i = 0; i < ts->pub_bag_count; i++) {
1853 if (!strcmp(lyd_get_value(node), ts->pub_bags[i].name)) {
1854 break;
1855 }
1856 }
1857
1858 if (i == ts->pub_bag_count) {
roman3f9b65c2023-06-05 14:26:58 +02001859 ERR(NULL, "Public-key bag \"%s\" not found in truststore.", lyd_get_value(node));
romanc1d2b092023-02-02 08:58:27 +01001860 return 1;
1861 }
1862
romand57b3722023-04-05 11:26:25 +02001863 client_auth->ts_ref = &ts->pub_bags[i];
1864
romanc1d2b092023-02-02 08:58:27 +01001865 return 0;
1866}
1867
roman3f9b65c2023-06-05 14:26:58 +02001868static int
1869nc_server_config_tls_replace_truststore_reference(const struct lyd_node *node, struct nc_cert_grouping *auth_client)
1870{
1871 uint16_t i;
1872 struct nc_truststore *ts = &server_opts.truststore;
1873
1874 /* lookup name */
1875 for (i = 0; i < ts->cert_bag_count; i++) {
1876 if (!strcmp(lyd_get_value(node), ts->cert_bags[i].name)) {
1877 break;
1878 }
1879 }
1880
1881 if (i == ts->cert_bag_count) {
1882 ERR(NULL, "Certificate bag \"%s\" not found in truststore.", lyd_get_value(node));
1883 return 1;
1884 }
1885
1886 auth_client->ts_ref = &ts->cert_bags[i];
1887
1888 return 0;
1889}
1890
romanc1d2b092023-02-02 08:58:27 +01001891/* leaf */
1892static int
romane028ef92023-02-24 16:33:08 +01001893nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001894{
romanc1d2b092023-02-02 08:58:27 +01001895 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02001896 struct nc_endpt *endpt;
roman3f9b65c2023-06-05 14:26:58 +02001897 struct nc_client_auth *auth_client;
romanc1d2b092023-02-02 08:58:27 +01001898
1899 assert(!strcmp(LYD_NAME(node), "truststore-reference"));
1900
roman3f9b65c2023-06-05 14:26:58 +02001901 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
1902 ret = 1;
1903 goto cleanup;
1904 }
romanc1d2b092023-02-02 08:58:27 +01001905
roman3f9b65c2023-06-05 14:26:58 +02001906 if ((equal_parent_name(node, 1, "public-keys")) && (is_ssh(node)) && (is_listen(node))) {
romanf02273a2023-05-25 09:44:11 +02001907 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001908 ret = 1;
1909 goto cleanup;
1910 }
1911
1912 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02001913 /* set to truststore */
roman874fed12023-05-25 10:20:01 +02001914 auth_client->store = NC_STORE_TRUSTSTORE;
romanf02273a2023-05-25 09:44:11 +02001915
roman874fed12023-05-25 10:20:01 +02001916 ret = nc_server_config_replace_truststore_reference(node, auth_client);
romanc1d2b092023-02-02 08:58:27 +01001917 if (ret) {
1918 goto cleanup;
1919 }
1920 } else {
romand57b3722023-04-05 11:26:25 +02001921 auth_client->ts_ref = NULL;
romanc1d2b092023-02-02 08:58:27 +01001922 }
roman2eab4742023-06-06 10:00:26 +02001923 } else if ((equal_parent_name(node, 1, "ca-certs")) && (is_listen(node))) {
roman3f9b65c2023-06-05 14:26:58 +02001924 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1925 /* set to truststore */
1926 endpt->opts.tls->ca_certs.store = NC_STORE_TRUSTSTORE;
1927
1928 ret = nc_server_config_tls_replace_truststore_reference(node, &endpt->opts.tls->ca_certs);
1929 if (ret) {
1930 goto cleanup;
1931 }
1932 } else {
1933 endpt->opts.tls->ca_certs.ts_ref = NULL;
1934 }
1935 } else if ((equal_parent_name(node, 1, "ee-certs")) && (is_listen(node))) {
1936 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1937 /* set to truststore */
1938 endpt->opts.tls->ee_certs.store = NC_STORE_TRUSTSTORE;
1939
1940 ret = nc_server_config_tls_replace_truststore_reference(node, &endpt->opts.tls->ee_certs);
1941 if (ret) {
1942 goto cleanup;
1943 }
1944 } else {
1945 endpt->opts.tls->ee_certs.ts_ref = NULL;
1946 }
1947 }
romanc1d2b092023-02-02 08:58:27 +01001948
1949cleanup:
1950 return ret;
1951}
1952
1953static int
roman874fed12023-05-25 10:20:01 +02001954nc_server_config_replace_password(const struct lyd_node *node, struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +01001955{
roman874fed12023-05-25 10:20:01 +02001956 nc_server_config_del_auth_client_password(auth_client);
romanc1d2b092023-02-02 08:58:27 +01001957
1958 auth_client->password = strdup(lyd_get_value(node));
1959 if (!auth_client->password) {
1960 ERRMEM;
1961 return 1;
1962 }
1963
1964 return 0;
1965}
1966
1967/* leaf */
1968static int
romane028ef92023-02-24 16:33:08 +01001969nc_server_config_password(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001970{
1971 struct nc_endpt *endpt;
1972 struct nc_client_auth *auth_client;
1973 int ret = 0;
1974
1975 assert(!strcmp(LYD_NAME(node), "password"));
1976
1977 if (equal_parent_name(node, 7, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001978 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001979 ret = 1;
1980 goto cleanup;
1981 }
1982
romanf02273a2023-05-25 09:44:11 +02001983 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001984 ret = 1;
1985 goto cleanup;
1986 }
1987
1988 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02001989 ret = nc_server_config_replace_password(node, auth_client);
romanc1d2b092023-02-02 08:58:27 +01001990 if (ret) {
1991 goto cleanup;
1992 }
1993 } else {
roman874fed12023-05-25 10:20:01 +02001994 nc_server_config_del_auth_client_password(auth_client);
romanc1d2b092023-02-02 08:58:27 +01001995 }
1996 }
1997
1998cleanup:
1999 return ret;
2000}
2001
2002static int
romane028ef92023-02-24 16:33:08 +01002003nc_server_config_pam_name(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002004{
2005 struct nc_endpt *endpt;
2006 struct nc_client_auth *auth_client;
2007 int ret = 0;
2008
2009 assert(!strcmp(LYD_NAME(node), "pam-config-file-name"));
2010
2011 if (equal_parent_name(node, 8, "listen")) {
romanf02273a2023-05-25 09:44:11 +02002012 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01002013 ret = 1;
2014 goto cleanup;
2015 }
2016
romanf02273a2023-05-25 09:44:11 +02002017 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002018 ret = 1;
2019 goto cleanup;
2020 }
2021
2022 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02002023 nc_server_config_del_auth_client_pam_name(auth_client);
romanc1d2b092023-02-02 08:58:27 +01002024
2025 auth_client->pam_config_name = strdup(lyd_get_value(node));
2026 if (!auth_client->pam_config_name) {
2027 ERRMEM;
2028 ret = 1;
2029 goto cleanup;
2030 }
2031 }
2032 }
2033
2034cleanup:
2035 return ret;
2036}
2037
2038static int
romane028ef92023-02-24 16:33:08 +01002039nc_server_config_pam_dir(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002040{
2041 struct nc_endpt *endpt;
2042 struct nc_client_auth *auth_client;
2043 int ret = 0;
2044
2045 assert(!strcmp(LYD_NAME(node), "pam-config-file-dir"));
2046
2047 if (equal_parent_name(node, 8, "listen")) {
romanf02273a2023-05-25 09:44:11 +02002048 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01002049 ret = 1;
2050 goto cleanup;
2051 }
2052
romanf02273a2023-05-25 09:44:11 +02002053 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002054 ret = 1;
2055 goto cleanup;
2056 }
2057
2058 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02002059 nc_server_config_del_auth_client_pam_dir(auth_client);
romanc1d2b092023-02-02 08:58:27 +01002060 auth_client->pam_config_dir = strdup(lyd_get_value(node));
2061 if (!auth_client->pam_config_dir) {
2062 ERRMEM;
2063 ret = 1;
2064 goto cleanup;
2065 }
2066 }
2067 }
2068
2069cleanup:
2070 return ret;
2071}
2072
2073/* leaf */
2074static int
romane028ef92023-02-24 16:33:08 +01002075nc_server_config_none(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002076{
2077 struct nc_endpt *endpt;
2078 struct nc_client_auth *auth_client;
2079 int ret = 0;
2080
2081 assert(!strcmp(LYD_NAME(node), "none"));
2082
2083 if (equal_parent_name(node, 7, "listen")) {
romanf02273a2023-05-25 09:44:11 +02002084 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01002085 ret = 1;
2086 goto cleanup;
2087 }
2088
romanf02273a2023-05-25 09:44:11 +02002089 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002090 ret = 1;
2091 goto cleanup;
2092 }
2093
2094 if (op == NC_OP_CREATE) {
2095 auth_client->supports_none = 1;
2096 } else {
2097 auth_client->supports_none = 0;
2098 }
2099 }
2100
2101cleanup:
2102 return ret;
2103}
2104
2105static int
romana6bf6ab2023-05-26 13:26:02 +02002106nc_server_config_transport_params(const char *algorithm, char **alg_store, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002107{
2108 int ret = 0, alg_found = 0;
romana6bf6ab2023-05-26 13:26:02 +02002109 char *substr, *haystack, *alg = NULL;
2110 size_t alg_len;
2111
2112 if (!strncmp(algorithm, "openssh-", 8)) {
2113 /* if the name starts with openssh, convert it to it's original libssh accepted form */
2114 asprintf(&alg, "%s@openssh.com", algorithm + 8);
2115 if (!alg) {
2116 ERRMEM;
2117 ret = 1;
2118 goto cleanup;
2119 }
2120 } else if (!strncmp(algorithm, "libssh-", 7)) {
2121 /* if the name starts with libssh, convert it to it's original libssh accepted form */
2122 asprintf(&alg, "%s@libssh.org", algorithm + 7);
2123 if (!alg) {
2124 ERRMEM;
2125 ret = 1;
2126 goto cleanup;
2127 }
2128 } else {
2129 alg = strdup(algorithm);
2130 if (!alg) {
2131 ERRMEM;
2132 ret = 1;
2133 goto cleanup;
2134 }
2135 }
2136
2137 alg_len = strlen(alg);
romanc1d2b092023-02-02 08:58:27 +01002138
2139 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2140 if (!*alg_store) {
2141 /* first call */
2142 *alg_store = strdup(alg);
2143 if (!*alg_store) {
2144 ERRMEM;
2145 ret = 1;
2146 goto cleanup;
2147 }
2148 } else {
2149 /* +1 because of ',' between algorithms */
2150 *alg_store = nc_realloc(*alg_store, strlen(*alg_store) + alg_len + 1 + 1);
2151 if (!*alg_store) {
2152 ERRMEM;
2153 ret = 1;
2154 goto cleanup;
2155 }
2156 sprintf(*alg_store, "%s,%s", *alg_store, alg);
2157 }
2158 } else {
2159 /* delete */
2160 haystack = *alg_store;
2161 while ((substr = strstr(haystack, alg))) {
2162 /* iterate over all the substrings */
2163 if (((substr == haystack) && (*(substr + alg_len) == ',')) ||
2164 ((substr != haystack) && (*(substr - 1) == ',') && (*(substr + alg_len) == ','))) {
2165 /* either the first element of the string or somewhere in the middle */
2166 memmove(substr, substr + alg_len + 1, strlen(substr + alg_len + 1));
2167 alg_found = 1;
2168 break;
2169 } else if ((*(substr - 1) == ',') && (*(substr + alg_len) == '\0')) {
2170 /* the last element of the string */
2171 *(substr - 1) = '\0';
2172 alg_found = 1;
2173 break;
2174 }
2175 haystack++;
2176 }
2177 if (!alg_found) {
2178 ERR(NULL, "Unable to delete an algorithm (%s), which was not previously added.", alg);
2179 ret = 1;
2180 }
2181 }
2182
2183cleanup:
romana6bf6ab2023-05-26 13:26:02 +02002184 free(alg);
romanc1d2b092023-02-02 08:58:27 +01002185 return ret;
2186}
2187
2188/* leaf-list */
2189static int
romane028ef92023-02-24 16:33:08 +01002190nc_server_config_host_key_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002191{
2192 struct nc_endpt *endpt;
2193 int ret = 0, listen = 0;
2194 const char *alg;
2195 uint8_t i;
2196
2197 /* get the algorithm name and compare it with algs supported by libssh */
2198 alg = ((struct lyd_node_term *)node)->value.ident->name;
2199
2200 if (equal_parent_name(node, 6, "listen")) {
2201 listen = 1;
romanf02273a2023-05-25 09:44:11 +02002202 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01002203 ret = 1;
2204 goto cleanup;
2205 }
2206 }
2207
2208 i = 0;
2209 while (supported_hostkey_algs[i]) {
2210 if (!strcmp(supported_hostkey_algs[i], alg)) {
2211 if (listen) {
romane028ef92023-02-24 16:33:08 +01002212 if (nc_server_config_transport_params(alg, &endpt->opts.ssh->hostkey_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002213 ret = 1;
2214 goto cleanup;
2215 }
2216 }
2217 break;
2218 }
2219 i++;
2220 }
2221 if (!supported_hostkey_algs[i]) {
2222 /* algorithm not supported */
2223 ERR(NULL, "Public key algorithm (%s) not supported by libssh.", alg);
2224 ret = 1;
2225 }
2226
2227cleanup:
2228 return ret;
2229}
2230
2231/* leaf-list */
2232static int
romane028ef92023-02-24 16:33:08 +01002233nc_server_config_kex_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002234{
2235 struct nc_endpt *endpt;
2236 int ret = 0, listen = 0;
2237 const char *alg;
2238 uint8_t i;
2239
2240 /* get the algorithm name and compare it with algs supported by libssh */
2241 alg = ((struct lyd_node_term *)node)->value.ident->name;
2242
2243 if (equal_parent_name(node, 6, "listen")) {
2244 listen = 1;
romanf02273a2023-05-25 09:44:11 +02002245 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01002246 ret = 1;
2247 goto cleanup;
2248 }
2249 }
2250
2251 i = 0;
2252 while (supported_kex_algs[i]) {
2253 if (!strcmp(supported_kex_algs[i], alg)) {
2254 if (listen) {
romane028ef92023-02-24 16:33:08 +01002255 if (nc_server_config_transport_params(alg, &endpt->opts.ssh->kex_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002256 ret = 1;
2257 goto cleanup;
2258 }
2259 }
2260 break;
2261 }
2262 i++;
2263 }
2264 if (!supported_kex_algs[i]) {
2265 /* algorithm not supported */
2266 ERR(NULL, "Key exchange algorithm (%s) not supported by libssh.", alg);
2267 ret = 1;
2268 }
2269
2270cleanup:
2271 return ret;
2272}
2273
2274/* leaf-list */
2275static int
romane028ef92023-02-24 16:33:08 +01002276nc_server_config_encryption_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002277{
2278 struct nc_endpt *endpt;
2279 int ret = 0, listen = 0;
2280 const char *alg;
2281 uint8_t i;
2282
2283 /* get the algorithm name and compare it with algs supported by libssh */
2284 alg = ((struct lyd_node_term *)node)->value.ident->name;
2285
2286 if (equal_parent_name(node, 6, "listen")) {
2287 listen = 1;
romanf02273a2023-05-25 09:44:11 +02002288 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01002289 ret = 1;
2290 goto cleanup;
2291 }
2292 }
2293
2294 i = 0;
2295 while (supported_encryption_algs[i]) {
2296 if (!strcmp(supported_encryption_algs[i], alg)) {
2297 if (listen) {
romane028ef92023-02-24 16:33:08 +01002298 if (nc_server_config_transport_params(alg, &endpt->opts.ssh->encryption_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002299 ret = 1;
2300 goto cleanup;
2301 }
2302 }
2303 break;
2304 }
2305 i++;
2306 }
2307 if (!supported_encryption_algs[i]) {
2308 /* algorithm not supported */
2309 ERR(NULL, "Encryption algorithm (%s) not supported by libssh.", alg);
2310 ret = 1;
2311 }
2312
2313cleanup:
2314 return ret;
2315}
2316
2317/* leaf-list */
2318static int
romane028ef92023-02-24 16:33:08 +01002319nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002320{
2321 struct nc_endpt *endpt;
2322 int ret = 0, listen = 0;
2323 const char *alg;
2324 uint8_t i;
2325
2326 /* get the algorithm name and compare it with algs supported by libssh */
2327 alg = ((struct lyd_node_term *)node)->value.ident->name;
2328
2329 if (equal_parent_name(node, 6, "listen")) {
2330 listen = 1;
romanf02273a2023-05-25 09:44:11 +02002331 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01002332 ret = 1;
2333 goto cleanup;
2334 }
2335 }
2336
2337 i = 0;
2338 while (supported_mac_algs[i]) {
2339 if (!strcmp(supported_mac_algs[i], alg)) {
2340 if (listen) {
romane028ef92023-02-24 16:33:08 +01002341 if (nc_server_config_transport_params(alg, &endpt->opts.ssh->mac_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002342 ret = 1;
2343 goto cleanup;
2344 }
2345 }
2346 break;
2347 }
2348 i++;
2349 }
2350 if (!supported_mac_algs[i]) {
2351 /* algorithm not supported */
2352 ERR(NULL, "MAC algorithm (%s) not supported by libssh.", alg);
2353 ret = 1;
2354 }
2355
2356cleanup:
2357 return ret;
2358}
2359
roman2eab4742023-06-06 10:00:26 +02002360#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02002361
romanc1d2b092023-02-02 08:58:27 +01002362static int
roman874fed12023-05-25 10:20:01 +02002363nc_server_config_create_unix_socket(struct nc_endpt *endpt)
roman83683fb2023-02-24 09:15:23 +01002364{
2365 endpt->ti = NC_TI_UNIX;
2366 endpt->opts.unixsock = calloc(1, sizeof *endpt->opts.unixsock);
2367 if (!endpt->opts.unixsock) {
2368 ERRMEM;
2369 return 1;
2370 }
2371
2372 /* set default values */
2373 endpt->opts.unixsock->mode = -1;
2374 endpt->opts.unixsock->uid = -1;
2375 endpt->opts.unixsock->gid = -1;
2376
2377 return 0;
2378}
2379
2380static int
romane028ef92023-02-24 16:33:08 +01002381nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op)
roman83683fb2023-02-24 09:15:23 +01002382{
2383 int ret = 0;
2384 uint32_t prev_lo;
2385 struct nc_endpt *endpt;
2386 struct nc_bind *bind;
2387 struct nc_server_unix_opts *opts;
2388 struct lyd_node *data = NULL;
2389
2390 assert(!strcmp(LYD_NAME(node), "unix-socket"));
2391
romanf02273a2023-05-25 09:44:11 +02002392 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
roman83683fb2023-02-24 09:15:23 +01002393 ret = 1;
2394 goto cleanup;
2395 }
2396
2397 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +02002398 if (nc_server_config_create_unix_socket(endpt)) {
roman83683fb2023-02-24 09:15:23 +01002399 ret = 1;
2400 goto cleanup;
2401 }
2402
2403 opts = endpt->opts.unixsock;
2404
2405 lyd_find_path(node, "path", 0, &data);
2406 assert(data);
2407
2408 opts->address = strdup(lyd_get_value(data));
2409 bind->address = strdup(lyd_get_value(data));
2410 if (!opts->address || !bind->address) {
2411 ERRMEM;
2412 ret = 1;
2413 goto cleanup;
2414 }
2415
2416 /* silently search for non-mandatory parameters */
2417 prev_lo = ly_log_options(0);
2418 ret = lyd_find_path(node, "mode", 0, &data);
2419 if (!ret) {
2420 opts->mode = strtol(lyd_get_value(data), NULL, 8);
2421 }
2422
2423 ret = lyd_find_path(node, "uid", 0, &data);
2424 if (!ret) {
2425 opts->uid = strtol(lyd_get_value(data), NULL, 10);
2426 }
2427
2428 ret = lyd_find_path(node, "gid", 0, &data);
2429 if (!ret) {
2430 opts->gid = strtol(lyd_get_value(data), NULL, 10);
2431 }
2432
2433 /* reset the logging options */
2434 ly_log_options(prev_lo);
2435
2436 ret = nc_server_config_set_address_port(endpt, bind, NULL, 0);
2437 if (ret) {
2438 goto cleanup;
2439 }
2440 } else if (op == NC_OP_DELETE) {
roman874fed12023-05-25 10:20:01 +02002441 nc_server_config_del_unix_socket(bind, endpt->opts.unixsock);
roman83683fb2023-02-24 09:15:23 +01002442 }
2443
2444cleanup:
2445 return ret;
2446}
2447
roman2eab4742023-06-06 10:00:26 +02002448#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02002449
roman0bbc19c2023-05-26 09:59:09 +02002450/**
2451 * @brief Set all endpoint client auth references, which couldn't be set beforehand.
2452 *
2453 * The references that could not be set are those, which reference endpoints, which
2454 * lie below the given endpoint in the YANG data (because of DFS tree parsing).
2455 *
2456 * @return 0 on success, 1 on error.
2457 */
2458static int
2459nc_server_config_fill_endpt_client_auth(void)
2460{
2461 uint16_t i, j;
2462
2463 for (i = 0; i < server_opts.endpt_count; i++) {
2464 /* go through all the endpoint */
2465 if (server_opts.endpts[i].referenced_endpt_name) {
2466 /* endpt has a reference, that hasn't been set yet */
2467 for (j = i + 1; j < server_opts.endpt_count; j++) {
2468 /* go through all the remaining endpts */
2469 if (!strcmp(server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[j].name)) {
2470 /* found the endpoint we were looking for */
2471 if (server_opts.endpts[i].ti == NC_TI_LIBSSH) {
2472 server_opts.endpts[i].opts.ssh->endpt_client_ref = &server_opts.endpts[j];
2473 break;
2474 } else {
2475 ERRINT;
2476 return 1;
2477 }
2478 }
2479 }
2480
2481 /* didn't find the endpoint */
2482 if (j == server_opts.endpt_count) {
2483 ERR(NULL, "Endpoint \"%s\" referenced by \"%s\" not found.",
2484 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2485 return 1;
2486 }
2487 }
2488 }
2489
2490 return 0;
2491}
2492
2493static int
2494nc_server_config_endpoint_client_auth_has_cycle(struct nc_endpt *original, struct nc_endpt *next, NC_TRANSPORT_IMPL transport)
2495{
2496 if (transport == NC_TI_LIBSSH) {
2497 if (next->opts.ssh->endpt_client_ref) {
2498 if (next->opts.ssh->endpt_client_ref == original) {
2499 return 1;
2500 } else {
2501 return nc_server_config_endpoint_client_auth_has_cycle(original, next->opts.ssh->endpt_client_ref, NC_TI_LIBSSH);
2502 }
2503 } else {
2504 return 0;
2505 }
2506 } else {
2507 ERRINT;
2508 return 1;
2509 }
2510}
2511
2512static int
2513nc_server_config_endpoint_client_auth(const struct lyd_node *node, NC_OPERATION op)
2514{
2515 int ret = 0;
2516 uint16_t i;
2517 const char *endpt_name;
2518 struct nc_endpt *endpt;
2519
2520 assert(!strcmp(LYD_NAME(node), "endpoint-client-auth"));
2521
2522 /* get current endpoint */
2523 ret = nc_server_config_get_endpt(node, &endpt, NULL);
2524 if (ret) {
2525 goto cleanup;
2526 }
2527
2528 if (op == NC_OP_DELETE) {
2529 endpt->opts.ssh->endpt_client_ref = NULL;
2530 goto cleanup;
2531 }
2532
2533 /* find the endpoint leafref is referring to */
2534 endpt_name = lyd_get_value(node);
2535 for (i = 0; i < server_opts.endpt_count; i++) {
2536 if (!strcmp(endpt_name, server_opts.endpts[i].name)) {
2537 break;
2538 }
2539 }
2540
2541 if (i == server_opts.endpt_count) {
2542 /* endpt not found, save the name and try to look it up later */
2543 endpt->referenced_endpt_name = strdup(endpt_name);
2544 if (!endpt->referenced_endpt_name) {
2545 ERRMEM;
2546 ret = 1;
2547 goto cleanup;
2548 }
2549 goto cleanup;
2550 }
2551
2552 /* check for self reference */
2553 if (endpt == &server_opts.endpts[i]) {
2554 ERR(NULL, "Self client authentication reference detected.");
2555 ret = 1;
2556 goto cleanup;
2557 }
2558
2559 /* check for cyclic references */
2560 ret = nc_server_config_endpoint_client_auth_has_cycle(endpt, &server_opts.endpts[i], endpt->ti);
2561 if (ret) {
2562 ERR(NULL, "Cyclic client authentication reference detected.");
2563 goto cleanup;
2564 }
2565
2566 /* assign the current endpt the referrenced endpt */
2567 endpt->opts.ssh->endpt_client_ref = &server_opts.endpts[i];
2568
2569cleanup:
2570 return ret;
2571}
2572
roman3f9b65c2023-06-05 14:26:58 +02002573static int
2574nc_server_config_tls_replace_cert_data(const struct lyd_node *node, struct nc_server_tls_opts *opts)
2575{
2576 nc_server_config_tls_del_cert_data(opts);
2577 opts->cert_data = strdup(lyd_get_value(node));
2578 if (!opts->cert_data) {
2579 ERRMEM;
2580 return 1;
2581 }
2582
2583 return 0;
2584}
2585
2586static int
2587nc_server_config_tls_replace_cert_data_client_auth(const struct lyd_node *node, struct nc_certificate *cert)
2588{
2589 nc_server_config_tls_del_cert_data_certificate(cert);
2590 cert->data = strdup(lyd_get_value(node));
2591 if (!cert->data) {
2592 ERRMEM;
2593 return 1;
2594 }
2595
2596 return 0;
2597}
2598
2599static int
2600nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op)
2601{
2602 int ret = 0;
2603 struct nc_endpt *endpt;
2604 struct nc_certificate *cert;
2605
2606 assert(!strcmp(LYD_NAME(node), "cert-data"));
2607
2608 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
2609 ret = 1;
2610 goto cleanup;
2611 }
2612
2613 if ((equal_parent_name(node, 3, "server-identity")) && (is_listen(node))) {
2614 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2615 ret = nc_server_config_tls_replace_cert_data(node, endpt->opts.tls);
2616 if (ret) {
2617 goto cleanup;
2618 }
2619 }
2620 } else if ((equal_parent_name(node, 3, "ca-certs")) && (is_listen(node))) {
2621 if (nc_server_config_get_cert(node, &endpt->opts.tls->ca_certs, &cert)) {
2622 ret = 1;
2623 goto cleanup;
2624 }
2625
2626 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2627 ret = nc_server_config_tls_replace_cert_data_client_auth(node, cert);
2628 if (ret) {
2629 goto cleanup;
2630 }
2631 } else {
2632 nc_server_config_tls_del_cert_data_certificate(cert);
2633 }
2634 } else if ((equal_parent_name(node, 3, "ee-certs")) && (is_listen(node))) {
2635 if (nc_server_config_get_cert(node, &endpt->opts.tls->ee_certs, &cert)) {
2636 ret = 1;
2637 goto cleanup;
2638 }
2639
2640 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2641 ret = nc_server_config_tls_replace_cert_data_client_auth(node, cert);
2642 if (ret) {
2643 goto cleanup;
2644 }
2645 } else {
2646 nc_server_config_tls_del_cert_data_certificate(cert);
2647 }
2648 }
2649
2650cleanup:
2651 return ret;
2652}
2653
2654static int
2655nc_server_config_tls_create_asymmetric_key_ref(const struct lyd_node *node, struct nc_endpt *endpt)
2656{
2657 uint16_t i;
2658 struct nc_keystore *ks = &server_opts.keystore;
2659
2660 /* lookup name */
2661 for (i = 0; i < ks->asym_key_count; i++) {
2662 if (!strcmp(lyd_get_value(node), ks->asym_keys[i].name)) {
2663 break;
2664 }
2665 }
2666
2667 if (i == ks->asym_key_count) {
2668 ERR(NULL, "Asymmetric key \"%s\" not found in the keystore.", lyd_get_value(node));
2669 return 1;
2670 }
2671
2672 endpt->opts.tls->key_ref = &ks->asym_keys[i];
2673
2674 return 0;
2675}
2676
2677static int
2678nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op)
2679{
2680 int ret = 0;
2681 struct nc_endpt *endpt;
2682
2683 assert(!strcmp(LYD_NAME(node), "asymmetric-key"));
2684
2685 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
2686 ret = 1;
2687 goto cleanup;
2688 }
2689
2690 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2691 /* set to keystore */
2692 endpt->opts.tls->store = NC_STORE_KEYSTORE;
2693
2694 ret = nc_server_config_tls_create_asymmetric_key_ref(node, endpt);
2695 if (ret) {
2696 goto cleanup;
2697 }
2698 } else {
2699 endpt->opts.tls->key_ref = NULL;
2700 }
2701
2702cleanup:
2703 return ret;
2704}
2705
2706static int
2707nc_server_config_tls_create_certificate_ref(const struct lyd_node *node, struct nc_endpt *endpt, struct nc_asymmetric_key *key)
2708{
2709 uint16_t i;
2710
2711 /* lookup name */
2712 for (i = 0; i < key->cert_count; i++) {
2713 if (!strcmp(lyd_get_value(node), key->certs[i].name)) {
2714 break;
2715 }
2716 }
2717
2718 if (i == key->cert_count) {
2719 ERR(NULL, "Certificate \"%s\" not found in the asymmetric key \"%s\".", lyd_get_value(node), key->name);
2720 return 1;
2721 }
2722
2723 endpt->opts.tls->cert_ref = &key->certs[i];
2724
2725 return 0;
2726}
2727
2728static struct nc_asymmetric_key *
2729cert_get_asymmetric_key(const struct lyd_node *node)
2730{
2731 uint16_t i;
2732 struct nc_keystore *ks = &server_opts.keystore;
2733
2734 /* starting with certificate node */
2735 assert(!strcmp(LYD_NAME(node), "certificate"));
2736
2737 /* switch to it's only sibling, must be asymmetric-key */
2738 node = node->prev;
2739 assert(!strcmp(LYD_NAME(node), "asymmetric-key"));
2740
2741 /* find the given asymmetric key */
2742 for (i = 0; i < ks->asym_key_count; i++) {
2743 if (!strcmp(lyd_get_value(node), ks->asym_keys[i].name)) {
2744 return &ks->asym_keys[i];
2745 }
2746 }
2747
2748 /* didn't find it */
2749 ERR(NULL, "Asymmetric key \"%s\" not found in the keystore.", lyd_get_value(node));
2750 return NULL;
2751}
2752
2753static int
2754nc_server_config_create_ca_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
2755{
2756 assert(!strcmp(LYD_NAME(node), "certificate"));
2757
2758 node = lyd_child(node);
2759 assert(!strcmp(LYD_NAME(node), "name"));
2760
2761 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ca_certs.certs, sizeof *opts->ca_certs.certs, &opts->ca_certs.cert_count);
2762}
2763
2764static int
2765nc_server_config_create_ee_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
2766{
2767 assert(!strcmp(LYD_NAME(node), "certificate"));
2768
2769 node = lyd_child(node);
2770 assert(!strcmp(LYD_NAME(node), "name"));
2771
2772 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ee_certs.certs, sizeof *opts->ee_certs.certs, &opts->ee_certs.cert_count);
2773}
2774
2775static int
2776nc_server_config_certificate(const struct lyd_node *node, NC_OPERATION op)
2777{
2778 int ret = 0;
2779 struct nc_endpt *endpt;
2780 struct nc_asymmetric_key *key;
2781
2782 assert(!strcmp(LYD_NAME(node), "certificate"));
2783
2784 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
2785 ret = 1;
2786 goto cleanup;
2787 }
2788
2789 if ((equal_parent_name(node, 1, "keystore-reference")) && (is_listen(node))) {
2790 /* server-identity TLS listen */
2791
2792 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2793 /* set to keystore */
2794 endpt->opts.tls->store = NC_STORE_KEYSTORE;
2795
2796 if (!endpt->opts.tls->key_ref) {
2797 /* we don't have a key from which we need the cert yet */
2798 key = cert_get_asymmetric_key(node);
2799 if (!key) {
2800 ret = 1;
2801 goto cleanup;
2802 }
2803 } else {
2804 /* we have the key */
2805 key = endpt->opts.tls->key_ref;
2806 }
2807
2808 /* find the given cert in the key and set it */
2809 ret = nc_server_config_tls_create_certificate_ref(node, endpt, key);
2810 if (ret) {
2811 goto cleanup;
2812 }
2813 } else {
2814 endpt->opts.tls->cert_ref = NULL;
2815 }
2816 } else if ((equal_parent_name(node, 2, "ca-certs")) && (is_listen(node))) {
2817 /* client auth TLS listen */
2818 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2819 ret = nc_server_config_create_ca_certs_certificate(node, endpt->opts.tls);
2820 if (ret) {
2821 goto cleanup;
2822 }
2823 } else {
2824 nc_server_config_tls_del_certs(&endpt->opts.tls->ca_certs);
2825 }
2826 } else if ((equal_parent_name(node, 2, "ee-certs")) && (is_listen(node))) {
2827 /* client auth TLS listen */
2828 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2829 ret = nc_server_config_create_ee_certs_certificate(node, endpt->opts.tls);
2830 if (ret) {
2831 goto cleanup;
2832 }
2833 } else {
2834 nc_server_config_tls_del_certs(&endpt->opts.tls->ee_certs);
2835 }
2836 }
2837
2838cleanup:
2839 return ret;
2840}
2841
2842static int
2843nc_server_config_create_cert_to_name(const struct lyd_node *node, struct nc_server_tls_opts *opts)
2844{
2845 int ret = 0;
2846 struct lyd_node *n;
2847 struct nc_ctn *new, *iter;
2848 const char *map_type, *name;
2849 uint32_t id;
2850 NC_TLS_CTN_MAPTYPE m_type;
2851
2852 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
2853
2854 /* create new ctn */
2855 new = calloc(1, sizeof *new);
2856 if (!new) {
2857 ERRMEM;
2858 ret = 1;
2859 goto cleanup;
2860 }
2861
2862 /* get all the data */
2863 /* find the list's key */
2864 lyd_find_path(node, "id", 0, &n);
2865 assert(n);
2866 id = strtoul(lyd_get_value(n), NULL, 10);
2867
2868 /* find the ctn's name */
2869 lyd_find_path(node, "name", 0, &n);
2870 assert(n);
2871 name = lyd_get_value(n);
2872
2873 /* find the ctn's map-type */
2874 lyd_find_path(node, "map-type", 0, &n);
2875 assert(n);
2876 map_type = ((struct lyd_node_term *)n)->value.ident->name;
2877 if (!strcmp(map_type, "specified")) {
2878 m_type = NC_TLS_CTN_SPECIFIED;
2879 } else if (!strcmp(map_type, "san-rfc822-name")) {
2880 m_type = NC_TLS_CTN_SAN_RFC822_NAME;
2881 } else if (!strcmp(map_type, "san-dns-name")) {
2882 m_type = NC_TLS_CTN_SAN_DNS_NAME;
2883 } else if (!strcmp(map_type, "san-ip-address")) {
2884 m_type = NC_TLS_CTN_SAN_IP_ADDRESS;
2885 } else if (!strcmp(map_type, "san-any")) {
2886 m_type = NC_TLS_CTN_SAN_ANY;
2887 } else if (!strcmp(map_type, "common-name")) {
2888 m_type = NC_TLS_CTN_COMMON_NAME;
2889 } else {
2890 ERR(NULL, "Map-type identity \"%s\" not supported.", map_type);
2891 ret = 1;
2892 goto cleanup;
2893 }
2894
2895 /* find the right place for insertion */
2896 if (!opts->ctn) {
2897 /* inserting the first one */
2898 opts->ctn = new;
2899 } else if (opts->ctn->id > new->id) {
2900 /* insert at the beginning */
2901 new->next = opts->ctn;
2902 opts->ctn = new;
2903 } else {
2904 /* have to find the right place */
2905 for (iter = opts->ctn; iter->next && iter->next->id <= new->id; iter = iter->next) {}
2906 if (iter->id == new->id) {
2907 /* collision */
2908 new = iter;
2909 } else {
2910 new->next = iter->next;
2911 iter->next = new;
2912 }
2913 }
2914
2915 /* insert the right data */
2916 new->id = id;
2917 if (new->name) {
2918 free(new->name);
2919 }
2920 new->name = strdup(name);
2921 if (!new->name) {
2922 ERRMEM;
2923 ret = 1;
2924 goto cleanup;
2925 }
2926 new->map_type = m_type;
2927
2928cleanup:
2929 return ret;
2930}
2931
2932static int
2933nc_server_config_cert_to_name(const struct lyd_node *node, NC_OPERATION op)
2934{
2935 int ret = 0;
2936 struct nc_endpt *endpt;
2937 struct lyd_node *key;
2938 struct nc_ctn *ctn;
2939
2940 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
2941
2942 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
2943 ret = 1;
2944 goto cleanup;
2945 }
2946
2947 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2948 ret = nc_server_config_create_cert_to_name(node, endpt->opts.tls);
2949 if (ret) {
2950 goto cleanup;
2951 }
2952 } else {
2953 /* find the given ctn entry */
2954 lyd_find_path(node, "id", 0, &key);
2955 assert(key);
2956 if (nc_server_config_get_ctn(node, endpt, &ctn)) {
2957 ret = 1;
2958 goto cleanup;
2959 }
2960 nc_server_config_del_ctn(endpt->opts.tls, ctn);
2961 }
2962
2963cleanup:
2964 return ret;
2965}
2966
2967static int
2968nc_server_config_replace_fingerprint(const struct lyd_node *node, struct nc_ctn *ctn)
2969{
2970 nc_server_config_del_fingerprint(ctn);
2971
2972 ctn->fingerprint = strdup(lyd_get_value(node));
2973 if (!ctn->fingerprint) {
2974 ERRMEM;
2975 return 1;
2976 }
2977
2978 return 0;
2979}
2980
2981static int
2982nc_server_config_fingerprint(const struct lyd_node *node, NC_OPERATION op)
2983{
2984 int ret = 0;
2985 struct nc_endpt *endpt;
2986 struct nc_ctn *ctn;
2987
2988 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
2989 ret = 1;
2990 goto cleanup;
2991 }
2992
2993 if (nc_server_config_get_ctn(node, endpt, &ctn)) {
2994 ret = 1;
2995 goto cleanup;
2996 }
2997
2998 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2999 ret = nc_server_config_replace_fingerprint(node, ctn);
3000 if (ret) {
3001 goto cleanup;
3002 }
3003 } else {
3004 nc_server_config_del_fingerprint(ctn);
3005 }
3006
3007cleanup:
3008 return ret;
3009}
3010
roman12644fe2023-06-08 11:06:42 +02003011static void
3012nc_server_config_set_tls_version(struct nc_server_tls_opts *opts, NC_TLS_VERSION version, NC_OPERATION op)
3013{
3014 if (op == NC_OP_CREATE) {
3015 /* add the version if it isn't there already */
3016 opts->tls_versions |= version;
3017 } else if ((op == NC_OP_DELETE) && (opts->tls_versions & version)) {
3018 /* delete the version if it is there */
3019 opts->tls_versions -= version;
3020 }
3021}
3022
3023static int
3024nc_server_config_tls_version(const struct lyd_node *node, NC_OPERATION op)
3025{
3026 int ret = 0;
3027 struct nc_endpt *endpt;
3028 const char *version = NULL;
3029
3030 assert(!strcmp(LYD_NAME(node), "tls-version"));
3031
3032 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
3033 ret = 1;
3034 goto cleanup;
3035 }
3036
3037 version = ((struct lyd_node_term *)node)->value.ident->name;
3038 if (!strcmp(version, "tls10")) {
3039 nc_server_config_set_tls_version(endpt->opts.tls, NC_TLS_VERSION_10, op);
3040 } else if (!strcmp(version, "tls11")) {
3041 nc_server_config_set_tls_version(endpt->opts.tls, NC_TLS_VERSION_11, op);
3042 } else if (!strcmp(version, "tls12")) {
3043 nc_server_config_set_tls_version(endpt->opts.tls, NC_TLS_VERSION_12, op);
3044 } else if (!strcmp(version, "tls13")) {
3045 nc_server_config_set_tls_version(endpt->opts.tls, NC_TLS_VERSION_13, op);
3046 } else {
3047 ERR(NULL, "TLS version \"%s\" not supported.", version);
3048 ret = 1;
3049 goto cleanup;
3050 }
3051
3052cleanup:
3053 return ret;
3054}
3055
3056static int
3057nc_server_config_create_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher)
3058{
3059 int ret = 0;
3060 char *ssl_cipher = NULL;
3061 uint16_t i;
3062
3063 ssl_cipher = malloc(strlen(cipher) + 1);
3064 if (!ssl_cipher) {
3065 ERRMEM;
3066 ret = 1;
3067 goto cleanup;
3068 }
3069
3070 for (i = 0; cipher[i]; i++) {
3071 if (cipher[i] == '-') {
3072 /* OpenSSL requires _ instead of - in cipher names */
3073 ssl_cipher[i] = '_';
3074 } else {
3075 /* and requires uppercase unlike the identities */
3076 ssl_cipher[i] = toupper(cipher[i]);
3077 }
3078 }
3079 ssl_cipher[i] = '\0';
3080
3081 if (!opts->ciphers) {
3082 /* first entry */
3083 opts->ciphers = strdup(ssl_cipher);
3084 if (!opts->ciphers) {
3085 ERRMEM;
3086 ret = 1;
3087 goto cleanup;
3088 }
3089 } else {
3090 /* + 1 because of : between entries */
3091 opts->ciphers = nc_realloc(opts->ciphers, strlen(opts->ciphers) + strlen(ssl_cipher) + 1 + 1);
3092 if (!opts->ciphers) {
3093 ERRMEM;
3094 ret = 1;
3095 goto cleanup;
3096 }
3097 sprintf(opts->ciphers, "%s:%s", opts->ciphers, ssl_cipher);
3098 }
3099
3100cleanup:
3101 free(ssl_cipher);
3102 return ret;
3103}
3104
3105static int
3106nc_server_config_del_concrete_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher)
3107{
3108 int cipher_found = 0;
3109 char *haystack, *substr;
3110 size_t cipher_len = strlen(cipher);
3111
3112 /* delete */
3113 haystack = opts->ciphers;
3114 while ((substr = strstr(haystack, cipher))) {
3115 /* iterate over all the substrings */
3116 if (((substr == haystack) && (*(substr + cipher_len) == ':')) ||
3117 ((substr != haystack) && (*(substr - 1) == ':') && (*(substr + cipher_len) == ':'))) {
3118 /* either the first element of the string or somewhere in the middle */
3119 memmove(substr, substr + cipher_len + 1, strlen(substr + cipher_len + 1));
3120 cipher_found = 1;
3121 break;
3122 } else if ((*(substr - 1) == ':') && (*(substr + cipher_len) == '\0')) {
3123 /* the last element of the string */
3124 *(substr - 1) = '\0';
3125 cipher_found = 1;
3126 break;
3127 }
3128 haystack++;
3129 }
3130
3131 if (!cipher_found) {
3132 ERR(NULL, "Unable to delete a cipher (%s), which was not previously added.", cipher);
3133 return 1;
3134 }
3135
3136 return 0;
3137}
3138
3139static int
3140nc_server_config_cipher_suite(const struct lyd_node *node, NC_OPERATION op)
3141{
3142 int ret = 0;
3143 struct nc_endpt *endpt;
3144 const char *cipher = NULL;
3145
3146 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
3147 ret = 1;
3148 goto cleanup;
3149 }
3150
3151 cipher = ((struct lyd_node_term *)node)->value.ident->name;
3152 if (op == NC_OP_CREATE) {
3153 ret = nc_server_config_create_cipher_suite(endpt->opts.tls, cipher);
3154 if (ret) {
3155 goto cleanup;
3156 }
3157 } else if (op == NC_OP_DELETE) {
3158 ret = nc_server_config_del_concrete_cipher_suite(endpt->opts.tls, cipher);
3159 if (ret) {
3160 goto cleanup;
3161 }
3162 }
3163
3164cleanup:
3165 return ret;
3166}
3167
roman2eab4742023-06-06 10:00:26 +02003168#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02003169
roman83683fb2023-02-24 09:15:23 +01003170static int
romanf02273a2023-05-25 09:44:11 +02003171nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01003172{
3173 const char *name = LYD_NAME(node);
3174
3175 if (!strcmp(name, "listen")) {
romanf02273a2023-05-25 09:44:11 +02003176 if (nc_server_config_listen(NULL, op)) {
romanc1d2b092023-02-02 08:58:27 +01003177 goto error;
3178 }
3179 } else if (!strcmp(name, "idle-timeout")) {
romane028ef92023-02-24 16:33:08 +01003180 if (nc_server_config_idle_timeout(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003181 goto error;
3182 }
3183 } else if (!strcmp(name, "endpoint")) {
romane028ef92023-02-24 16:33:08 +01003184 if (nc_server_config_endpoint(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003185 goto error;
3186 }
roman2eab4742023-06-06 10:00:26 +02003187 } else if (!strcmp(name, "unix-socket")) {
3188 if (nc_server_config_unix_socket(node, op)) {
3189 goto error;
3190 }
roman3f9b65c2023-06-05 14:26:58 +02003191 }
roman2eab4742023-06-06 10:00:26 +02003192#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02003193 else if (!strcmp(name, "ssh")) {
romane028ef92023-02-24 16:33:08 +01003194 if (nc_server_config_ssh(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003195 goto error;
3196 }
roman2eab4742023-06-06 10:00:26 +02003197 } else if (!strcmp(name, "local-address")) {
romane028ef92023-02-24 16:33:08 +01003198 if (nc_server_config_local_address(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003199 goto error;
3200 }
3201 } else if (!strcmp(name, "local-port")) {
romane028ef92023-02-24 16:33:08 +01003202 if (nc_server_config_local_port(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003203 goto error;
3204 }
3205 } else if (!strcmp(name, "keepalives")) {
romane028ef92023-02-24 16:33:08 +01003206 if (nc_server_config_keepalives(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003207 goto error;
3208 }
3209 } else if (!strcmp(name, "idle-time")) {
romane028ef92023-02-24 16:33:08 +01003210 if (nc_server_config_idle_time(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003211 goto error;
3212 }
3213 } else if (!strcmp(name, "max-probes")) {
romane028ef92023-02-24 16:33:08 +01003214 if (nc_server_config_max_probes(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003215 goto error;
3216 }
3217 } else if (!strcmp(name, "probe-interval")) {
romane028ef92023-02-24 16:33:08 +01003218 if (nc_server_config_probe_interval(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003219 goto error;
3220 }
roman2eab4742023-06-06 10:00:26 +02003221 } else if (!strcmp(name, "host-key")) {
romane028ef92023-02-24 16:33:08 +01003222 if (nc_server_config_host_key(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003223 goto error;
3224 }
roman2eab4742023-06-06 10:00:26 +02003225 } else if (!strcmp(name, "public-key-format")) {
romane028ef92023-02-24 16:33:08 +01003226 if (nc_server_config_public_key_format(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003227 goto error;
3228 }
3229 } else if (!strcmp(name, "public-key")) {
romane028ef92023-02-24 16:33:08 +01003230 if (nc_server_config_public_key(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003231 goto error;
3232 }
3233 } else if (!strcmp(name, "private-key-format")) {
romane028ef92023-02-24 16:33:08 +01003234 if (nc_server_config_private_key_format(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003235 goto error;
3236 }
3237 } else if (!strcmp(name, "cleartext-private-key")) {
romane028ef92023-02-24 16:33:08 +01003238 if (nc_server_config_cleartext_private_key(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003239 goto error;
3240 }
roman2eab4742023-06-06 10:00:26 +02003241 } else if (!strcmp(name, "keystore-reference")) {
romane028ef92023-02-24 16:33:08 +01003242 if (nc_server_config_keystore_reference(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003243 goto error;
3244 }
3245 } else if (!strcmp(name, "user")) {
romane028ef92023-02-24 16:33:08 +01003246 if (nc_server_config_user(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003247 goto error;
3248 }
3249 } else if (!strcmp(name, "auth-attempts")) {
romane028ef92023-02-24 16:33:08 +01003250 if (nc_server_config_auth_attempts(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003251 goto error;
3252 }
3253 } else if (!strcmp(name, "auth-timeout")) {
romane028ef92023-02-24 16:33:08 +01003254 if (nc_server_config_auth_timeout(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003255 goto error;
3256 }
roman2eab4742023-06-06 10:00:26 +02003257 } else if (!strcmp(name, "truststore-reference")) {
romane028ef92023-02-24 16:33:08 +01003258 if (nc_server_config_truststore_reference(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003259 goto error;
3260 }
roman2eab4742023-06-06 10:00:26 +02003261 } else if (!strcmp(name, "password")) {
romane028ef92023-02-24 16:33:08 +01003262 if (nc_server_config_password(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003263 goto error;
3264 }
3265 } else if (!strcmp(name, "pam-config-file-name")) {
romane028ef92023-02-24 16:33:08 +01003266 if (nc_server_config_pam_name(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003267 goto error;
3268 }
3269 } else if (!strcmp(name, "pam-config-file-dir")) {
romane028ef92023-02-24 16:33:08 +01003270 if (nc_server_config_pam_dir(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003271 goto error;
3272 }
3273 } else if (!strcmp(name, "none")) {
romane028ef92023-02-24 16:33:08 +01003274 if (nc_server_config_none(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003275 goto error;
3276 }
3277 } else if (!strcmp(name, "host-key-alg")) {
romane028ef92023-02-24 16:33:08 +01003278 if (nc_server_config_host_key_alg(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003279 goto error;
3280 }
3281 } else if (!strcmp(name, "key-exchange-alg")) {
romane028ef92023-02-24 16:33:08 +01003282 if (nc_server_config_kex_alg(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003283 goto error;
3284 }
3285 } else if (!strcmp(name, "encryption-alg")) {
romane028ef92023-02-24 16:33:08 +01003286 if (nc_server_config_encryption_alg(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003287 goto error;
3288 }
3289 } else if (!strcmp(name, "mac-alg")) {
romane028ef92023-02-24 16:33:08 +01003290 if (nc_server_config_mac_alg(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01003291 goto error;
3292 }
roman2eab4742023-06-06 10:00:26 +02003293 } else if (!strcmp(name, "endpoint-client-auth")) {
roman0bbc19c2023-05-26 09:59:09 +02003294 if (nc_server_config_endpoint_client_auth(node, op)) {
3295 goto error;
3296 }
roman2eab4742023-06-06 10:00:26 +02003297 } else if (!strcmp(name, "tls")) {
roman3f9b65c2023-06-05 14:26:58 +02003298 if (nc_server_config_tls(node, op)) {
3299 goto error;
3300 }
3301 } else if (!strcmp(name, "cert-data")) {
3302 if (nc_server_config_cert_data(node, op)) {
3303 goto error;
3304 }
3305 } else if (!strcmp(name, "asymmetric-key")) {
3306 if (nc_server_config_asymmetric_key(node, op)) {
3307 goto error;
3308 }
3309 } else if (!strcmp(name, "certificate")) {
3310 if (nc_server_config_certificate(node, op)) {
3311 goto error;
3312 }
3313 } else if (!strcmp(name, "cert-to-name")) {
3314 if (nc_server_config_cert_to_name(node, op)) {
3315 goto error;
3316 }
3317 } else if (!strcmp(name, "fingerprint")) {
3318 if (nc_server_config_fingerprint(node, op)) {
3319 goto error;
3320 }
roman12644fe2023-06-08 11:06:42 +02003321 } else if (!strcmp(name, "tls-version")) {
3322 if (nc_server_config_tls_version(node, op)) {
3323 goto error;
3324 }
3325 } else if (!strcmp(name, "cipher-suite")) {
3326 if (nc_server_config_cipher_suite(node, op)) {
3327 goto error;
3328 }
roman3f9b65c2023-06-05 14:26:58 +02003329 }
roman2eab4742023-06-06 10:00:26 +02003330#endif /* NC_ENABLED_SSH_TLS */
romanc1d2b092023-02-02 08:58:27 +01003331
3332 return 0;
3333
3334error:
3335 ERR(NULL, "Configuring (%s) failed.", LYD_NAME(node));
3336 return 1;
3337}
3338
3339int
roman0bbc19c2023-05-26 09:59:09 +02003340nc_server_config_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, NC_MODULE module)
romanc1d2b092023-02-02 08:58:27 +01003341{
3342 struct lyd_node *child;
3343 struct lyd_meta *m;
romanf9906b42023-05-22 14:04:29 +02003344 NC_OPERATION current_op = NC_OP_UNKNOWN;
romanf02273a2023-05-25 09:44:11 +02003345 int ret;
romanc1d2b092023-02-02 08:58:27 +01003346
3347 assert(node);
3348
romanf9906b42023-05-22 14:04:29 +02003349 /* get current op if there is any */
3350 if ((m = lyd_find_meta(node->meta, NULL, "yang:operation"))) {
3351 if (!strcmp(lyd_get_meta_value(m), "create")) {
3352 current_op = NC_OP_CREATE;
3353 } else if (!strcmp(lyd_get_meta_value(m), "delete")) {
3354 current_op = NC_OP_DELETE;
3355 } else if (!strcmp(lyd_get_meta_value(m), "replace")) {
3356 current_op = NC_OP_REPLACE;
3357 } else if (!strcmp(lyd_get_meta_value(m), "none")) {
3358 current_op = NC_OP_NONE;
romanc1d2b092023-02-02 08:58:27 +01003359 }
3360 }
3361
3362 /* node has no op, inherit from the parent */
romanf9906b42023-05-22 14:04:29 +02003363 if (!current_op) {
3364 if (!parent_op) {
3365 ERR(NULL, "Unknown operation for node \"%s\".", LYD_NAME(node));
3366 return 1;
3367 }
3368
romanc1d2b092023-02-02 08:58:27 +01003369 current_op = parent_op;
3370 }
3371
3372 switch (current_op) {
3373 case NC_OP_NONE:
3374 break;
3375 case NC_OP_CREATE:
3376 case NC_OP_DELETE:
3377 case NC_OP_REPLACE:
roman2eab4742023-06-06 10:00:26 +02003378#ifdef NC_ENABLED_SSH_TLS
3379 if (module == NC_MODULE_KEYSTORE) {
romanf02273a2023-05-25 09:44:11 +02003380 ret = nc_server_config_parse_keystore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02003381 } else if (module == NC_MODULE_TRUSTSTORE) {
romanf02273a2023-05-25 09:44:11 +02003382 ret = nc_server_config_parse_truststore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02003383 } else
3384#endif /* NC_ENABLED_SSH_TLS */
3385 {
3386 ret = nc_server_config_parse_netconf_server(node, current_op);
romanf02273a2023-05-25 09:44:11 +02003387 }
3388 if (ret) {
3389 return ret;
romanc1d2b092023-02-02 08:58:27 +01003390 }
3391 break;
3392 default:
3393 break;
3394 }
3395
3396 if (current_op != NC_OP_DELETE) {
3397 LY_LIST_FOR(lyd_child(node), child) {
roman0bbc19c2023-05-26 09:59:09 +02003398 if (nc_server_config_parse_tree(child, current_op, module)) {
romanc1d2b092023-02-02 08:58:27 +01003399 return 1;
3400 }
3401 }
3402 }
3403 return 0;
3404}
3405
romanc1d2b092023-02-02 08:58:27 +01003406API int
3407nc_server_config_load_modules(struct ly_ctx **ctx)
3408{
3409 int i, new_ctx = 0;
3410
3411 if (!*ctx) {
3412 if (ly_ctx_new(NC_SERVER_SEARCH_DIR, 0, ctx)) {
3413 ERR(NULL, "Couldn't create new libyang context.\n");
3414 goto error;
3415 }
3416 new_ctx = 1;
3417 }
3418
3419 /* all features */
3420 const char *ietf_nectonf_server[] = {"ssh-listen", "tls-listen", "ssh-call-home", "tls-call-home", "central-netconf-server-supported", NULL};
3421 /* all features */
3422 const char *ietf_x509_cert_to_name[] = {NULL};
roman7fdc84d2023-06-06 13:14:53 +02003423 /* no private-key-encryption, csr-generation, p10-csr-format, certificate-expiration-notification,
3424 * encrypted-passwords, hidden-symmetric-keys, encrypted-symmetric-keys, hidden-private-keys, encrypted-private-keys
3425 */
romanc1d2b092023-02-02 08:58:27 +01003426 const char *ietf_crypto_types[] = {
3427 "one-symmetric-key-format", "one-asymmetric-key-format", "symmetrically-encrypted-value-format",
3428 "asymmetrically-encrypted-value-format", "cms-enveloped-data-format", "cms-encrypted-data-format",
roman7fdc84d2023-06-06 13:14:53 +02003429 "cleartext-passwords", "cleartext-symmetric-keys", "cleartext-private-keys", NULL
romanc1d2b092023-02-02 08:58:27 +01003430 };
3431 /* all features */
3432 const char *ietf_tcp_common[] = {"keepalives-supported", NULL};
roman7fdc84d2023-06-06 13:14:53 +02003433 /* all features */
3434 const char *ietf_tcp_server[] = {"tcp-server-keepalives", NULL};
3435 /* all features */
3436 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 +01003437 /* no ssh-x509-certs */
3438 const char *ietf_ssh_common[] = {"transport-params", "public-key-generation", NULL};
roman7fdc84d2023-06-06 13:14:53 +02003439 /* no ssh-server-keepalives and local-user-auth-hostbased */
3440 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 +01003441 /* all features */
3442 const char *iana_ssh_encryption_algs[] = {NULL};
3443 /* all features */
3444 const char *iana_ssh_key_exchange_algs[] = {NULL};
3445 /* all features */
3446 const char *iana_ssh_mac_algs[] = {NULL};
3447 /* all features */
3448 const char *iana_ssh_public_key_algs[] = {NULL};
romanc1d2b092023-02-02 08:58:27 +01003449 /* all features */
roman7fdc84d2023-06-06 13:14:53 +02003450 const char *iana_crypt_hash[] = {"crypt-hash-md5", "crypt-hash-sha-256", "crypt-hash-sha-512", NULL};
3451 /* no symmetric-keys */
3452 const char *ietf_keystore[] = {"central-keystore-supported", "inline-definitions-supported", "asymmetric-keys", NULL};
3453 /* all features */
3454 const char *ietf_truststore[] = {"central-truststore-supported", "inline-definitions-supported", "certificates", "public-keys", NULL};
3455 /* all features */
3456 const char *ietf_tls_common[] = {"tls10", "tls11", "tls12", "tls13", "hello-params", "public-key-generation", NULL};
romanc1d2b092023-02-02 08:58:27 +01003457 /* all features */
3458 const char *ietf_tls_server[] = {
3459 "tls-server-keepalives", "server-ident-x509-cert", "server-ident-raw-public-key", "server-ident-tls12-psk",
3460 "server-ident-tls13-epsk", "client-auth-supported", "client-auth-x509-cert", "client-auth-raw-public-key",
3461 "client-auth-tls12-psk", "client-auth-tls13-epsk", NULL
3462 };
roman12644fe2023-06-08 11:06:42 +02003463 const char *iana_tls_cipher_suite_algs[] = {NULL};
romanc1d2b092023-02-02 08:58:27 +01003464 /* all features */
3465 const char *libnetconf2_netconf_server[] = {NULL};
3466
3467 const char *module_names[] = {
roman7fdc84d2023-06-06 13:14:53 +02003468 "ietf-netconf-server", "ietf-x509-cert-to-name", "ietf-crypto-types", "ietf-tcp-common", "ietf-tcp-server",
3469 "ietf-tcp-client", "ietf-ssh-common", "ietf-ssh-server", "iana-ssh-encryption-algs",
3470 "iana-ssh-key-exchange-algs", "iana-ssh-mac-algs", "iana-ssh-public-key-algs", "iana-crypt-hash",
roman12644fe2023-06-08 11:06:42 +02003471 "ietf-keystore", "ietf-truststore", "ietf-tls-common", "ietf-tls-server", "iana-tls-cipher-suite-algs",
3472 "libnetconf2-netconf-server", NULL
romanc1d2b092023-02-02 08:58:27 +01003473 };
3474
3475 const char **module_features[] = {
roman7fdc84d2023-06-06 13:14:53 +02003476 ietf_nectonf_server, ietf_x509_cert_to_name, ietf_crypto_types, ietf_tcp_common,
3477 ietf_tcp_server, ietf_tcp_client, ietf_ssh_common, ietf_ssh_server, iana_ssh_encryption_algs,
3478 iana_ssh_key_exchange_algs, iana_ssh_mac_algs, iana_ssh_public_key_algs, iana_crypt_hash,
roman12644fe2023-06-08 11:06:42 +02003479 ietf_keystore, ietf_truststore, ietf_tls_common, ietf_tls_server, iana_tls_cipher_suite_algs,
3480 libnetconf2_netconf_server, NULL
romanc1d2b092023-02-02 08:58:27 +01003481 };
3482
3483 for (i = 0; module_names[i] != NULL; i++) {
3484 if (!ly_ctx_load_module(*ctx, module_names[i], NULL, module_features[i])) {
3485 ERR(NULL, "Loading module \"%s\" failed.\n", module_names[i]);
3486 goto error;
3487 }
3488 }
3489
3490 return 0;
3491
3492error:
3493 if (new_ctx) {
3494 ly_ctx_destroy(*ctx);
3495 *ctx = NULL;
3496 }
3497 return 1;
3498}
3499
romanf9906b42023-05-22 14:04:29 +02003500static int
3501nc_server_config_fill_nectonf_server(const struct lyd_node *data, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01003502{
3503 int ret = 0;
3504 struct lyd_node *tree;
romand57b3722023-04-05 11:26:25 +02003505
romanc1d2b092023-02-02 08:58:27 +01003506 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &tree);
3507 if (ret) {
3508 ERR(NULL, "Unable to find the netconf-server container in the YANG data.");
3509 goto cleanup;
3510 }
3511
roman0bbc19c2023-05-26 09:59:09 +02003512 if (nc_server_config_parse_tree(tree, op, NC_MODULE_NETCONF_SERVER)) {
3513 ret = 1;
3514 goto cleanup;
3515 }
3516
roman2eab4742023-06-06 10:00:26 +02003517#ifdef NC_ENABLED_SSH_TLS
3518 /* backward check of client auth reference */
roman0bbc19c2023-05-26 09:59:09 +02003519 if (nc_server_config_fill_endpt_client_auth()) {
romanf9906b42023-05-22 14:04:29 +02003520 ret = 1;
3521 goto cleanup;
3522 }
roman2eab4742023-06-06 10:00:26 +02003523#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02003524
3525cleanup:
3526 return ret;
3527}
3528
3529API int
romanf6f37a52023-05-25 14:27:51 +02003530nc_server_config_setup_diff(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02003531{
3532 int ret = 0;
3533
3534 /* LOCK */
3535 pthread_rwlock_wrlock(&server_opts.config_lock);
3536
roman2eab4742023-06-06 10:00:26 +02003537#ifdef NC_ENABLED_SSH_TLS
romanf9906b42023-05-22 14:04:29 +02003538 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02003539 ret = nc_server_config_fill_keystore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02003540 if (ret) {
3541 ERR(NULL, "Filling keystore failed.");
3542 goto cleanup;
3543 }
3544
3545 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02003546 ret = nc_server_config_fill_truststore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02003547 if (ret) {
3548 ERR(NULL, "Filling truststore failed.");
3549 goto cleanup;
3550 }
roman2eab4742023-06-06 10:00:26 +02003551#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02003552
3553 /* configure netconf-server */
3554 ret = nc_server_config_fill_nectonf_server(data, NC_OP_UNKNOWN);
3555 if (ret) {
3556 ERR(NULL, "Filling netconf-server failed.");
3557 goto cleanup;
3558 }
3559
3560cleanup:
3561 /* UNLOCK */
3562 pthread_rwlock_unlock(&server_opts.config_lock);
3563 return ret;
3564}
3565
3566API int
romanf6f37a52023-05-25 14:27:51 +02003567nc_server_config_setup_data(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02003568{
3569 int ret = 0;
3570 struct lyd_node *tree, *iter, *root;
3571
3572 /* LOCK */
3573 pthread_rwlock_wrlock(&server_opts.config_lock);
3574
3575 /* find the netconf-server node */
3576 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &root);
3577 if (ret) {
3578 ERR(NULL, "Unable to find the netconf-server container in the YANG data.");
3579 goto cleanup;
3580 }
3581
3582 /* iterate through all the nodes and make sure there is no operation attribute */
3583 LY_LIST_FOR(root, tree) {
3584 LYD_TREE_DFS_BEGIN(tree, iter) {
3585 if (lyd_find_meta(iter->meta, NULL, "yang:operation")) {
3586 ERR(NULL, "Unexpected operation attribute in the YANG data.");
romanc1d2b092023-02-02 08:58:27 +01003587 ret = 1;
3588 goto cleanup;
3589 }
romanf9906b42023-05-22 14:04:29 +02003590 LYD_TREE_DFS_END(tree, iter);
romanc1d2b092023-02-02 08:58:27 +01003591 }
3592 }
3593
romanf9906b42023-05-22 14:04:29 +02003594 /* delete the current configuration */
romanf02273a2023-05-25 09:44:11 +02003595 nc_server_config_listen(NULL, NC_OP_DELETE);
roman2eab4742023-06-06 10:00:26 +02003596#ifdef NC_ENABLED_SSH_TLS
romanf02273a2023-05-25 09:44:11 +02003597 nc_server_config_ks_keystore(NULL, NC_OP_DELETE);
3598 nc_server_config_ts_truststore(NULL, NC_OP_DELETE);
romanf9906b42023-05-22 14:04:29 +02003599
3600 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02003601 ret = nc_server_config_fill_keystore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02003602 if (ret) {
3603 ERR(NULL, "Filling keystore failed.");
3604 goto cleanup;
3605 }
3606
3607 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02003608 ret = nc_server_config_fill_truststore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02003609 if (ret) {
3610 ERR(NULL, "Filling truststore failed.");
3611 goto cleanup;
3612 }
roman2eab4742023-06-06 10:00:26 +02003613#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02003614
3615 /* configure netconf-server */
3616 ret = nc_server_config_fill_nectonf_server(data, NC_OP_CREATE);
3617 if (ret) {
3618 ERR(NULL, "Filling netconf-server failed.");
romanc1d2b092023-02-02 08:58:27 +01003619 goto cleanup;
3620 }
3621
3622cleanup:
3623 /* UNLOCK */
3624 pthread_rwlock_unlock(&server_opts.config_lock);
3625 return ret;
3626}
roman3f9b65c2023-06-05 14:26:58 +02003627
3628API int
3629nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path)
3630{
3631 struct lyd_node *tree = NULL;
3632 int ret = 0;
3633
3634 NC_CHECK_ARG_RET(NULL, path, 1);
3635
3636 ret = lyd_parse_data_path(ctx, path, LYD_UNKNOWN, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree);
3637 if (ret) {
3638 goto cleanup;
3639 }
3640
3641 ret = nc_server_config_setup_data(tree);
3642 if (ret) {
3643 goto cleanup;
3644 }
3645
3646cleanup:
3647 lyd_free_all(tree);
3648 return ret;
3649}