blob: 41c5a2f4517534a1abf7a92f04e7b4b788e09808 [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>
19#include <stdlib.h>
20#include <string.h>
21
22#include "compat.h"
romanc1d2b092023-02-02 08:58:27 +010023#include "libnetconf.h"
romane028ef92023-02-24 16:33:08 +010024#include "server_config.h"
romanf02273a2023-05-25 09:44:11 +020025#include "server_config_p.h"
romanc1d2b092023-02-02 08:58:27 +010026#include "session_server.h"
27#include "session_server_ch.h"
28
29/* All libssh supported host-key, key-exchange, encryption and mac algorithms as of version 0.10.90 */
30
31static const char *supported_hostkey_algs[] = {
32 "ssh-ed25519-cert-v01@openssh.com", "ecdsa-sha2-nistp521-cert-v01@openssh.com",
33 "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ecdsa-sha2-nistp256-cert-v01@openssh.com",
34 "rsa-sha2-512-cert-v01@openssh.com", "rsa-sha2-256-cert-v01@openssh.com",
35 "ssh-rsa-cert-v01@openssh.com", "ssh-dss-cert-v01@openssh.com",
36 "ssh-ed25519", "ecdsa-sha2-nistp521", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp256",
37 "rsa-sha2-512", "rsa-sha2-256", "ssh-rsa", "ssh-dss", NULL
38};
39
40static const char *supported_kex_algs[] = {
41 "diffie-hellman-group-exchange-sha1", "curve25519-sha256", "curve25519-sha256@libssh.org",
42 "ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", "diffie-hellman-group18-sha512",
43 "diffie-hellman-group16-sha512", "diffie-hellman-group-exchange-sha256", "diffie-hellman-group14-sha256", NULL
44};
45
46static const char *supported_encryption_algs[] = {
47 "chacha20-poly1305@openssh.com", "aes256-gcm@openssh.com", "aes128-gcm@openssh.com",
48 "aes256-ctr", "aes192-ctr", "aes128-ctr", "aes256-cbc", "aes192-cbc", "aes128-cbc",
roman27215242023-03-10 14:55:00 +010049 "blowfish-cbc", "triple-des-cbc", "none", NULL
romanc1d2b092023-02-02 08:58:27 +010050};
51
52static const char *supported_mac_algs[] = {
53 "hmac-sha2-256-etm@openssh.com", "hmac-sha2-512-etm@openssh.com", "hmac-sha1-etm@openssh.com",
54 "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1", NULL
55};
56
57extern struct nc_server_opts server_opts;
58
romanf02273a2023-05-25 09:44:11 +020059int
60nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, struct nc_bind **bind)
romanc1d2b092023-02-02 08:58:27 +010061{
62 uint16_t i;
63 const char *endpt_name;
64
65 assert(node);
66
67 while (node) {
68 if (!strcmp(LYD_NAME(node), "endpoint")) {
69 break;
70 }
71 node = lyd_parent(node);
72 }
73
74 if (!node) {
75 ERR(NULL, "Node \"%s\" is not contained in an endpoint subtree.", LYD_NAME(node));
76 return 1;
77 }
78
79 node = lyd_child(node);
80 assert(!strcmp(LYD_NAME(node), "name"));
81 endpt_name = lyd_get_value(node);
82
83 for (i = 0; i < server_opts.endpt_count; i++) {
84 if (!strcmp(server_opts.endpts[i].name, endpt_name)) {
85 *endpt = &server_opts.endpts[i];
86 if (bind) {
87 *bind = &server_opts.binds[i];
88 }
89 return 0;
90 }
91 }
92
93 ERR(NULL, "Endpoint \"%s\" was not found.", endpt_name);
94 return 1;
95}
96
romanf02273a2023-05-25 09:44:11 +020097int
98nc_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 +010099{
100 uint16_t i;
101 const char *hostkey_name;
102
103 assert(node && opts);
104
105 while (node) {
106 if (!strcmp(LYD_NAME(node), "host-key")) {
107 break;
108 }
109 node = lyd_parent(node);
110 }
111
112 if (!node) {
113 ERR(NULL, "Node \"%s\" is not contained in a host-key subtree.", LYD_NAME(node));
114 return 1;
115 }
116
117 node = lyd_child(node);
118 assert(!strcmp(LYD_NAME(node), "name"));
119 hostkey_name = lyd_get_value(node);
120
121 for (i = 0; i < opts->hostkey_count; i++) {
122 if (!strcmp(opts->hostkeys[i].name, hostkey_name)) {
123 *hostkey = &opts->hostkeys[i];
124 return 0;
125 }
126 }
127
128 ERR(NULL, "Host-key \"%s\" was not found.", hostkey_name);
129 return 1;
130}
131
romanf02273a2023-05-25 09:44:11 +0200132int
133nc_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 +0100134{
135 uint16_t i;
136 const char *authkey_name;
137
138 assert(node && opts);
139
140 while (node) {
141 if (!strcmp(LYD_NAME(node), "user")) {
142 break;
143 }
144 node = lyd_parent(node);
145 }
146
147 if (!node) {
148 ERR(NULL, "Node \"%s\" is not contained in a client-authentication subtree.", LYD_NAME(node));
149 return 1;
150 }
151
152 node = lyd_child(node);
153 assert(!strcmp(LYD_NAME(node), "name"));
154 authkey_name = lyd_get_value(node);
155
156 for (i = 0; i < opts->client_count; i++) {
157 if (!strcmp(opts->auth_clients[i].username, authkey_name)) {
158 *auth_client = &opts->auth_clients[i];
159 return 0;
160 }
161 }
162
163 ERR(NULL, "Authorized key \"%s\" was not found.", authkey_name);
164 return 1;
165}
166
romanf02273a2023-05-25 09:44:11 +0200167int
168nc_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 +0100169{
170 uint16_t i;
171 const char *pubkey_name;
172
173 assert(node && auth_client);
174
175 node = lyd_parent(node);
176 while (node) {
177 if (!strcmp(LYD_NAME(node), "public-key")) {
178 break;
179 }
180 node = lyd_parent(node);
181 }
182
183 if (!node) {
184 ERR(NULL, "Node \"%s\" is not contained in a public-key subtree.", LYD_NAME(node));
185 return 1;
186 }
187
188 node = lyd_child(node);
189 assert(!strcmp(LYD_NAME(node), "name"));
190 pubkey_name = lyd_get_value(node);
191
192 for (i = 0; i < auth_client->pubkey_count; i++) {
193 if (!strcmp(auth_client->pubkeys[i].name, pubkey_name)) {
194 *pubkey = &auth_client->pubkeys[i];
195 return 0;
196 }
197 }
198
199 ERR(NULL, "Public key \"%s\" was not found.", pubkey_name);
200 return 1;
201}
202
romanf02273a2023-05-25 09:44:11 +0200203int
romanc1d2b092023-02-02 08:58:27 +0100204equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char *parent_name)
205{
206 uint16_t i;
207
208 assert(node && parent_count > 0 && parent_name);
209
210 node = lyd_parent(node);
211 for (i = 1; i < parent_count; i++) {
212 node = lyd_parent(node);
213 }
214
215 if (!strcmp(LYD_NAME(node), parent_name)) {
216 return 1;
217 }
218
219 return 0;
220}
221
romanf02273a2023-05-25 09:44:11 +0200222int
223nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uint16_t *count)
224{
225 int ret = 0;
226 void *tmp;
227 char **name;
228
229 tmp = realloc(*ptr, (*count + 1) * size);
230 if (!tmp) {
231 ERRMEM;
232 ret = 1;
233 goto cleanup;
234 }
235 *ptr = tmp;
236
237 /* set the newly allocated memory to 0 */
238 memset((char *)(*ptr) + (*count * size), 0, size);
239 (*count)++;
240
241 /* access the first member of the supposed structure */
242 name = (char **)((*ptr) + ((*count - 1) * size));
243
244 /* and set it's value */
245 *name = strdup(key_value);
246 if (!*name) {
247 ERRMEM;
248 ret = 1;
249 goto cleanup;
250 }
251
252cleanup:
253 return ret;
254}
255
romanc1d2b092023-02-02 08:58:27 +0100256static void
roman874fed12023-05-25 10:20:01 +0200257nc_server_config_del_auth_client_pam_name(struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100258{
259 free(auth_client->pam_config_name);
260 auth_client->pam_config_name = NULL;
261}
262
263static void
roman874fed12023-05-25 10:20:01 +0200264nc_server_config_del_auth_client_pam_dir(struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100265{
266 free(auth_client->pam_config_dir);
267 auth_client->pam_config_dir = NULL;
268}
269
270static void
roman874fed12023-05-25 10:20:01 +0200271nc_server_config_del_endpt_name(struct nc_endpt *endpt)
romanc1d2b092023-02-02 08:58:27 +0100272{
273 free(endpt->name);
274 endpt->name = NULL;
275}
276
277static void
roman874fed12023-05-25 10:20:01 +0200278nc_server_config_del_local_address(struct nc_bind *bind)
romanc1d2b092023-02-02 08:58:27 +0100279{
280 free(bind->address);
281 bind->address = NULL;
282}
283
284static void
roman874fed12023-05-25 10:20:01 +0200285nc_server_config_del_hostkey_name(struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100286{
287 free(hostkey->name);
288 hostkey->name = NULL;
289}
290
291static void
roman874fed12023-05-25 10:20:01 +0200292nc_server_config_del_public_key(struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100293{
roman8edee342023-03-31 13:25:48 +0200294 free(hostkey->key.pub_base64);
295 hostkey->key.pub_base64 = NULL;
romanc1d2b092023-02-02 08:58:27 +0100296}
297
298static void
roman874fed12023-05-25 10:20:01 +0200299nc_server_config_del_private_key(struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100300{
roman8edee342023-03-31 13:25:48 +0200301 free(hostkey->key.priv_base64);
302 hostkey->key.priv_base64 = NULL;
romanc1d2b092023-02-02 08:58:27 +0100303}
304
305static void
roman874fed12023-05-25 10:20:01 +0200306nc_server_config_del_auth_client_username(struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100307{
308 free(auth_client->username);
309 auth_client->username = NULL;
310}
311
312static void
roman874fed12023-05-25 10:20:01 +0200313nc_server_config_del_auth_client_pubkey_name(struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +0100314{
315 free(pubkey->name);
316 pubkey->name = NULL;
317}
318
319static void
roman874fed12023-05-25 10:20:01 +0200320nc_server_config_del_auth_client_pubkey_pub_base64(struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +0100321{
322 free(pubkey->pub_base64);
323 pubkey->pub_base64 = NULL;
324}
325
326static void
roman874fed12023-05-25 10:20:01 +0200327nc_server_config_del_auth_client_password(struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100328{
329 free(auth_client->password);
330 auth_client->password = NULL;
331}
332
333static void
roman874fed12023-05-25 10:20:01 +0200334nc_server_config_del_hostkey_algs(struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100335{
336 free(opts->hostkey_algs);
337 opts->hostkey_algs = NULL;
338}
339
340static void
roman874fed12023-05-25 10:20:01 +0200341nc_server_config_del_kex_algs(struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100342{
343 free(opts->kex_algs);
344 opts->kex_algs = NULL;
345}
346
347static void
roman874fed12023-05-25 10:20:01 +0200348nc_server_config_del_encryption_algs(struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100349{
350 free(opts->encryption_algs);
351 opts->encryption_algs = NULL;
352}
353
354static void
roman874fed12023-05-25 10:20:01 +0200355nc_server_config_del_mac_algs(struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100356{
357 free(opts->mac_algs);
358 opts->mac_algs = NULL;
359}
360
361static void
roman874fed12023-05-25 10:20:01 +0200362nc_server_config_del_hostkey(struct nc_server_ssh_opts *opts, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100363{
roman874fed12023-05-25 10:20:01 +0200364 assert(hostkey->store == NC_STORE_LOCAL || hostkey->store == NC_STORE_KEYSTORE);
romanc1d2b092023-02-02 08:58:27 +0100365
roman874fed12023-05-25 10:20:01 +0200366 if (hostkey->store == NC_STORE_LOCAL) {
367 nc_server_config_del_public_key(hostkey);
368 nc_server_config_del_private_key(hostkey);
romanc1d2b092023-02-02 08:58:27 +0100369 }
370
roman874fed12023-05-25 10:20:01 +0200371 nc_server_config_del_hostkey_name(hostkey);
romanc1d2b092023-02-02 08:58:27 +0100372 opts->hostkey_count--;
373 if (!opts->hostkey_count) {
374 free(opts->hostkeys);
375 opts->hostkeys = NULL;
376 }
377}
378
379static void
roman874fed12023-05-25 10:20:01 +0200380nc_server_config_del_auth_client_pubkey(struct nc_client_auth *auth_client, struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +0100381{
roman874fed12023-05-25 10:20:01 +0200382 nc_server_config_del_auth_client_pubkey_name(pubkey);
383 nc_server_config_del_auth_client_pubkey_pub_base64(pubkey);
romanc1d2b092023-02-02 08:58:27 +0100384
385 auth_client->pubkey_count--;
386 if (!auth_client->pubkey_count) {
387 free(auth_client->pubkeys);
388 auth_client->pubkeys = NULL;
389 }
390}
391
392static void
roman874fed12023-05-25 10:20:01 +0200393nc_server_config_del_auth_client(struct nc_server_ssh_opts *opts, struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100394{
395 uint16_t i, pubkey_count;
396
roman874fed12023-05-25 10:20:01 +0200397 if (auth_client->store == NC_STORE_LOCAL) {
romanc1d2b092023-02-02 08:58:27 +0100398 pubkey_count = auth_client->pubkey_count;
399 for (i = 0; i < pubkey_count; i++) {
roman874fed12023-05-25 10:20:01 +0200400 nc_server_config_del_auth_client_pubkey(auth_client, &auth_client->pubkeys[i]);
romanc1d2b092023-02-02 08:58:27 +0100401 }
romanc1d2b092023-02-02 08:58:27 +0100402 }
403
roman874fed12023-05-25 10:20:01 +0200404 nc_server_config_del_auth_client_password(auth_client);
405 nc_server_config_del_auth_client_pam_name(auth_client);
406 nc_server_config_del_auth_client_pam_dir(auth_client);
407 nc_server_config_del_auth_client_username(auth_client);
romanc1d2b092023-02-02 08:58:27 +0100408
409 opts->client_count--;
410 if (!opts->client_count) {
411 free(opts->auth_clients);
412 opts->auth_clients = NULL;
413 }
414}
415
416static void
roman874fed12023-05-25 10:20:01 +0200417nc_server_config_del_ssh(struct nc_bind *bind, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100418{
419 uint16_t i, hostkey_count, client_count;
420
roman874fed12023-05-25 10:20:01 +0200421 nc_server_config_del_local_address(bind);
romanc1d2b092023-02-02 08:58:27 +0100422 if (bind->sock > -1) {
423 close(bind->sock);
424 }
425
426 /* store in variable because it gets decremented in the function call */
427 hostkey_count = opts->hostkey_count;
428 for (i = 0; i < hostkey_count; i++) {
roman874fed12023-05-25 10:20:01 +0200429 nc_server_config_del_hostkey(opts, &opts->hostkeys[i]);
romanc1d2b092023-02-02 08:58:27 +0100430 }
431
432 client_count = opts->client_count;
433 for (i = 0; i < client_count; i++) {
roman874fed12023-05-25 10:20:01 +0200434 nc_server_config_del_auth_client(opts, &opts->auth_clients[i]);
romanc1d2b092023-02-02 08:58:27 +0100435 }
436
roman874fed12023-05-25 10:20:01 +0200437 nc_server_config_del_hostkey_algs(opts);
438 nc_server_config_del_kex_algs(opts);
439 nc_server_config_del_encryption_algs(opts);
440 nc_server_config_del_mac_algs(opts);
romanc1d2b092023-02-02 08:58:27 +0100441
442 free(opts);
443 opts = NULL;
444}
445
446void
roman874fed12023-05-25 10:20:01 +0200447nc_server_config_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind)
romanc1d2b092023-02-02 08:58:27 +0100448{
roman874fed12023-05-25 10:20:01 +0200449 nc_server_config_del_endpt_name(endpt);
450 nc_server_config_del_ssh(bind, endpt->opts.ssh);
romanc1d2b092023-02-02 08:58:27 +0100451
452 server_opts.endpt_count--;
453 if (!server_opts.endpt_count) {
454 free(server_opts.endpts);
455 free(server_opts.binds);
456 server_opts.endpts = NULL;
457 server_opts.binds = NULL;
458 }
459}
460
roman45cec4e2023-02-17 10:21:39 +0100461void
roman874fed12023-05-25 10:20:01 +0200462nc_server_config_del_unix_socket(struct nc_bind *bind, struct nc_server_unix_opts *opts)
roman83683fb2023-02-24 09:15:23 +0100463{
464 if (bind->sock > -1) {
465 close(bind->sock);
466 }
467
468 free(bind->address);
469 free(opts->address);
470
471 free(opts);
472 opts = NULL;
473}
474
475void
roman874fed12023-05-25 10:20:01 +0200476nc_server_config_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *bind)
roman83683fb2023-02-24 09:15:23 +0100477{
roman874fed12023-05-25 10:20:01 +0200478 nc_server_config_del_endpt_name(endpt);
479 nc_server_config_del_unix_socket(bind, endpt->opts.unixsock);
roman83683fb2023-02-24 09:15:23 +0100480
481 server_opts.endpt_count--;
482 if (!server_opts.endpt_count) {
483 free(server_opts.endpts);
484 free(server_opts.binds);
485 server_opts.endpts = NULL;
486 server_opts.binds = NULL;
487 }
488}
489
romanc1d2b092023-02-02 08:58:27 +0100490/* presence container */
491int
romanf02273a2023-05-25 09:44:11 +0200492nc_server_config_listen(struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100493{
494 uint16_t i;
495
romanf02273a2023-05-25 09:44:11 +0200496 (void) node;
497
romanc1d2b092023-02-02 08:58:27 +0100498 assert(op == NC_OP_CREATE || op == NC_OP_DELETE);
499
500 if (op == NC_OP_DELETE) {
501 for (i = 0; i < server_opts.endpt_count; i++) {
roman456f92d2023-04-28 10:28:12 +0200502 switch (server_opts.endpts[i].ti) {
503#ifdef NC_ENABLED_SSH
504 case NC_TI_LIBSSH:
roman874fed12023-05-25 10:20:01 +0200505 nc_server_config_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]);
roman456f92d2023-04-28 10:28:12 +0200506 break;
507#endif
508#ifdef NC_ENABLED_TLS
509 case NC_TI_OPENSSL:
roman83683fb2023-02-24 09:15:23 +0100510 /* todo */
roman456f92d2023-04-28 10:28:12 +0200511 break;
512#endif
513 case NC_TI_UNIX:
roman874fed12023-05-25 10:20:01 +0200514 nc_server_config_del_endpt_unix_socket(&server_opts.endpts[i], &server_opts.binds[i]);
roman456f92d2023-04-28 10:28:12 +0200515 break;
516 case NC_TI_NONE:
517 case NC_TI_FD:
518 ERRINT;
519 return 1;
roman83683fb2023-02-24 09:15:23 +0100520 }
romanc1d2b092023-02-02 08:58:27 +0100521 }
522 }
523
524 return 0;
525}
526
527/* default leaf */
528static int
romane028ef92023-02-24 16:33:08 +0100529nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100530{
531 assert(!strcmp(LYD_NAME(node), "idle-timeout"));
532
533 if (equal_parent_name(node, 1, "listen")) {
534 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
535 server_opts.idle_timeout = strtoul(lyd_get_value(node), NULL, 10);
536 } else {
537 /* default value */
538 server_opts.idle_timeout = 3600;
539 }
540 }
541
542 return 0;
543}
544
545static int
roman874fed12023-05-25 10:20:01 +0200546nc_server_config_create_bind(void)
romanc1d2b092023-02-02 08:58:27 +0100547{
548 int ret = 0;
549 void *tmp;
550
551 tmp = realloc(server_opts.binds, (server_opts.endpt_count + 1) * sizeof *server_opts.binds);
552 if (!tmp) {
553 ERRMEM;
554 ret = 1;
555 goto cleanup;
556 }
557 server_opts.binds = tmp;
558 memset(&server_opts.binds[server_opts.endpt_count], 0, sizeof *server_opts.binds);
559
560 server_opts.binds[server_opts.endpt_count].sock = -1;
561
562cleanup:
563 return ret;
564}
565
566static int
roman874fed12023-05-25 10:20:01 +0200567nc_server_config_create_endpoint(const struct lyd_node *node)
romanc1d2b092023-02-02 08:58:27 +0100568{
roman874fed12023-05-25 10:20:01 +0200569 if (nc_server_config_create_bind()) {
romanf02273a2023-05-25 09:44:11 +0200570 return 1;
romanc1d2b092023-02-02 08:58:27 +0100571 }
romanc1d2b092023-02-02 08:58:27 +0100572
573 node = lyd_child(node);
574 assert(!strcmp(LYD_NAME(node), "name"));
575
romanf02273a2023-05-25 09:44:11 +0200576 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 +0100577}
578
579/* list */
580static int
romane028ef92023-02-24 16:33:08 +0100581nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100582{
583 int ret = 0;
584 struct nc_endpt *endpt;
585 struct nc_bind *bind;
586
587 assert(!strcmp(LYD_NAME(node), "endpoint"));
588
589 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +0200590 ret = nc_server_config_create_endpoint(node);
romanc1d2b092023-02-02 08:58:27 +0100591 if (ret) {
592 goto cleanup;
593 }
594 } else if (op == NC_OP_DELETE) {
595 /* free all children */
romanf02273a2023-05-25 09:44:11 +0200596 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +0100597 ret = 1;
598 goto cleanup;
599 }
roman874fed12023-05-25 10:20:01 +0200600 nc_server_config_del_endpt_ssh(endpt, bind);
romanc1d2b092023-02-02 08:58:27 +0100601 }
602
603cleanup:
604 return ret;
605}
606
607static int
roman874fed12023-05-25 10:20:01 +0200608nc_server_config_create_ssh(struct nc_endpt *endpt)
romanc1d2b092023-02-02 08:58:27 +0100609{
610 endpt->ti = NC_TI_LIBSSH;
611 endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
612 if (!endpt->opts.ssh) {
613 ERRMEM;
614 return 1;
615 }
616
617 return 0;
618}
619
620/* NP container */
621static int
romane028ef92023-02-24 16:33:08 +0100622nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100623{
624 struct nc_endpt *endpt;
625 struct nc_bind *bind;
626 int ret = 0;
627
628 assert(!strcmp(LYD_NAME(node), "ssh"));
629
romanf02273a2023-05-25 09:44:11 +0200630 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +0100631 ret = 1;
632 goto cleanup;
633 }
634
635 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +0200636 ret = nc_server_config_create_ssh(endpt);
romanc1d2b092023-02-02 08:58:27 +0100637 if (ret) {
638 goto cleanup;
639 }
640 } else if (op == NC_OP_DELETE) {
roman874fed12023-05-25 10:20:01 +0200641 nc_server_config_del_ssh(bind, endpt->opts.ssh);
romanc1d2b092023-02-02 08:58:27 +0100642 }
643
644cleanup:
645 return ret;
646}
647
648static int
649nc_server_config_set_address_port(struct nc_endpt *endpt, struct nc_bind *bind, const char *address, uint16_t port)
650{
651 int sock = -1, set_addr, ret = 0;
652
roman83683fb2023-02-24 09:15:23 +0100653 assert((address && !port) || (!address && port) || (endpt->ti == NC_TI_UNIX));
romanc1d2b092023-02-02 08:58:27 +0100654
655 if (address) {
656 set_addr = 1;
657 } else {
658 set_addr = 0;
659 }
660
661 if (set_addr) {
662 port = bind->port;
663 } else {
664 address = bind->address;
665 }
666
romanc1d2b092023-02-02 08:58:27 +0100667 /* we have all the information we need to create a listening socket */
roman83683fb2023-02-24 09:15:23 +0100668 if ((address && port) || (endpt->ti == NC_TI_UNIX)) {
romanc1d2b092023-02-02 08:58:27 +0100669 /* create new socket, close the old one */
roman83683fb2023-02-24 09:15:23 +0100670 if (endpt->ti == NC_TI_UNIX) {
671 sock = nc_sock_listen_unix(endpt->opts.unixsock);
672 } else {
673 sock = nc_sock_listen_inet(address, port, &endpt->ka);
674 }
675
romanc1d2b092023-02-02 08:58:27 +0100676 if (sock == -1) {
677 ret = 1;
678 goto cleanup;
679 }
680
681 if (bind->sock > -1) {
682 close(bind->sock);
683 }
684 bind->sock = sock;
685 }
686
687 if (sock > -1) {
688 switch (endpt->ti) {
roman83683fb2023-02-24 09:15:23 +0100689 case NC_TI_UNIX:
690 VRB(NULL, "Listening on %s for UNIX connections.", endpt->opts.unixsock->address);
691 break;
romanc1d2b092023-02-02 08:58:27 +0100692#ifdef NC_ENABLED_SSH
693 case NC_TI_LIBSSH:
694 VRB(NULL, "Listening on %s:%u for SSH connections.", address, port);
695 break;
696#endif
697#ifdef NC_ENABLED_TLS
698 case NC_TI_OPENSSL:
699 VRB(NULL, "Listening on %s:%u for TLS connections.", address, port);
700 break;
701#endif
702 default:
703 ERRINT;
704 ret = 1;
705 break;
706 }
707 }
708
709cleanup:
710 return ret;
711}
712
713/* mandatory leaf */
714static int
romane028ef92023-02-24 16:33:08 +0100715nc_server_config_local_address(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100716{
717 struct nc_endpt *endpt;
718 struct nc_bind *bind;
719 int ret = 0;
720
721 (void) op;
722
723 assert(!strcmp(LYD_NAME(node), "local-address"));
724
725 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +0200726 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +0100727 ret = 1;
728 goto cleanup;
729 }
730
roman874fed12023-05-25 10:20:01 +0200731 nc_server_config_del_local_address(bind);
romanc1d2b092023-02-02 08:58:27 +0100732 bind->address = strdup(lyd_get_value(node));
733 if (!bind->address) {
734 ERRMEM;
735 ret = 1;
736 goto cleanup;
737 }
738
739 ret = nc_server_config_set_address_port(endpt, bind, lyd_get_value(node), 0);
740 if (ret) {
741 goto cleanup;
742 }
743 }
744
745cleanup:
746 return ret;
747}
748
749/* leaf with default value */
750static int
romane028ef92023-02-24 16:33:08 +0100751nc_server_config_local_port(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100752{
753 struct nc_endpt *endpt;
754 struct nc_bind *bind;
755 int ret = 0;
756
757 assert(!strcmp(LYD_NAME(node), "local-port"));
758
759 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +0200760 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +0100761 ret = 1;
762 goto cleanup;
763 }
764
765 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
766 bind->port = strtoul(lyd_get_value(node), NULL, 10);
767 } else {
768 /* delete -> set to default */
769 bind->port = 0;
770 }
771
772 ret = nc_server_config_set_address_port(endpt, bind, NULL, bind->port);
773 if (ret) {
774 goto cleanup;
775 }
776 }
777
778cleanup:
779 return ret;
780}
781
782/* P container */
783static int
romane028ef92023-02-24 16:33:08 +0100784nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100785{
786 struct nc_endpt *endpt;
787 struct nc_bind *bind;
788 int ret = 0;
789
790 assert(!strcmp(LYD_NAME(node), "keepalives"));
791
792 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +0200793 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +0100794 ret = 1;
795 goto cleanup;
796 }
797
798 if (op == NC_OP_CREATE) {
799 endpt->ka.enabled = 1;
800 } else {
801 endpt->ka.enabled = 0;
802 }
803 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
804 if (ret) {
805 goto cleanup;
806 }
807 }
808
809cleanup:
810 return ret;
811}
812
813/* mandatory leaf */
814static int
romane028ef92023-02-24 16:33:08 +0100815nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100816{
817 struct nc_endpt *endpt;
818 struct nc_bind *bind;
819 int ret = 0;
820
821 assert(!strcmp(LYD_NAME(node), "idle-time"));
822
823 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +0200824 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +0100825 ret = 1;
826 goto cleanup;
827 }
828
829 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
830 endpt->ka.idle_time = strtoul(lyd_get_value(node), NULL, 10);
831 } else {
832 endpt->ka.idle_time = 0;
833 }
834 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
835 if (ret) {
836 goto cleanup;
837 }
838 }
839
840cleanup:
841 return ret;
842}
843
844/* mandatory leaf */
845static int
romane028ef92023-02-24 16:33:08 +0100846nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100847{
848 struct nc_endpt *endpt;
849 struct nc_bind *bind;
850 int ret = 0;
851
852 assert(!strcmp(LYD_NAME(node), "max-probes"));
853
854 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +0200855 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +0100856 ret = 1;
857 goto cleanup;
858 }
859
860 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
861 endpt->ka.max_probes = strtoul(lyd_get_value(node), NULL, 10);
862 } else {
863 endpt->ka.max_probes = 0;
864 }
865 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
866 if (ret) {
867 goto cleanup;
868 }
869 }
870
871cleanup:
872 return ret;
873}
874
875/* mandatory leaf */
876static int
romane028ef92023-02-24 16:33:08 +0100877nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100878{
879 struct nc_endpt *endpt;
880 struct nc_bind *bind;
881 int ret = 0;
882
883 assert(!strcmp(LYD_NAME(node), "probe-interval"));
884
885 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +0200886 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +0100887 ret = 1;
888 goto cleanup;
889 }
890
891 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
892 endpt->ka.probe_interval = strtoul(lyd_get_value(node), NULL, 10);
893 } else {
894 endpt->ka.probe_interval = 0;
895 }
896 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
897 if (ret) {
898 goto cleanup;
899 }
900 }
901
902cleanup:
903 return ret;
904}
905
906static int
roman874fed12023-05-25 10:20:01 +0200907nc_server_config_create_host_key(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100908{
romanf02273a2023-05-25 09:44:11 +0200909 node = lyd_child(node);
910 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +0100911
romanf02273a2023-05-25 09:44:11 +0200912 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->hostkeys, sizeof *opts->hostkeys, &opts->hostkey_count);
romanc1d2b092023-02-02 08:58:27 +0100913}
914
915/* list */
916static int
romane028ef92023-02-24 16:33:08 +0100917nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100918{
919 struct nc_endpt *endpt;
920 struct nc_hostkey *hostkey;
921 int ret = 0;
922
923 assert(!strcmp(LYD_NAME(node), "host-key"));
924
925 if ((equal_parent_name(node, 1, "server-identity")) && (equal_parent_name(node, 5, "listen"))) {
romanf02273a2023-05-25 09:44:11 +0200926 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +0100927 ret = 1;
928 goto cleanup;
929 }
930
931 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +0200932 ret = nc_server_config_create_host_key(node, endpt->opts.ssh);
romanc1d2b092023-02-02 08:58:27 +0100933 if (ret) {
934 goto cleanup;
935 }
936 } else if (op == NC_OP_DELETE) {
romanf02273a2023-05-25 09:44:11 +0200937 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +0100938 ret = 1;
939 goto cleanup;
940 }
941
roman874fed12023-05-25 10:20:01 +0200942 nc_server_config_del_hostkey(endpt->opts.ssh, hostkey);
romanc1d2b092023-02-02 08:58:27 +0100943 }
944 } else if (equal_parent_name(node, 1, "transport-params")) {
945 /* just a container with the name host-key, nothing to be done */
946 goto cleanup;
947 } else {
948 ERRINT;
949 ret = 1;
950 goto cleanup;
951 }
952
953cleanup:
954 return ret;
955}
956
957/* mandatory leaf */
romane028ef92023-02-24 16:33:08 +0100958static int
959nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100960{
961 const char *format;
962 struct nc_endpt *endpt;
963 struct nc_client_auth *auth_client;
roman8edee342023-03-31 13:25:48 +0200964 struct nc_public_key *pubkey;
romanc1d2b092023-02-02 08:58:27 +0100965 struct nc_hostkey *hostkey;
966 int ret = 0;
967
968 assert(!strcmp(LYD_NAME(node), "public-key-format"));
969
970 format = ((struct lyd_node_term *)node)->value.ident->name;
971
972 if ((equal_parent_name(node, 6, "client-authentication")) && (equal_parent_name(node, 10, "listen"))) {
romanf02273a2023-05-25 09:44:11 +0200973 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +0100974 ret = 1;
975 goto cleanup;
976 }
977
romanf02273a2023-05-25 09:44:11 +0200978 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +0100979 ret = 1;
980 goto cleanup;
981 }
982
romanf02273a2023-05-25 09:44:11 +0200983 if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +0100984 ret = 1;
985 goto cleanup;
986 }
987
988 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
989 if (!strcmp(format, "ssh-public-key-format")) {
romanc1d2b092023-02-02 08:58:27 +0100990 pubkey->pubkey_type = NC_SSH_PUBKEY_SSH2;
romanf02273a2023-05-25 09:44:11 +0200991 } else if (!strcmp(format, "subject-public-key-info-format")) {
992 pubkey->pubkey_type = NC_SSH_PUBKEY_X509;
romanc1d2b092023-02-02 08:58:27 +0100993 } else {
994 ERR(NULL, "Public key format (%s) not supported.", format);
995 }
996 }
997 } else if ((equal_parent_name(node, 5, "server-identity")) && (equal_parent_name(node, 11, "listen"))) {
romanf02273a2023-05-25 09:44:11 +0200998 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +0100999 ret = 1;
1000 goto cleanup;
1001 }
1002
romanf02273a2023-05-25 09:44:11 +02001003 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001004 ret = 1;
1005 goto cleanup;
1006 }
1007
1008 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1009 if (!strcmp(format, "ssh-public-key-format")) {
roman8edee342023-03-31 13:25:48 +02001010 hostkey->key.pubkey_type = NC_SSH_PUBKEY_SSH2;
romane028ef92023-02-24 16:33:08 +01001011 } else if (!strcmp(format, "subject-public-key-info-format")) {
roman8edee342023-03-31 13:25:48 +02001012 hostkey->key.pubkey_type = NC_SSH_PUBKEY_X509;
romanc1d2b092023-02-02 08:58:27 +01001013 } else {
1014 ERR(NULL, "Public key format (%s) not supported.", format);
1015 }
1016 }
1017 }
1018
1019cleanup:
1020 return ret;
1021}
1022
1023/* leaf */
romane028ef92023-02-24 16:33:08 +01001024static int
1025nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001026{
1027 const char *format;
1028 struct nc_endpt *endpt;
1029 struct nc_hostkey *hostkey;
1030 int ret = 0;
1031
1032 assert(!strcmp(LYD_NAME(node), "private-key-format"));
1033
romanf02273a2023-05-25 09:44:11 +02001034 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001035 ret = 1;
1036 goto cleanup;
1037 }
1038
romanf02273a2023-05-25 09:44:11 +02001039 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001040 ret = 1;
1041 goto cleanup;
1042 }
1043
1044 format = ((struct lyd_node_term *)node)->value.ident->name;
1045 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1046 if (!strcmp(format, "rsa-private-key-format")) {
roman466719d2023-05-05 16:14:37 +02001047 hostkey->key.privkey_type = NC_PRIVKEY_FORMAT_RSA;
romanc1d2b092023-02-02 08:58:27 +01001048 } else if (!strcmp(format, "ec-private-key-format")) {
roman466719d2023-05-05 16:14:37 +02001049 hostkey->key.privkey_type = NC_PRIVKEY_FORMAT_EC;
1050 } else if (!strcmp(format, "subject-private-key-info-format")) {
1051 hostkey->key.privkey_type = NC_PRIVKEY_FORMAT_PKCS8;
1052 } else if (!strcmp(format, "openssh-private-key-format")) {
1053 hostkey->key.privkey_type = NC_PRIVKEY_FORMAT_OPENSSH;
romanc1d2b092023-02-02 08:58:27 +01001054 } else {
1055 ERR(NULL, "Private key format (%s) not supported.", format);
1056 }
1057 }
1058
1059cleanup:
1060 return ret;
1061}
1062
1063static int
roman874fed12023-05-25 10:20:01 +02001064nc_server_config_replace_cleartext_private_key(const struct lyd_node *node, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +01001065{
roman874fed12023-05-25 10:20:01 +02001066 nc_server_config_del_private_key(hostkey);
roman8edee342023-03-31 13:25:48 +02001067 hostkey->key.priv_base64 = strdup(lyd_get_value(node));
1068 if (!hostkey->key.priv_base64) {
romanc1d2b092023-02-02 08:58:27 +01001069 ERRMEM;
1070 return 1;
1071 }
1072
1073 return 0;
1074}
1075
1076static int
romane028ef92023-02-24 16:33:08 +01001077nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001078{
1079 struct nc_endpt *endpt;
1080 struct nc_hostkey *hostkey;
1081 int ret = 0;
1082
1083 assert(!strcmp(LYD_NAME(node), "cleartext-private-key"));
1084
1085 if ((equal_parent_name(node, 6, "ssh")) && (equal_parent_name(node, 8, "listen"))) {
romanf02273a2023-05-25 09:44:11 +02001086 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001087 ret = 1;
1088 goto cleanup;
1089 }
romanf02273a2023-05-25 09:44:11 +02001090 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001091 ret = 1;
1092 goto cleanup;
1093 }
1094
1095 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02001096 ret = nc_server_config_replace_cleartext_private_key(node, hostkey);
romanc1d2b092023-02-02 08:58:27 +01001097 if (ret) {
1098 goto cleanup;
1099 }
1100 } else {
roman874fed12023-05-25 10:20:01 +02001101 nc_server_config_del_private_key(hostkey);
romanc1d2b092023-02-02 08:58:27 +01001102 }
1103 }
1104
1105cleanup:
1106 return ret;
1107}
1108
1109static int
roman874fed12023-05-25 10:20:01 +02001110nc_server_config_create_keystore_reference(const struct lyd_node *node, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +01001111{
1112 uint16_t i;
roman45cec4e2023-02-17 10:21:39 +01001113 struct nc_keystore *ks = &server_opts.keystore;
romanc1d2b092023-02-02 08:58:27 +01001114
1115 /* lookup name */
roman45cec4e2023-02-17 10:21:39 +01001116 for (i = 0; i < ks->asym_key_count; i++) {
1117 if (!strcmp(lyd_get_value(node), ks->asym_keys[i].name)) {
romanc1d2b092023-02-02 08:58:27 +01001118 break;
1119 }
1120 }
1121
roman45cec4e2023-02-17 10:21:39 +01001122 if (i == ks->asym_key_count) {
1123 ERR(NULL, "Keystore \"%s\" not found.", lyd_get_value(node));
romanc1d2b092023-02-02 08:58:27 +01001124 return 1;
1125 }
1126
roman45cec4e2023-02-17 10:21:39 +01001127 hostkey->ks_ref = &ks->asym_keys[i];
romanc1d2b092023-02-02 08:58:27 +01001128
1129 return 0;
1130}
1131
1132/* leaf */
1133static int
romane028ef92023-02-24 16:33:08 +01001134nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001135{
1136 struct nc_endpt *endpt;
1137 struct nc_hostkey *hostkey;
1138 int ret = 0;
1139
1140 assert(!strcmp(LYD_NAME(node), "keystore-reference"));
1141
roman45cec4e2023-02-17 10:21:39 +01001142 if ((equal_parent_name(node, 3, "server-identity")) && (equal_parent_name(node, 7, "listen"))) {
romanf02273a2023-05-25 09:44:11 +02001143 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001144 ret = 1;
1145 goto cleanup;
1146 }
romanf02273a2023-05-25 09:44:11 +02001147 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001148 ret = 1;
1149 goto cleanup;
1150 }
1151
1152 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02001153 /* set to keystore */
roman874fed12023-05-25 10:20:01 +02001154 hostkey->store = NC_STORE_KEYSTORE;
romanf02273a2023-05-25 09:44:11 +02001155
roman874fed12023-05-25 10:20:01 +02001156 ret = nc_server_config_create_keystore_reference(node, hostkey);
romanc1d2b092023-02-02 08:58:27 +01001157 if (ret) {
1158 goto cleanup;
1159 }
1160 } else {
roman45cec4e2023-02-17 10:21:39 +01001161 hostkey->ks_ref = NULL;
romanc1d2b092023-02-02 08:58:27 +01001162 }
1163 }
1164
1165cleanup:
1166 return ret;
1167}
1168
1169static int
roman874fed12023-05-25 10:20:01 +02001170nc_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 +01001171{
romanc1d2b092023-02-02 08:58:27 +01001172 assert(!strcmp(LYD_NAME(node), "public-key"));
1173
romanc1d2b092023-02-02 08:58:27 +01001174 node = lyd_child(node);
1175 assert(!strcmp(LYD_NAME(node), "name"));
1176
romanf02273a2023-05-25 09:44:11 +02001177 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 +01001178}
1179
1180static int
roman874fed12023-05-25 10:20:01 +02001181nc_server_config_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +01001182{
roman874fed12023-05-25 10:20:01 +02001183 nc_server_config_del_auth_client_pubkey_pub_base64(pubkey);
romanc1d2b092023-02-02 08:58:27 +01001184
1185 pubkey->pub_base64 = strdup(lyd_get_value(node));
1186 if (!pubkey->pub_base64) {
1187 ERRMEM;
1188 return 1;
1189 }
1190
1191 return 0;
1192}
1193
1194static int
roman874fed12023-05-25 10:20:01 +02001195nc_server_config_replace_host_key_public_key(const struct lyd_node *node, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +01001196{
roman874fed12023-05-25 10:20:01 +02001197 nc_server_config_del_public_key(hostkey);
romanc1d2b092023-02-02 08:58:27 +01001198
roman8edee342023-03-31 13:25:48 +02001199 hostkey->key.pub_base64 = strdup(lyd_get_value(node));
1200 if (!hostkey->key.pub_base64) {
romanc1d2b092023-02-02 08:58:27 +01001201 ERRMEM;
1202 return 1;
1203 }
1204
1205 return 0;
1206}
1207
1208static int
romane028ef92023-02-24 16:33:08 +01001209nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001210{
1211 struct nc_endpt *endpt;
1212 struct nc_hostkey *hostkey;
1213 struct nc_client_auth *auth_client;
roman8edee342023-03-31 13:25:48 +02001214 struct nc_public_key *pubkey;
romanc1d2b092023-02-02 08:58:27 +01001215 int ret = 0;
1216
1217 assert(!strcmp(LYD_NAME(node), "public-key"));
1218
1219 if ((equal_parent_name(node, 3, "host-key")) && (equal_parent_name(node, 8, "listen"))) {
1220 /* server's public-key, mandatory leaf */
romanf02273a2023-05-25 09:44:11 +02001221 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001222 ret = 1;
1223 goto cleanup;
1224 }
1225
romanf02273a2023-05-25 09:44:11 +02001226 if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001227 ret = 1;
1228 goto cleanup;
1229 }
1230
1231 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02001232 /* set to local */
roman874fed12023-05-25 10:20:01 +02001233 hostkey->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02001234
roman874fed12023-05-25 10:20:01 +02001235 ret = nc_server_config_replace_host_key_public_key(node, hostkey);
romanc1d2b092023-02-02 08:58:27 +01001236 if (ret) {
1237 goto cleanup;
1238 }
1239 }
1240 } else if ((equal_parent_name(node, 5, "client-authentication")) && (equal_parent_name(node, 9, "listen"))) {
1241 /* client auth pubkeys, list */
romanf02273a2023-05-25 09:44:11 +02001242 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001243 ret = 1;
1244 goto cleanup;
1245 }
1246
romanf02273a2023-05-25 09:44:11 +02001247 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001248 ret = 1;
1249 goto cleanup;
1250 }
1251
1252 if (op == NC_OP_CREATE) {
romanf02273a2023-05-25 09:44:11 +02001253 /* set to local */
roman874fed12023-05-25 10:20:01 +02001254 auth_client->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02001255
roman874fed12023-05-25 10:20:01 +02001256 ret = nc_server_config_create_auth_key_public_key_list(node, auth_client);
romanc1d2b092023-02-02 08:58:27 +01001257 if (ret) {
1258 goto cleanup;
1259 }
1260 } else if (op == NC_OP_DELETE) {
romanf02273a2023-05-25 09:44:11 +02001261 if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001262 ret = 1;
1263 goto cleanup;
1264 }
1265
roman874fed12023-05-25 10:20:01 +02001266 nc_server_config_del_auth_client_pubkey(auth_client, pubkey);
romanc1d2b092023-02-02 08:58:27 +01001267 }
1268 } else if ((equal_parent_name(node, 6, "client-authentication")) && (equal_parent_name(node, 10, "listen"))) {
1269 /* client auth pubkey, leaf */
romanf02273a2023-05-25 09:44:11 +02001270 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001271 ret = 1;
1272 goto cleanup;
1273 }
1274
romanf02273a2023-05-25 09:44:11 +02001275 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001276 ret = 1;
1277 goto cleanup;
1278 }
1279
romanf02273a2023-05-25 09:44:11 +02001280 if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001281 ret = 1;
1282 goto cleanup;
1283 }
1284
1285 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02001286 ret = nc_server_config_replace_auth_key_public_key_leaf(node, pubkey);
romanc1d2b092023-02-02 08:58:27 +01001287 if (ret) {
1288 goto cleanup;
1289 }
1290 } else {
roman874fed12023-05-25 10:20:01 +02001291 nc_server_config_del_auth_client_pubkey_pub_base64(pubkey);
romanc1d2b092023-02-02 08:58:27 +01001292 }
1293 }
1294
1295cleanup:
1296 return ret;
1297}
1298
1299static int
roman874fed12023-05-25 10:20:01 +02001300nc_server_config_create_user(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01001301{
romanf02273a2023-05-25 09:44:11 +02001302 node = lyd_child(node);
1303 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01001304
romanf02273a2023-05-25 09:44:11 +02001305 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->auth_clients, sizeof *opts->auth_clients, &opts->client_count);
romanc1d2b092023-02-02 08:58:27 +01001306}
1307
1308/* list */
1309static int
romane028ef92023-02-24 16:33:08 +01001310nc_server_config_user(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001311{
1312 struct nc_endpt *endpt;
1313 struct nc_client_auth *auth_client;
1314 int ret = 0;
1315
1316 assert(!strcmp(LYD_NAME(node), "user"));
1317
1318 if (equal_parent_name(node, 6, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001319 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001320 ret = 1;
1321 goto cleanup;
1322 }
1323
1324 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +02001325 ret = nc_server_config_create_user(node, endpt->opts.ssh);
romanc1d2b092023-02-02 08:58:27 +01001326 if (ret) {
1327 goto cleanup;
1328 }
1329 } else if (op == NC_OP_DELETE) {
romanf02273a2023-05-25 09:44:11 +02001330 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001331 ret = 1;
1332 goto cleanup;
1333 }
1334
roman874fed12023-05-25 10:20:01 +02001335 nc_server_config_del_auth_client(endpt->opts.ssh, auth_client);
romanc1d2b092023-02-02 08:58:27 +01001336 }
1337 }
1338
1339cleanup:
1340 return ret;
1341}
1342
1343static int
romane028ef92023-02-24 16:33:08 +01001344nc_server_config_auth_attempts(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001345{
1346 struct nc_endpt *endpt;
1347 int ret = 0;
1348
1349 assert(!strcmp(LYD_NAME(node), "auth-attempts"));
1350
1351 if (equal_parent_name(node, 5, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001352 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001353 ret = 1;
1354 goto cleanup;
1355 }
1356
1357 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1358 endpt->opts.ssh->auth_attempts = strtoul(lyd_get_value(node), NULL, 10);
1359 }
1360 }
1361
1362cleanup:
1363 return ret;
1364}
1365
1366static int
romane028ef92023-02-24 16:33:08 +01001367nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001368{
1369 struct nc_endpt *endpt;
1370 int ret = 0;
1371
1372 assert(!strcmp(LYD_NAME(node), "auth-timeout"));
1373
1374 if (equal_parent_name(node, 5, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001375 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001376 ret = 1;
1377 goto cleanup;
1378 }
1379
1380 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1381 endpt->opts.ssh->auth_timeout = strtoul(lyd_get_value(node), NULL, 10);
1382 }
1383 }
1384
1385cleanup:
1386 return ret;
1387}
1388
1389static int
roman874fed12023-05-25 10:20:01 +02001390nc_server_config_replace_truststore_reference(const struct lyd_node *node, struct nc_client_auth *client_auth)
romanc1d2b092023-02-02 08:58:27 +01001391{
romand57b3722023-04-05 11:26:25 +02001392 uint16_t i;
1393 struct nc_truststore *ts = &server_opts.truststore;
romanc1d2b092023-02-02 08:58:27 +01001394
romand57b3722023-04-05 11:26:25 +02001395 /* lookup name */
1396 for (i = 0; i < ts->pub_bag_count; i++) {
1397 if (!strcmp(lyd_get_value(node), ts->pub_bags[i].name)) {
1398 break;
1399 }
1400 }
1401
1402 if (i == ts->pub_bag_count) {
1403 ERR(NULL, "Truststore \"%s\" not found.", lyd_get_value(node));
romanc1d2b092023-02-02 08:58:27 +01001404 return 1;
1405 }
1406
romand57b3722023-04-05 11:26:25 +02001407 client_auth->ts_ref = &ts->pub_bags[i];
1408
romanc1d2b092023-02-02 08:58:27 +01001409 return 0;
1410}
1411
1412/* leaf */
1413static int
romane028ef92023-02-24 16:33:08 +01001414nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001415{
1416 struct nc_endpt *endpt;
1417 struct nc_client_auth *auth_client;
1418 int ret = 0;
1419
1420 assert(!strcmp(LYD_NAME(node), "truststore-reference"));
1421
1422 if ((equal_parent_name(node, 1, "public-keys")) && (equal_parent_name(node, 8, "listen"))) {
romanf02273a2023-05-25 09:44:11 +02001423 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001424 ret = 1;
1425 goto cleanup;
1426 }
1427
romanf02273a2023-05-25 09:44:11 +02001428 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001429 ret = 1;
1430 goto cleanup;
1431 }
1432
1433 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02001434 /* set to truststore */
roman874fed12023-05-25 10:20:01 +02001435 auth_client->store = NC_STORE_TRUSTSTORE;
romanf02273a2023-05-25 09:44:11 +02001436
roman874fed12023-05-25 10:20:01 +02001437 ret = nc_server_config_replace_truststore_reference(node, auth_client);
romanc1d2b092023-02-02 08:58:27 +01001438 if (ret) {
1439 goto cleanup;
1440 }
1441 } else {
romand57b3722023-04-05 11:26:25 +02001442 auth_client->ts_ref = NULL;
romanc1d2b092023-02-02 08:58:27 +01001443 }
1444 }
1445
1446cleanup:
1447 return ret;
1448}
1449
1450static int
roman874fed12023-05-25 10:20:01 +02001451nc_server_config_replace_password(const struct lyd_node *node, struct nc_client_auth *auth_client)
romanc1d2b092023-02-02 08:58:27 +01001452{
roman874fed12023-05-25 10:20:01 +02001453 nc_server_config_del_auth_client_password(auth_client);
romanc1d2b092023-02-02 08:58:27 +01001454
1455 auth_client->password = strdup(lyd_get_value(node));
1456 if (!auth_client->password) {
1457 ERRMEM;
1458 return 1;
1459 }
1460
1461 return 0;
1462}
1463
1464/* leaf */
1465static int
romane028ef92023-02-24 16:33:08 +01001466nc_server_config_password(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001467{
1468 struct nc_endpt *endpt;
1469 struct nc_client_auth *auth_client;
1470 int ret = 0;
1471
1472 assert(!strcmp(LYD_NAME(node), "password"));
1473
1474 if (equal_parent_name(node, 7, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001475 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001476 ret = 1;
1477 goto cleanup;
1478 }
1479
romanf02273a2023-05-25 09:44:11 +02001480 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001481 ret = 1;
1482 goto cleanup;
1483 }
1484
1485 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02001486 ret = nc_server_config_replace_password(node, auth_client);
romanc1d2b092023-02-02 08:58:27 +01001487 if (ret) {
1488 goto cleanup;
1489 }
1490 } else {
roman874fed12023-05-25 10:20:01 +02001491 nc_server_config_del_auth_client_password(auth_client);
romanc1d2b092023-02-02 08:58:27 +01001492 }
1493 }
1494
1495cleanup:
1496 return ret;
1497}
1498
1499static int
romane028ef92023-02-24 16:33:08 +01001500nc_server_config_pam_name(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001501{
1502 struct nc_endpt *endpt;
1503 struct nc_client_auth *auth_client;
1504 int ret = 0;
1505
1506 assert(!strcmp(LYD_NAME(node), "pam-config-file-name"));
1507
1508 if (equal_parent_name(node, 8, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001509 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001510 ret = 1;
1511 goto cleanup;
1512 }
1513
romanf02273a2023-05-25 09:44:11 +02001514 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001515 ret = 1;
1516 goto cleanup;
1517 }
1518
1519 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02001520 nc_server_config_del_auth_client_pam_name(auth_client);
romanc1d2b092023-02-02 08:58:27 +01001521
1522 auth_client->pam_config_name = strdup(lyd_get_value(node));
1523 if (!auth_client->pam_config_name) {
1524 ERRMEM;
1525 ret = 1;
1526 goto cleanup;
1527 }
1528 }
1529 }
1530
1531cleanup:
1532 return ret;
1533}
1534
1535static int
romane028ef92023-02-24 16:33:08 +01001536nc_server_config_pam_dir(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001537{
1538 struct nc_endpt *endpt;
1539 struct nc_client_auth *auth_client;
1540 int ret = 0;
1541
1542 assert(!strcmp(LYD_NAME(node), "pam-config-file-dir"));
1543
1544 if (equal_parent_name(node, 8, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001545 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001546 ret = 1;
1547 goto cleanup;
1548 }
1549
romanf02273a2023-05-25 09:44:11 +02001550 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001551 ret = 1;
1552 goto cleanup;
1553 }
1554
1555 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02001556 nc_server_config_del_auth_client_pam_dir(auth_client);
romanc1d2b092023-02-02 08:58:27 +01001557 auth_client->pam_config_dir = strdup(lyd_get_value(node));
1558 if (!auth_client->pam_config_dir) {
1559 ERRMEM;
1560 ret = 1;
1561 goto cleanup;
1562 }
1563 }
1564 }
1565
1566cleanup:
1567 return ret;
1568}
1569
1570/* leaf */
1571static int
romane028ef92023-02-24 16:33:08 +01001572nc_server_config_none(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001573{
1574 struct nc_endpt *endpt;
1575 struct nc_client_auth *auth_client;
1576 int ret = 0;
1577
1578 assert(!strcmp(LYD_NAME(node), "none"));
1579
1580 if (equal_parent_name(node, 7, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001581 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001582 ret = 1;
1583 goto cleanup;
1584 }
1585
romanf02273a2023-05-25 09:44:11 +02001586 if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001587 ret = 1;
1588 goto cleanup;
1589 }
1590
1591 if (op == NC_OP_CREATE) {
1592 auth_client->supports_none = 1;
1593 } else {
1594 auth_client->supports_none = 0;
1595 }
1596 }
1597
1598cleanup:
1599 return ret;
1600}
1601
1602static int
romane028ef92023-02-24 16:33:08 +01001603nc_server_config_transport_params(const char *alg, char **alg_store, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001604{
1605 int ret = 0, alg_found = 0;
1606 char *substr, *haystack;
1607 size_t alg_len = strlen(alg);
1608
1609 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1610 if (!*alg_store) {
1611 /* first call */
1612 *alg_store = strdup(alg);
1613 if (!*alg_store) {
1614 ERRMEM;
1615 ret = 1;
1616 goto cleanup;
1617 }
1618 } else {
1619 /* +1 because of ',' between algorithms */
1620 *alg_store = nc_realloc(*alg_store, strlen(*alg_store) + alg_len + 1 + 1);
1621 if (!*alg_store) {
1622 ERRMEM;
1623 ret = 1;
1624 goto cleanup;
1625 }
1626 sprintf(*alg_store, "%s,%s", *alg_store, alg);
1627 }
1628 } else {
1629 /* delete */
1630 haystack = *alg_store;
1631 while ((substr = strstr(haystack, alg))) {
1632 /* iterate over all the substrings */
1633 if (((substr == haystack) && (*(substr + alg_len) == ',')) ||
1634 ((substr != haystack) && (*(substr - 1) == ',') && (*(substr + alg_len) == ','))) {
1635 /* either the first element of the string or somewhere in the middle */
1636 memmove(substr, substr + alg_len + 1, strlen(substr + alg_len + 1));
1637 alg_found = 1;
1638 break;
1639 } else if ((*(substr - 1) == ',') && (*(substr + alg_len) == '\0')) {
1640 /* the last element of the string */
1641 *(substr - 1) = '\0';
1642 alg_found = 1;
1643 break;
1644 }
1645 haystack++;
1646 }
1647 if (!alg_found) {
1648 ERR(NULL, "Unable to delete an algorithm (%s), which was not previously added.", alg);
1649 ret = 1;
1650 }
1651 }
1652
1653cleanup:
1654 return ret;
1655}
1656
1657/* leaf-list */
1658static int
romane028ef92023-02-24 16:33:08 +01001659nc_server_config_host_key_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001660{
1661 struct nc_endpt *endpt;
1662 int ret = 0, listen = 0;
1663 const char *alg;
1664 uint8_t i;
1665
1666 /* get the algorithm name and compare it with algs supported by libssh */
1667 alg = ((struct lyd_node_term *)node)->value.ident->name;
1668
1669 if (equal_parent_name(node, 6, "listen")) {
1670 listen = 1;
romanf02273a2023-05-25 09:44:11 +02001671 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001672 ret = 1;
1673 goto cleanup;
1674 }
1675 }
1676
1677 i = 0;
1678 while (supported_hostkey_algs[i]) {
1679 if (!strcmp(supported_hostkey_algs[i], alg)) {
1680 if (listen) {
romane028ef92023-02-24 16:33:08 +01001681 if (nc_server_config_transport_params(alg, &endpt->opts.ssh->hostkey_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01001682 ret = 1;
1683 goto cleanup;
1684 }
1685 }
1686 break;
1687 }
1688 i++;
1689 }
1690 if (!supported_hostkey_algs[i]) {
1691 /* algorithm not supported */
1692 ERR(NULL, "Public key algorithm (%s) not supported by libssh.", alg);
1693 ret = 1;
1694 }
1695
1696cleanup:
1697 return ret;
1698}
1699
1700/* leaf-list */
1701static int
romane028ef92023-02-24 16:33:08 +01001702nc_server_config_kex_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001703{
1704 struct nc_endpt *endpt;
1705 int ret = 0, listen = 0;
1706 const char *alg;
1707 uint8_t i;
1708
1709 /* get the algorithm name and compare it with algs supported by libssh */
1710 alg = ((struct lyd_node_term *)node)->value.ident->name;
1711
1712 if (equal_parent_name(node, 6, "listen")) {
1713 listen = 1;
romanf02273a2023-05-25 09:44:11 +02001714 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001715 ret = 1;
1716 goto cleanup;
1717 }
1718 }
1719
1720 i = 0;
1721 while (supported_kex_algs[i]) {
1722 if (!strcmp(supported_kex_algs[i], alg)) {
1723 if (listen) {
romane028ef92023-02-24 16:33:08 +01001724 if (nc_server_config_transport_params(alg, &endpt->opts.ssh->kex_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01001725 ret = 1;
1726 goto cleanup;
1727 }
1728 }
1729 break;
1730 }
1731 i++;
1732 }
1733 if (!supported_kex_algs[i]) {
1734 /* algorithm not supported */
1735 ERR(NULL, "Key exchange algorithm (%s) not supported by libssh.", alg);
1736 ret = 1;
1737 }
1738
1739cleanup:
1740 return ret;
1741}
1742
1743/* leaf-list */
1744static int
romane028ef92023-02-24 16:33:08 +01001745nc_server_config_encryption_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001746{
1747 struct nc_endpt *endpt;
1748 int ret = 0, listen = 0;
1749 const char *alg;
1750 uint8_t i;
1751
1752 /* get the algorithm name and compare it with algs supported by libssh */
1753 alg = ((struct lyd_node_term *)node)->value.ident->name;
1754
1755 if (equal_parent_name(node, 6, "listen")) {
1756 listen = 1;
romanf02273a2023-05-25 09:44:11 +02001757 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001758 ret = 1;
1759 goto cleanup;
1760 }
1761 }
1762
1763 i = 0;
1764 while (supported_encryption_algs[i]) {
1765 if (!strcmp(supported_encryption_algs[i], alg)) {
1766 if (listen) {
romane028ef92023-02-24 16:33:08 +01001767 if (nc_server_config_transport_params(alg, &endpt->opts.ssh->encryption_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01001768 ret = 1;
1769 goto cleanup;
1770 }
1771 }
1772 break;
1773 }
1774 i++;
1775 }
1776 if (!supported_encryption_algs[i]) {
1777 /* algorithm not supported */
1778 ERR(NULL, "Encryption algorithm (%s) not supported by libssh.", alg);
1779 ret = 1;
1780 }
1781
1782cleanup:
1783 return ret;
1784}
1785
1786/* leaf-list */
1787static int
romane028ef92023-02-24 16:33:08 +01001788nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001789{
1790 struct nc_endpt *endpt;
1791 int ret = 0, listen = 0;
1792 const char *alg;
1793 uint8_t i;
1794
1795 /* get the algorithm name and compare it with algs supported by libssh */
1796 alg = ((struct lyd_node_term *)node)->value.ident->name;
1797
1798 if (equal_parent_name(node, 6, "listen")) {
1799 listen = 1;
romanf02273a2023-05-25 09:44:11 +02001800 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
romanc1d2b092023-02-02 08:58:27 +01001801 ret = 1;
1802 goto cleanup;
1803 }
1804 }
1805
1806 i = 0;
1807 while (supported_mac_algs[i]) {
1808 if (!strcmp(supported_mac_algs[i], alg)) {
1809 if (listen) {
romane028ef92023-02-24 16:33:08 +01001810 if (nc_server_config_transport_params(alg, &endpt->opts.ssh->mac_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01001811 ret = 1;
1812 goto cleanup;
1813 }
1814 }
1815 break;
1816 }
1817 i++;
1818 }
1819 if (!supported_mac_algs[i]) {
1820 /* algorithm not supported */
1821 ERR(NULL, "MAC algorithm (%s) not supported by libssh.", alg);
1822 ret = 1;
1823 }
1824
1825cleanup:
1826 return ret;
1827}
1828
1829static int
roman874fed12023-05-25 10:20:01 +02001830nc_server_config_create_unix_socket(struct nc_endpt *endpt)
roman83683fb2023-02-24 09:15:23 +01001831{
1832 endpt->ti = NC_TI_UNIX;
1833 endpt->opts.unixsock = calloc(1, sizeof *endpt->opts.unixsock);
1834 if (!endpt->opts.unixsock) {
1835 ERRMEM;
1836 return 1;
1837 }
1838
1839 /* set default values */
1840 endpt->opts.unixsock->mode = -1;
1841 endpt->opts.unixsock->uid = -1;
1842 endpt->opts.unixsock->gid = -1;
1843
1844 return 0;
1845}
1846
1847static int
romane028ef92023-02-24 16:33:08 +01001848nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op)
roman83683fb2023-02-24 09:15:23 +01001849{
1850 int ret = 0;
1851 uint32_t prev_lo;
1852 struct nc_endpt *endpt;
1853 struct nc_bind *bind;
1854 struct nc_server_unix_opts *opts;
1855 struct lyd_node *data = NULL;
1856
1857 assert(!strcmp(LYD_NAME(node), "unix-socket"));
1858
romanf02273a2023-05-25 09:44:11 +02001859 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
roman83683fb2023-02-24 09:15:23 +01001860 ret = 1;
1861 goto cleanup;
1862 }
1863
1864 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +02001865 if (nc_server_config_create_unix_socket(endpt)) {
roman83683fb2023-02-24 09:15:23 +01001866 ret = 1;
1867 goto cleanup;
1868 }
1869
1870 opts = endpt->opts.unixsock;
1871
1872 lyd_find_path(node, "path", 0, &data);
1873 assert(data);
1874
1875 opts->address = strdup(lyd_get_value(data));
1876 bind->address = strdup(lyd_get_value(data));
1877 if (!opts->address || !bind->address) {
1878 ERRMEM;
1879 ret = 1;
1880 goto cleanup;
1881 }
1882
1883 /* silently search for non-mandatory parameters */
1884 prev_lo = ly_log_options(0);
1885 ret = lyd_find_path(node, "mode", 0, &data);
1886 if (!ret) {
1887 opts->mode = strtol(lyd_get_value(data), NULL, 8);
1888 }
1889
1890 ret = lyd_find_path(node, "uid", 0, &data);
1891 if (!ret) {
1892 opts->uid = strtol(lyd_get_value(data), NULL, 10);
1893 }
1894
1895 ret = lyd_find_path(node, "gid", 0, &data);
1896 if (!ret) {
1897 opts->gid = strtol(lyd_get_value(data), NULL, 10);
1898 }
1899
1900 /* reset the logging options */
1901 ly_log_options(prev_lo);
1902
1903 ret = nc_server_config_set_address_port(endpt, bind, NULL, 0);
1904 if (ret) {
1905 goto cleanup;
1906 }
1907 } else if (op == NC_OP_DELETE) {
roman874fed12023-05-25 10:20:01 +02001908 nc_server_config_del_unix_socket(bind, endpt->opts.unixsock);
roman83683fb2023-02-24 09:15:23 +01001909 }
1910
1911cleanup:
1912 return ret;
1913}
1914
1915static int
romanf02273a2023-05-25 09:44:11 +02001916nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001917{
1918 const char *name = LYD_NAME(node);
1919
1920 if (!strcmp(name, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001921 if (nc_server_config_listen(NULL, op)) {
romanc1d2b092023-02-02 08:58:27 +01001922 goto error;
1923 }
1924 } else if (!strcmp(name, "idle-timeout")) {
romane028ef92023-02-24 16:33:08 +01001925 if (nc_server_config_idle_timeout(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01001926 goto error;
1927 }
1928 } else if (!strcmp(name, "endpoint")) {
romane028ef92023-02-24 16:33:08 +01001929 if (nc_server_config_endpoint(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01001930 goto error;
1931 }
1932 } else if (!strcmp(name, "ssh")) {
romane028ef92023-02-24 16:33:08 +01001933 if (nc_server_config_ssh(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01001934 goto error;
1935 }
1936 } else if (!strcmp(name, "local-address")) {
romane028ef92023-02-24 16:33:08 +01001937 if (nc_server_config_local_address(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01001938 goto error;
1939 }
1940 } else if (!strcmp(name, "local-port")) {
romane028ef92023-02-24 16:33:08 +01001941 if (nc_server_config_local_port(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01001942 goto error;
1943 }
1944 } else if (!strcmp(name, "keepalives")) {
romane028ef92023-02-24 16:33:08 +01001945 if (nc_server_config_keepalives(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01001946 goto error;
1947 }
1948 } else if (!strcmp(name, "idle-time")) {
romane028ef92023-02-24 16:33:08 +01001949 if (nc_server_config_idle_time(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01001950 goto error;
1951 }
1952 } else if (!strcmp(name, "max-probes")) {
romane028ef92023-02-24 16:33:08 +01001953 if (nc_server_config_max_probes(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01001954 goto error;
1955 }
1956 } else if (!strcmp(name, "probe-interval")) {
romane028ef92023-02-24 16:33:08 +01001957 if (nc_server_config_probe_interval(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01001958 goto error;
1959 }
1960 } else if (!strcmp(name, "host-key")) {
romane028ef92023-02-24 16:33:08 +01001961 if (nc_server_config_host_key(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01001962 goto error;
1963 }
1964 } else if (!strcmp(name, "public-key-format")) {
romane028ef92023-02-24 16:33:08 +01001965 if (nc_server_config_public_key_format(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01001966 goto error;
1967 }
1968 } else if (!strcmp(name, "public-key")) {
romane028ef92023-02-24 16:33:08 +01001969 if (nc_server_config_public_key(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01001970 goto error;
1971 }
1972 } else if (!strcmp(name, "private-key-format")) {
romane028ef92023-02-24 16:33:08 +01001973 if (nc_server_config_private_key_format(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01001974 goto error;
1975 }
1976 } else if (!strcmp(name, "cleartext-private-key")) {
romane028ef92023-02-24 16:33:08 +01001977 if (nc_server_config_cleartext_private_key(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01001978 goto error;
1979 }
1980 } else if (!strcmp(name, "keystore-reference")) {
romane028ef92023-02-24 16:33:08 +01001981 if (nc_server_config_keystore_reference(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01001982 goto error;
1983 }
1984 } else if (!strcmp(name, "user")) {
romane028ef92023-02-24 16:33:08 +01001985 if (nc_server_config_user(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01001986 goto error;
1987 }
1988 } else if (!strcmp(name, "auth-attempts")) {
romane028ef92023-02-24 16:33:08 +01001989 if (nc_server_config_auth_attempts(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01001990 goto error;
1991 }
1992 } else if (!strcmp(name, "auth-timeout")) {
romane028ef92023-02-24 16:33:08 +01001993 if (nc_server_config_auth_timeout(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01001994 goto error;
1995 }
1996 } else if (!strcmp(name, "truststore-reference")) {
romane028ef92023-02-24 16:33:08 +01001997 if (nc_server_config_truststore_reference(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01001998 goto error;
1999 }
2000 } else if (!strcmp(name, "password")) {
romane028ef92023-02-24 16:33:08 +01002001 if (nc_server_config_password(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01002002 goto error;
2003 }
2004 } else if (!strcmp(name, "pam-config-file-name")) {
romane028ef92023-02-24 16:33:08 +01002005 if (nc_server_config_pam_name(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01002006 goto error;
2007 }
2008 } else if (!strcmp(name, "pam-config-file-dir")) {
romane028ef92023-02-24 16:33:08 +01002009 if (nc_server_config_pam_dir(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01002010 goto error;
2011 }
2012 } else if (!strcmp(name, "none")) {
romane028ef92023-02-24 16:33:08 +01002013 if (nc_server_config_none(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01002014 goto error;
2015 }
2016 } else if (!strcmp(name, "host-key-alg")) {
romane028ef92023-02-24 16:33:08 +01002017 if (nc_server_config_host_key_alg(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01002018 goto error;
2019 }
2020 } else if (!strcmp(name, "key-exchange-alg")) {
romane028ef92023-02-24 16:33:08 +01002021 if (nc_server_config_kex_alg(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01002022 goto error;
2023 }
2024 } else if (!strcmp(name, "encryption-alg")) {
romane028ef92023-02-24 16:33:08 +01002025 if (nc_server_config_encryption_alg(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01002026 goto error;
2027 }
2028 } else if (!strcmp(name, "mac-alg")) {
romane028ef92023-02-24 16:33:08 +01002029 if (nc_server_config_mac_alg(node, op)) {
romanc1d2b092023-02-02 08:58:27 +01002030 goto error;
2031 }
roman83683fb2023-02-24 09:15:23 +01002032 } else if (!strcmp(name, "unix-socket")) {
romane028ef92023-02-24 16:33:08 +01002033 if (nc_server_config_unix_socket(node, op)) {
roman83683fb2023-02-24 09:15:23 +01002034 goto error;
2035 }
romanc1d2b092023-02-02 08:58:27 +01002036 } else if (!strcmp(name, "cert-data")) {} else if (!strcmp(name, "expiration-date")) {} else if (!strcmp(name, "asymmetric-key")) {} else if (!strcmp(name, "certificate")) {} else if (!strcmp(name, "key-format")) {} else if (!strcmp(name,
2037 "cleartext-key")) {} else if (!strcmp(name, "hidden-key")) {} else if (!strcmp(name, "id_hint")) {} else if (!strcmp(name, "external-identity")) {} else if (!strcmp(name, "hash")) {} else if (!strcmp(name, "context")) {} else if (!strcmp(name,
2038 "target-protocol")) {} else if (!strcmp(name, "target-kdf")) {} else if (!strcmp(name, "client-authentication")) {} else if (!strcmp(name, "ca-certs")) {} else if (!strcmp(name, "ee-certs")) {} else if (!strcmp(name,
2039 "raw-public-keys")) {} else if (!strcmp(name, "tls12-psks")) {} else if (!strcmp(name, "tls13-epsks")) {} else if (!strcmp(name, "tls-version")) {} else if (!strcmp(name, "cipher-suite")) {} else if (!strcmp(name,
2040 "peer-allowed-to-send")) {} else if (!strcmp(name, "test-peer-aliveness")) {} else if (!strcmp(name, "max-wait")) {} else if (!strcmp(name, "max-attempts")) {} else if (!strcmp(name, "cert-to-name")) {} else if (!strcmp(name,
2041 "id")) {} else if (!strcmp(name, "fingerprint")) {} else if (!strcmp(name, "map-type")) {}
2042
2043 return 0;
2044
2045error:
2046 ERR(NULL, "Configuring (%s) failed.", LYD_NAME(node));
2047 return 1;
2048}
2049
2050int
romanf02273a2023-05-25 09:44:11 +02002051nc_session_server_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, NC_MODULE module)
romanc1d2b092023-02-02 08:58:27 +01002052{
2053 struct lyd_node *child;
2054 struct lyd_meta *m;
romanf9906b42023-05-22 14:04:29 +02002055 NC_OPERATION current_op = NC_OP_UNKNOWN;
romanf02273a2023-05-25 09:44:11 +02002056 int ret;
romanc1d2b092023-02-02 08:58:27 +01002057
2058 assert(node);
2059
romanf9906b42023-05-22 14:04:29 +02002060 /* get current op if there is any */
2061 if ((m = lyd_find_meta(node->meta, NULL, "yang:operation"))) {
2062 if (!strcmp(lyd_get_meta_value(m), "create")) {
2063 current_op = NC_OP_CREATE;
2064 } else if (!strcmp(lyd_get_meta_value(m), "delete")) {
2065 current_op = NC_OP_DELETE;
2066 } else if (!strcmp(lyd_get_meta_value(m), "replace")) {
2067 current_op = NC_OP_REPLACE;
2068 } else if (!strcmp(lyd_get_meta_value(m), "none")) {
2069 current_op = NC_OP_NONE;
romanc1d2b092023-02-02 08:58:27 +01002070 }
2071 }
2072
2073 /* node has no op, inherit from the parent */
romanf9906b42023-05-22 14:04:29 +02002074 if (!current_op) {
2075 if (!parent_op) {
2076 ERR(NULL, "Unknown operation for node \"%s\".", LYD_NAME(node));
2077 return 1;
2078 }
2079
romanc1d2b092023-02-02 08:58:27 +01002080 current_op = parent_op;
2081 }
2082
2083 switch (current_op) {
2084 case NC_OP_NONE:
2085 break;
2086 case NC_OP_CREATE:
2087 case NC_OP_DELETE:
2088 case NC_OP_REPLACE:
romanf02273a2023-05-25 09:44:11 +02002089 if (module == NC_MODULE_NETCONF_SERVER) {
2090 ret = nc_server_config_parse_netconf_server(node, current_op);
2091 } else if (module == NC_MODULE_KEYSTORE) {
2092 ret = nc_server_config_parse_keystore(node, current_op);
2093 } else {
2094 ret = nc_server_config_parse_truststore(node, current_op);
2095 }
2096 if (ret) {
2097 return ret;
romanc1d2b092023-02-02 08:58:27 +01002098 }
2099 break;
2100 default:
2101 break;
2102 }
2103
2104 if (current_op != NC_OP_DELETE) {
2105 LY_LIST_FOR(lyd_child(node), child) {
romanf02273a2023-05-25 09:44:11 +02002106 if (nc_session_server_parse_tree(child, current_op, module)) {
romanc1d2b092023-02-02 08:58:27 +01002107 return 1;
2108 }
2109 }
2110 }
2111 return 0;
2112}
2113
romanc1d2b092023-02-02 08:58:27 +01002114API int
2115nc_server_config_load_modules(struct ly_ctx **ctx)
2116{
2117 int i, new_ctx = 0;
2118
2119 if (!*ctx) {
2120 if (ly_ctx_new(NC_SERVER_SEARCH_DIR, 0, ctx)) {
2121 ERR(NULL, "Couldn't create new libyang context.\n");
2122 goto error;
2123 }
2124 new_ctx = 1;
2125 }
2126
2127 /* all features */
2128 const char *ietf_nectonf_server[] = {"ssh-listen", "tls-listen", "ssh-call-home", "tls-call-home", "central-netconf-server-supported", NULL};
2129 /* all features */
2130 const char *ietf_x509_cert_to_name[] = {NULL};
2131 /* no private-key-encryption and csr-generation */
2132 const char *ietf_crypto_types[] = {
2133 "one-symmetric-key-format", "one-asymmetric-key-format", "symmetrically-encrypted-value-format",
2134 "asymmetrically-encrypted-value-format", "cms-enveloped-data-format", "cms-encrypted-data-format",
2135 "p10-based-csrs", "certificate-expiration-notification", "hidden-keys", "password-encryption",
2136 "symmetric-key-encryption", NULL
2137 };
2138 /* all features */
2139 const char *ietf_tcp_common[] = {"keepalives-supported", NULL};
2140 /* no ssh-x509-certs */
2141 const char *ietf_ssh_common[] = {"transport-params", "public-key-generation", NULL};
2142 /* all features */
2143 const char *iana_ssh_encryption_algs[] = {NULL};
2144 /* all features */
2145 const char *iana_ssh_key_exchange_algs[] = {NULL};
2146 /* all features */
2147 const char *iana_ssh_mac_algs[] = {NULL};
2148 /* all features */
2149 const char *iana_ssh_public_key_algs[] = {NULL};
romanf02273a2023-05-25 09:44:11 +02002150 /* no symmetric-keys */
2151 const char *ietf_keystore[] = {"central-keystore-supported", "local-definitions-supported", "asymmetric-keys", NULL};
romanc1d2b092023-02-02 08:58:27 +01002152 /* no ssh-server-keepalives and local-user-auth-hostbased */
2153 const char *ietf_ssh_server[] = {"local-users-supported", "local-user-auth-publickey", "local-user-auth-password", "local-user-auth-none", NULL};
2154 /* all features */
2155 const char *ietf_truststore[] = {"central-truststore-supported", "local-definitions-supported", "certificates", "public-keys", NULL};
2156 /* all features */
2157 const char *ietf_tls_server[] = {
2158 "tls-server-keepalives", "server-ident-x509-cert", "server-ident-raw-public-key", "server-ident-tls12-psk",
2159 "server-ident-tls13-epsk", "client-auth-supported", "client-auth-x509-cert", "client-auth-raw-public-key",
2160 "client-auth-tls12-psk", "client-auth-tls13-epsk", NULL
2161 };
2162 /* all features */
2163 const char *libnetconf2_netconf_server[] = {NULL};
2164
2165 const char *module_names[] = {
2166 "ietf-netconf-server", "ietf-x509-cert-to-name", "ietf-crypto-types",
2167 "ietf-tcp-common", "ietf-ssh-common", "iana-ssh-encryption-algs",
2168 "iana-ssh-key-exchange-algs", "iana-ssh-mac-algs", "iana-ssh-public-key-algs",
2169 "ietf-keystore", "ietf-ssh-server", "ietf-truststore",
2170 "ietf-tls-server", "libnetconf2-netconf-server", NULL
2171 };
2172
2173 const char **module_features[] = {
2174 ietf_nectonf_server, ietf_x509_cert_to_name, ietf_crypto_types,
2175 ietf_tcp_common, ietf_ssh_common, iana_ssh_encryption_algs,
2176 iana_ssh_key_exchange_algs, iana_ssh_mac_algs, iana_ssh_public_key_algs,
2177 ietf_keystore, ietf_ssh_server, ietf_truststore,
2178 ietf_tls_server, libnetconf2_netconf_server, NULL
2179 };
2180
2181 for (i = 0; module_names[i] != NULL; i++) {
2182 if (!ly_ctx_load_module(*ctx, module_names[i], NULL, module_features[i])) {
2183 ERR(NULL, "Loading module \"%s\" failed.\n", module_names[i]);
2184 goto error;
2185 }
2186 }
2187
2188 return 0;
2189
2190error:
2191 if (new_ctx) {
2192 ly_ctx_destroy(*ctx);
2193 *ctx = NULL;
2194 }
2195 return 1;
2196}
2197
2198API int
2199nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path)
2200{
2201 struct lyd_node *tree = NULL;
2202 int ret = 0;
2203
roman40672412023-05-04 11:10:22 +02002204 NC_CHECK_ARG_RET(NULL, path, 1);
romanc1d2b092023-02-02 08:58:27 +01002205
2206 ret = lyd_parse_data_path(ctx, path, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree);
2207 if (ret) {
2208 goto cleanup;
2209 }
2210
2211 ret = nc_server_config_setup(tree);
2212 if (ret) {
2213 goto cleanup;
2214 }
2215
2216cleanup:
2217 lyd_free_all(tree);
2218 return ret;
2219}
2220
romanf9906b42023-05-22 14:04:29 +02002221static int
2222nc_server_config_fill_nectonf_server(const struct lyd_node *data, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002223{
2224 int ret = 0;
2225 struct lyd_node *tree;
romand57b3722023-04-05 11:26:25 +02002226
romanc1d2b092023-02-02 08:58:27 +01002227 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &tree);
2228 if (ret) {
2229 ERR(NULL, "Unable to find the netconf-server container in the YANG data.");
2230 goto cleanup;
2231 }
2232
romanf02273a2023-05-25 09:44:11 +02002233 if (nc_session_server_parse_tree(tree, op, NC_MODULE_NETCONF_SERVER)) {
romanf9906b42023-05-22 14:04:29 +02002234 ret = 1;
2235 goto cleanup;
2236 }
2237
2238cleanup:
2239 return ret;
2240}
2241
2242API int
2243nc_server_config_setup(const struct lyd_node *data)
2244{
2245 int ret = 0;
2246
2247 /* LOCK */
2248 pthread_rwlock_wrlock(&server_opts.config_lock);
2249
2250 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02002251 ret = nc_server_config_fill_keystore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02002252 if (ret) {
2253 ERR(NULL, "Filling keystore failed.");
2254 goto cleanup;
2255 }
2256
2257 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02002258 ret = nc_server_config_fill_truststore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02002259 if (ret) {
2260 ERR(NULL, "Filling truststore failed.");
2261 goto cleanup;
2262 }
2263
2264 /* configure netconf-server */
2265 ret = nc_server_config_fill_nectonf_server(data, NC_OP_UNKNOWN);
2266 if (ret) {
2267 ERR(NULL, "Filling netconf-server failed.");
2268 goto cleanup;
2269 }
2270
2271cleanup:
2272 /* UNLOCK */
2273 pthread_rwlock_unlock(&server_opts.config_lock);
2274 return ret;
2275}
2276
2277API int
2278nc_server_config_setup2(const struct lyd_node *data)
2279{
2280 int ret = 0;
2281 struct lyd_node *tree, *iter, *root;
2282
2283 /* LOCK */
2284 pthread_rwlock_wrlock(&server_opts.config_lock);
2285
2286 /* find the netconf-server node */
2287 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &root);
2288 if (ret) {
2289 ERR(NULL, "Unable to find the netconf-server container in the YANG data.");
2290 goto cleanup;
2291 }
2292
2293 /* iterate through all the nodes and make sure there is no operation attribute */
2294 LY_LIST_FOR(root, tree) {
2295 LYD_TREE_DFS_BEGIN(tree, iter) {
2296 if (lyd_find_meta(iter->meta, NULL, "yang:operation")) {
2297 ERR(NULL, "Unexpected operation attribute in the YANG data.");
romanc1d2b092023-02-02 08:58:27 +01002298 ret = 1;
2299 goto cleanup;
2300 }
romanf9906b42023-05-22 14:04:29 +02002301 LYD_TREE_DFS_END(tree, iter);
romanc1d2b092023-02-02 08:58:27 +01002302 }
2303 }
2304
romanf9906b42023-05-22 14:04:29 +02002305 /* delete the current configuration */
romanf02273a2023-05-25 09:44:11 +02002306 nc_server_config_listen(NULL, NC_OP_DELETE);
2307 nc_server_config_ks_keystore(NULL, NC_OP_DELETE);
2308 nc_server_config_ts_truststore(NULL, NC_OP_DELETE);
romanf9906b42023-05-22 14:04:29 +02002309
2310 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02002311 ret = nc_server_config_fill_keystore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02002312 if (ret) {
2313 ERR(NULL, "Filling keystore failed.");
2314 goto cleanup;
2315 }
2316
2317 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02002318 ret = nc_server_config_fill_truststore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02002319 if (ret) {
2320 ERR(NULL, "Filling truststore failed.");
2321 goto cleanup;
2322 }
2323
2324 /* configure netconf-server */
2325 ret = nc_server_config_fill_nectonf_server(data, NC_OP_CREATE);
2326 if (ret) {
2327 ERR(NULL, "Filling netconf-server failed.");
romanc1d2b092023-02-02 08:58:27 +01002328 goto cleanup;
2329 }
2330
2331cleanup:
2332 /* UNLOCK */
2333 pthread_rwlock_unlock(&server_opts.config_lock);
2334 return ret;
2335}