blob: d0aaedadd09772fb7d17d8a579795ede88196fba [file] [log] [blame]
romanc1d2b092023-02-02 08:58:27 +01001/**
2 * @file config_server.c
3 * @author Roman Janota <janota@cesnet.cz>
4 * @brief libnetconf2 server configuration functions
5 *
6 * @copyright
7 * Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
8 *
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 */
15#include <assert.h>
16#include <stdlib.h>
17#include <string.h>
18
19#include "compat.h"
20#include "config_server.h"
21#include "libnetconf.h"
22#include "session_server.h"
23#include "session_server_ch.h"
24
25/* All libssh supported host-key, key-exchange, encryption and mac algorithms as of version 0.10.90 */
26
27static const char *supported_hostkey_algs[] = {
28 "ssh-ed25519-cert-v01@openssh.com", "ecdsa-sha2-nistp521-cert-v01@openssh.com",
29 "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ecdsa-sha2-nistp256-cert-v01@openssh.com",
30 "rsa-sha2-512-cert-v01@openssh.com", "rsa-sha2-256-cert-v01@openssh.com",
31 "ssh-rsa-cert-v01@openssh.com", "ssh-dss-cert-v01@openssh.com",
32 "ssh-ed25519", "ecdsa-sha2-nistp521", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp256",
33 "rsa-sha2-512", "rsa-sha2-256", "ssh-rsa", "ssh-dss", NULL
34};
35
36static const char *supported_kex_algs[] = {
37 "diffie-hellman-group-exchange-sha1", "curve25519-sha256", "curve25519-sha256@libssh.org",
38 "ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", "diffie-hellman-group18-sha512",
39 "diffie-hellman-group16-sha512", "diffie-hellman-group-exchange-sha256", "diffie-hellman-group14-sha256", NULL
40};
41
42static const char *supported_encryption_algs[] = {
43 "chacha20-poly1305@openssh.com", "aes256-gcm@openssh.com", "aes128-gcm@openssh.com",
44 "aes256-ctr", "aes192-ctr", "aes128-ctr", "aes256-cbc", "aes192-cbc", "aes128-cbc",
45 "blowfish-cbc", "3des-cbc", "none", NULL
46};
47
48static const char *supported_mac_algs[] = {
49 "hmac-sha2-256-etm@openssh.com", "hmac-sha2-512-etm@openssh.com", "hmac-sha1-etm@openssh.com",
50 "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1", NULL
51};
52
53extern struct nc_server_opts server_opts;
54
55/**
56 * @brief Get the pointer to an endpoint structure based on node's location in the YANG data.
57 *
58 * @param[in] node Node from which the endpoint containing this node is derived.
59 * @param[out] endpt Endpoint containing the node.
60 * @param[out] bind Bind corresponding to the endpoint. Optional.
61 * @return 0 on success, 1 on error.
62 */
63static int
64nc_server_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, struct nc_bind **bind)
65{
66 uint16_t i;
67 const char *endpt_name;
68
69 assert(node);
70
71 while (node) {
72 if (!strcmp(LYD_NAME(node), "endpoint")) {
73 break;
74 }
75 node = lyd_parent(node);
76 }
77
78 if (!node) {
79 ERR(NULL, "Node \"%s\" is not contained in an endpoint subtree.", LYD_NAME(node));
80 return 1;
81 }
82
83 node = lyd_child(node);
84 assert(!strcmp(LYD_NAME(node), "name"));
85 endpt_name = lyd_get_value(node);
86
87 for (i = 0; i < server_opts.endpt_count; i++) {
88 if (!strcmp(server_opts.endpts[i].name, endpt_name)) {
89 *endpt = &server_opts.endpts[i];
90 if (bind) {
91 *bind = &server_opts.binds[i];
92 }
93 return 0;
94 }
95 }
96
97 ERR(NULL, "Endpoint \"%s\" was not found.", endpt_name);
98 return 1;
99}
100
101/**
102 * @brief Get the pointer to a hostkey structure based on node's location in the YANG data.
103 *
104 * @param[in] node Node from which the hotkey containing this node is derived.
105 * @param[in] opts Server SSH opts storing the array of the hostkey structures.
106 * @param[out] hostkey Hostkey containing the node.
107 * @return 0 on success, 1 on error.
108 */
109static int
110nc_server_get_hostkey(const struct lyd_node *node, const struct nc_server_ssh_opts *opts, struct nc_hostkey **hostkey)
111{
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
144/**
145 * @brief Get the pointer to a client authentication structure based on node's location in the YANG data.
146 *
147 * @param[in] node Node from which the client-authentication structure containing this node is derived.
148 * @param[in] opts Server SSH opts storing the array of the client authentication structures.
149 * @param[out] auth_client Client authentication structure containing the node.
150 * @return 0 on success, 1 on error.
151 */
152static int
153nc_server_get_auth_client(const struct lyd_node *node, const struct nc_server_ssh_opts *opts, struct nc_client_auth **auth_client)
154{
155 uint16_t i;
156 const char *authkey_name;
157
158 assert(node && opts);
159
160 while (node) {
161 if (!strcmp(LYD_NAME(node), "user")) {
162 break;
163 }
164 node = lyd_parent(node);
165 }
166
167 if (!node) {
168 ERR(NULL, "Node \"%s\" is not contained in a client-authentication subtree.", LYD_NAME(node));
169 return 1;
170 }
171
172 node = lyd_child(node);
173 assert(!strcmp(LYD_NAME(node), "name"));
174 authkey_name = lyd_get_value(node);
175
176 for (i = 0; i < opts->client_count; i++) {
177 if (!strcmp(opts->auth_clients[i].username, authkey_name)) {
178 *auth_client = &opts->auth_clients[i];
179 return 0;
180 }
181 }
182
183 ERR(NULL, "Authorized key \"%s\" was not found.", authkey_name);
184 return 1;
185}
186
187/**
188 * @brief Get the pointer to a client authentication public key structure based on node's location in the YANG data.
189 *
190 * @param[in] node Node from which the ca-public key structure containing this node is derived.
191 * @param[in] auth_client Client authentication structure storing the array of the public key structures.
192 * @param[out] pubkey Public key structure containing the node.
193 * @return 0 on success, 1 on error.
194 */
195static int
196nc_server_get_pubkey(const struct lyd_node *node, const struct nc_client_auth *auth_client, struct nc_client_auth_pubkey **pubkey)
197{
198 uint16_t i;
199 const char *pubkey_name;
200
201 assert(node && auth_client);
202
203 node = lyd_parent(node);
204 while (node) {
205 if (!strcmp(LYD_NAME(node), "public-key")) {
206 break;
207 }
208 node = lyd_parent(node);
209 }
210
211 if (!node) {
212 ERR(NULL, "Node \"%s\" is not contained in a public-key subtree.", LYD_NAME(node));
213 return 1;
214 }
215
216 node = lyd_child(node);
217 assert(!strcmp(LYD_NAME(node), "name"));
218 pubkey_name = lyd_get_value(node);
219
220 for (i = 0; i < auth_client->pubkey_count; i++) {
221 if (!strcmp(auth_client->pubkeys[i].name, pubkey_name)) {
222 *pubkey = &auth_client->pubkeys[i];
223 return 0;
224 }
225 }
226
227 ERR(NULL, "Public key \"%s\" was not found.", pubkey_name);
228 return 1;
229}
230
231/**
232 * @brief Compares the nth-parent name.
233 *
234 * @param[in] node Node of which nth-parent to compare.
235 * @param[in] parent_count Count of parents.
236 * @param[in] parent_name Expected name of the parent.
237 * @return 1 if the name matches, 0 otherwise.
238 */
239static int
240equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char *parent_name)
241{
242 uint16_t i;
243
244 assert(node && parent_count > 0 && parent_name);
245
246 node = lyd_parent(node);
247 for (i = 1; i < parent_count; i++) {
248 node = lyd_parent(node);
249 }
250
251 if (!strcmp(LYD_NAME(node), parent_name)) {
252 return 1;
253 }
254
255 return 0;
256}
257
258static void
259nc_server_del_auth_client_pam_name(struct nc_client_auth *auth_client)
260{
261 free(auth_client->pam_config_name);
262 auth_client->pam_config_name = NULL;
263}
264
265static void
266nc_server_del_auth_client_pam_dir(struct nc_client_auth *auth_client)
267{
268 free(auth_client->pam_config_dir);
269 auth_client->pam_config_dir = NULL;
270}
271
272static void
273nc_server_del_endpt_name(struct nc_endpt *endpt)
274{
275 free(endpt->name);
276 endpt->name = NULL;
277}
278
279static void
280nc_server_del_local_address(struct nc_bind *bind)
281{
282 free(bind->address);
283 bind->address = NULL;
284}
285
286static void
287nc_server_del_hostkey_name(struct nc_hostkey *hostkey)
288{
289 free(hostkey->name);
290 hostkey->name = NULL;
291}
292
293static void
294nc_server_del_public_key(struct nc_hostkey *hostkey)
295{
296 free(hostkey->pub_base64);
297 hostkey->pub_base64 = NULL;
298}
299
300static void
301nc_server_del_truststore_reference(struct nc_client_auth *client_auth)
302{
303 free(client_auth->ts_reference);
304 client_auth->ts_reference = NULL;
305}
306
307static void
308nc_server_del_private_key(struct nc_hostkey *hostkey)
309{
310 free(hostkey->priv_base64);
311 hostkey->priv_base64 = NULL;
312}
313
314static void
315nc_server_del_keystore_reference(struct nc_hostkey *hostkey)
316{
317 hostkey->keystore = NULL;
318}
319
320static void
321nc_server_del_auth_client_username(struct nc_client_auth *auth_client)
322{
323 free(auth_client->username);
324 auth_client->username = NULL;
325}
326
327static void
328nc_server_del_auth_client_pubkey_name(struct nc_client_auth_pubkey *pubkey)
329{
330 free(pubkey->name);
331 pubkey->name = NULL;
332}
333
334static void
335nc_server_del_auth_client_pubkey_pub_base64(struct nc_client_auth_pubkey *pubkey)
336{
337 free(pubkey->pub_base64);
338 pubkey->pub_base64 = NULL;
339}
340
341static void
342nc_server_del_auth_client_ts_reference(struct nc_client_auth *auth_client)
343{
344 free(auth_client->ts_reference);
345 auth_client->ts_reference = NULL;
346}
347
348static void
349nc_server_del_auth_client_password(struct nc_client_auth *auth_client)
350{
351 free(auth_client->password);
352 auth_client->password = NULL;
353}
354
355static void
356nc_server_del_hostkey_algs(struct nc_server_ssh_opts *opts)
357{
358 free(opts->hostkey_algs);
359 opts->hostkey_algs = NULL;
360}
361
362static void
363nc_server_del_kex_algs(struct nc_server_ssh_opts *opts)
364{
365 free(opts->kex_algs);
366 opts->kex_algs = NULL;
367}
368
369static void
370nc_server_del_encryption_algs(struct nc_server_ssh_opts *opts)
371{
372 free(opts->encryption_algs);
373 opts->encryption_algs = NULL;
374}
375
376static void
377nc_server_del_mac_algs(struct nc_server_ssh_opts *opts)
378{
379 free(opts->mac_algs);
380 opts->mac_algs = NULL;
381}
382
383static void
384nc_server_del_hostkey(struct nc_server_ssh_opts *opts, struct nc_hostkey *hostkey)
385{
386 assert(hostkey->ks_type == NC_STORE_LOCAL || hostkey->ks_type == NC_STORE_KEYSTORE);
387
388 if (hostkey->ks_type == NC_STORE_LOCAL) {
389 nc_server_del_public_key(hostkey);
390 nc_server_del_private_key(hostkey);
391 } else if (hostkey->ks_type == NC_STORE_KEYSTORE) {
392 nc_server_del_keystore_reference(hostkey);
393 }
394
395 nc_server_del_hostkey_name(hostkey);
396 opts->hostkey_count--;
397 if (!opts->hostkey_count) {
398 free(opts->hostkeys);
399 opts->hostkeys = NULL;
400 }
401}
402
403static void
404nc_server_del_auth_client_pubkey(struct nc_client_auth *auth_client, struct nc_client_auth_pubkey *pubkey)
405{
406 nc_server_del_auth_client_pubkey_name(pubkey);
407 nc_server_del_auth_client_pubkey_pub_base64(pubkey);
408
409 auth_client->pubkey_count--;
410 if (!auth_client->pubkey_count) {
411 free(auth_client->pubkeys);
412 auth_client->pubkeys = NULL;
413 }
414}
415
416static void
417nc_server_del_auth_client(struct nc_server_ssh_opts *opts, struct nc_client_auth *auth_client)
418{
419 uint16_t i, pubkey_count;
420
421 if (auth_client->ks_type == NC_STORE_LOCAL) {
422 pubkey_count = auth_client->pubkey_count;
423 for (i = 0; i < pubkey_count; i++) {
424 nc_server_del_auth_client_pubkey(auth_client, &auth_client->pubkeys[i]);
425 }
426 } else if (auth_client->ks_type == NC_STORE_TRUSTSTORE) {
427 nc_server_del_auth_client_ts_reference(auth_client);
428 } else {
429 return;
430 }
431
432 nc_server_del_auth_client_password(auth_client);
433 nc_server_del_auth_client_pam_name(auth_client);
434 nc_server_del_auth_client_pam_dir(auth_client);
435 nc_server_del_auth_client_username(auth_client);
436
437 opts->client_count--;
438 if (!opts->client_count) {
439 free(opts->auth_clients);
440 opts->auth_clients = NULL;
441 }
442}
443
444static void
445nc_server_del_ssh(struct nc_bind *bind, struct nc_server_ssh_opts *opts)
446{
447 uint16_t i, hostkey_count, client_count;
448
449 nc_server_del_local_address(bind);
450 if (bind->sock > -1) {
451 close(bind->sock);
452 }
453
454 /* store in variable because it gets decremented in the function call */
455 hostkey_count = opts->hostkey_count;
456 for (i = 0; i < hostkey_count; i++) {
457 nc_server_del_hostkey(opts, &opts->hostkeys[i]);
458 }
459
460 client_count = opts->client_count;
461 for (i = 0; i < client_count; i++) {
462 nc_server_del_auth_client(opts, &opts->auth_clients[i]);
463 }
464
465 nc_server_del_hostkey_algs(opts);
466 nc_server_del_kex_algs(opts);
467 nc_server_del_encryption_algs(opts);
468 nc_server_del_mac_algs(opts);
469
470 free(opts);
471 opts = NULL;
472}
473
474void
475nc_server_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind)
476{
477 nc_server_del_endpt_name(endpt);
478 nc_server_del_ssh(bind, endpt->opts.ssh);
479
480 server_opts.endpt_count--;
481 if (!server_opts.endpt_count) {
482 free(server_opts.endpts);
483 free(server_opts.binds);
484 server_opts.endpts = NULL;
485 server_opts.binds = NULL;
486 }
487}
488
489/* presence container */
490int
491nc_server_configure_listen(NC_OPERATION op)
492{
493 uint16_t i;
494
495 assert(op == NC_OP_CREATE || op == NC_OP_DELETE);
496
497 if (op == NC_OP_DELETE) {
498 for (i = 0; i < server_opts.endpt_count; i++) {
499 nc_server_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]);
500 }
501 }
502
503 return 0;
504}
505
506/* default leaf */
507static int
508nc_server_configure_idle_timeout(const struct lyd_node *node, NC_OPERATION op)
509{
510 assert(!strcmp(LYD_NAME(node), "idle-timeout"));
511
512 if (equal_parent_name(node, 1, "listen")) {
513 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
514 server_opts.idle_timeout = strtoul(lyd_get_value(node), NULL, 10);
515 } else {
516 /* default value */
517 server_opts.idle_timeout = 3600;
518 }
519 }
520
521 return 0;
522}
523
524static int
525nc_server_create_bind(void)
526{
527 int ret = 0;
528 void *tmp;
529
530 tmp = realloc(server_opts.binds, (server_opts.endpt_count + 1) * sizeof *server_opts.binds);
531 if (!tmp) {
532 ERRMEM;
533 ret = 1;
534 goto cleanup;
535 }
536 server_opts.binds = tmp;
537 memset(&server_opts.binds[server_opts.endpt_count], 0, sizeof *server_opts.binds);
538
539 server_opts.binds[server_opts.endpt_count].sock = -1;
540
541cleanup:
542 return ret;
543}
544
545static int
546nc_server_create_endpoint(const struct lyd_node *node)
547{
548 int ret = 0;
549 void *tmp;
550
551 tmp = realloc(server_opts.endpts, (server_opts.endpt_count + 1) * sizeof *server_opts.endpts);
552 if (!tmp) {
553 ERRMEM;
554 ret = 1;
555 goto cleanup;
556 }
557 server_opts.endpts = tmp;
558 memset(&server_opts.endpts[server_opts.endpt_count], 0, sizeof *server_opts.endpts);
559
560 node = lyd_child(node);
561 assert(!strcmp(LYD_NAME(node), "name"));
562
563 server_opts.endpts[server_opts.endpt_count].name = strdup(lyd_get_value(node));
564 if (!server_opts.endpts[server_opts.endpt_count].name) {
565 ERRMEM;
566 ret = 1;
567 goto cleanup;
568 }
569
570 if (nc_server_create_bind()) {
571 ret = 1;
572 goto cleanup;
573 }
574
575 server_opts.endpt_count++;
576
577cleanup:
578 return ret;
579}
580
581/* list */
582static int
583nc_server_configure_endpoint(const struct lyd_node *node, NC_OPERATION op)
584{
585 int ret = 0;
586 struct nc_endpt *endpt;
587 struct nc_bind *bind;
588
589 assert(!strcmp(LYD_NAME(node), "endpoint"));
590
591 if (op == NC_OP_CREATE) {
592 ret = nc_server_create_endpoint(node);
593 if (ret) {
594 goto cleanup;
595 }
596 } else if (op == NC_OP_DELETE) {
597 /* free all children */
598 if (nc_server_get_endpt(node, &endpt, &bind)) {
599 ret = 1;
600 goto cleanup;
601 }
602 nc_server_del_endpt_ssh(endpt, bind);
603 }
604
605cleanup:
606 return ret;
607}
608
609static int
610nc_server_create_ssh(struct nc_endpt *endpt)
611{
612 endpt->ti = NC_TI_LIBSSH;
613 endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
614 if (!endpt->opts.ssh) {
615 ERRMEM;
616 return 1;
617 }
618
619 return 0;
620}
621
622/* NP container */
623static int
624nc_server_configure_ssh(const struct lyd_node *node, NC_OPERATION op)
625{
626 struct nc_endpt *endpt;
627 struct nc_bind *bind;
628 int ret = 0;
629
630 assert(!strcmp(LYD_NAME(node), "ssh"));
631
632 if (nc_server_get_endpt(node, &endpt, &bind)) {
633 ret = 1;
634 goto cleanup;
635 }
636
637 if (op == NC_OP_CREATE) {
638 ret = nc_server_create_ssh(endpt);
639 if (ret) {
640 goto cleanup;
641 }
642 } else if (op == NC_OP_DELETE) {
643 nc_server_del_ssh(bind, endpt->opts.ssh);
644 }
645
646cleanup:
647 return ret;
648}
649
650static int
651nc_server_config_set_address_port(struct nc_endpt *endpt, struct nc_bind *bind, const char *address, uint16_t port)
652{
653 int sock = -1, set_addr, ret = 0;
654
655 assert((address && !port) || (!address && port));
656
657 if (address) {
658 set_addr = 1;
659 } else {
660 set_addr = 0;
661 }
662
663 if (set_addr) {
664 port = bind->port;
665 } else {
666 address = bind->address;
667 }
668
669 if (!set_addr && (endpt->ti == NC_TI_UNIX)) {
670 ret = 1;
671 goto cleanup;
672 }
673
674 /* we have all the information we need to create a listening socket */
675 if (address && port) {
676 /* create new socket, close the old one */
677 sock = nc_sock_listen_inet(address, port, &endpt->ka);
678 if (sock == -1) {
679 ret = 1;
680 goto cleanup;
681 }
682
683 if (bind->sock > -1) {
684 close(bind->sock);
685 }
686 bind->sock = sock;
687 }
688
689 if (sock > -1) {
690 switch (endpt->ti) {
691#ifdef NC_ENABLED_SSH
692 case NC_TI_LIBSSH:
693 VRB(NULL, "Listening on %s:%u for SSH connections.", address, port);
694 break;
695#endif
696#ifdef NC_ENABLED_TLS
697 case NC_TI_OPENSSL:
698 VRB(NULL, "Listening on %s:%u for TLS connections.", address, port);
699 break;
700#endif
701 default:
702 ERRINT;
703 ret = 1;
704 break;
705 }
706 }
707
708cleanup:
709 return ret;
710}
711
712/* mandatory leaf */
713static int
714nc_server_configure_local_address(const struct lyd_node *node, NC_OPERATION op)
715{
716 struct nc_endpt *endpt;
717 struct nc_bind *bind;
718 int ret = 0;
719
720 (void) op;
721
722 assert(!strcmp(LYD_NAME(node), "local-address"));
723
724 if (equal_parent_name(node, 4, "listen")) {
725 if (nc_server_get_endpt(node, &endpt, &bind)) {
726 ret = 1;
727 goto cleanup;
728 }
729
730 nc_server_del_local_address(bind);
731 bind->address = strdup(lyd_get_value(node));
732 if (!bind->address) {
733 ERRMEM;
734 ret = 1;
735 goto cleanup;
736 }
737
738 ret = nc_server_config_set_address_port(endpt, bind, lyd_get_value(node), 0);
739 if (ret) {
740 goto cleanup;
741 }
742 }
743
744cleanup:
745 return ret;
746}
747
748/* leaf with default value */
749static int
750nc_server_configure_local_port(const struct lyd_node *node, NC_OPERATION op)
751{
752 struct nc_endpt *endpt;
753 struct nc_bind *bind;
754 int ret = 0;
755
756 assert(!strcmp(LYD_NAME(node), "local-port"));
757
758 if (equal_parent_name(node, 4, "listen")) {
759 if (nc_server_get_endpt(node, &endpt, &bind)) {
760 ret = 1;
761 goto cleanup;
762 }
763
764 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
765 bind->port = strtoul(lyd_get_value(node), NULL, 10);
766 } else {
767 /* delete -> set to default */
768 bind->port = 0;
769 }
770
771 ret = nc_server_config_set_address_port(endpt, bind, NULL, bind->port);
772 if (ret) {
773 goto cleanup;
774 }
775 }
776
777cleanup:
778 return ret;
779}
780
781/* P container */
782static int
783nc_server_configure_keepalives(const struct lyd_node *node, NC_OPERATION op)
784{
785 struct nc_endpt *endpt;
786 struct nc_bind *bind;
787 int ret = 0;
788
789 assert(!strcmp(LYD_NAME(node), "keepalives"));
790
791 if (equal_parent_name(node, 4, "listen")) {
792 if (nc_server_get_endpt(node, &endpt, &bind)) {
793 ret = 1;
794 goto cleanup;
795 }
796
797 if (op == NC_OP_CREATE) {
798 endpt->ka.enabled = 1;
799 } else {
800 endpt->ka.enabled = 0;
801 }
802 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
803 if (ret) {
804 goto cleanup;
805 }
806 }
807
808cleanup:
809 return ret;
810}
811
812/* mandatory leaf */
813static int
814nc_server_configure_idle_time(const struct lyd_node *node, NC_OPERATION op)
815{
816 struct nc_endpt *endpt;
817 struct nc_bind *bind;
818 int ret = 0;
819
820 assert(!strcmp(LYD_NAME(node), "idle-time"));
821
822 if (equal_parent_name(node, 4, "listen")) {
823 if (nc_server_get_endpt(node, &endpt, &bind)) {
824 ret = 1;
825 goto cleanup;
826 }
827
828 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
829 endpt->ka.idle_time = strtoul(lyd_get_value(node), NULL, 10);
830 } else {
831 endpt->ka.idle_time = 0;
832 }
833 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
834 if (ret) {
835 goto cleanup;
836 }
837 }
838
839cleanup:
840 return ret;
841}
842
843/* mandatory leaf */
844static int
845nc_server_configure_max_probes(const struct lyd_node *node, NC_OPERATION op)
846{
847 struct nc_endpt *endpt;
848 struct nc_bind *bind;
849 int ret = 0;
850
851 assert(!strcmp(LYD_NAME(node), "max-probes"));
852
853 if (equal_parent_name(node, 4, "listen")) {
854 if (nc_server_get_endpt(node, &endpt, &bind)) {
855 ret = 1;
856 goto cleanup;
857 }
858
859 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
860 endpt->ka.max_probes = strtoul(lyd_get_value(node), NULL, 10);
861 } else {
862 endpt->ka.max_probes = 0;
863 }
864 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
865 if (ret) {
866 goto cleanup;
867 }
868 }
869
870cleanup:
871 return ret;
872}
873
874/* mandatory leaf */
875static int
876nc_server_configure_probe_interval(const struct lyd_node *node, NC_OPERATION op)
877{
878 struct nc_endpt *endpt;
879 struct nc_bind *bind;
880 int ret = 0;
881
882 assert(!strcmp(LYD_NAME(node), "probe-interval"));
883
884 if (equal_parent_name(node, 4, "listen")) {
885 if (nc_server_get_endpt(node, &endpt, &bind)) {
886 ret = 1;
887 goto cleanup;
888 }
889
890 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
891 endpt->ka.probe_interval = strtoul(lyd_get_value(node), NULL, 10);
892 } else {
893 endpt->ka.probe_interval = 0;
894 }
895 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
896 if (ret) {
897 goto cleanup;
898 }
899 }
900
901cleanup:
902 return ret;
903}
904
905static int
906nc_server_create_host_key(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
907{
908 int ret = 0;
909 void *tmp;
910
911 tmp = realloc(opts->hostkeys,
912 (opts->hostkey_count + 1) * sizeof *opts->hostkeys);
913 if (!tmp) {
914 ERRMEM;
915 ret = 1;
916 goto cleanup;
917 }
918 opts->hostkeys = tmp;
919
920 memset(&opts->hostkeys[opts->hostkey_count], 0, sizeof *opts->hostkeys);
921
922 opts->hostkeys[opts->hostkey_count].name = strdup(lyd_get_value(lyd_child(node)));
923 if (!opts->hostkeys[opts->hostkey_count].name) {
924 ERRMEM;
925 ret = 1;
926 goto cleanup;
927 }
928
929 /* set union selector */
930 lyd_find_path(node, "public-key", 0, (struct lyd_node **)&node);
931 assert(node);
932
933 if (!lyd_find_path(node, "local-definition", 0, NULL)) {
934 opts->hostkeys[opts->hostkey_count].ks_type = NC_STORE_LOCAL;
935 } else {
936 opts->hostkeys[opts->hostkey_count].ks_type = NC_STORE_KEYSTORE;
937 }
938
939 opts->hostkey_count++;
940
941cleanup:
942 return ret;
943}
944
945/* list */
946static int
947nc_server_configure_host_key(const struct lyd_node *node, NC_OPERATION op)
948{
949 struct nc_endpt *endpt;
950 struct nc_hostkey *hostkey;
951 int ret = 0;
952
953 assert(!strcmp(LYD_NAME(node), "host-key"));
954
955 if ((equal_parent_name(node, 1, "server-identity")) && (equal_parent_name(node, 5, "listen"))) {
956 if (nc_server_get_endpt(node, &endpt, NULL)) {
957 ret = 1;
958 goto cleanup;
959 }
960
961 if (op == NC_OP_CREATE) {
962 ret = nc_server_create_host_key(node, endpt->opts.ssh);
963 if (ret) {
964 goto cleanup;
965 }
966 } else if (op == NC_OP_DELETE) {
967 if (nc_server_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
968 ret = 1;
969 goto cleanup;
970 }
971
972 nc_server_del_hostkey(endpt->opts.ssh, hostkey);
973 }
974 } else if (equal_parent_name(node, 1, "transport-params")) {
975 /* just a container with the name host-key, nothing to be done */
976 goto cleanup;
977 } else {
978 ERRINT;
979 ret = 1;
980 goto cleanup;
981 }
982
983cleanup:
984 return ret;
985}
986
987/* mandatory leaf */
988int
989nc_server_configure_public_key_format(const struct lyd_node *node, NC_OPERATION op)
990{
991 const char *format;
992 struct nc_endpt *endpt;
993 struct nc_client_auth *auth_client;
994 struct nc_client_auth_pubkey *pubkey;
995 struct nc_hostkey *hostkey;
996 int ret = 0;
997
998 assert(!strcmp(LYD_NAME(node), "public-key-format"));
999
1000 format = ((struct lyd_node_term *)node)->value.ident->name;
1001
1002 if ((equal_parent_name(node, 6, "client-authentication")) && (equal_parent_name(node, 10, "listen"))) {
1003 if (nc_server_get_endpt(node, &endpt, NULL)) {
1004 ret = 1;
1005 goto cleanup;
1006 }
1007
1008 if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
1009 ret = 1;
1010 goto cleanup;
1011 }
1012
1013 if (nc_server_get_pubkey(node, auth_client, &pubkey)) {
1014 ret = 1;
1015 goto cleanup;
1016 }
1017
1018 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1019 if (!strcmp(format, "ssh-public-key-format")) {
1020 pubkey->pubkey_type = NC_SSH_PUBKEY_X509;
1021 } else if (!strcmp(format, "subject-public-key-info-format")) {
1022 pubkey->pubkey_type = NC_SSH_PUBKEY_SSH2;
1023 } else {
1024 ERR(NULL, "Public key format (%s) not supported.", format);
1025 }
1026 }
1027 } else if ((equal_parent_name(node, 5, "server-identity")) && (equal_parent_name(node, 11, "listen"))) {
1028 if (nc_server_get_endpt(node, &endpt, NULL)) {
1029 ret = 1;
1030 goto cleanup;
1031 }
1032
1033 if (nc_server_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
1034 ret = 1;
1035 goto cleanup;
1036 }
1037
1038 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1039 if (!strcmp(format, "ssh-public-key-format")) {
1040 hostkey->pubkey_type = NC_SSH_PUBKEY_X509;
1041 } else if (!strcmp(format, "subject-public-key-info-format")) {
1042 hostkey->pubkey_type = NC_SSH_PUBKEY_SSH2;
1043 } else {
1044 ERR(NULL, "Public key format (%s) not supported.", format);
1045 }
1046 }
1047 }
1048
1049cleanup:
1050 return ret;
1051}
1052
1053/* leaf */
1054int
1055nc_server_configure_private_key_format(const struct lyd_node *node, NC_OPERATION op)
1056{
1057 const char *format;
1058 struct nc_endpt *endpt;
1059 struct nc_hostkey *hostkey;
1060 int ret = 0;
1061
1062 assert(!strcmp(LYD_NAME(node), "private-key-format"));
1063
1064 if (nc_server_get_endpt(node, &endpt, NULL)) {
1065 ret = 1;
1066 goto cleanup;
1067 }
1068
1069 if (nc_server_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
1070 ret = 1;
1071 goto cleanup;
1072 }
1073
1074 format = ((struct lyd_node_term *)node)->value.ident->name;
1075 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1076 if (!strcmp(format, "rsa-private-key-format")) {
1077 hostkey->privkey_type = NC_SSH_KEY_RSA;
1078 } else if (!strcmp(format, "ec-private-key-format")) {
1079 hostkey->privkey_type = NC_SSH_KEY_ECDSA;
1080 } else {
1081 ERR(NULL, "Private key format (%s) not supported.", format);
1082 }
1083 }
1084
1085cleanup:
1086 return ret;
1087}
1088
1089static int
1090nc_server_replace_cleartext_private_key(const struct lyd_node *node, struct nc_hostkey *hostkey)
1091{
1092 nc_server_del_private_key(hostkey);
1093 hostkey->priv_base64 = strdup(lyd_get_value(node));
1094 if (!hostkey->priv_base64) {
1095 ERRMEM;
1096 return 1;
1097 }
1098
1099 return 0;
1100}
1101
1102static int
1103nc_server_configure_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op)
1104{
1105 struct nc_endpt *endpt;
1106 struct nc_hostkey *hostkey;
1107 int ret = 0;
1108
1109 assert(!strcmp(LYD_NAME(node), "cleartext-private-key"));
1110
1111 if ((equal_parent_name(node, 6, "ssh")) && (equal_parent_name(node, 8, "listen"))) {
1112 if (nc_server_get_endpt(node, &endpt, NULL)) {
1113 ret = 1;
1114 goto cleanup;
1115 }
1116 if (nc_server_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
1117 ret = 1;
1118 goto cleanup;
1119 }
1120
1121 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1122 ret = nc_server_replace_cleartext_private_key(node, hostkey);
1123 if (ret) {
1124 goto cleanup;
1125 }
1126 } else {
1127 nc_server_del_private_key(hostkey);
1128 }
1129 }
1130
1131cleanup:
1132 return ret;
1133}
1134
1135static int
1136nc_server_create_keystore_reference(const struct lyd_node *node, struct nc_hostkey *hostkey)
1137{
1138 uint16_t i;
1139 struct nc_keystore *ks = NULL;
1140
1141 /* lookup name */
1142 for (i = 0; i < server_opts.keystore_count; i++) {
1143 if (!strcmp(lyd_get_value(node), server_opts.keystore[i].name)) {
1144 ks = &server_opts.keystore[i];
1145 break;
1146 }
1147 }
1148
1149 if (!ks) {
1150 ERR(NULL, "Keystore (%s) not found.", lyd_get_value(node));
1151 return 1;
1152 }
1153
1154 hostkey->keystore = ks;
1155
1156 return 0;
1157}
1158
1159/* leaf */
1160static int
1161nc_server_configure_keystore_reference(const struct lyd_node *node, NC_OPERATION op)
1162{
1163 struct nc_endpt *endpt;
1164 struct nc_hostkey *hostkey;
1165 int ret = 0;
1166
1167 assert(!strcmp(LYD_NAME(node), "keystore-reference"));
1168
1169 if ((equal_parent_name(node, 4, "server-identity")) && (equal_parent_name(node, 7, "listen"))) {
1170 if (nc_server_get_endpt(node, &endpt, NULL)) {
1171 ret = 1;
1172 goto cleanup;
1173 }
1174 if (nc_server_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
1175 ret = 1;
1176 goto cleanup;
1177 }
1178
1179 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1180 ret = nc_server_create_keystore_reference(node, hostkey);
1181 if (ret) {
1182 goto cleanup;
1183 }
1184 } else {
1185 hostkey->keystore = NULL;
1186 }
1187 }
1188
1189cleanup:
1190 return ret;
1191}
1192
1193static int
1194nc_server_create_auth_key_public_key_list(const struct lyd_node *node, struct nc_client_auth *auth_client)
1195{
1196 int ret = 0;
1197 void *tmp;
1198
1199 assert(!strcmp(LYD_NAME(node), "public-key"));
1200
1201 tmp = realloc(auth_client->pubkeys, (auth_client->pubkey_count + 1) * sizeof *auth_client->pubkeys);
1202 if (!tmp) {
1203 ERRMEM;
1204 ret = 1;
1205 goto cleanup;
1206 }
1207 auth_client->pubkeys = tmp;
1208
1209 memset(&auth_client->pubkeys[auth_client->pubkey_count], 0, sizeof *auth_client->pubkeys);
1210
1211 node = lyd_child(node);
1212 assert(!strcmp(LYD_NAME(node), "name"));
1213
1214 auth_client->pubkeys[auth_client->pubkey_count].name = strdup(lyd_get_value(node));
1215 if (!auth_client->pubkeys[auth_client->pubkey_count].name) {
1216 ERRMEM;
1217 ret = 1;
1218 goto cleanup;
1219 }
1220
1221 ++auth_client->pubkey_count;
1222
1223cleanup:
1224 return ret;
1225}
1226
1227static int
1228nc_server_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct nc_client_auth_pubkey *pubkey)
1229{
1230 nc_server_del_auth_client_pubkey_pub_base64(pubkey);
1231
1232 pubkey->pub_base64 = strdup(lyd_get_value(node));
1233 if (!pubkey->pub_base64) {
1234 ERRMEM;
1235 return 1;
1236 }
1237
1238 return 0;
1239}
1240
1241static int
1242nc_server_replace_host_key_public_key(const struct lyd_node *node, struct nc_hostkey *hostkey)
1243{
1244 nc_server_del_public_key(hostkey);
1245
1246 hostkey->pub_base64 = strdup(lyd_get_value(node));
1247 if (!hostkey->pub_base64) {
1248 ERRMEM;
1249 return 1;
1250 }
1251
1252 return 0;
1253}
1254
1255static int
1256nc_server_configure_public_key(const struct lyd_node *node, NC_OPERATION op)
1257{
1258 struct nc_endpt *endpt;
1259 struct nc_hostkey *hostkey;
1260 struct nc_client_auth *auth_client;
1261 struct nc_client_auth_pubkey *pubkey;
1262 int ret = 0;
1263
1264 assert(!strcmp(LYD_NAME(node), "public-key"));
1265
1266 if ((equal_parent_name(node, 3, "host-key")) && (equal_parent_name(node, 8, "listen"))) {
1267 /* server's public-key, mandatory leaf */
1268 if (nc_server_get_endpt(node, &endpt, NULL)) {
1269 ret = 1;
1270 goto cleanup;
1271 }
1272
1273 if (nc_server_get_hostkey(node, endpt->opts.ssh, &hostkey)) {
1274 ret = 1;
1275 goto cleanup;
1276 }
1277
1278 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1279 ret = nc_server_replace_host_key_public_key(node, hostkey);
1280 if (ret) {
1281 goto cleanup;
1282 }
1283 }
1284 } else if ((equal_parent_name(node, 5, "client-authentication")) && (equal_parent_name(node, 9, "listen"))) {
1285 /* client auth pubkeys, list */
1286 if (nc_server_get_endpt(node, &endpt, NULL)) {
1287 ret = 1;
1288 goto cleanup;
1289 }
1290
1291 if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
1292 ret = 1;
1293 goto cleanup;
1294 }
1295
1296 if (op == NC_OP_CREATE) {
1297 ret = nc_server_create_auth_key_public_key_list(node, auth_client);
1298 if (ret) {
1299 goto cleanup;
1300 }
1301 } else if (op == NC_OP_DELETE) {
1302 if (nc_server_get_pubkey(node, auth_client, &pubkey)) {
1303 ret = 1;
1304 goto cleanup;
1305 }
1306
1307 nc_server_del_auth_client_pubkey(auth_client, pubkey);
1308 }
1309 } else if ((equal_parent_name(node, 6, "client-authentication")) && (equal_parent_name(node, 10, "listen"))) {
1310 /* client auth pubkey, leaf */
1311 if (nc_server_get_endpt(node, &endpt, NULL)) {
1312 ret = 1;
1313 goto cleanup;
1314 }
1315
1316 if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
1317 ret = 1;
1318 goto cleanup;
1319 }
1320
1321 if (nc_server_get_pubkey(node, auth_client, &pubkey)) {
1322 ret = 1;
1323 goto cleanup;
1324 }
1325
1326 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1327 ret = nc_server_replace_auth_key_public_key_leaf(node, pubkey);
1328 if (ret) {
1329 goto cleanup;
1330 }
1331 } else {
1332 nc_server_del_auth_client_pubkey_pub_base64(pubkey);
1333 }
1334 }
1335
1336cleanup:
1337 return ret;
1338}
1339
1340static int
1341nc_server_create_user(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
1342{
1343 int ret = 0;
1344 void *tmp;
1345
1346 tmp = realloc(opts->auth_clients, (opts->client_count + 1) * sizeof *opts->auth_clients);
1347 if (!tmp) {
1348 ERRMEM;
1349 ret = 1;
1350 goto cleanup;
1351 }
1352 opts->auth_clients = tmp;
1353
1354 memset(&opts->auth_clients[opts->client_count], 0, sizeof *opts->auth_clients);
1355
1356 opts->auth_clients[opts->client_count].username = strdup(lyd_get_value(lyd_child(node)));
1357 if (!opts->auth_clients[opts->client_count].username) {
1358 ERRMEM;
1359 ret = 1;
1360 goto cleanup;
1361 }
1362
1363 lyd_find_path(node, "public-keys", 0, (struct lyd_node **)&node);
1364
1365 if (node) {
1366 /* set union selector */
1367 if (!lyd_find_path(node, "local-definition", 0, NULL)) {
1368 opts->auth_clients[opts->client_count].ks_type = NC_STORE_LOCAL;
1369 } else {
1370 opts->auth_clients[opts->client_count].ks_type = NC_STORE_TRUSTSTORE;
1371 }
1372 }
1373
1374 ++opts->client_count;
1375
1376cleanup:
1377 return ret;
1378}
1379
1380/* list */
1381static int
1382nc_server_configure_user(const struct lyd_node *node, NC_OPERATION op)
1383{
1384 struct nc_endpt *endpt;
1385 struct nc_client_auth *auth_client;
1386 int ret = 0;
1387
1388 assert(!strcmp(LYD_NAME(node), "user"));
1389
1390 if (equal_parent_name(node, 6, "listen")) {
1391 if (nc_server_get_endpt(node, &endpt, NULL)) {
1392 ret = 1;
1393 goto cleanup;
1394 }
1395
1396 if (op == NC_OP_CREATE) {
1397 ret = nc_server_create_user(node, endpt->opts.ssh);
1398 if (ret) {
1399 goto cleanup;
1400 }
1401 } else if (op == NC_OP_DELETE) {
1402 if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
1403 ret = 1;
1404 goto cleanup;
1405 }
1406
1407 nc_server_del_auth_client(endpt->opts.ssh, auth_client);
1408 }
1409 }
1410
1411cleanup:
1412 return ret;
1413}
1414
1415static int
1416nc_server_configure_auth_attempts(const struct lyd_node *node, NC_OPERATION op)
1417{
1418 struct nc_endpt *endpt;
1419 int ret = 0;
1420
1421 assert(!strcmp(LYD_NAME(node), "auth-attempts"));
1422
1423 if (equal_parent_name(node, 5, "listen")) {
1424 if (nc_server_get_endpt(node, &endpt, NULL)) {
1425 ret = 1;
1426 goto cleanup;
1427 }
1428
1429 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1430 endpt->opts.ssh->auth_attempts = strtoul(lyd_get_value(node), NULL, 10);
1431 }
1432 }
1433
1434cleanup:
1435 return ret;
1436}
1437
1438static int
1439nc_server_configure_auth_timeout(const struct lyd_node *node, NC_OPERATION op)
1440{
1441 struct nc_endpt *endpt;
1442 int ret = 0;
1443
1444 assert(!strcmp(LYD_NAME(node), "auth-timeout"));
1445
1446 if (equal_parent_name(node, 5, "listen")) {
1447 if (nc_server_get_endpt(node, &endpt, NULL)) {
1448 ret = 1;
1449 goto cleanup;
1450 }
1451
1452 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1453 endpt->opts.ssh->auth_timeout = strtoul(lyd_get_value(node), NULL, 10);
1454 }
1455 }
1456
1457cleanup:
1458 return ret;
1459}
1460
1461static int
1462nc_server_replace_truststore_reference(const struct lyd_node *node, struct nc_client_auth *client_auth)
1463{
1464 /*todo*/
1465 nc_server_del_truststore_reference(client_auth);
1466
1467 client_auth->ts_reference = strdup(lyd_get_value(node));
1468 if (!client_auth->ts_reference) {
1469 ERRMEM;
1470 return 1;
1471 }
1472
1473 return 0;
1474}
1475
1476/* leaf */
1477static int
1478nc_server_configure_truststore_reference(const struct lyd_node *node, NC_OPERATION op)
1479{
1480 struct nc_endpt *endpt;
1481 struct nc_client_auth *auth_client;
1482 int ret = 0;
1483
1484 assert(!strcmp(LYD_NAME(node), "truststore-reference"));
1485
1486 if ((equal_parent_name(node, 1, "public-keys")) && (equal_parent_name(node, 8, "listen"))) {
1487 if (nc_server_get_endpt(node, &endpt, NULL)) {
1488 ret = 1;
1489 goto cleanup;
1490 }
1491
1492 if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
1493 ret = 1;
1494 goto cleanup;
1495 }
1496
1497 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1498 ret = nc_server_replace_truststore_reference(node, auth_client);
1499 if (ret) {
1500 goto cleanup;
1501 }
1502 } else {
1503 nc_server_del_truststore_reference(auth_client);
1504 }
1505 }
1506
1507cleanup:
1508 return ret;
1509}
1510
1511static int
1512nc_server_replace_password(const struct lyd_node *node, struct nc_client_auth *auth_client)
1513{
1514 nc_server_del_auth_client_password(auth_client);
1515
1516 auth_client->password = strdup(lyd_get_value(node));
1517 if (!auth_client->password) {
1518 ERRMEM;
1519 return 1;
1520 }
1521
1522 return 0;
1523}
1524
1525/* leaf */
1526static int
1527nc_server_configure_password(const struct lyd_node *node, NC_OPERATION op)
1528{
1529 struct nc_endpt *endpt;
1530 struct nc_client_auth *auth_client;
1531 int ret = 0;
1532
1533 assert(!strcmp(LYD_NAME(node), "password"));
1534
1535 if (equal_parent_name(node, 7, "listen")) {
1536 if (nc_server_get_endpt(node, &endpt, NULL)) {
1537 ret = 1;
1538 goto cleanup;
1539 }
1540
1541 if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
1542 ret = 1;
1543 goto cleanup;
1544 }
1545
1546 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1547 ret = nc_server_replace_password(node, auth_client);
1548 if (ret) {
1549 goto cleanup;
1550 }
1551 } else {
1552 nc_server_del_auth_client_password(auth_client);
1553 }
1554 }
1555
1556cleanup:
1557 return ret;
1558}
1559
1560static int
1561nc_server_configure_pam_name(const struct lyd_node *node, NC_OPERATION op)
1562{
1563 struct nc_endpt *endpt;
1564 struct nc_client_auth *auth_client;
1565 int ret = 0;
1566
1567 assert(!strcmp(LYD_NAME(node), "pam-config-file-name"));
1568
1569 if (equal_parent_name(node, 8, "listen")) {
1570 if (nc_server_get_endpt(node, &endpt, NULL)) {
1571 ret = 1;
1572 goto cleanup;
1573 }
1574
1575 if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
1576 ret = 1;
1577 goto cleanup;
1578 }
1579
1580 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1581 nc_server_del_auth_client_pam_name(auth_client);
1582
1583 auth_client->pam_config_name = strdup(lyd_get_value(node));
1584 if (!auth_client->pam_config_name) {
1585 ERRMEM;
1586 ret = 1;
1587 goto cleanup;
1588 }
1589 }
1590 }
1591
1592cleanup:
1593 return ret;
1594}
1595
1596static int
1597nc_server_configure_pam_dir(const struct lyd_node *node, NC_OPERATION op)
1598{
1599 struct nc_endpt *endpt;
1600 struct nc_client_auth *auth_client;
1601 int ret = 0;
1602
1603 assert(!strcmp(LYD_NAME(node), "pam-config-file-dir"));
1604
1605 if (equal_parent_name(node, 8, "listen")) {
1606 if (nc_server_get_endpt(node, &endpt, NULL)) {
1607 ret = 1;
1608 goto cleanup;
1609 }
1610
1611 if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
1612 ret = 1;
1613 goto cleanup;
1614 }
1615
1616 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1617 nc_server_del_auth_client_pam_dir(auth_client);
1618 auth_client->pam_config_dir = strdup(lyd_get_value(node));
1619 if (!auth_client->pam_config_dir) {
1620 ERRMEM;
1621 ret = 1;
1622 goto cleanup;
1623 }
1624 }
1625 }
1626
1627cleanup:
1628 return ret;
1629}
1630
1631/* leaf */
1632static int
1633nc_server_configure_none(const struct lyd_node *node, NC_OPERATION op)
1634{
1635 struct nc_endpt *endpt;
1636 struct nc_client_auth *auth_client;
1637 int ret = 0;
1638
1639 assert(!strcmp(LYD_NAME(node), "none"));
1640
1641 if (equal_parent_name(node, 7, "listen")) {
1642 if (nc_server_get_endpt(node, &endpt, NULL)) {
1643 ret = 1;
1644 goto cleanup;
1645 }
1646
1647 if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) {
1648 ret = 1;
1649 goto cleanup;
1650 }
1651
1652 if (op == NC_OP_CREATE) {
1653 auth_client->supports_none = 1;
1654 } else {
1655 auth_client->supports_none = 0;
1656 }
1657 }
1658
1659cleanup:
1660 return ret;
1661}
1662
1663static int
1664nc_server_configure_transport_params(const char *alg, char **alg_store, NC_OPERATION op)
1665{
1666 int ret = 0, alg_found = 0;
1667 char *substr, *haystack;
1668 size_t alg_len = strlen(alg);
1669
1670 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1671 if (!*alg_store) {
1672 /* first call */
1673 *alg_store = strdup(alg);
1674 if (!*alg_store) {
1675 ERRMEM;
1676 ret = 1;
1677 goto cleanup;
1678 }
1679 } else {
1680 /* +1 because of ',' between algorithms */
1681 *alg_store = nc_realloc(*alg_store, strlen(*alg_store) + alg_len + 1 + 1);
1682 if (!*alg_store) {
1683 ERRMEM;
1684 ret = 1;
1685 goto cleanup;
1686 }
1687 sprintf(*alg_store, "%s,%s", *alg_store, alg);
1688 }
1689 } else {
1690 /* delete */
1691 haystack = *alg_store;
1692 while ((substr = strstr(haystack, alg))) {
1693 /* iterate over all the substrings */
1694 if (((substr == haystack) && (*(substr + alg_len) == ',')) ||
1695 ((substr != haystack) && (*(substr - 1) == ',') && (*(substr + alg_len) == ','))) {
1696 /* either the first element of the string or somewhere in the middle */
1697 memmove(substr, substr + alg_len + 1, strlen(substr + alg_len + 1));
1698 alg_found = 1;
1699 break;
1700 } else if ((*(substr - 1) == ',') && (*(substr + alg_len) == '\0')) {
1701 /* the last element of the string */
1702 *(substr - 1) = '\0';
1703 alg_found = 1;
1704 break;
1705 }
1706 haystack++;
1707 }
1708 if (!alg_found) {
1709 ERR(NULL, "Unable to delete an algorithm (%s), which was not previously added.", alg);
1710 ret = 1;
1711 }
1712 }
1713
1714cleanup:
1715 return ret;
1716}
1717
1718/* leaf-list */
1719static int
1720nc_server_configure_host_key_alg(const struct lyd_node *node, NC_OPERATION op)
1721{
1722 struct nc_endpt *endpt;
1723 int ret = 0, listen = 0;
1724 const char *alg;
1725 uint8_t i;
1726
1727 /* get the algorithm name and compare it with algs supported by libssh */
1728 alg = ((struct lyd_node_term *)node)->value.ident->name;
1729
1730 if (equal_parent_name(node, 6, "listen")) {
1731 listen = 1;
1732 if (nc_server_get_endpt(node, &endpt, NULL)) {
1733 ret = 1;
1734 goto cleanup;
1735 }
1736 }
1737
1738 i = 0;
1739 while (supported_hostkey_algs[i]) {
1740 if (!strcmp(supported_hostkey_algs[i], alg)) {
1741 if (listen) {
1742 if (nc_server_configure_transport_params(alg, &endpt->opts.ssh->hostkey_algs, op)) {
1743 ret = 1;
1744 goto cleanup;
1745 }
1746 }
1747 break;
1748 }
1749 i++;
1750 }
1751 if (!supported_hostkey_algs[i]) {
1752 /* algorithm not supported */
1753 ERR(NULL, "Public key algorithm (%s) not supported by libssh.", alg);
1754 ret = 1;
1755 }
1756
1757cleanup:
1758 return ret;
1759}
1760
1761/* leaf-list */
1762static int
1763nc_server_configure_kex_alg(const struct lyd_node *node, NC_OPERATION op)
1764{
1765 struct nc_endpt *endpt;
1766 int ret = 0, listen = 0;
1767 const char *alg;
1768 uint8_t i;
1769
1770 /* get the algorithm name and compare it with algs supported by libssh */
1771 alg = ((struct lyd_node_term *)node)->value.ident->name;
1772
1773 if (equal_parent_name(node, 6, "listen")) {
1774 listen = 1;
1775 if (nc_server_get_endpt(node, &endpt, NULL)) {
1776 ret = 1;
1777 goto cleanup;
1778 }
1779 }
1780
1781 i = 0;
1782 while (supported_kex_algs[i]) {
1783 if (!strcmp(supported_kex_algs[i], alg)) {
1784 if (listen) {
1785 if (nc_server_configure_transport_params(alg, &endpt->opts.ssh->kex_algs, op)) {
1786 ret = 1;
1787 goto cleanup;
1788 }
1789 }
1790 break;
1791 }
1792 i++;
1793 }
1794 if (!supported_kex_algs[i]) {
1795 /* algorithm not supported */
1796 ERR(NULL, "Key exchange algorithm (%s) not supported by libssh.", alg);
1797 ret = 1;
1798 }
1799
1800cleanup:
1801 return ret;
1802}
1803
1804/* leaf-list */
1805static int
1806nc_server_configure_encryption_alg(const struct lyd_node *node, NC_OPERATION op)
1807{
1808 struct nc_endpt *endpt;
1809 int ret = 0, listen = 0;
1810 const char *alg;
1811 uint8_t i;
1812
1813 /* get the algorithm name and compare it with algs supported by libssh */
1814 alg = ((struct lyd_node_term *)node)->value.ident->name;
1815
1816 if (equal_parent_name(node, 6, "listen")) {
1817 listen = 1;
1818 if (nc_server_get_endpt(node, &endpt, NULL)) {
1819 ret = 1;
1820 goto cleanup;
1821 }
1822 }
1823
1824 i = 0;
1825 while (supported_encryption_algs[i]) {
1826 if (!strcmp(supported_encryption_algs[i], alg)) {
1827 if (listen) {
1828 if (nc_server_configure_transport_params(alg, &endpt->opts.ssh->encryption_algs, op)) {
1829 ret = 1;
1830 goto cleanup;
1831 }
1832 }
1833 break;
1834 }
1835 i++;
1836 }
1837 if (!supported_encryption_algs[i]) {
1838 /* algorithm not supported */
1839 ERR(NULL, "Encryption algorithm (%s) not supported by libssh.", alg);
1840 ret = 1;
1841 }
1842
1843cleanup:
1844 return ret;
1845}
1846
1847/* leaf-list */
1848static int
1849nc_server_configure_mac_alg(const struct lyd_node *node, NC_OPERATION op)
1850{
1851 struct nc_endpt *endpt;
1852 int ret = 0, listen = 0;
1853 const char *alg;
1854 uint8_t i;
1855
1856 /* get the algorithm name and compare it with algs supported by libssh */
1857 alg = ((struct lyd_node_term *)node)->value.ident->name;
1858
1859 if (equal_parent_name(node, 6, "listen")) {
1860 listen = 1;
1861 if (nc_server_get_endpt(node, &endpt, NULL)) {
1862 ret = 1;
1863 goto cleanup;
1864 }
1865 }
1866
1867 i = 0;
1868 while (supported_mac_algs[i]) {
1869 if (!strcmp(supported_mac_algs[i], alg)) {
1870 if (listen) {
1871 if (nc_server_configure_transport_params(alg, &endpt->opts.ssh->mac_algs, op)) {
1872 ret = 1;
1873 goto cleanup;
1874 }
1875 }
1876 break;
1877 }
1878 i++;
1879 }
1880 if (!supported_mac_algs[i]) {
1881 /* algorithm not supported */
1882 ERR(NULL, "MAC algorithm (%s) not supported by libssh.", alg);
1883 ret = 1;
1884 }
1885
1886cleanup:
1887 return ret;
1888}
1889
1890static int
1891nc_server_configure(const struct lyd_node *node, NC_OPERATION op)
1892{
1893 const char *name = LYD_NAME(node);
1894
1895 if (!strcmp(name, "listen")) {
1896 if (nc_server_configure_listen(op)) {
1897 goto error;
1898 }
1899 } else if (!strcmp(name, "idle-timeout")) {
1900 if (nc_server_configure_idle_timeout(node, op)) {
1901 goto error;
1902 }
1903 } else if (!strcmp(name, "endpoint")) {
1904 if (nc_server_configure_endpoint(node, op)) {
1905 goto error;
1906 }
1907 } else if (!strcmp(name, "ssh")) {
1908 if (nc_server_configure_ssh(node, op)) {
1909 goto error;
1910 }
1911 } else if (!strcmp(name, "local-address")) {
1912 if (nc_server_configure_local_address(node, op)) {
1913 goto error;
1914 }
1915 } else if (!strcmp(name, "local-port")) {
1916 if (nc_server_configure_local_port(node, op)) {
1917 goto error;
1918 }
1919 } else if (!strcmp(name, "keepalives")) {
1920 if (nc_server_configure_keepalives(node, op)) {
1921 goto error;
1922 }
1923 } else if (!strcmp(name, "idle-time")) {
1924 if (nc_server_configure_idle_time(node, op)) {
1925 goto error;
1926 }
1927 } else if (!strcmp(name, "max-probes")) {
1928 if (nc_server_configure_max_probes(node, op)) {
1929 goto error;
1930 }
1931 } else if (!strcmp(name, "probe-interval")) {
1932 if (nc_server_configure_probe_interval(node, op)) {
1933 goto error;
1934 }
1935 } else if (!strcmp(name, "host-key")) {
1936 if (nc_server_configure_host_key(node, op)) {
1937 goto error;
1938 }
1939 } else if (!strcmp(name, "public-key-format")) {
1940 if (nc_server_configure_public_key_format(node, op)) {
1941 goto error;
1942 }
1943 } else if (!strcmp(name, "public-key")) {
1944 if (nc_server_configure_public_key(node, op)) {
1945 goto error;
1946 }
1947 } else if (!strcmp(name, "private-key-format")) {
1948 if (nc_server_configure_private_key_format(node, op)) {
1949 goto error;
1950 }
1951 } else if (!strcmp(name, "cleartext-private-key")) {
1952 if (nc_server_configure_cleartext_private_key(node, op)) {
1953 goto error;
1954 }
1955 } else if (!strcmp(name, "keystore-reference")) {
1956 if (nc_server_configure_keystore_reference(node, op)) {
1957 goto error;
1958 }
1959 } else if (!strcmp(name, "user")) {
1960 if (nc_server_configure_user(node, op)) {
1961 goto error;
1962 }
1963 } else if (!strcmp(name, "auth-attempts")) {
1964 if (nc_server_configure_auth_attempts(node, op)) {
1965 goto error;
1966 }
1967 } else if (!strcmp(name, "auth-timeout")) {
1968 if (nc_server_configure_auth_timeout(node, op)) {
1969 goto error;
1970 }
1971 } else if (!strcmp(name, "truststore-reference")) {
1972 if (nc_server_configure_truststore_reference(node, op)) {
1973 goto error;
1974 }
1975 } else if (!strcmp(name, "password")) {
1976 if (nc_server_configure_password(node, op)) {
1977 goto error;
1978 }
1979 } else if (!strcmp(name, "pam-config-file-name")) {
1980 if (nc_server_configure_pam_name(node, op)) {
1981 goto error;
1982 }
1983 } else if (!strcmp(name, "pam-config-file-dir")) {
1984 if (nc_server_configure_pam_dir(node, op)) {
1985 goto error;
1986 }
1987 } else if (!strcmp(name, "none")) {
1988 if (nc_server_configure_none(node, op)) {
1989 goto error;
1990 }
1991 } else if (!strcmp(name, "host-key-alg")) {
1992 if (nc_server_configure_host_key_alg(node, op)) {
1993 goto error;
1994 }
1995 } else if (!strcmp(name, "key-exchange-alg")) {
1996 if (nc_server_configure_kex_alg(node, op)) {
1997 goto error;
1998 }
1999 } else if (!strcmp(name, "encryption-alg")) {
2000 if (nc_server_configure_encryption_alg(node, op)) {
2001 goto error;
2002 }
2003 } else if (!strcmp(name, "mac-alg")) {
2004 if (nc_server_configure_mac_alg(node, op)) {
2005 goto error;
2006 }
2007 } 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,
2008 "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,
2009 "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,
2010 "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,
2011 "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,
2012 "id")) {} else if (!strcmp(name, "fingerprint")) {} else if (!strcmp(name, "map-type")) {}
2013
2014 return 0;
2015
2016error:
2017 ERR(NULL, "Configuring (%s) failed.", LYD_NAME(node));
2018 return 1;
2019}
2020
2021int
2022nc_session_server_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op)
2023{
2024 struct lyd_node *child;
2025 struct lyd_meta *m;
2026 NC_OPERATION current_op;
2027
2028 assert(node);
2029
2030 /* get current op */
2031 LY_LIST_FOR(node->meta, m) {
2032 if (!strcmp(m->name, "operation")) {
2033 if (!strcmp(lyd_get_meta_value(m), "create")) {
2034 current_op = NC_OP_CREATE;
2035 } else if (!strcmp(lyd_get_meta_value(m), "delete")) {
2036 current_op = NC_OP_DELETE;
2037 } else if (!strcmp(lyd_get_meta_value(m), "replace")) {
2038 current_op = NC_OP_REPLACE;
2039 } else if (!strcmp(lyd_get_meta_value(m), "none")) {
2040 current_op = NC_OP_NONE;
2041 }
2042 break;
2043 }
2044 }
2045
2046 /* node has no op, inherit from the parent */
2047 if (!m) {
2048 current_op = parent_op;
2049 }
2050
2051 switch (current_op) {
2052 case NC_OP_NONE:
2053 break;
2054 case NC_OP_CREATE:
2055 case NC_OP_DELETE:
2056 case NC_OP_REPLACE:
2057 if (nc_server_configure(node, current_op)) {
2058 return 1;
2059 }
2060 break;
2061 default:
2062 break;
2063 }
2064
2065 if (current_op != NC_OP_DELETE) {
2066 LY_LIST_FOR(lyd_child(node), child) {
2067 if (nc_session_server_parse_tree(child, current_op)) {
2068 return 1;
2069 }
2070 }
2071 }
2072 return 0;
2073}
2074
2075static int
2076nc_server_configure_certificates(const struct lyd_node *node, struct nc_keystore *ks)
2077{
2078 int ret = 0;
2079 uint16_t cert_count;
2080 void *tmp;
2081
2082 node = node->next;
2083 if ((!node) || (strcmp(LYD_NAME(node), "certificate"))) {
2084 WRN(NULL, "Certificates container is empty");
2085 goto cleanup;
2086 }
2087
2088 /* certificate list */
2089 while (node) {
2090 cert_count = ks->cert_count;
2091 tmp = realloc(ks->certs, cert_count + 1);
2092 if (!tmp) {
2093 ERRMEM;
2094 ret = 1;
2095 goto cleanup;
2096 }
2097 ks->certs = tmp;
2098
2099 ks->certs[cert_count].name = strdup(lyd_get_value(lyd_child(node)));
2100 if (!ks->certs[cert_count].name) {
2101 ERRMEM;
2102 ret = 1;
2103 goto cleanup;
2104 }
2105
2106 ks->certs[cert_count].cert_data = strdup(lyd_get_value(lyd_child(node)->next));
2107 if (!ks->certs[cert_count].cert_data) {
2108 ERRMEM;
2109 free(ks->certs[cert_count].name);
2110 ret = 1;
2111 goto cleanup;
2112 }
2113
2114 ks->cert_count++;
2115 }
2116
2117cleanup:
2118 if (ret) {
2119 for (cert_count = 0; cert_count < ks->cert_count; cert_count++) {
2120 free(ks->certs[cert_count].name);
2121 free(ks->certs[cert_count].cert_data);
2122 }
2123 free(ks->certs);
2124 }
2125 return ret;
2126}
2127
2128static int
2129nc_fill_keystore(const struct lyd_node *data)
2130{
2131 int ret = 0;
2132 uint32_t prev_lo;
2133 struct lyd_node *tree, *node, *iter, *iter_tmp;
2134 void *tmp;
2135 struct nc_keystore *ks;
2136
2137 /* silently search for keystore node */
2138 prev_lo = ly_log_options(0);
2139 ret = lyd_find_path(data, "/ks:keystore", 0, &tree);
2140 ly_log_options(prev_lo);
2141 if (ret) {
2142 WRN(NULL, "Keystore container not found in the YANG data.");
2143 return 0;
2144 }
2145
2146 /* asymmetric keys container */
2147 lyd_find_path(tree, "asymmetric-keys", 0, (struct lyd_node **)&node);
2148 if (!node) {
2149 WRN(NULL, "Asymmetric keys container not found in the YANG data.");
2150 return 0;
2151 }
2152
2153 /* asymmetric key list */
2154 lyd_find_path(node, "asymmetric-key", 0, (struct lyd_node **)&node);
2155 if (!node) {
2156 WRN(NULL, "Asymmetric keys container is empty.");
2157 return 0;
2158 }
2159
2160 LY_LIST_FOR(node, iter) {
2161 tmp = realloc(server_opts.keystore, server_opts.keystore_count + 1);
2162 if (!tmp) {
2163 ERRMEM;
2164 goto fail;
2165 }
2166 server_opts.keystore = tmp;
2167 ks = &server_opts.keystore[server_opts.keystore_count];
2168
2169 iter_tmp = iter;
2170 /* name */
2171 iter_tmp = lyd_child(iter_tmp);
2172 ks->name = strdup(lyd_get_value(iter_tmp));
2173 if (!ks->name) {
2174 ERRMEM;
2175 goto fail;
2176 }
2177
2178 /* mandatory public-key-format */
2179 iter_tmp = iter_tmp->next;
2180 if (nc_server_configure_public_key_format(iter_tmp, 0)) {
2181 free(ks->name);
2182 goto fail;
2183 }
2184
2185 /* mandatory public-key */
2186 iter_tmp = iter_tmp->next;
2187 ks->pub_base64 = strdup(lyd_get_value(iter_tmp));
2188 if (!ks->pub_base64) {
2189 free(ks->name);
2190 ERRMEM;
2191 goto fail;
2192 }
2193
2194 iter_tmp = iter_tmp->next;
2195 while (iter_tmp) {
2196 if (!strcmp(LYD_NAME(iter_tmp), "private-key-format")) {
2197 if (nc_server_configure_private_key_format(iter_tmp, 0)) {
2198 goto fail;
2199 }
2200 } else if (!strcmp(LYD_NAME(iter_tmp), "private-key-type")) {
2201 if ((!strcmp(LYD_NAME(lyd_child(iter_tmp)), "cleartext-private-key")) &&
2202 (!strcmp(LYD_NAME(lyd_child(lyd_child(iter_tmp))), "cleartext-private-key"))) {
2203 ks->priv_base64 = strdup(lyd_get_value(lyd_child(lyd_child(iter_tmp))));
2204 if (!ks->priv_base64) {
2205 ERRMEM;
2206 goto fail;
2207 }
2208 }
2209 } else if (!strcmp(LYD_NAME(iter_tmp), "certificates")) {
2210 if (nc_server_configure_certificates(iter_tmp, ks)) {
2211 goto fail;
2212 }
2213 }
2214 /* todo CSR? */
2215 iter_tmp = iter_tmp->next;
2216 }
2217
2218 server_opts.keystore_count++;
2219 }
2220
2221 return 0;
2222
2223fail:
2224 free(server_opts.keystore);
2225 return 1;
2226}
2227
2228API int
2229nc_server_config_load_modules(struct ly_ctx **ctx)
2230{
2231 int i, new_ctx = 0;
2232
2233 if (!*ctx) {
2234 if (ly_ctx_new(NC_SERVER_SEARCH_DIR, 0, ctx)) {
2235 ERR(NULL, "Couldn't create new libyang context.\n");
2236 goto error;
2237 }
2238 new_ctx = 1;
2239 }
2240
2241 /* all features */
2242 const char *ietf_nectonf_server[] = {"ssh-listen", "tls-listen", "ssh-call-home", "tls-call-home", "central-netconf-server-supported", NULL};
2243 /* all features */
2244 const char *ietf_x509_cert_to_name[] = {NULL};
2245 /* no private-key-encryption and csr-generation */
2246 const char *ietf_crypto_types[] = {
2247 "one-symmetric-key-format", "one-asymmetric-key-format", "symmetrically-encrypted-value-format",
2248 "asymmetrically-encrypted-value-format", "cms-enveloped-data-format", "cms-encrypted-data-format",
2249 "p10-based-csrs", "certificate-expiration-notification", "hidden-keys", "password-encryption",
2250 "symmetric-key-encryption", NULL
2251 };
2252 /* all features */
2253 const char *ietf_tcp_common[] = {"keepalives-supported", NULL};
2254 /* no ssh-x509-certs */
2255 const char *ietf_ssh_common[] = {"transport-params", "public-key-generation", NULL};
2256 /* all features */
2257 const char *iana_ssh_encryption_algs[] = {NULL};
2258 /* all features */
2259 const char *iana_ssh_key_exchange_algs[] = {NULL};
2260 /* all features */
2261 const char *iana_ssh_mac_algs[] = {NULL};
2262 /* all features */
2263 const char *iana_ssh_public_key_algs[] = {NULL};
2264 /* all features */
2265 const char *ietf_keystore[] = {"central-keystore-supported", "local-definitions-supported", "asymmetric-keys", "symmetric-keys", NULL};
2266 /* no ssh-server-keepalives and local-user-auth-hostbased */
2267 const char *ietf_ssh_server[] = {"local-users-supported", "local-user-auth-publickey", "local-user-auth-password", "local-user-auth-none", NULL};
2268 /* all features */
2269 const char *ietf_truststore[] = {"central-truststore-supported", "local-definitions-supported", "certificates", "public-keys", NULL};
2270 /* all features */
2271 const char *ietf_tls_server[] = {
2272 "tls-server-keepalives", "server-ident-x509-cert", "server-ident-raw-public-key", "server-ident-tls12-psk",
2273 "server-ident-tls13-epsk", "client-auth-supported", "client-auth-x509-cert", "client-auth-raw-public-key",
2274 "client-auth-tls12-psk", "client-auth-tls13-epsk", NULL
2275 };
2276 /* all features */
2277 const char *libnetconf2_netconf_server[] = {NULL};
2278
2279 const char *module_names[] = {
2280 "ietf-netconf-server", "ietf-x509-cert-to-name", "ietf-crypto-types",
2281 "ietf-tcp-common", "ietf-ssh-common", "iana-ssh-encryption-algs",
2282 "iana-ssh-key-exchange-algs", "iana-ssh-mac-algs", "iana-ssh-public-key-algs",
2283 "ietf-keystore", "ietf-ssh-server", "ietf-truststore",
2284 "ietf-tls-server", "libnetconf2-netconf-server", NULL
2285 };
2286
2287 const char **module_features[] = {
2288 ietf_nectonf_server, ietf_x509_cert_to_name, ietf_crypto_types,
2289 ietf_tcp_common, ietf_ssh_common, iana_ssh_encryption_algs,
2290 iana_ssh_key_exchange_algs, iana_ssh_mac_algs, iana_ssh_public_key_algs,
2291 ietf_keystore, ietf_ssh_server, ietf_truststore,
2292 ietf_tls_server, libnetconf2_netconf_server, NULL
2293 };
2294
2295 for (i = 0; module_names[i] != NULL; i++) {
2296 if (!ly_ctx_load_module(*ctx, module_names[i], NULL, module_features[i])) {
2297 ERR(NULL, "Loading module \"%s\" failed.\n", module_names[i]);
2298 goto error;
2299 }
2300 }
2301
2302 return 0;
2303
2304error:
2305 if (new_ctx) {
2306 ly_ctx_destroy(*ctx);
2307 *ctx = NULL;
2308 }
2309 return 1;
2310}
2311
2312API int
2313nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path)
2314{
2315 struct lyd_node *tree = NULL;
2316 int ret = 0;
2317
2318 if (!path) {
2319 ERRARG("Missing path parameter.");
2320 ret = 1;
2321 goto cleanup;
2322 }
2323
2324 ret = lyd_parse_data_path(ctx, path, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree);
2325 if (ret) {
2326 goto cleanup;
2327 }
2328
2329 ret = nc_server_config_setup(tree);
2330 if (ret) {
2331 goto cleanup;
2332 }
2333
2334cleanup:
2335 lyd_free_all(tree);
2336 return ret;
2337}
2338
2339API int
2340nc_server_config_setup(const struct lyd_node *data)
2341{
2342 int ret = 0;
2343 struct lyd_node *tree;
2344 struct lyd_meta *m;
2345 NC_OPERATION op;
2346
2347 /* LOCK */
2348 pthread_rwlock_wrlock(&server_opts.config_lock);
2349
2350 ret = nc_fill_keystore(data);
2351 if (ret) {
2352 ERR(NULL, "Filling keystore failed.");
2353 goto cleanup;
2354 }
2355
2356 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &tree);
2357 if (ret) {
2358 ERR(NULL, "Unable to find the netconf-server container in the YANG data.");
2359 goto cleanup;
2360 }
2361
2362 LY_LIST_FOR(tree->meta, m) {
2363 if (!strcmp(m->name, "operation")) {
2364 if (!strcmp(lyd_get_meta_value(m), "create")) {
2365 op = NC_OP_CREATE;
2366 } else if (!strcmp(lyd_get_meta_value(m), "delete")) {
2367 op = NC_OP_DELETE;
2368 } else if (!strcmp(lyd_get_meta_value(m), "replace")) {
2369 op = NC_OP_REPLACE;
2370 } else if (!strcmp(lyd_get_meta_value(m), "none")) {
2371 op = NC_OP_NONE;
2372 } else {
2373 ERR(NULL, "Unexpected operation (%s).", lyd_get_meta_value(m));
2374 ret = 1;
2375 goto cleanup;
2376 }
2377 }
2378 }
2379
2380 if (nc_session_server_parse_tree(tree, op)) {
2381 ret = 1;
2382 goto cleanup;
2383 }
2384
2385cleanup:
2386 /* UNLOCK */
2387 pthread_rwlock_unlock(&server_opts.config_lock);
2388 return ret;
2389}