blob: ce67f576f7020ff795ddbf98f3b66f5d3b0d9782 [file] [log] [blame]
romanc1d2b092023-02-02 08:58:27 +01001/**
romane028ef92023-02-24 16:33:08 +01002 * @file server_config.c
romanc1d2b092023-02-02 08:58:27 +01003 * @author Roman Janota <janota@cesnet.cz>
4 * @brief libnetconf2 server configuration functions
5 *
6 * @copyright
romanf02273a2023-05-25 09:44:11 +02007 * Copyright (c) 2022-2023 CESNET, z.s.p.o.
romanc1d2b092023-02-02 08:58:27 +01008 *
9 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * https://opensource.org/licenses/BSD-3-Clause
14 */
roman27215242023-03-10 14:55:00 +010015
16#define _GNU_SOURCE
17
romanc1d2b092023-02-02 08:58:27 +010018#include <assert.h>
roman12644fe2023-06-08 11:06:42 +020019#include <ctype.h>
roman3f9b65c2023-06-05 14:26:58 +020020#include <pthread.h>
21#include <stdint.h>
romanc1d2b092023-02-02 08:58:27 +010022#include <stdlib.h>
23#include <string.h>
roman2eab4742023-06-06 10:00:26 +020024#include <unistd.h>
romanc1d2b092023-02-02 08:58:27 +010025
roman3f9b65c2023-06-05 14:26:58 +020026#include <libyang/libyang.h>
romana3c95c72023-10-26 11:15:53 +020027#include <libyang/tree_data.h>
roman3f9b65c2023-06-05 14:26:58 +020028
romanfaecc582023-06-15 16:13:31 +020029#ifdef NC_ENABLED_SSH_TLS
roman13145912023-08-17 15:36:54 +020030#include <openssl/err.h>
31#include <openssl/evp.h> // EVP_PKEY_free
32#include <openssl/x509.h> // d2i_PUBKEY
romanfaecc582023-06-15 16:13:31 +020033#include <openssl/x509_vfy.h> // X509_STORE_free
34#endif
35
romanc1d2b092023-02-02 08:58:27 +010036#include "compat.h"
roman3f9b65c2023-06-05 14:26:58 +020037#include "config.h"
38#include "log_p.h"
romane028ef92023-02-24 16:33:08 +010039#include "server_config.h"
romanf02273a2023-05-25 09:44:11 +020040#include "server_config_p.h"
roman3f9b65c2023-06-05 14:26:58 +020041#include "session_p.h"
42
roman2eab4742023-06-06 10:00:26 +020043#ifdef NC_ENABLED_SSH_TLS
romanc1d2b092023-02-02 08:58:27 +010044
45/* All libssh supported host-key, key-exchange, encryption and mac algorithms as of version 0.10.90 */
46
47static const char *supported_hostkey_algs[] = {
romana6bf6ab2023-05-26 13:26:02 +020048 "openssh-ssh-ed25519-cert-v01", "openssh-ecdsa-sha2-nistp521-cert-v01",
49 "openssh-ecdsa-sha2-nistp384-cert-v01", "openssh-ecdsa-sha2-nistp256-cert-v01",
50 "openssh-rsa-sha2-512-cert-v01", "openssh-rsa-sha2-256-cert-v01",
51 "openssh-ssh-rsa-cert-v01", "openssh-ssh-dss-cert-v01",
romanc1d2b092023-02-02 08:58:27 +010052 "ssh-ed25519", "ecdsa-sha2-nistp521", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp256",
53 "rsa-sha2-512", "rsa-sha2-256", "ssh-rsa", "ssh-dss", NULL
54};
55
56static const char *supported_kex_algs[] = {
romana6bf6ab2023-05-26 13:26:02 +020057 "diffie-hellman-group-exchange-sha1", "curve25519-sha256", "libssh-curve25519-sha256",
romanc1d2b092023-02-02 08:58:27 +010058 "ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", "diffie-hellman-group18-sha512",
59 "diffie-hellman-group16-sha512", "diffie-hellman-group-exchange-sha256", "diffie-hellman-group14-sha256", NULL
60};
61
62static const char *supported_encryption_algs[] = {
romana6bf6ab2023-05-26 13:26:02 +020063 "openssh-chacha20-poly1305", "openssh-aes256-gcm", "openssh-aes128-gcm",
romanc1d2b092023-02-02 08:58:27 +010064 "aes256-ctr", "aes192-ctr", "aes128-ctr", "aes256-cbc", "aes192-cbc", "aes128-cbc",
roman27215242023-03-10 14:55:00 +010065 "blowfish-cbc", "triple-des-cbc", "none", NULL
romanc1d2b092023-02-02 08:58:27 +010066};
67
68static const char *supported_mac_algs[] = {
romana6bf6ab2023-05-26 13:26:02 +020069 "openssh-hmac-sha2-256-etm", "openssh-hmac-sha2-512-etm", "openssh-hmac-sha1-etm",
romanc1d2b092023-02-02 08:58:27 +010070 "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1", NULL
71};
72
roman2eab4742023-06-06 10:00:26 +020073#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +020074
romanc1d2b092023-02-02 08:58:27 +010075extern struct nc_server_opts server_opts;
76
roman6430c152023-10-12 11:28:47 +020077/* returns true if a node is a part of the listen subtree */
roman4cb8bb12023-06-29 09:16:46 +020078static int
79is_listen(const struct lyd_node *node)
80{
81 assert(node);
82
83 while (node) {
84 if (!strcmp(LYD_NAME(node), "listen")) {
85 break;
86 }
87 node = lyd_parent(node);
88 }
89
90 return node != NULL;
91}
92
roman6430c152023-10-12 11:28:47 +020093/* returns true if a node is a part of the Call Home subtree */
roman4cb8bb12023-06-29 09:16:46 +020094static int
95is_ch(const struct lyd_node *node)
96{
97 assert(node);
98
99 while (node) {
100 if (!strcmp(LYD_NAME(node), "call-home")) {
101 break;
102 }
103 node = lyd_parent(node);
104 }
105
106 return node != NULL;
107}
108
109#ifdef NC_ENABLED_SSH_TLS
110
roman6430c152023-10-12 11:28:47 +0200111/* returns true if a node is a part of the ssh subtree */
roman4cb8bb12023-06-29 09:16:46 +0200112static int
113is_ssh(const struct lyd_node *node)
114{
115 assert(node);
116
117 while (node) {
118 if (!strcmp(LYD_NAME(node), "ssh")) {
119 break;
120 }
121 node = lyd_parent(node);
122 }
123
124 return node != NULL;
125}
126
roman6430c152023-10-12 11:28:47 +0200127/* returns true if a node is a part of the tls subtree */
roman4cb8bb12023-06-29 09:16:46 +0200128static int
129is_tls(const struct lyd_node *node)
130{
131 assert(node);
132
133 while (node) {
134 if (!strcmp(LYD_NAME(node), "tls")) {
135 break;
136 }
137 node = lyd_parent(node);
138 }
139
140 return node != NULL;
141}
142
143#endif /* NC_ENABLED_SSH_TLS */
144
roman6430c152023-10-12 11:28:47 +0200145/* gets the endpoint struct (and optionally bind) based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200146static int
romanf02273a2023-05-25 09:44:11 +0200147nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, struct nc_bind **bind)
romanc1d2b092023-02-02 08:58:27 +0100148{
149 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200150 const char *name;
romanc1d2b092023-02-02 08:58:27 +0100151
roman4cb8bb12023-06-29 09:16:46 +0200152 assert(node && endpt);
romanb9beb112023-07-18 09:06:58 +0200153 name = LYD_NAME(node);
romanc1d2b092023-02-02 08:58:27 +0100154
155 while (node) {
156 if (!strcmp(LYD_NAME(node), "endpoint")) {
157 break;
158 }
159 node = lyd_parent(node);
160 }
161
162 if (!node) {
romanb9beb112023-07-18 09:06:58 +0200163 ERR(NULL, "Node \"%s\" is not contained in an endpoint subtree.", name);
romanc1d2b092023-02-02 08:58:27 +0100164 return 1;
165 }
166
167 node = lyd_child(node);
168 assert(!strcmp(LYD_NAME(node), "name"));
romanb9beb112023-07-18 09:06:58 +0200169 name = lyd_get_value(node);
romanc1d2b092023-02-02 08:58:27 +0100170
171 for (i = 0; i < server_opts.endpt_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200172 if (!strcmp(server_opts.endpts[i].name, name)) {
romanc1d2b092023-02-02 08:58:27 +0100173 *endpt = &server_opts.endpts[i];
174 if (bind) {
175 *bind = &server_opts.binds[i];
176 }
177 return 0;
178 }
179 }
180
romanb9beb112023-07-18 09:06:58 +0200181 ERR(NULL, "Endpoint \"%s\" was not found.", name);
romanc1d2b092023-02-02 08:58:27 +0100182 return 1;
183}
184
roman6430c152023-10-12 11:28:47 +0200185/* gets the ch_client struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200186static int
roman5cbb6532023-06-22 12:53:17 +0200187nc_server_config_get_ch_client(const struct lyd_node *node, struct nc_ch_client **ch_client)
188{
189 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200190 const char *name;
roman5cbb6532023-06-22 12:53:17 +0200191
roman4cb8bb12023-06-29 09:16:46 +0200192 assert(node && ch_client);
romanb9beb112023-07-18 09:06:58 +0200193 name = LYD_NAME(node);
roman4cb8bb12023-06-29 09:16:46 +0200194
roman5cbb6532023-06-22 12:53:17 +0200195 while (node) {
196 if (!strcmp(LYD_NAME(node), "netconf-client")) {
197 break;
198 }
199 node = lyd_parent(node);
200 }
201
202 if (!node) {
romanb9beb112023-07-18 09:06:58 +0200203 ERR(NULL, "Node \"%s\" is not contained in a netconf-client subtree.", name);
roman5cbb6532023-06-22 12:53:17 +0200204 return 1;
205 }
206
207 node = lyd_child(node);
208 assert(!strcmp(LYD_NAME(node), "name"));
romanb9beb112023-07-18 09:06:58 +0200209 name = lyd_get_value(node);
roman5cbb6532023-06-22 12:53:17 +0200210
romanb9beb112023-07-18 09:06:58 +0200211 /* LOCK */
212 pthread_rwlock_rdlock(&server_opts.ch_client_lock);
roman5cbb6532023-06-22 12:53:17 +0200213 for (i = 0; i < server_opts.ch_client_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200214 if (!strcmp(server_opts.ch_clients[i].name, name)) {
roman5cbb6532023-06-22 12:53:17 +0200215 *ch_client = &server_opts.ch_clients[i];
romanb9beb112023-07-18 09:06:58 +0200216 /* UNLOCK */
217 pthread_rwlock_unlock(&server_opts.ch_client_lock);
roman5cbb6532023-06-22 12:53:17 +0200218 return 0;
219 }
220 }
221
romanb9beb112023-07-18 09:06:58 +0200222 /* UNLOCK */
223 pthread_rwlock_unlock(&server_opts.ch_client_lock);
224 ERR(NULL, "Call-home client \"%s\" was not found.", name);
roman5cbb6532023-06-22 12:53:17 +0200225 return 1;
226}
227
roman6430c152023-10-12 11:28:47 +0200228/* gets the ch_endpt struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200229static int
230nc_server_config_get_ch_endpt(const struct lyd_node *node, struct nc_ch_endpt **ch_endpt)
roman5cbb6532023-06-22 12:53:17 +0200231{
232 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200233 const char *name;
roman4cb8bb12023-06-29 09:16:46 +0200234 struct nc_ch_client *ch_client;
235
236 assert(node && ch_endpt);
romanb9beb112023-07-18 09:06:58 +0200237 name = LYD_NAME(node);
roman4cb8bb12023-06-29 09:16:46 +0200238
239 if (nc_server_config_get_ch_client(node, &ch_client)) {
240 return 1;
241 }
roman5cbb6532023-06-22 12:53:17 +0200242
243 while (node) {
244 if (!strcmp(LYD_NAME(node), "endpoint")) {
245 break;
246 }
247 node = lyd_parent(node);
248 }
249
250 if (!node) {
romanb9beb112023-07-18 09:06:58 +0200251 ERR(NULL, "Node \"%s\" is not contained in a call-home endpoint subtree.", name);
roman5cbb6532023-06-22 12:53:17 +0200252 return 1;
253 }
254
255 node = lyd_child(node);
256 assert(!strcmp(LYD_NAME(node), "name"));
romanb9beb112023-07-18 09:06:58 +0200257 name = lyd_get_value(node);
roman5cbb6532023-06-22 12:53:17 +0200258
roman6430c152023-10-12 11:28:47 +0200259 /* LOCK */
260 pthread_rwlock_rdlock(&server_opts.ch_client_lock);
roman5cbb6532023-06-22 12:53:17 +0200261 for (i = 0; i < ch_client->ch_endpt_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200262 if (!strcmp(ch_client->ch_endpts[i].name, name)) {
roman5cbb6532023-06-22 12:53:17 +0200263 *ch_endpt = &ch_client->ch_endpts[i];
roman6430c152023-10-12 11:28:47 +0200264 /* UNLOCK */
265 pthread_rwlock_unlock(&server_opts.ch_client_lock);
roman5cbb6532023-06-22 12:53:17 +0200266 return 0;
267 }
268 }
269
roman6430c152023-10-12 11:28:47 +0200270 /* UNLOCK */
271 pthread_rwlock_unlock(&server_opts.ch_client_lock);
romanb9beb112023-07-18 09:06:58 +0200272 ERR(NULL, "Call-home client's \"%s\" endpoint \"%s\" was not found.", ch_client->name, name);
roman5cbb6532023-06-22 12:53:17 +0200273 return 1;
274}
275
roman6430c152023-10-12 11:28:47 +0200276#ifdef NC_ENABLED_SSH_TLS
277
278/* gets the ssh_opts struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200279static int
280nc_server_config_get_ssh_opts(const struct lyd_node *node, struct nc_server_ssh_opts **opts)
281{
282 struct nc_endpt *endpt;
283 struct nc_ch_endpt *ch_endpt;
roman3f9b65c2023-06-05 14:26:58 +0200284
roman4cb8bb12023-06-29 09:16:46 +0200285 assert(node && opts);
286
287 if (is_listen(node)) {
288 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
289 return 1;
290 }
291 *opts = endpt->opts.ssh;
292 } else {
293 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
294 return 1;
295 }
296 *opts = ch_endpt->opts.ssh;
297 }
298
299 return 0;
300}
301
roman6430c152023-10-12 11:28:47 +0200302/* gets the hostkey struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200303static int
304nc_server_config_get_hostkey(const struct lyd_node *node, struct nc_hostkey **hostkey)
romanc1d2b092023-02-02 08:58:27 +0100305{
306 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200307 const char *name;
roman4cb8bb12023-06-29 09:16:46 +0200308 struct nc_server_ssh_opts *opts;
romanc1d2b092023-02-02 08:58:27 +0100309
roman4cb8bb12023-06-29 09:16:46 +0200310 assert(node && hostkey);
romanb9beb112023-07-18 09:06:58 +0200311 name = LYD_NAME(node);
romanc1d2b092023-02-02 08:58:27 +0100312
313 while (node) {
314 if (!strcmp(LYD_NAME(node), "host-key")) {
315 break;
316 }
317 node = lyd_parent(node);
318 }
319
320 if (!node) {
romanb9beb112023-07-18 09:06:58 +0200321 ERR(NULL, "Node \"%s\" is not contained in a host-key subtree.", name);
romanc1d2b092023-02-02 08:58:27 +0100322 return 1;
323 }
324
325 node = lyd_child(node);
326 assert(!strcmp(LYD_NAME(node), "name"));
romanb9beb112023-07-18 09:06:58 +0200327 name = lyd_get_value(node);
romanc1d2b092023-02-02 08:58:27 +0100328
romanb9beb112023-07-18 09:06:58 +0200329 if (nc_server_config_get_ssh_opts(node, &opts)) {
330 return 1;
331 }
romanc1d2b092023-02-02 08:58:27 +0100332 for (i = 0; i < opts->hostkey_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200333 if (!strcmp(opts->hostkeys[i].name, name)) {
romanc1d2b092023-02-02 08:58:27 +0100334 *hostkey = &opts->hostkeys[i];
335 return 0;
336 }
337 }
338
romanb9beb112023-07-18 09:06:58 +0200339 ERR(NULL, "Host-key \"%s\" was not found.", name);
romanc1d2b092023-02-02 08:58:27 +0100340 return 1;
341}
342
roman6430c152023-10-12 11:28:47 +0200343/* gets the client_auth struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200344static int
roman6430c152023-10-12 11:28:47 +0200345nc_server_config_get_auth_client(const struct lyd_node *node, struct nc_auth_client **auth_client)
romanc1d2b092023-02-02 08:58:27 +0100346{
347 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200348 const char *name;
roman4cb8bb12023-06-29 09:16:46 +0200349 struct nc_server_ssh_opts *opts;
romanc1d2b092023-02-02 08:58:27 +0100350
roman4cb8bb12023-06-29 09:16:46 +0200351 assert(node && auth_client);
romanb9beb112023-07-18 09:06:58 +0200352 name = LYD_NAME(node);
romanc1d2b092023-02-02 08:58:27 +0100353
354 while (node) {
355 if (!strcmp(LYD_NAME(node), "user")) {
356 break;
357 }
358 node = lyd_parent(node);
359 }
360
361 if (!node) {
romanb9beb112023-07-18 09:06:58 +0200362 ERR(NULL, "Node \"%s\" is not contained in a client-authentication subtree.", name);
romanc1d2b092023-02-02 08:58:27 +0100363 return 1;
364 }
365
366 node = lyd_child(node);
367 assert(!strcmp(LYD_NAME(node), "name"));
romanb9beb112023-07-18 09:06:58 +0200368 name = lyd_get_value(node);
romanc1d2b092023-02-02 08:58:27 +0100369
romanb9beb112023-07-18 09:06:58 +0200370 if (nc_server_config_get_ssh_opts(node, &opts)) {
371 return 1;
372 }
romanc1d2b092023-02-02 08:58:27 +0100373 for (i = 0; i < opts->client_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200374 if (!strcmp(opts->auth_clients[i].username, name)) {
romanc1d2b092023-02-02 08:58:27 +0100375 *auth_client = &opts->auth_clients[i];
376 return 0;
377 }
378 }
379
romanb9beb112023-07-18 09:06:58 +0200380 ERR(NULL, "Authorized key \"%s\" was not found.", name);
romanc1d2b092023-02-02 08:58:27 +0100381 return 1;
382}
383
roman6430c152023-10-12 11:28:47 +0200384/* gets the pubkey struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200385static int
386nc_server_config_get_pubkey(const struct lyd_node *node, struct nc_public_key **pubkey)
romanc1d2b092023-02-02 08:58:27 +0100387{
388 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200389 const char *name;
roman6430c152023-10-12 11:28:47 +0200390 struct nc_auth_client *auth_client;
romanc1d2b092023-02-02 08:58:27 +0100391
roman4cb8bb12023-06-29 09:16:46 +0200392 assert(node && pubkey);
romanb9beb112023-07-18 09:06:58 +0200393 name = LYD_NAME(node);
romanc1d2b092023-02-02 08:58:27 +0100394
395 node = lyd_parent(node);
396 while (node) {
397 if (!strcmp(LYD_NAME(node), "public-key")) {
398 break;
399 }
400 node = lyd_parent(node);
401 }
402
403 if (!node) {
romanb9beb112023-07-18 09:06:58 +0200404 ERR(NULL, "Node \"%s\" is not contained in a public-key subtree.", name);
romanc1d2b092023-02-02 08:58:27 +0100405 return 1;
406 }
407
408 node = lyd_child(node);
409 assert(!strcmp(LYD_NAME(node), "name"));
romanb9beb112023-07-18 09:06:58 +0200410 name = lyd_get_value(node);
romanc1d2b092023-02-02 08:58:27 +0100411
romanb9beb112023-07-18 09:06:58 +0200412 if (nc_server_config_get_auth_client(node, &auth_client)) {
413 return 1;
414 }
romanc1d2b092023-02-02 08:58:27 +0100415 for (i = 0; i < auth_client->pubkey_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200416 if (!strcmp(auth_client->pubkeys[i].name, name)) {
romanc1d2b092023-02-02 08:58:27 +0100417 *pubkey = &auth_client->pubkeys[i];
418 return 0;
419 }
420 }
421
romanb9beb112023-07-18 09:06:58 +0200422 ERR(NULL, "Public key \"%s\" was not found.", name);
romanc1d2b092023-02-02 08:58:27 +0100423 return 1;
424}
425
roman6430c152023-10-12 11:28:47 +0200426/* gets the tls_opts struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200427static int
romanb6f44032023-06-30 15:07:56 +0200428nc_server_config_get_tls_opts(const struct lyd_node *node, struct nc_server_tls_opts **opts)
429{
430 struct nc_endpt *endpt;
431 struct nc_ch_endpt *ch_endpt;
432
433 assert(node && opts);
434
435 if (is_listen(node)) {
436 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
437 return 1;
438 }
439 *opts = endpt->opts.tls;
440 } else {
441 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
442 return 1;
443 }
444 *opts = ch_endpt->opts.tls;
445 }
446
447 return 0;
448}
449
roman6430c152023-10-12 11:28:47 +0200450/* gets the cert struct based on node's location in the YANG data tree */
romanb6f44032023-06-30 15:07:56 +0200451static int
roman6430c152023-10-12 11:28:47 +0200452nc_server_config_get_cert(const struct lyd_node *node, struct nc_certificate **cert)
roman3f9b65c2023-06-05 14:26:58 +0200453{
454 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200455 const char *name;
roman4cb8bb12023-06-29 09:16:46 +0200456 struct nc_cert_grouping *auth_client;
romanb6f44032023-06-30 15:07:56 +0200457 struct nc_server_tls_opts *opts;
roman6430c152023-10-12 11:28:47 +0200458 int is_cert_end_entity;
459 struct lyd_node *name_node;
roman3f9b65c2023-06-05 14:26:58 +0200460
roman4cb8bb12023-06-29 09:16:46 +0200461 assert(node && cert);
romanb9beb112023-07-18 09:06:58 +0200462 name = LYD_NAME(node);
roman3f9b65c2023-06-05 14:26:58 +0200463
roman6430c152023-10-12 11:28:47 +0200464 /* check if node is in certificate subtree */
roman3f9b65c2023-06-05 14:26:58 +0200465 while (node) {
466 if (!strcmp(LYD_NAME(node), "certificate")) {
467 break;
468 }
469 node = lyd_parent(node);
470 }
roman3f9b65c2023-06-05 14:26:58 +0200471 if (!node) {
romanb9beb112023-07-18 09:06:58 +0200472 ERR(NULL, "Node \"%s\" is not contained in a certificate subtree.", name);
roman3f9b65c2023-06-05 14:26:58 +0200473 return 1;
474 }
475
roman6430c152023-10-12 11:28:47 +0200476 /* it's child should be the list's key, check later */
477 name_node = lyd_child(node);
478
479 /* it's in certificate node, now check if it's end entity or certificate authority */
480 while (node) {
481 if (!strcmp(LYD_NAME(node), "ee-certs")) {
482 is_cert_end_entity = 1;
483 break;
484 } else if (!strcmp(LYD_NAME(node), "ca-certs")) {
485 is_cert_end_entity = 0;
486 break;
487 }
488 node = lyd_parent(node);
489 }
490 if (!node) {
491 ERR(NULL, "Node \"%s\" is not contained in ee-certs nor ca-certs subtree.", name);
492 return 1;
493 }
494
495 assert(!strcmp(LYD_NAME(name_node), "name"));
496 name = lyd_get_value(name_node);
romanb9beb112023-07-18 09:06:58 +0200497
498 if (nc_server_config_get_tls_opts(node, &opts)) {
499 return 1;
500 }
roman6430c152023-10-12 11:28:47 +0200501 if (is_cert_end_entity) {
romanb9beb112023-07-18 09:06:58 +0200502 auth_client = &opts->ee_certs;
503 } else {
504 auth_client = &opts->ca_certs;
505 }
roman3f9b65c2023-06-05 14:26:58 +0200506
507 for (i = 0; i < auth_client->cert_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200508 if (!strcmp(auth_client->certs[i].name, name)) {
roman3f9b65c2023-06-05 14:26:58 +0200509 *cert = &auth_client->certs[i];
510 return 0;
511 }
512 }
513
romanb9beb112023-07-18 09:06:58 +0200514 ERR(NULL, "Certificate \"%s\" was not found.", name);
roman3f9b65c2023-06-05 14:26:58 +0200515 return 1;
516}
517
roman6430c152023-10-12 11:28:47 +0200518/* gets the ctn struct based on node's location in the YANG data tree */
roman3f9b65c2023-06-05 14:26:58 +0200519static int
roman4cb8bb12023-06-29 09:16:46 +0200520nc_server_config_get_ctn(const struct lyd_node *node, struct nc_ctn **ctn)
roman3f9b65c2023-06-05 14:26:58 +0200521{
522 uint32_t id;
523 struct nc_ctn *iter;
romanb6f44032023-06-30 15:07:56 +0200524 struct nc_server_tls_opts *opts;
romanb9beb112023-07-18 09:06:58 +0200525 const char *name;
roman3f9b65c2023-06-05 14:26:58 +0200526
roman4cb8bb12023-06-29 09:16:46 +0200527 assert(node && ctn);
romanb9beb112023-07-18 09:06:58 +0200528 name = LYD_NAME(node);
roman3f9b65c2023-06-05 14:26:58 +0200529
530 node = lyd_parent(node);
531 while (node) {
532 if (!strcmp(LYD_NAME(node), "cert-to-name")) {
533 break;
534 }
535 node = lyd_parent(node);
536 }
537
538 if (!node) {
romanb9beb112023-07-18 09:06:58 +0200539 ERR(NULL, "Node \"%s\" is not contained in a cert-to-name subtree.", name);
roman3f9b65c2023-06-05 14:26:58 +0200540 return 1;
541 }
542
543 node = lyd_child(node);
544 assert(!strcmp(LYD_NAME(node), "id"));
roman91ffeb42023-10-25 13:32:03 +0200545 id = ((struct lyd_node_term *)node)->value.uint32;
roman3f9b65c2023-06-05 14:26:58 +0200546
romanb9beb112023-07-18 09:06:58 +0200547 if (nc_server_config_get_tls_opts(node, &opts)) {
548 return 1;
549 }
550
romanb6f44032023-06-30 15:07:56 +0200551 iter = opts->ctn;
roman3f9b65c2023-06-05 14:26:58 +0200552 while (iter) {
553 if (iter->id == id) {
554 *ctn = iter;
555 return 0;
556 }
557
558 iter = iter->next;
559 }
560
561 ERR(NULL, "Cert-to-name entry with id \"%d\" was not found.", id);
562 return 1;
563}
564
roman2eab4742023-06-06 10:00:26 +0200565NC_PRIVKEY_FORMAT
566nc_server_config_get_private_key_type(const char *format)
567{
568 if (!strcmp(format, "rsa-private-key-format")) {
569 return NC_PRIVKEY_FORMAT_RSA;
570 } else if (!strcmp(format, "ec-private-key-format")) {
571 return NC_PRIVKEY_FORMAT_EC;
roman13145912023-08-17 15:36:54 +0200572 } else if (!strcmp(format, "private-key-info-format")) {
roman2eab4742023-06-06 10:00:26 +0200573 return NC_PRIVKEY_FORMAT_X509;
574 } else if (!strcmp(format, "openssh-private-key-format")) {
575 return NC_PRIVKEY_FORMAT_OPENSSH;
576 } else {
577 ERR(NULL, "Private key format (%s) not supported.", format);
578 return NC_PRIVKEY_FORMAT_UNKNOWN;
579 }
580}
581
582#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200583
roman6430c152023-10-12 11:28:47 +0200584/* gets the ch_client struct based on node's location in the YANG data tree and locks it for reading */
romanba93eac2023-07-18 14:36:48 +0200585static int
586nc_server_config_get_ch_client_with_lock(const struct lyd_node *node, struct nc_ch_client **ch_client)
587{
588 uint16_t i;
589 const char *name;
590
591 assert(node && ch_client);
592 name = LYD_NAME(node);
593
594 while (node) {
595 if (!strcmp(LYD_NAME(node), "netconf-client")) {
596 break;
597 }
598 node = lyd_parent(node);
599 }
600
601 if (!node) {
602 ERR(NULL, "Node \"%s\" is not contained in a netconf-client subtree.", name);
603 return 1;
604 }
605
606 node = lyd_child(node);
607 assert(!strcmp(LYD_NAME(node), "name"));
608 name = lyd_get_value(node);
609
610 /* LOCK */
611 pthread_rwlock_rdlock(&server_opts.ch_client_lock);
612 for (i = 0; i < server_opts.ch_client_count; i++) {
613 if (!strcmp(server_opts.ch_clients[i].name, name)) {
614 /* LOCK */
615 pthread_mutex_lock(&server_opts.ch_clients[i].lock);
616 *ch_client = &server_opts.ch_clients[i];
617 return 0;
618 }
619 }
620
roman6430c152023-10-12 11:28:47 +0200621 /* UNLOCK */
622 pthread_rwlock_unlock(&server_opts.ch_client_lock);
romanba93eac2023-07-18 14:36:48 +0200623 ERR(NULL, "Call-home client \"%s\" was not found.", name);
624 return 1;
625}
626
627static void
628nc_ch_client_unlock(struct nc_ch_client *client)
629{
630 assert(client);
631
632 pthread_mutex_unlock(&client->lock);
633 pthread_rwlock_unlock(&server_opts.ch_client_lock);
634}
635
romanf02273a2023-05-25 09:44:11 +0200636int
romanc1d2b092023-02-02 08:58:27 +0100637equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char *parent_name)
638{
639 uint16_t i;
640
roman6430c152023-10-12 11:28:47 +0200641 assert(node && parent_count && parent_name);
romanc1d2b092023-02-02 08:58:27 +0100642
643 node = lyd_parent(node);
644 for (i = 1; i < parent_count; i++) {
645 node = lyd_parent(node);
646 }
647
648 if (!strcmp(LYD_NAME(node), parent_name)) {
649 return 1;
650 }
651
652 return 0;
653}
654
romanf02273a2023-05-25 09:44:11 +0200655int
656nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uint16_t *count)
657{
658 int ret = 0;
659 void *tmp;
660 char **name;
661
662 tmp = realloc(*ptr, (*count + 1) * size);
roman3a95bb22023-10-26 11:07:17 +0200663 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
romanf02273a2023-05-25 09:44:11 +0200664 *ptr = tmp;
665
666 /* set the newly allocated memory to 0 */
667 memset((char *)(*ptr) + (*count * size), 0, size);
668 (*count)++;
669
670 /* access the first member of the supposed structure */
671 name = (char **)((*ptr) + ((*count - 1) * size));
672
673 /* and set it's value */
674 *name = strdup(key_value);
roman3a95bb22023-10-26 11:07:17 +0200675 NC_CHECK_ERRMEM_GOTO(!*name, ret = 1, cleanup);
romanf02273a2023-05-25 09:44:11 +0200676
677cleanup:
678 return ret;
679}
680
roman2eab4742023-06-06 10:00:26 +0200681#ifdef NC_ENABLED_SSH_TLS
682
roman3f9b65c2023-06-05 14:26:58 +0200683static void
roman874fed12023-05-25 10:20:01 +0200684nc_server_config_del_hostkey(struct nc_server_ssh_opts *opts, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100685{
roman874fed12023-05-25 10:20:01 +0200686 assert(hostkey->store == NC_STORE_LOCAL || hostkey->store == NC_STORE_KEYSTORE);
romanc1d2b092023-02-02 08:58:27 +0100687
roman6430c152023-10-12 11:28:47 +0200688 free(hostkey->name);
689
roman874fed12023-05-25 10:20:01 +0200690 if (hostkey->store == NC_STORE_LOCAL) {
roman6430c152023-10-12 11:28:47 +0200691 free(hostkey->key.pubkey_data);
692 free(hostkey->key.privkey_data);
romandd019a92023-09-14 10:17:07 +0200693 } else {
roman6430c152023-10-12 11:28:47 +0200694 free(hostkey->ks_ref);
romanc1d2b092023-02-02 08:58:27 +0100695 }
696
romanc1d2b092023-02-02 08:58:27 +0100697 opts->hostkey_count--;
698 if (!opts->hostkey_count) {
699 free(opts->hostkeys);
700 opts->hostkeys = NULL;
roman6430c152023-10-12 11:28:47 +0200701 } else if (hostkey != &opts->hostkeys[opts->hostkey_count]) {
roman33981232023-07-08 11:55:13 +0200702 memcpy(hostkey, &opts->hostkeys[opts->hostkey_count], sizeof *opts->hostkeys);
romanc1d2b092023-02-02 08:58:27 +0100703 }
704}
705
706static void
roman58f79d02023-10-06 10:20:31 +0200707nc_server_config_del_auth_client_pubkey(struct nc_auth_client *auth_client, struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +0100708{
roman6430c152023-10-12 11:28:47 +0200709 free(pubkey->name);
710 free(pubkey->data);
romanc1d2b092023-02-02 08:58:27 +0100711
712 auth_client->pubkey_count--;
713 if (!auth_client->pubkey_count) {
714 free(auth_client->pubkeys);
715 auth_client->pubkeys = NULL;
roman6430c152023-10-12 11:28:47 +0200716 } else if (pubkey != &auth_client->pubkeys[auth_client->pubkey_count]) {
roman33981232023-07-08 11:55:13 +0200717 memcpy(pubkey, &auth_client->pubkeys[auth_client->pubkey_count], sizeof *auth_client->pubkeys);
romanc1d2b092023-02-02 08:58:27 +0100718 }
719}
720
721static void
roman58f79d02023-10-06 10:20:31 +0200722nc_server_config_del_auth_client(struct nc_server_ssh_opts *opts, struct nc_auth_client *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100723{
724 uint16_t i, pubkey_count;
725
roman4cb8bb12023-06-29 09:16:46 +0200726 free(auth_client->username);
roman4cb8bb12023-06-29 09:16:46 +0200727
roman874fed12023-05-25 10:20:01 +0200728 if (auth_client->store == NC_STORE_LOCAL) {
romanc1d2b092023-02-02 08:58:27 +0100729 pubkey_count = auth_client->pubkey_count;
730 for (i = 0; i < pubkey_count; i++) {
roman874fed12023-05-25 10:20:01 +0200731 nc_server_config_del_auth_client_pubkey(auth_client, &auth_client->pubkeys[i]);
romanc1d2b092023-02-02 08:58:27 +0100732 }
roman6430c152023-10-12 11:28:47 +0200733 } else {
734 free(auth_client->ts_ref);
romanc1d2b092023-02-02 08:58:27 +0100735 }
736
roman6430c152023-10-12 11:28:47 +0200737 free(auth_client->password);
738 free(auth_client->pam_config_name);
739 free(auth_client->pam_config_dir);
romanc1d2b092023-02-02 08:58:27 +0100740
741 opts->client_count--;
742 if (!opts->client_count) {
743 free(opts->auth_clients);
744 opts->auth_clients = NULL;
roman6430c152023-10-12 11:28:47 +0200745 } else if (auth_client != &opts->auth_clients[opts->client_count]) {
roman33981232023-07-08 11:55:13 +0200746 memcpy(auth_client, &opts->auth_clients[opts->client_count], sizeof *opts->auth_clients);
romanc1d2b092023-02-02 08:58:27 +0100747 }
748}
749
750static void
roman6430c152023-10-12 11:28:47 +0200751nc_server_config_del_ssh_opts(struct nc_bind *bind, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100752{
753 uint16_t i, hostkey_count, client_count;
754
roman6430c152023-10-12 11:28:47 +0200755 free(bind->address);
romanc1d2b092023-02-02 08:58:27 +0100756 if (bind->sock > -1) {
757 close(bind->sock);
758 }
759
760 /* store in variable because it gets decremented in the function call */
761 hostkey_count = opts->hostkey_count;
762 for (i = 0; i < hostkey_count; i++) {
roman874fed12023-05-25 10:20:01 +0200763 nc_server_config_del_hostkey(opts, &opts->hostkeys[i]);
romanc1d2b092023-02-02 08:58:27 +0100764 }
765
766 client_count = opts->client_count;
767 for (i = 0; i < client_count; i++) {
roman874fed12023-05-25 10:20:01 +0200768 nc_server_config_del_auth_client(opts, &opts->auth_clients[i]);
romanc1d2b092023-02-02 08:58:27 +0100769 }
770
roman6430c152023-10-12 11:28:47 +0200771 free(opts->hostkey_algs);
772 free(opts->kex_algs);
773 free(opts->encryption_algs);
774 free(opts->mac_algs);
romanc1d2b092023-02-02 08:58:27 +0100775
776 free(opts);
romanc1d2b092023-02-02 08:58:27 +0100777}
778
779void
roman874fed12023-05-25 10:20:01 +0200780nc_server_config_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind)
romanc1d2b092023-02-02 08:58:27 +0100781{
roman6430c152023-10-12 11:28:47 +0200782 free(endpt->name);
783 free(endpt->referenced_endpt_name);
784 nc_server_config_del_ssh_opts(bind, endpt->opts.ssh);
romanc1d2b092023-02-02 08:58:27 +0100785
786 server_opts.endpt_count--;
787 if (!server_opts.endpt_count) {
788 free(server_opts.endpts);
789 free(server_opts.binds);
790 server_opts.endpts = NULL;
791 server_opts.binds = NULL;
roman6430c152023-10-12 11:28:47 +0200792 } else if (endpt != &server_opts.endpts[server_opts.endpt_count]) {
roman33981232023-07-08 11:55:13 +0200793 memcpy(endpt, &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts);
794 memcpy(bind, &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds);
romanc1d2b092023-02-02 08:58:27 +0100795 }
796}
797
roman2eab4742023-06-06 10:00:26 +0200798#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200799
roman45cec4e2023-02-17 10:21:39 +0100800void
roman6430c152023-10-12 11:28:47 +0200801nc_server_config_del_unix_socket_opts(struct nc_bind *bind, struct nc_server_unix_opts *opts)
roman83683fb2023-02-24 09:15:23 +0100802{
803 if (bind->sock > -1) {
804 close(bind->sock);
805 }
806
romand0b78372023-09-14 10:06:03 +0200807 unlink(bind->address);
roman83683fb2023-02-24 09:15:23 +0100808 free(bind->address);
809 free(opts->address);
810
811 free(opts);
roman83683fb2023-02-24 09:15:23 +0100812}
813
814void
roman874fed12023-05-25 10:20:01 +0200815nc_server_config_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *bind)
roman83683fb2023-02-24 09:15:23 +0100816{
roman6430c152023-10-12 11:28:47 +0200817 free(endpt->name);
818 nc_server_config_del_unix_socket_opts(bind, endpt->opts.unixsock);
roman83683fb2023-02-24 09:15:23 +0100819
820 server_opts.endpt_count--;
821 if (!server_opts.endpt_count) {
822 free(server_opts.endpts);
823 free(server_opts.binds);
824 server_opts.endpts = NULL;
825 server_opts.binds = NULL;
roman6430c152023-10-12 11:28:47 +0200826 } else if (endpt != &server_opts.endpts[server_opts.endpt_count]) {
roman33981232023-07-08 11:55:13 +0200827 memcpy(endpt, &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts);
828 memcpy(bind, &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds);
roman83683fb2023-02-24 09:15:23 +0100829 }
830}
831
roman2eab4742023-06-06 10:00:26 +0200832#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +0200833
834static void
roman3f9b65c2023-06-05 14:26:58 +0200835nc_server_config_del_cert(struct nc_cert_grouping *certs, struct nc_certificate *cert)
836{
837 free(cert->name);
roman3f9b65c2023-06-05 14:26:58 +0200838 free(cert->data);
roman3f9b65c2023-06-05 14:26:58 +0200839
840 certs->cert_count--;
841 if (!certs->cert_count) {
842 free(certs->certs);
843 certs->certs = NULL;
roman6430c152023-10-12 11:28:47 +0200844 } else if (cert != &certs->certs[certs->cert_count]) {
roman33981232023-07-08 11:55:13 +0200845 memcpy(cert, &certs->certs[certs->cert_count], sizeof *certs->certs);
roman3f9b65c2023-06-05 14:26:58 +0200846 }
847}
848
849static void
roman6430c152023-10-12 11:28:47 +0200850nc_server_config_del_certs(struct nc_cert_grouping *certs_grp)
roman3f9b65c2023-06-05 14:26:58 +0200851{
roman6430c152023-10-12 11:28:47 +0200852 uint16_t i;
roman3f9b65c2023-06-05 14:26:58 +0200853
roman6430c152023-10-12 11:28:47 +0200854 if (certs_grp->store == NC_STORE_LOCAL) {
855 for (i = 0; i < certs_grp->cert_count; i++) {
856 free(certs_grp->certs[i].name);
857 free(certs_grp->certs[i].data);
roman3f9b65c2023-06-05 14:26:58 +0200858 }
roman6430c152023-10-12 11:28:47 +0200859 free(certs_grp->certs);
860 certs_grp->certs = NULL;
861 } else {
862 free(certs_grp->ts_ref);
roman3f9b65c2023-06-05 14:26:58 +0200863 }
864}
865
866static void
867nc_server_config_del_ctn(struct nc_server_tls_opts *opts, struct nc_ctn *ctn)
868{
869 struct nc_ctn *iter;
870
roman3f9b65c2023-06-05 14:26:58 +0200871 free(ctn->name);
roman6430c152023-10-12 11:28:47 +0200872 free(ctn->fingerprint);
roman3f9b65c2023-06-05 14:26:58 +0200873
874 if (opts->ctn == ctn) {
875 /* it's the first in the list */
876 opts->ctn = ctn->next;
877 free(ctn);
878 return;
879 }
880
roman84fe3252023-10-25 11:28:32 +0200881 for (iter = opts->ctn; iter; iter = iter->next) {
roman3f9b65c2023-06-05 14:26:58 +0200882 if (iter->next == ctn) {
883 /* found the ctn */
884 break;
885 }
roman3f9b65c2023-06-05 14:26:58 +0200886 }
887
888 iter->next = ctn->next;
889 free(ctn);
890}
891
892static void
roman6430c152023-10-12 11:28:47 +0200893nc_server_config_del_ctns(struct nc_server_tls_opts *opts)
roman3f9b65c2023-06-05 14:26:58 +0200894{
895 struct nc_ctn *cur, *next;
896
roman84fe3252023-10-25 11:28:32 +0200897 for (cur = opts->ctn; cur; cur = next) {
roman3f9b65c2023-06-05 14:26:58 +0200898 next = cur->next;
roman3f9b65c2023-06-05 14:26:58 +0200899 free(cur->name);
roman6430c152023-10-12 11:28:47 +0200900 free(cur->fingerprint);
roman3f9b65c2023-06-05 14:26:58 +0200901 free(cur);
roman3f9b65c2023-06-05 14:26:58 +0200902 }
roman3a95bb22023-10-26 11:07:17 +0200903
roman3f9b65c2023-06-05 14:26:58 +0200904 opts->ctn = NULL;
905}
906
907static void
roman6430c152023-10-12 11:28:47 +0200908nc_server_config_del_tls_opts(struct nc_bind *bind, struct nc_server_tls_opts *opts)
roman3f9b65c2023-06-05 14:26:58 +0200909{
roman6430c152023-10-12 11:28:47 +0200910 free(bind->address);
roman3f9b65c2023-06-05 14:26:58 +0200911 if (bind->sock > -1) {
912 close(bind->sock);
913 }
914
915 if (opts->store == NC_STORE_LOCAL) {
roman6430c152023-10-12 11:28:47 +0200916 free(opts->pubkey_data);
917 free(opts->privkey_data);
918 free(opts->cert_data);
919 } else {
920 free(opts->key_ref);
921 free(opts->cert_ref);
roman3f9b65c2023-06-05 14:26:58 +0200922 }
923
roman6430c152023-10-12 11:28:47 +0200924 nc_server_config_del_certs(&opts->ca_certs);
925 nc_server_config_del_certs(&opts->ee_certs);
roman3f9b65c2023-06-05 14:26:58 +0200926
roman6430c152023-10-12 11:28:47 +0200927 free(opts->crl_path);
928 free(opts->crl_url);
romanfaecc582023-06-15 16:13:31 +0200929 X509_STORE_free(opts->crl_store);
romanfaecc582023-06-15 16:13:31 +0200930
roman6430c152023-10-12 11:28:47 +0200931 nc_server_config_del_ctns(opts);
932 free(opts->ciphers);
roman3f9b65c2023-06-05 14:26:58 +0200933 free(opts);
934}
935
936static void
937nc_server_config_del_endpt_tls(struct nc_endpt *endpt, struct nc_bind *bind)
938{
roman6430c152023-10-12 11:28:47 +0200939 free(endpt->name);
940 free(endpt->referenced_endpt_name);
941
942 nc_server_config_del_tls_opts(bind, endpt->opts.tls);
roman3f9b65c2023-06-05 14:26:58 +0200943
944 server_opts.endpt_count--;
945 if (!server_opts.endpt_count) {
946 free(server_opts.endpts);
947 free(server_opts.binds);
948 server_opts.endpts = NULL;
949 server_opts.binds = NULL;
roman6430c152023-10-12 11:28:47 +0200950 } else if (endpt != &server_opts.endpts[server_opts.endpt_count]) {
roman33981232023-07-08 11:55:13 +0200951 memcpy(endpt, &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts);
952 memcpy(bind, &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds);
roman3f9b65c2023-06-05 14:26:58 +0200953 }
954}
955
roman2eab4742023-06-06 10:00:26 +0200956#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200957
romanc1d2b092023-02-02 08:58:27 +0100958/* presence container */
959int
roman6430c152023-10-12 11:28:47 +0200960nc_server_config_listen(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +0100961{
roman0bbc19c2023-05-26 09:59:09 +0200962 uint16_t i, endpt_count;
romanc1d2b092023-02-02 08:58:27 +0100963
romanf02273a2023-05-25 09:44:11 +0200964 (void) node;
965
romanc1d2b092023-02-02 08:58:27 +0100966 assert(op == NC_OP_CREATE || op == NC_OP_DELETE);
967
968 if (op == NC_OP_DELETE) {
roman0bbc19c2023-05-26 09:59:09 +0200969 endpt_count = server_opts.endpt_count;
970 for (i = 0; i < endpt_count; i++) {
roman456f92d2023-04-28 10:28:12 +0200971 switch (server_opts.endpts[i].ti) {
roman2eab4742023-06-06 10:00:26 +0200972#ifdef NC_ENABLED_SSH_TLS
roman456f92d2023-04-28 10:28:12 +0200973 case NC_TI_LIBSSH:
roman874fed12023-05-25 10:20:01 +0200974 nc_server_config_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]);
roman456f92d2023-04-28 10:28:12 +0200975 break;
roman456f92d2023-04-28 10:28:12 +0200976 case NC_TI_OPENSSL:
roman3f9b65c2023-06-05 14:26:58 +0200977 nc_server_config_del_endpt_tls(&server_opts.endpts[i], &server_opts.binds[i]);
roman456f92d2023-04-28 10:28:12 +0200978 break;
roman2eab4742023-06-06 10:00:26 +0200979#endif /* NC_ENABLED_SSH_TLS */
roman456f92d2023-04-28 10:28:12 +0200980 case NC_TI_UNIX:
roman874fed12023-05-25 10:20:01 +0200981 nc_server_config_del_endpt_unix_socket(&server_opts.endpts[i], &server_opts.binds[i]);
roman456f92d2023-04-28 10:28:12 +0200982 break;
983 case NC_TI_NONE:
984 case NC_TI_FD:
985 ERRINT;
986 return 1;
roman83683fb2023-02-24 09:15:23 +0100987 }
romanc1d2b092023-02-02 08:58:27 +0100988 }
989 }
990
991 return 0;
992}
993
roman5cbb6532023-06-22 12:53:17 +0200994#ifdef NC_ENABLED_SSH_TLS
995
996static void
roman6430c152023-10-12 11:28:47 +0200997nc_server_config_ch_del_ssh_opts(struct nc_server_ssh_opts *opts)
roman5cbb6532023-06-22 12:53:17 +0200998{
999 uint16_t i, hostkey_count, client_count;
1000
1001 /* store in variable because it gets decremented in the function call */
1002 hostkey_count = opts->hostkey_count;
1003 for (i = 0; i < hostkey_count; i++) {
1004 nc_server_config_del_hostkey(opts, &opts->hostkeys[i]);
1005 }
1006
1007 client_count = opts->client_count;
1008 for (i = 0; i < client_count; i++) {
1009 nc_server_config_del_auth_client(opts, &opts->auth_clients[i]);
1010 }
1011
roman6430c152023-10-12 11:28:47 +02001012 free(opts->hostkey_algs);
1013 free(opts->kex_algs);
1014 free(opts->encryption_algs);
1015 free(opts->mac_algs);
roman5cbb6532023-06-22 12:53:17 +02001016
1017 free(opts);
roman5cbb6532023-06-22 12:53:17 +02001018}
1019
1020static void
roman6430c152023-10-12 11:28:47 +02001021nc_server_config_ch_del_tls_opts(struct nc_server_tls_opts *opts)
romanb6f44032023-06-30 15:07:56 +02001022{
1023 if (opts->store == NC_STORE_LOCAL) {
roman6430c152023-10-12 11:28:47 +02001024 free(opts->pubkey_data);
1025 free(opts->privkey_data);
1026 free(opts->cert_data);
romanb6f44032023-06-30 15:07:56 +02001027 }
1028
roman6430c152023-10-12 11:28:47 +02001029 nc_server_config_del_certs(&opts->ca_certs);
1030 nc_server_config_del_certs(&opts->ee_certs);
romanb6f44032023-06-30 15:07:56 +02001031
roman6430c152023-10-12 11:28:47 +02001032 free(opts->crl_path);
1033 free(opts->crl_url);
romanb6f44032023-06-30 15:07:56 +02001034 X509_STORE_free(opts->crl_store);
roman6430c152023-10-12 11:28:47 +02001035 nc_server_config_del_ctns(opts);
1036 free(opts->ciphers);
romanb6f44032023-06-30 15:07:56 +02001037
1038 free(opts);
1039}
1040
roman5cbb6532023-06-22 12:53:17 +02001041#endif /* NC_ENABLED_SSH_TLS */
1042
1043static void
1044nc_server_config_ch_del_endpt(struct nc_ch_client *ch_client, struct nc_ch_endpt *ch_endpt)
1045{
1046 free(ch_endpt->name);
roman5cbb6532023-06-22 12:53:17 +02001047
1048#ifdef NC_ENABLED_SSH_TLS
roman6430c152023-10-12 11:28:47 +02001049 free(ch_endpt->address);
roman5cbb6532023-06-22 12:53:17 +02001050 if (ch_endpt->sock_pending > -1) {
1051 close(ch_endpt->sock_pending);
1052 ch_endpt->sock_pending = -1;
1053 }
1054#endif /* NC_ENABLED_SSH_TLS */
1055
1056 switch (ch_endpt->ti) {
1057#ifdef NC_ENABLED_SSH_TLS
1058 case NC_TI_LIBSSH:
roman6430c152023-10-12 11:28:47 +02001059 nc_server_config_ch_del_ssh_opts(ch_endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +02001060 break;
romanb6f44032023-06-30 15:07:56 +02001061 case NC_TI_OPENSSL:
roman6430c152023-10-12 11:28:47 +02001062 nc_server_config_ch_del_tls_opts(ch_endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +02001063 break;
roman5cbb6532023-06-22 12:53:17 +02001064#endif /* NC_ENABLED_SSH_TLS */
1065 default:
1066 ERRINT;
1067 break;
1068 }
1069
1070 ch_client->ch_endpt_count--;
1071 if (!ch_client->ch_endpt_count) {
1072 free(ch_client->ch_endpts);
1073 ch_client->ch_endpts = NULL;
1074 }
1075}
1076
1077static void
1078nc_server_config_ch_del_client(struct nc_ch_client *ch_client)
1079{
1080 uint16_t i, ch_endpt_count;
romanba93eac2023-07-18 14:36:48 +02001081 struct nc_ch_client client;
1082 pthread_t tid;
roman5cbb6532023-06-22 12:53:17 +02001083
romanba93eac2023-07-18 14:36:48 +02001084 /* WR LOCK */
roman5cbb6532023-06-22 12:53:17 +02001085 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
1086
romanba93eac2023-07-18 14:36:48 +02001087 /* copy the client we want to delete into a local variable */
1088 memcpy(&client, ch_client, sizeof *ch_client);
1089 /* get his tid */
1090 tid = client.tid;
roman5cbb6532023-06-22 12:53:17 +02001091
romanba93eac2023-07-18 14:36:48 +02001092 /* delete the client */
roman5cbb6532023-06-22 12:53:17 +02001093 server_opts.ch_client_count--;
1094 if (!server_opts.ch_client_count) {
1095 free(server_opts.ch_clients);
1096 server_opts.ch_clients = NULL;
romanba93eac2023-07-18 14:36:48 +02001097 } else {
1098 memcpy(ch_client, &server_opts.ch_clients[server_opts.ch_client_count], sizeof *server_opts.ch_clients);
roman5cbb6532023-06-22 12:53:17 +02001099 }
1100
romanba93eac2023-07-18 14:36:48 +02001101 /* WR UNLOCK */
roman5cbb6532023-06-22 12:53:17 +02001102 pthread_rwlock_unlock(&server_opts.ch_client_lock);
romanba93eac2023-07-18 14:36:48 +02001103
1104 /* RD LOCK */
1105 pthread_rwlock_rdlock(&server_opts.ch_client_lock);
roman84fe3252023-10-25 11:28:32 +02001106 /* MUTEX LOCK */
1107 pthread_mutex_lock(&client.lock);
romanba93eac2023-07-18 14:36:48 +02001108
1109 if (client.thread_data->thread_running) {
1110 /* CH COND LOCK */
1111 pthread_mutex_lock(&client.thread_data->cond_lock);
1112 client.thread_data->thread_running = 0;
1113 pthread_cond_signal(&client.thread_data->cond);
1114 /* CH COND UNLOCK */
1115 pthread_mutex_unlock(&client.thread_data->cond_lock);
1116
roman84fe3252023-10-25 11:28:32 +02001117 /* MUTEX UNLOCK */
1118 pthread_mutex_unlock(&client.lock);
romanba93eac2023-07-18 14:36:48 +02001119 /* RD UNLOCK */
1120 pthread_rwlock_unlock(&server_opts.ch_client_lock);
1121
1122 /* wait for the thread to terminate */
1123 pthread_join(tid, NULL);
1124 }
1125
1126 /* free its members */
1127 free(client.name);
1128
1129 ch_endpt_count = client.ch_endpt_count;
1130 for (i = 0; i < ch_endpt_count; i++) {
1131 nc_server_config_ch_del_endpt(&client, &client.ch_endpts[i]);
1132 }
roman5cbb6532023-06-22 12:53:17 +02001133}
1134
roman6430c152023-10-12 11:28:47 +02001135int
roman5cbb6532023-06-22 12:53:17 +02001136nc_server_config_ch(const struct lyd_node *node, NC_OPERATION op)
1137{
1138 uint16_t i, ch_client_count;
1139
1140 (void) node;
1141
1142 if (op == NC_OP_DELETE) {
1143 ch_client_count = server_opts.ch_client_count;
1144 for (i = 0; i < ch_client_count; i++) {
1145 nc_server_config_ch_del_client(&server_opts.ch_clients[i]);
1146 }
1147 }
roman6430c152023-10-12 11:28:47 +02001148
1149 return 0;
roman5cbb6532023-06-22 12:53:17 +02001150}
1151
romanc1d2b092023-02-02 08:58:27 +01001152/* default leaf */
1153static int
romaneaf84c72023-10-19 14:38:05 +02001154nc_server_config_hello_timeout(const struct lyd_node *node, NC_OPERATION op)
1155{
1156 assert(!strcmp(LYD_NAME(node), "hello-timeout"));
1157
1158 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001159 server_opts.hello_timeout = ((struct lyd_node_term *)node)->value.uint16;
romaneaf84c72023-10-19 14:38:05 +02001160 } else {
1161 /* default value */
1162 server_opts.hello_timeout = 60;
1163 }
1164
1165 return 0;
1166}
1167
1168/* default leaf */
1169static int
romane028ef92023-02-24 16:33:08 +01001170nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001171{
romanb6f44032023-06-30 15:07:56 +02001172 struct nc_ch_client *ch_client;
1173
romanc1d2b092023-02-02 08:58:27 +01001174 assert(!strcmp(LYD_NAME(node), "idle-timeout"));
1175
romaneaf84c72023-10-19 14:38:05 +02001176 if (is_ch(node)) {
romanb6f44032023-06-30 15:07:56 +02001177 /* call-home idle timeout */
roman6430c152023-10-12 11:28:47 +02001178 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
1179 /* to avoid unlock on fail */
romanb6f44032023-06-30 15:07:56 +02001180 return 1;
1181 }
1182
1183 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001184 ch_client->idle_timeout = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02001185 } else if (op == NC_OP_DELETE) {
1186 ch_client->idle_timeout = 180;
1187 }
roman6430c152023-10-12 11:28:47 +02001188
1189 nc_ch_client_unlock(ch_client);
romaneaf84c72023-10-19 14:38:05 +02001190 } else {
1191 /* whole server idle timeout */
1192 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001193 server_opts.idle_timeout = ((struct lyd_node_term *)node)->value.uint16;
romaneaf84c72023-10-19 14:38:05 +02001194 } else {
1195 /* default value */
1196 server_opts.idle_timeout = 0;
1197 }
romanc1d2b092023-02-02 08:58:27 +01001198 }
1199
1200 return 0;
1201}
1202
1203static int
roman874fed12023-05-25 10:20:01 +02001204nc_server_config_create_bind(void)
romanc1d2b092023-02-02 08:58:27 +01001205{
1206 int ret = 0;
1207 void *tmp;
1208
1209 tmp = realloc(server_opts.binds, (server_opts.endpt_count + 1) * sizeof *server_opts.binds);
roman3a95bb22023-10-26 11:07:17 +02001210 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01001211 server_opts.binds = tmp;
1212 memset(&server_opts.binds[server_opts.endpt_count], 0, sizeof *server_opts.binds);
1213
1214 server_opts.binds[server_opts.endpt_count].sock = -1;
1215
1216cleanup:
1217 return ret;
1218}
1219
1220static int
roman874fed12023-05-25 10:20:01 +02001221nc_server_config_create_endpoint(const struct lyd_node *node)
romanc1d2b092023-02-02 08:58:27 +01001222{
roman874fed12023-05-25 10:20:01 +02001223 if (nc_server_config_create_bind()) {
romanf02273a2023-05-25 09:44:11 +02001224 return 1;
romanc1d2b092023-02-02 08:58:27 +01001225 }
romanc1d2b092023-02-02 08:58:27 +01001226
1227 node = lyd_child(node);
1228 assert(!strcmp(LYD_NAME(node), "name"));
1229
romanf02273a2023-05-25 09:44:11 +02001230 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 +01001231}
1232
roman5cbb6532023-06-22 12:53:17 +02001233static int
1234nc_server_config_ch_create_endpoint(const struct lyd_node *node, struct nc_ch_client *ch_client)
1235{
1236 node = lyd_child(node);
1237 assert(!strcmp(LYD_NAME(node), "name"));
1238
1239 return nc_server_config_realloc(lyd_get_value(node), (void **)&ch_client->ch_endpts, sizeof *ch_client->ch_endpts, &ch_client->ch_endpt_count);
1240}
1241
romanc1d2b092023-02-02 08:58:27 +01001242/* list */
1243static int
romane028ef92023-02-24 16:33:08 +01001244nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001245{
1246 int ret = 0;
1247 struct nc_endpt *endpt;
1248 struct nc_bind *bind;
roman6430c152023-10-12 11:28:47 +02001249 struct nc_ch_endpt *ch_endpt;
roman5cbb6532023-06-22 12:53:17 +02001250 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001251
1252 assert(!strcmp(LYD_NAME(node), "endpoint"));
1253
roman5cbb6532023-06-22 12:53:17 +02001254 if (is_listen(node)) {
1255 /* listen */
1256 if (op == NC_OP_CREATE) {
1257 ret = nc_server_config_create_endpoint(node);
1258 if (ret) {
1259 goto cleanup;
1260 }
1261 } else if (op == NC_OP_DELETE) {
1262 /* free all children */
1263 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1264 ret = 1;
1265 goto cleanup;
1266 }
1267
1268 switch (endpt->ti) {
1269#ifdef NC_ENABLED_SSH_TLS
1270 case NC_TI_LIBSSH:
1271 nc_server_config_del_endpt_ssh(endpt, bind);
1272 break;
1273 case NC_TI_OPENSSL:
1274 nc_server_config_del_endpt_tls(endpt, bind);
1275 break;
1276#endif /* NC_ENABLED_SSH_TLS */
1277 case NC_TI_UNIX:
1278 nc_server_config_del_endpt_unix_socket(endpt, bind);
1279 break;
1280 case NC_TI_NONE:
1281 case NC_TI_FD:
1282 ERRINT;
1283 ret = 1;
1284 goto cleanup;
1285 }
romanc1d2b092023-02-02 08:58:27 +01001286 }
roman5cbb6532023-06-22 12:53:17 +02001287 } else if (is_ch(node)) {
romanba93eac2023-07-18 14:36:48 +02001288 /* LOCK */
1289 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001290 /* to avoid unlock on fail */
1291 return 1;
romanc1d2b092023-02-02 08:58:27 +01001292 }
roman3f9b65c2023-06-05 14:26:58 +02001293
roman5cbb6532023-06-22 12:53:17 +02001294 if (op == NC_OP_CREATE) {
1295 ret = nc_server_config_ch_create_endpoint(node, ch_client);
1296 if (ret) {
1297 goto cleanup;
1298 }
1299
1300 /* init ch sock */
1301 ch_client->ch_endpts[ch_client->ch_endpt_count - 1].sock_pending = -1;
roman6430c152023-10-12 11:28:47 +02001302 } else if (op == NC_OP_DELETE) {
1303 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
1304 ret = 1;
1305 goto cleanup;
1306 }
1307
1308 nc_server_config_ch_del_endpt(ch_client, ch_endpt);
roman3f9b65c2023-06-05 14:26:58 +02001309 }
romanc1d2b092023-02-02 08:58:27 +01001310 }
1311
1312cleanup:
romanba93eac2023-07-18 14:36:48 +02001313 if (is_ch(node)) {
1314 /* UNLOCK */
1315 nc_ch_client_unlock(ch_client);
1316 }
romanc1d2b092023-02-02 08:58:27 +01001317 return ret;
1318}
1319
roman2eab4742023-06-06 10:00:26 +02001320#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02001321
romanc1d2b092023-02-02 08:58:27 +01001322static int
roman874fed12023-05-25 10:20:01 +02001323nc_server_config_create_ssh(struct nc_endpt *endpt)
romanc1d2b092023-02-02 08:58:27 +01001324{
1325 endpt->ti = NC_TI_LIBSSH;
1326 endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
roman3a95bb22023-10-26 11:07:17 +02001327 NC_CHECK_ERRMEM_RET(!endpt->opts.ssh, 1);
romanc1d2b092023-02-02 08:58:27 +01001328
1329 return 0;
1330}
1331
roman5cbb6532023-06-22 12:53:17 +02001332static int
1333nc_server_config_ch_create_ssh(struct nc_ch_endpt *ch_endpt)
1334{
1335 ch_endpt->ti = NC_TI_LIBSSH;
1336 ch_endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
roman3a95bb22023-10-26 11:07:17 +02001337 NC_CHECK_ERRMEM_RET(!ch_endpt->opts.ssh, 1);
roman5cbb6532023-06-22 12:53:17 +02001338
1339 return 0;
1340}
1341
romanc1d2b092023-02-02 08:58:27 +01001342/* NP container */
1343static int
romane028ef92023-02-24 16:33:08 +01001344nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001345{
1346 struct nc_endpt *endpt;
1347 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001348 struct nc_ch_endpt *ch_endpt;
romanba93eac2023-07-18 14:36:48 +02001349 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001350 int ret = 0;
1351
1352 assert(!strcmp(LYD_NAME(node), "ssh"));
1353
roman5cbb6532023-06-22 12:53:17 +02001354 if (is_listen(node)) {
1355 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1356 ret = 1;
romanc1d2b092023-02-02 08:58:27 +01001357 goto cleanup;
1358 }
roman5cbb6532023-06-22 12:53:17 +02001359
1360 if (op == NC_OP_CREATE) {
1361 ret = nc_server_config_create_ssh(endpt);
1362 if (ret) {
1363 goto cleanup;
1364 }
1365 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02001366 nc_server_config_del_ssh_opts(bind, endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +02001367 }
1368 } else {
romanba93eac2023-07-18 14:36:48 +02001369 /* LOCK */
1370 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001371 /* to avoid unlock on fail */
1372 return 1;
romanba93eac2023-07-18 14:36:48 +02001373 }
1374
roman4cb8bb12023-06-29 09:16:46 +02001375 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001376 ret = 1;
1377 goto cleanup;
1378 }
1379
1380 if (op == NC_OP_CREATE) {
1381 ret = nc_server_config_ch_create_ssh(ch_endpt);
1382 if (ret) {
1383 goto cleanup;
1384 }
romanb6f44032023-06-30 15:07:56 +02001385 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02001386 nc_server_config_ch_del_ssh_opts(ch_endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +02001387 }
romanc1d2b092023-02-02 08:58:27 +01001388 }
1389
1390cleanup:
romanba93eac2023-07-18 14:36:48 +02001391 if (is_ch(node)) {
1392 /* UNLOCK */
1393 nc_ch_client_unlock(ch_client);
1394 }
romanc1d2b092023-02-02 08:58:27 +01001395 return ret;
1396}
1397
roman3f9b65c2023-06-05 14:26:58 +02001398static int
1399nc_server_config_create_tls(struct nc_endpt *endpt)
1400{
1401 endpt->ti = NC_TI_OPENSSL;
1402 endpt->opts.tls = calloc(1, sizeof *endpt->opts.tls);
roman3a95bb22023-10-26 11:07:17 +02001403 NC_CHECK_ERRMEM_RET(!endpt->opts.tls, 1);
roman3f9b65c2023-06-05 14:26:58 +02001404
1405 return 0;
1406}
1407
1408static int
romanb6f44032023-06-30 15:07:56 +02001409nc_server_config_ch_create_tls(struct nc_ch_endpt *ch_endpt)
1410{
1411 ch_endpt->ti = NC_TI_OPENSSL;
1412 ch_endpt->opts.tls = calloc(1, sizeof(struct nc_server_tls_opts));
roman3a95bb22023-10-26 11:07:17 +02001413 NC_CHECK_ERRMEM_RET(!ch_endpt->opts.tls, 1);
romanb6f44032023-06-30 15:07:56 +02001414
1415 return 0;
1416}
1417
1418static int
roman3f9b65c2023-06-05 14:26:58 +02001419nc_server_config_tls(const struct lyd_node *node, NC_OPERATION op)
1420{
1421 struct nc_endpt *endpt;
1422 struct nc_bind *bind;
romanb6f44032023-06-30 15:07:56 +02001423 struct nc_ch_endpt *ch_endpt;
romanba93eac2023-07-18 14:36:48 +02001424 struct nc_ch_client *ch_client;
roman3f9b65c2023-06-05 14:26:58 +02001425 int ret = 0;
1426
1427 assert(!strcmp(LYD_NAME(node), "tls"));
1428
romanb6f44032023-06-30 15:07:56 +02001429 if (is_listen(node)) {
1430 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1431 ret = 1;
roman3f9b65c2023-06-05 14:26:58 +02001432 goto cleanup;
1433 }
romanb6f44032023-06-30 15:07:56 +02001434
1435 if (op == NC_OP_CREATE) {
1436 ret = nc_server_config_create_tls(endpt);
1437 if (ret) {
1438 goto cleanup;
1439 }
1440 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02001441 nc_server_config_del_tls_opts(bind, endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +02001442 }
1443 } else {
romanba93eac2023-07-18 14:36:48 +02001444 /* LOCK */
1445 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001446 /* to avoid unlock on fail */
1447 return 1;
romanba93eac2023-07-18 14:36:48 +02001448 }
1449
romanb6f44032023-06-30 15:07:56 +02001450 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
1451 ret = 1;
1452 goto cleanup;
1453 }
1454
1455 if (op == NC_OP_CREATE) {
1456 ret = nc_server_config_ch_create_tls(ch_endpt);
1457 if (ret) {
1458 goto cleanup;
1459 }
roman6430c152023-10-12 11:28:47 +02001460 } else if (op == NC_OP_DELETE) {
1461 nc_server_config_ch_del_tls_opts(ch_endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +02001462 }
roman3f9b65c2023-06-05 14:26:58 +02001463 }
1464
1465cleanup:
romanba93eac2023-07-18 14:36:48 +02001466 if (is_ch(node)) {
1467 /* UNLOCK */
1468 nc_ch_client_unlock(ch_client);
1469 }
roman3f9b65c2023-06-05 14:26:58 +02001470 return ret;
1471}
1472
roman2eab4742023-06-06 10:00:26 +02001473#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02001474
romanc1d2b092023-02-02 08:58:27 +01001475static int
1476nc_server_config_set_address_port(struct nc_endpt *endpt, struct nc_bind *bind, const char *address, uint16_t port)
1477{
1478 int sock = -1, set_addr, ret = 0;
1479
roman83683fb2023-02-24 09:15:23 +01001480 assert((address && !port) || (!address && port) || (endpt->ti == NC_TI_UNIX));
romanc1d2b092023-02-02 08:58:27 +01001481
1482 if (address) {
1483 set_addr = 1;
1484 } else {
1485 set_addr = 0;
1486 }
1487
1488 if (set_addr) {
1489 port = bind->port;
1490 } else {
1491 address = bind->address;
1492 }
1493
romanc1d2b092023-02-02 08:58:27 +01001494 /* we have all the information we need to create a listening socket */
roman83683fb2023-02-24 09:15:23 +01001495 if ((address && port) || (endpt->ti == NC_TI_UNIX)) {
romanc1d2b092023-02-02 08:58:27 +01001496 /* create new socket, close the old one */
roman83683fb2023-02-24 09:15:23 +01001497 if (endpt->ti == NC_TI_UNIX) {
1498 sock = nc_sock_listen_unix(endpt->opts.unixsock);
1499 } else {
1500 sock = nc_sock_listen_inet(address, port, &endpt->ka);
1501 }
1502
romanc1d2b092023-02-02 08:58:27 +01001503 if (sock == -1) {
1504 ret = 1;
1505 goto cleanup;
1506 }
1507
1508 if (bind->sock > -1) {
1509 close(bind->sock);
1510 }
1511 bind->sock = sock;
1512 }
1513
1514 if (sock > -1) {
1515 switch (endpt->ti) {
roman83683fb2023-02-24 09:15:23 +01001516 case NC_TI_UNIX:
1517 VRB(NULL, "Listening on %s for UNIX connections.", endpt->opts.unixsock->address);
1518 break;
roman2eab4742023-06-06 10:00:26 +02001519#ifdef NC_ENABLED_SSH_TLS
romanc1d2b092023-02-02 08:58:27 +01001520 case NC_TI_LIBSSH:
1521 VRB(NULL, "Listening on %s:%u for SSH connections.", address, port);
1522 break;
romanc1d2b092023-02-02 08:58:27 +01001523 case NC_TI_OPENSSL:
1524 VRB(NULL, "Listening on %s:%u for TLS connections.", address, port);
1525 break;
roman2eab4742023-06-06 10:00:26 +02001526#endif /* NC_ENABLED_SSH_TLS */
romanc1d2b092023-02-02 08:58:27 +01001527 default:
1528 ERRINT;
1529 ret = 1;
1530 break;
1531 }
1532 }
1533
1534cleanup:
1535 return ret;
1536}
1537
roman2eab4742023-06-06 10:00:26 +02001538#ifdef NC_ENABLED_SSH_TLS
1539
romanc1d2b092023-02-02 08:58:27 +01001540/* mandatory leaf */
1541static int
romane028ef92023-02-24 16:33:08 +01001542nc_server_config_local_address(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001543{
1544 struct nc_endpt *endpt;
1545 struct nc_bind *bind;
1546 int ret = 0;
1547
1548 (void) op;
1549
1550 assert(!strcmp(LYD_NAME(node), "local-address"));
1551
1552 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001553 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001554 ret = 1;
1555 goto cleanup;
1556 }
1557
roman6430c152023-10-12 11:28:47 +02001558 free(bind->address);
romanc1d2b092023-02-02 08:58:27 +01001559 bind->address = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001560 NC_CHECK_ERRMEM_GOTO(!bind->address, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01001561
1562 ret = nc_server_config_set_address_port(endpt, bind, lyd_get_value(node), 0);
1563 if (ret) {
1564 goto cleanup;
1565 }
1566 }
1567
1568cleanup:
1569 return ret;
1570}
1571
1572/* leaf with default value */
1573static int
romane028ef92023-02-24 16:33:08 +01001574nc_server_config_local_port(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001575{
1576 struct nc_endpt *endpt;
1577 struct nc_bind *bind;
1578 int ret = 0;
1579
1580 assert(!strcmp(LYD_NAME(node), "local-port"));
1581
1582 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001583 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001584 ret = 1;
1585 goto cleanup;
1586 }
1587
1588 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001589 bind->port = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001590 } else {
1591 /* delete -> set to default */
1592 bind->port = 0;
1593 }
1594
1595 ret = nc_server_config_set_address_port(endpt, bind, NULL, bind->port);
1596 if (ret) {
1597 goto cleanup;
1598 }
1599 }
1600
1601cleanup:
1602 return ret;
1603}
1604
1605/* P container */
1606static int
romane028ef92023-02-24 16:33:08 +01001607nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001608{
roman5cbb6532023-06-22 12:53:17 +02001609 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001610 struct nc_endpt *endpt;
1611 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001612 struct nc_ch_endpt *ch_endpt;
romanba93eac2023-07-18 14:36:48 +02001613 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001614
1615 assert(!strcmp(LYD_NAME(node), "keepalives"));
1616
roman5cbb6532023-06-22 12:53:17 +02001617 if (is_listen(node) && equal_parent_name(node, 1, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001618 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001619 ret = 1;
1620 goto cleanup;
1621 }
1622
1623 if (op == NC_OP_CREATE) {
1624 endpt->ka.enabled = 1;
1625 } else {
1626 endpt->ka.enabled = 0;
1627 }
1628 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1629 if (ret) {
1630 goto cleanup;
1631 }
roman5cbb6532023-06-22 12:53:17 +02001632 } else if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001633 /* LOCK */
1634 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001635 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001636 return 1;
1637 }
1638
roman4cb8bb12023-06-29 09:16:46 +02001639 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001640 ret = 1;
1641 goto cleanup;
1642 }
1643
1644 if (op == NC_OP_CREATE) {
1645 ch_endpt->ka.enabled = 1;
1646 } else {
1647 ch_endpt->ka.enabled = 0;
1648 }
romanc1d2b092023-02-02 08:58:27 +01001649 }
1650
1651cleanup:
romanba93eac2023-07-18 14:36:48 +02001652 if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) {
1653 /* UNLOCK */
1654 nc_ch_client_unlock(ch_client);
1655 }
romanc1d2b092023-02-02 08:58:27 +01001656 return ret;
1657}
1658
1659/* mandatory leaf */
1660static int
romane028ef92023-02-24 16:33:08 +01001661nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001662{
roman5cbb6532023-06-22 12:53:17 +02001663 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001664 struct nc_endpt *endpt;
1665 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001666 struct nc_ch_endpt *ch_endpt;
romanba93eac2023-07-18 14:36:48 +02001667 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001668
1669 assert(!strcmp(LYD_NAME(node), "idle-time"));
1670
roman5cbb6532023-06-22 12:53:17 +02001671 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001672 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001673 ret = 1;
1674 goto cleanup;
1675 }
1676
1677 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001678 endpt->ka.idle_time = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001679 } else {
1680 endpt->ka.idle_time = 0;
1681 }
1682 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1683 if (ret) {
1684 goto cleanup;
1685 }
roman5cbb6532023-06-22 12:53:17 +02001686 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001687 /* LOCK */
1688 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001689 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001690 return 1;
1691 }
1692
roman4cb8bb12023-06-29 09:16:46 +02001693 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001694 ret = 1;
1695 goto cleanup;
1696 }
1697
1698 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001699 ch_endpt->ka.idle_time = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001700 } else {
1701 ch_endpt->ka.idle_time = 0;
1702 }
romanc1d2b092023-02-02 08:58:27 +01001703 }
1704
1705cleanup:
roman6430c152023-10-12 11:28:47 +02001706 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001707 /* UNLOCK */
1708 nc_ch_client_unlock(ch_client);
1709 }
romanc1d2b092023-02-02 08:58:27 +01001710 return ret;
1711}
1712
1713/* mandatory leaf */
1714static int
romane028ef92023-02-24 16:33:08 +01001715nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001716{
roman5cbb6532023-06-22 12:53:17 +02001717 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001718 struct nc_endpt *endpt;
1719 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001720 struct nc_ch_endpt *ch_endpt;
romanba93eac2023-07-18 14:36:48 +02001721 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001722
1723 assert(!strcmp(LYD_NAME(node), "max-probes"));
1724
roman5cbb6532023-06-22 12:53:17 +02001725 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001726 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001727 ret = 1;
1728 goto cleanup;
1729 }
1730
1731 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001732 endpt->ka.max_probes = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001733 } else {
1734 endpt->ka.max_probes = 0;
1735 }
1736 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1737 if (ret) {
1738 goto cleanup;
1739 }
roman5cbb6532023-06-22 12:53:17 +02001740 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001741 /* LOCK */
1742 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001743 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001744 return 1;
1745 }
1746
roman4cb8bb12023-06-29 09:16:46 +02001747 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001748 ret = 1;
1749 goto cleanup;
1750 }
1751
1752 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001753 ch_endpt->ka.max_probes = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001754 } else {
1755 ch_endpt->ka.max_probes = 0;
1756 }
romanc1d2b092023-02-02 08:58:27 +01001757 }
1758
1759cleanup:
roman6430c152023-10-12 11:28:47 +02001760 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001761 /* UNLOCK */
1762 nc_ch_client_unlock(ch_client);
1763 }
romanc1d2b092023-02-02 08:58:27 +01001764 return ret;
1765}
1766
1767/* mandatory leaf */
1768static int
romane028ef92023-02-24 16:33:08 +01001769nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001770{
roman5cbb6532023-06-22 12:53:17 +02001771 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001772 struct nc_endpt *endpt;
1773 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001774 struct nc_ch_endpt *ch_endpt;
romanba93eac2023-07-18 14:36:48 +02001775 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001776
1777 assert(!strcmp(LYD_NAME(node), "probe-interval"));
1778
roman5cbb6532023-06-22 12:53:17 +02001779 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001780 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001781 ret = 1;
1782 goto cleanup;
1783 }
1784
1785 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001786 endpt->ka.probe_interval = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001787 } else {
1788 endpt->ka.probe_interval = 0;
1789 }
1790 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1791 if (ret) {
1792 goto cleanup;
1793 }
roman5cbb6532023-06-22 12:53:17 +02001794 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001795 /* LOCK */
1796 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001797 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001798 return 1;
1799 }
1800
roman4cb8bb12023-06-29 09:16:46 +02001801 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001802 ret = 1;
1803 goto cleanup;
1804 }
1805
1806 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001807 ch_endpt->ka.probe_interval = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001808 } else {
1809 ch_endpt->ka.max_probes = 0;
1810 }
romanc1d2b092023-02-02 08:58:27 +01001811 }
1812
1813cleanup:
roman6430c152023-10-12 11:28:47 +02001814 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001815 /* UNLOCK */
1816 nc_ch_client_unlock(ch_client);
1817 }
romanc1d2b092023-02-02 08:58:27 +01001818 return ret;
1819}
1820
1821static int
roman874fed12023-05-25 10:20:01 +02001822nc_server_config_create_host_key(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01001823{
romanf02273a2023-05-25 09:44:11 +02001824 node = lyd_child(node);
1825 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01001826
romanf02273a2023-05-25 09:44:11 +02001827 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->hostkeys, sizeof *opts->hostkeys, &opts->hostkey_count);
romanc1d2b092023-02-02 08:58:27 +01001828}
1829
1830/* list */
1831static int
romane028ef92023-02-24 16:33:08 +01001832nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001833{
roman5cbb6532023-06-22 12:53:17 +02001834 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001835 struct nc_hostkey *hostkey;
roman4cb8bb12023-06-29 09:16:46 +02001836 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02001837 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001838
1839 assert(!strcmp(LYD_NAME(node), "host-key"));
1840
roman4cb8bb12023-06-29 09:16:46 +02001841 if (nc_server_config_get_ssh_opts(node, &opts)) {
1842 ret = 1;
1843 goto cleanup;
1844 }
romanc1d2b092023-02-02 08:58:27 +01001845
roman4cb8bb12023-06-29 09:16:46 +02001846 if (equal_parent_name(node, 1, "server-identity")) {
romanba93eac2023-07-18 14:36:48 +02001847 /* LOCK */
1848 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001849 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001850 return 1;
1851 }
1852
romanc1d2b092023-02-02 08:58:27 +01001853 if (op == NC_OP_CREATE) {
roman4cb8bb12023-06-29 09:16:46 +02001854 ret = nc_server_config_create_host_key(node, opts);
romanc1d2b092023-02-02 08:58:27 +01001855 if (ret) {
1856 goto cleanup;
1857 }
1858 } else if (op == NC_OP_DELETE) {
roman4cb8bb12023-06-29 09:16:46 +02001859 if (nc_server_config_get_hostkey(node, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001860 ret = 1;
1861 goto cleanup;
1862 }
roman4cb8bb12023-06-29 09:16:46 +02001863 nc_server_config_del_hostkey(opts, hostkey);
roman5cbb6532023-06-22 12:53:17 +02001864 }
romanc1d2b092023-02-02 08:58:27 +01001865 }
1866
1867cleanup:
romanba93eac2023-07-18 14:36:48 +02001868 if (is_ch(node) && equal_parent_name(node, 1, "server-identity")) {
1869 /* UNLOCK */
1870 nc_ch_client_unlock(ch_client);
1871 }
romanc1d2b092023-02-02 08:58:27 +01001872 return ret;
1873}
1874
1875/* mandatory leaf */
romane028ef92023-02-24 16:33:08 +01001876static int
1877nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001878{
roman3f9b65c2023-06-05 14:26:58 +02001879 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02001880 const char *format;
roman3f9b65c2023-06-05 14:26:58 +02001881 NC_PUBKEY_FORMAT pubkey_type;
roman8edee342023-03-31 13:25:48 +02001882 struct nc_public_key *pubkey;
romanc1d2b092023-02-02 08:58:27 +01001883 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02001884 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02001885 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001886
1887 assert(!strcmp(LYD_NAME(node), "public-key-format"));
1888
1889 format = ((struct lyd_node_term *)node)->value.ident->name;
roman3f9b65c2023-06-05 14:26:58 +02001890 if (!strcmp(format, "ssh-public-key-format")) {
roman13145912023-08-17 15:36:54 +02001891 pubkey_type = NC_PUBKEY_FORMAT_SSH;
roman3f9b65c2023-06-05 14:26:58 +02001892 } else if (!strcmp(format, "subject-public-key-info-format")) {
1893 pubkey_type = NC_PUBKEY_FORMAT_X509;
1894 } else {
1895 ERR(NULL, "Public key format (%s) not supported.", format);
1896 ret = 1;
1897 goto cleanup;
1898 }
romanc1d2b092023-02-02 08:58:27 +01001899
romanba93eac2023-07-18 14:36:48 +02001900 /* LOCK */
1901 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001902 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001903 return 1;
1904 }
1905
roman4cb8bb12023-06-29 09:16:46 +02001906 if (is_ssh(node) && equal_parent_name(node, 4, "server-identity")) {
roman5cbb6532023-06-22 12:53:17 +02001907 /* SSH hostkey public key fmt */
roman4cb8bb12023-06-29 09:16:46 +02001908 if (nc_server_config_get_hostkey(node, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02001909 ret = 1;
1910 goto cleanup;
1911 }
1912
1913 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1914 hostkey->key.pubkey_type = pubkey_type;
1915 }
roman4cb8bb12023-06-29 09:16:46 +02001916 } else if (is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) {
roman5cbb6532023-06-22 12:53:17 +02001917 /* SSH client auth public key fmt */
roman4cb8bb12023-06-29 09:16:46 +02001918 if (nc_server_config_get_pubkey(node, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001919 ret = 1;
1920 goto cleanup;
1921 }
1922
1923 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman3f9b65c2023-06-05 14:26:58 +02001924 pubkey->type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001925 }
romanb6f44032023-06-30 15:07:56 +02001926 } else if (is_tls(node) && equal_parent_name(node, 3, "server-identity")) {
1927 /* TLS server-identity */
1928 if (nc_server_config_get_tls_opts(node, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02001929 ret = 1;
1930 goto cleanup;
1931 }
1932
roman5cbb6532023-06-22 12:53:17 +02001933 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02001934 opts->pubkey_type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001935 }
romanc1d2b092023-02-02 08:58:27 +01001936 }
1937
1938cleanup:
romanba93eac2023-07-18 14:36:48 +02001939 if (is_ch(node)) {
1940 /* UNLOCK */
1941 nc_ch_client_unlock(ch_client);
1942 }
romanc1d2b092023-02-02 08:58:27 +01001943 return ret;
1944}
1945
1946static int
roman58f79d02023-10-06 10:20:31 +02001947nc_server_config_create_auth_key_public_key_list(const struct lyd_node *node, struct nc_auth_client *auth_client)
romanc1d2b092023-02-02 08:58:27 +01001948{
romanc1d2b092023-02-02 08:58:27 +01001949 assert(!strcmp(LYD_NAME(node), "public-key"));
1950
romanc1d2b092023-02-02 08:58:27 +01001951 node = lyd_child(node);
1952 assert(!strcmp(LYD_NAME(node), "name"));
1953
romanf02273a2023-05-25 09:44:11 +02001954 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 +01001955}
1956
1957static int
roman874fed12023-05-25 10:20:01 +02001958nc_server_config_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +01001959{
roman6430c152023-10-12 11:28:47 +02001960 free(pubkey->data);
roman3f9b65c2023-06-05 14:26:58 +02001961 pubkey->data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001962 NC_CHECK_ERRMEM_RET(!pubkey->data, 1);
romanc1d2b092023-02-02 08:58:27 +01001963
1964 return 0;
1965}
1966
1967static int
roman874fed12023-05-25 10:20:01 +02001968nc_server_config_replace_host_key_public_key(const struct lyd_node *node, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +01001969{
roman6430c152023-10-12 11:28:47 +02001970 free(hostkey->key.pubkey_data);
roman3f9b65c2023-06-05 14:26:58 +02001971 hostkey->key.pubkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001972 NC_CHECK_ERRMEM_RET(!hostkey->key.pubkey_data, 1);
romanc1d2b092023-02-02 08:58:27 +01001973
1974 return 0;
1975}
1976
roman3f9b65c2023-06-05 14:26:58 +02001977static int
1978nc_server_config_tls_replace_server_public_key(const struct lyd_node *node, struct nc_server_tls_opts *opts)
1979{
roman6430c152023-10-12 11:28:47 +02001980 free(opts->pubkey_data);
roman3f9b65c2023-06-05 14:26:58 +02001981 opts->pubkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001982 NC_CHECK_ERRMEM_RET(!opts->pubkey_data, 1);
roman3f9b65c2023-06-05 14:26:58 +02001983
1984 return 0;
1985}
1986
romanc1d2b092023-02-02 08:58:27 +01001987static int
romane028ef92023-02-24 16:33:08 +01001988nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001989{
roman3f9b65c2023-06-05 14:26:58 +02001990 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001991 struct nc_hostkey *hostkey;
roman58f79d02023-10-06 10:20:31 +02001992 struct nc_auth_client *auth_client;
roman8edee342023-03-31 13:25:48 +02001993 struct nc_public_key *pubkey;
romanb6f44032023-06-30 15:07:56 +02001994 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02001995 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001996
1997 assert(!strcmp(LYD_NAME(node), "public-key"));
1998
romanba93eac2023-07-18 14:36:48 +02001999 /* LOCK */
2000 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002001 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002002 return 1;
2003 }
2004
roman4cb8bb12023-06-29 09:16:46 +02002005 if (is_ssh(node) && equal_parent_name(node, 3, "host-key")) {
roman3f9b65c2023-06-05 14:26:58 +02002006 /* server's public-key, mandatory leaf */
roman4cb8bb12023-06-29 09:16:46 +02002007 if (nc_server_config_get_hostkey(node, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01002008 ret = 1;
2009 goto cleanup;
2010 }
2011
roman13145912023-08-17 15:36:54 +02002012 /* the public key must not be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
roman51a1e192023-09-14 10:13:45 +02002013 if (nc_is_pk_subject_public_key_info(lyd_get_value(node))) {
roman13145912023-08-17 15:36:54 +02002014 ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH hostkey is forbidden!");
2015 ret = 1;
2016 goto cleanup;
2017 }
2018
romanc1d2b092023-02-02 08:58:27 +01002019 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02002020 /* set to local */
roman874fed12023-05-25 10:20:01 +02002021 hostkey->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02002022
roman874fed12023-05-25 10:20:01 +02002023 ret = nc_server_config_replace_host_key_public_key(node, hostkey);
romanc1d2b092023-02-02 08:58:27 +01002024 if (ret) {
2025 goto cleanup;
2026 }
2027 }
roman4cb8bb12023-06-29 09:16:46 +02002028 } else if (is_ssh(node) && equal_parent_name(node, 5, "client-authentication")) {
romanc1d2b092023-02-02 08:58:27 +01002029 /* client auth pubkeys, list */
roman4cb8bb12023-06-29 09:16:46 +02002030 if (nc_server_config_get_auth_client(node, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002031 ret = 1;
2032 goto cleanup;
2033 }
2034
2035 if (op == NC_OP_CREATE) {
romanf02273a2023-05-25 09:44:11 +02002036 /* set to local */
roman874fed12023-05-25 10:20:01 +02002037 auth_client->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02002038
roman874fed12023-05-25 10:20:01 +02002039 ret = nc_server_config_create_auth_key_public_key_list(node, auth_client);
romanc1d2b092023-02-02 08:58:27 +01002040 if (ret) {
2041 goto cleanup;
2042 }
2043 } else if (op == NC_OP_DELETE) {
roman4cb8bb12023-06-29 09:16:46 +02002044 if (nc_server_config_get_pubkey(node, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01002045 ret = 1;
2046 goto cleanup;
2047 }
2048
roman874fed12023-05-25 10:20:01 +02002049 nc_server_config_del_auth_client_pubkey(auth_client, pubkey);
romanc1d2b092023-02-02 08:58:27 +01002050 }
roman4cb8bb12023-06-29 09:16:46 +02002051 } else if (is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) {
romanc1d2b092023-02-02 08:58:27 +01002052 /* client auth pubkey, leaf */
roman4cb8bb12023-06-29 09:16:46 +02002053 if (nc_server_config_get_pubkey(node, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01002054 ret = 1;
2055 goto cleanup;
2056 }
2057
roman13145912023-08-17 15:36:54 +02002058 /* the public key must not be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
roman51a1e192023-09-14 10:13:45 +02002059 if (nc_is_pk_subject_public_key_info(lyd_get_value(node))) {
roman13145912023-08-17 15:36:54 +02002060 ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH user's key is forbidden!");
2061 ret = 1;
2062 goto cleanup;
2063 }
2064
romanc1d2b092023-02-02 08:58:27 +01002065 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02002066 ret = nc_server_config_replace_auth_key_public_key_leaf(node, pubkey);
romanc1d2b092023-02-02 08:58:27 +01002067 if (ret) {
2068 goto cleanup;
2069 }
roman6430c152023-10-12 11:28:47 +02002070 } else if (op == NC_OP_DELETE) {
2071 free(pubkey->data);
2072 pubkey->data = NULL;
romanc1d2b092023-02-02 08:58:27 +01002073 }
romanb6f44032023-06-30 15:07:56 +02002074 } else if (is_tls(node) && equal_parent_name(node, 3, "server-identity")) {
2075 /* TLS server-identity */
2076 if (nc_server_config_get_tls_opts(node, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002077 ret = 1;
2078 goto cleanup;
2079 }
2080
roman13145912023-08-17 15:36:54 +02002081 /* the public key must be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
roman51a1e192023-09-14 10:13:45 +02002082 if (!nc_is_pk_subject_public_key_info(lyd_get_value(node))) {
roman13145912023-08-17 15:36:54 +02002083 ERR(NULL, "TLS server certificate's Public Key must be in the SubjectPublicKeyInfo format!");
2084 ret = 1;
2085 goto cleanup;
2086 }
2087
roman3f9b65c2023-06-05 14:26:58 +02002088 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2089 /* set to local */
romanb6f44032023-06-30 15:07:56 +02002090 opts->store = NC_STORE_LOCAL;
roman3f9b65c2023-06-05 14:26:58 +02002091
romanb6f44032023-06-30 15:07:56 +02002092 ret = nc_server_config_tls_replace_server_public_key(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02002093 if (ret) {
2094 goto cleanup;
2095 }
2096 }
roman5cbb6532023-06-22 12:53:17 +02002097 }
2098
2099cleanup:
romanba93eac2023-07-18 14:36:48 +02002100 if (is_ch(node)) {
2101 /* UNLOCK */
2102 nc_ch_client_unlock(ch_client);
2103 }
roman5cbb6532023-06-22 12:53:17 +02002104 return ret;
2105}
2106
2107/* leaf */
2108static int
2109nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op)
2110{
2111 int ret = 0;
2112 const char *format;
2113 NC_PRIVKEY_FORMAT privkey_type;
roman5cbb6532023-06-22 12:53:17 +02002114 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02002115 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002116 struct nc_ch_client *ch_client;
roman5cbb6532023-06-22 12:53:17 +02002117
2118 (void) op;
2119
2120 assert(!strcmp(LYD_NAME(node), "private-key-format"));
2121
2122 format = ((struct lyd_node_term *)node)->value.ident->name;
2123 if (!format) {
2124 ret = 1;
2125 goto cleanup;
2126 }
2127
2128 privkey_type = nc_server_config_get_private_key_type(format);
2129 if (privkey_type == NC_PRIVKEY_FORMAT_UNKNOWN) {
2130 ERR(NULL, "Unknown private key format.");
2131 ret = 1;
2132 goto cleanup;
2133 }
2134
romanba93eac2023-07-18 14:36:48 +02002135 /* LOCK */
2136 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002137 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002138 return 1;
2139 }
2140
roman4cb8bb12023-06-29 09:16:46 +02002141 if (is_ssh(node)) {
2142 /* ssh */
2143 if (nc_server_config_get_hostkey(node, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02002144 ret = 1;
2145 goto cleanup;
2146 }
2147
2148 hostkey->key.privkey_type = privkey_type;
romanb6f44032023-06-30 15:07:56 +02002149 } else if (is_tls(node)) {
2150 /* tls */
2151 if (nc_server_config_get_tls_opts(node, &opts)) {
roman5cbb6532023-06-22 12:53:17 +02002152 ret = 1;
2153 goto cleanup;
2154 }
2155
romanb6f44032023-06-30 15:07:56 +02002156 opts->privkey_type = privkey_type;
roman5cbb6532023-06-22 12:53:17 +02002157 }
2158
2159cleanup:
romanba93eac2023-07-18 14:36:48 +02002160 if (is_ch(node)) {
2161 /* UNLOCK */
2162 nc_ch_client_unlock(ch_client);
2163 }
roman5cbb6532023-06-22 12:53:17 +02002164 return ret;
2165}
2166
2167static int
roman5cbb6532023-06-22 12:53:17 +02002168nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op)
2169{
2170 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02002171 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02002172 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002173 struct nc_ch_client *ch_client;
roman5cbb6532023-06-22 12:53:17 +02002174
2175 assert(!strcmp(LYD_NAME(node), "cleartext-private-key"));
2176
romanba93eac2023-07-18 14:36:48 +02002177 /* LOCK */
2178 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002179 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002180 return 1;
2181 }
2182
roman4cb8bb12023-06-29 09:16:46 +02002183 if (is_ssh(node)) {
2184 /* ssh */
2185 if (nc_server_config_get_hostkey(node, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02002186 ret = 1;
2187 goto cleanup;
2188 }
2189
2190 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002191 free(hostkey->key.privkey_data);
2192 hostkey->key.privkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002193 NC_CHECK_ERRMEM_GOTO(!hostkey->key.privkey_data, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02002194 } else {
roman6430c152023-10-12 11:28:47 +02002195 free(hostkey->key.privkey_data);
2196 hostkey->key.privkey_data = NULL;
roman5cbb6532023-06-22 12:53:17 +02002197 }
romanb6f44032023-06-30 15:07:56 +02002198 } else if (is_tls(node)) {
2199 /* tls */
2200 if (nc_server_config_get_tls_opts(node, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002201 ret = 1;
2202 goto cleanup;
2203 }
2204
roman5cbb6532023-06-22 12:53:17 +02002205 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002206 free(opts->privkey_data);
2207 opts->privkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002208 NC_CHECK_ERRMEM_GOTO(!opts->privkey_data, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02002209 } else {
roman6430c152023-10-12 11:28:47 +02002210 free(opts->privkey_data);
2211 opts->privkey_data = NULL;
roman5cbb6532023-06-22 12:53:17 +02002212 }
roman5cbb6532023-06-22 12:53:17 +02002213 }
2214
2215cleanup:
romanba93eac2023-07-18 14:36:48 +02002216 if (is_ch(node)) {
2217 /* UNLOCK */
2218 nc_ch_client_unlock(ch_client);
2219 }
roman5cbb6532023-06-22 12:53:17 +02002220 return ret;
2221}
2222
roman5cbb6532023-06-22 12:53:17 +02002223/* leaf */
2224static int
2225nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op)
2226{
2227 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02002228 struct nc_hostkey *hostkey;
romanba93eac2023-07-18 14:36:48 +02002229 struct nc_ch_client *ch_client;
roman5cbb6532023-06-22 12:53:17 +02002230
2231 assert(!strcmp(LYD_NAME(node), "keystore-reference"));
2232
romanba93eac2023-07-18 14:36:48 +02002233 /* LOCK */
2234 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002235 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002236 return 1;
2237 }
2238
roman4cb8bb12023-06-29 09:16:46 +02002239 if (is_ssh(node) && equal_parent_name(node, 3, "server-identity")) {
2240 if (nc_server_config_get_hostkey(node, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02002241 ret = 1;
2242 goto cleanup;
2243 }
2244
2245 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2246 /* set to keystore */
2247 hostkey->store = NC_STORE_KEYSTORE;
2248
roman6430c152023-10-12 11:28:47 +02002249 free(hostkey->ks_ref);
romandd019a92023-09-14 10:17:07 +02002250 hostkey->ks_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002251 NC_CHECK_ERRMEM_GOTO(!hostkey->ks_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002252 } else if (op == NC_OP_DELETE) {
2253 free(hostkey->ks_ref);
roman5cbb6532023-06-22 12:53:17 +02002254 hostkey->ks_ref = NULL;
2255 }
roman3f9b65c2023-06-05 14:26:58 +02002256 }
romanc1d2b092023-02-02 08:58:27 +01002257
2258cleanup:
romanba93eac2023-07-18 14:36:48 +02002259 if (is_ch(node)) {
2260 /* UNLOCK */
2261 nc_ch_client_unlock(ch_client);
2262 }
romanc1d2b092023-02-02 08:58:27 +01002263 return ret;
2264}
2265
2266static int
roman6430c152023-10-12 11:28:47 +02002267nc_server_config_create_auth_client(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01002268{
romanf02273a2023-05-25 09:44:11 +02002269 node = lyd_child(node);
2270 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01002271
romanf02273a2023-05-25 09:44:11 +02002272 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 +01002273}
2274
2275/* list */
2276static int
romane028ef92023-02-24 16:33:08 +01002277nc_server_config_user(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002278{
roman5cbb6532023-06-22 12:53:17 +02002279 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002280 struct nc_auth_client *auth_client;
roman4cb8bb12023-06-29 09:16:46 +02002281 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002282 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002283
2284 assert(!strcmp(LYD_NAME(node), "user"));
2285
romanba93eac2023-07-18 14:36:48 +02002286 /* LOCK */
2287 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002288 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002289 return 1;
2290 }
2291
roman4cb8bb12023-06-29 09:16:46 +02002292 if (nc_server_config_get_ssh_opts(node, &opts)) {
2293 ret = 1;
2294 goto cleanup;
2295 }
2296
2297 if (op == NC_OP_CREATE) {
roman6430c152023-10-12 11:28:47 +02002298 ret = nc_server_config_create_auth_client(node, opts);
roman4cb8bb12023-06-29 09:16:46 +02002299 if (ret) {
2300 goto cleanup;
2301 }
2302 } else if (op == NC_OP_DELETE) {
2303 if (nc_server_config_get_auth_client(node, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002304 ret = 1;
2305 goto cleanup;
2306 }
2307
roman4cb8bb12023-06-29 09:16:46 +02002308 nc_server_config_del_auth_client(opts, auth_client);
romanc1d2b092023-02-02 08:58:27 +01002309 }
2310
2311cleanup:
romanba93eac2023-07-18 14:36:48 +02002312 if (is_ch(node)) {
2313 /* UNLOCK */
2314 nc_ch_client_unlock(ch_client);
2315 }
romanc1d2b092023-02-02 08:58:27 +01002316 return ret;
2317}
2318
2319static int
romane028ef92023-02-24 16:33:08 +01002320nc_server_config_auth_attempts(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002321{
romanc1d2b092023-02-02 08:58:27 +01002322 int ret = 0;
roman4cb8bb12023-06-29 09:16:46 +02002323 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002324 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002325
2326 assert(!strcmp(LYD_NAME(node), "auth-attempts"));
2327
romanba93eac2023-07-18 14:36:48 +02002328 /* LOCK */
2329 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002330 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002331 return 1;
2332 }
2333
roman4cb8bb12023-06-29 09:16:46 +02002334 if (nc_server_config_get_ssh_opts(node, &opts)) {
2335 ret = 1;
2336 goto cleanup;
2337 }
romanc1d2b092023-02-02 08:58:27 +01002338
roman4cb8bb12023-06-29 09:16:46 +02002339 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02002340 opts->auth_attempts = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01002341 }
2342
2343cleanup:
romanba93eac2023-07-18 14:36:48 +02002344 if (is_ch(node)) {
2345 /* UNLOCK */
2346 nc_ch_client_unlock(ch_client);
2347 }
romanc1d2b092023-02-02 08:58:27 +01002348 return ret;
2349}
2350
2351static int
romane028ef92023-02-24 16:33:08 +01002352nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002353{
romanc1d2b092023-02-02 08:58:27 +01002354 int ret = 0;
roman4cb8bb12023-06-29 09:16:46 +02002355 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002356 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002357
2358 assert(!strcmp(LYD_NAME(node), "auth-timeout"));
2359
romanba93eac2023-07-18 14:36:48 +02002360 /* LOCK */
2361 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002362 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002363 return 1;
2364 }
2365
roman4cb8bb12023-06-29 09:16:46 +02002366 if (nc_server_config_get_ssh_opts(node, &opts)) {
2367 ret = 1;
2368 goto cleanup;
2369 }
romanc1d2b092023-02-02 08:58:27 +01002370
roman4cb8bb12023-06-29 09:16:46 +02002371 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02002372 opts->auth_timeout = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01002373 }
2374
2375cleanup:
romanba93eac2023-07-18 14:36:48 +02002376 if (is_ch(node)) {
2377 /* UNLOCK */
2378 nc_ch_client_unlock(ch_client);
2379 }
romanc1d2b092023-02-02 08:58:27 +01002380 return ret;
2381}
2382
romanc1d2b092023-02-02 08:58:27 +01002383/* leaf */
2384static int
romane028ef92023-02-24 16:33:08 +01002385nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002386{
romanc1d2b092023-02-02 08:58:27 +01002387 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002388 struct nc_auth_client *auth_client;
romanba93eac2023-07-18 14:36:48 +02002389 struct nc_ch_client *ch_client;
roman6430c152023-10-12 11:28:47 +02002390 struct nc_server_tls_opts *opts;
2391 struct nc_cert_grouping *certs_grp;
romanc1d2b092023-02-02 08:58:27 +01002392
2393 assert(!strcmp(LYD_NAME(node), "truststore-reference"));
2394
romanba93eac2023-07-18 14:36:48 +02002395 /* LOCK */
2396 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002397 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002398 return 1;
2399 }
2400
roman4cb8bb12023-06-29 09:16:46 +02002401 if (is_ssh(node) && equal_parent_name(node, 1, "public-keys")) {
2402 if (nc_server_config_get_auth_client(node, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002403 ret = 1;
2404 goto cleanup;
2405 }
2406
2407 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02002408 /* set to truststore */
roman874fed12023-05-25 10:20:01 +02002409 auth_client->store = NC_STORE_TRUSTSTORE;
romanf02273a2023-05-25 09:44:11 +02002410
roman6430c152023-10-12 11:28:47 +02002411 free(auth_client->ts_ref);
2412 auth_client->ts_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002413 NC_CHECK_ERRMEM_GOTO(!auth_client->ts_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002414 } else if (op == NC_OP_DELETE) {
2415 free(auth_client->ts_ref);
romand57b3722023-04-05 11:26:25 +02002416 auth_client->ts_ref = NULL;
romanc1d2b092023-02-02 08:58:27 +01002417 }
roman6430c152023-10-12 11:28:47 +02002418 } else if (is_tls(node) && (equal_parent_name(node, 1, "ca-certs") || equal_parent_name(node, 1, "ee-certs"))) {
2419 /* ee-certs or ca-certs */
2420 if (nc_server_config_get_tls_opts(node, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002421 ret = 1;
2422 goto cleanup;
2423 }
2424
roman6430c152023-10-12 11:28:47 +02002425 if (equal_parent_name(node, 1, "ca-certs")) {
2426 certs_grp = &opts->ca_certs;
roman3f9b65c2023-06-05 14:26:58 +02002427 } else {
roman6430c152023-10-12 11:28:47 +02002428 certs_grp = &opts->ee_certs;
roman4cb8bb12023-06-29 09:16:46 +02002429 }
2430
roman3f9b65c2023-06-05 14:26:58 +02002431 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2432 /* set to truststore */
roman6430c152023-10-12 11:28:47 +02002433 certs_grp->store = NC_STORE_TRUSTSTORE;
roman3f9b65c2023-06-05 14:26:58 +02002434
roman6430c152023-10-12 11:28:47 +02002435 free(certs_grp->ts_ref);
2436 certs_grp->ts_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002437 NC_CHECK_ERRMEM_GOTO(!certs_grp->ts_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002438 } else if (op == NC_OP_DELETE) {
2439 free(certs_grp->ts_ref);
2440 certs_grp->ts_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002441 }
2442 }
romanc1d2b092023-02-02 08:58:27 +01002443
2444cleanup:
romanba93eac2023-07-18 14:36:48 +02002445 if (is_ch(node)) {
2446 /* UNLOCK */
2447 nc_ch_client_unlock(ch_client);
2448 }
romanc1d2b092023-02-02 08:58:27 +01002449 return ret;
2450}
2451
romanc1d2b092023-02-02 08:58:27 +01002452/* leaf */
2453static int
romane028ef92023-02-24 16:33:08 +01002454nc_server_config_password(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002455{
roman5cbb6532023-06-22 12:53:17 +02002456 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002457 struct nc_auth_client *auth_client;
romanba93eac2023-07-18 14:36:48 +02002458 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002459
2460 assert(!strcmp(LYD_NAME(node), "password"));
2461
romanba93eac2023-07-18 14:36:48 +02002462 /* LOCK */
2463 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002464 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002465 return 1;
2466 }
2467
roman4cb8bb12023-06-29 09:16:46 +02002468 if (nc_server_config_get_auth_client(node, &auth_client)) {
2469 ret = 1;
2470 goto cleanup;
2471 }
2472
2473 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002474 free(auth_client->password);
2475 auth_client->password = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002476 NC_CHECK_ERRMEM_GOTO(!auth_client->password, ret = 1, cleanup);
roman4cb8bb12023-06-29 09:16:46 +02002477 } else {
roman6430c152023-10-12 11:28:47 +02002478 free(auth_client->password);
2479 auth_client->password = NULL;
romanc1d2b092023-02-02 08:58:27 +01002480 }
2481
2482cleanup:
romanba93eac2023-07-18 14:36:48 +02002483 if (is_ch(node)) {
2484 /* UNLOCK */
2485 nc_ch_client_unlock(ch_client);
2486 }
romanc1d2b092023-02-02 08:58:27 +01002487 return ret;
2488}
2489
2490static int
romane028ef92023-02-24 16:33:08 +01002491nc_server_config_pam_name(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002492{
roman5cbb6532023-06-22 12:53:17 +02002493 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002494 struct nc_auth_client *auth_client;
romanba93eac2023-07-18 14:36:48 +02002495 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002496
2497 assert(!strcmp(LYD_NAME(node), "pam-config-file-name"));
2498
romanba93eac2023-07-18 14:36:48 +02002499 /* LOCK */
2500 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002501 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002502 return 1;
2503 }
2504
roman4cb8bb12023-06-29 09:16:46 +02002505 if (nc_server_config_get_auth_client(node, &auth_client)) {
2506 ret = 1;
2507 goto cleanup;
2508 }
2509
2510 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002511 free(auth_client->pam_config_name);
roman4cb8bb12023-06-29 09:16:46 +02002512 auth_client->pam_config_name = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002513 NC_CHECK_ERRMEM_GOTO(!auth_client->pam_config_name, ret = 1, cleanup);
roman4cb8bb12023-06-29 09:16:46 +02002514 } else {
roman6430c152023-10-12 11:28:47 +02002515 free(auth_client->pam_config_name);
2516 auth_client->pam_config_name = NULL;
romanc1d2b092023-02-02 08:58:27 +01002517 }
2518
2519cleanup:
romanba93eac2023-07-18 14:36:48 +02002520 if (is_ch(node)) {
2521 /* UNLOCK */
2522 nc_ch_client_unlock(ch_client);
2523 }
romanc1d2b092023-02-02 08:58:27 +01002524 return ret;
2525}
2526
2527static int
romane028ef92023-02-24 16:33:08 +01002528nc_server_config_pam_dir(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002529{
roman5cbb6532023-06-22 12:53:17 +02002530 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002531 struct nc_auth_client *auth_client;
romanba93eac2023-07-18 14:36:48 +02002532 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002533
2534 assert(!strcmp(LYD_NAME(node), "pam-config-file-dir"));
2535
romanba93eac2023-07-18 14:36:48 +02002536 /* LOCK */
2537 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002538 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002539 return 1;
2540 }
2541
roman4cb8bb12023-06-29 09:16:46 +02002542 if (nc_server_config_get_auth_client(node, &auth_client)) {
2543 ret = 1;
2544 goto cleanup;
2545 }
2546
2547 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002548 free(auth_client->pam_config_dir);
roman4cb8bb12023-06-29 09:16:46 +02002549 auth_client->pam_config_dir = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002550 NC_CHECK_ERRMEM_GOTO(!auth_client->pam_config_dir, ret = 1, cleanup);
roman4cb8bb12023-06-29 09:16:46 +02002551 } else {
roman6430c152023-10-12 11:28:47 +02002552 free(auth_client->pam_config_dir);
2553 auth_client->pam_config_dir = NULL;
romanc1d2b092023-02-02 08:58:27 +01002554 }
2555
2556cleanup:
romanba93eac2023-07-18 14:36:48 +02002557 if (is_ch(node)) {
2558 /* UNLOCK */
2559 nc_ch_client_unlock(ch_client);
2560 }
romanc1d2b092023-02-02 08:58:27 +01002561 return ret;
2562}
2563
2564/* leaf */
2565static int
romane028ef92023-02-24 16:33:08 +01002566nc_server_config_none(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002567{
roman5cbb6532023-06-22 12:53:17 +02002568 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002569 struct nc_auth_client *auth_client;
romanba93eac2023-07-18 14:36:48 +02002570 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002571
2572 assert(!strcmp(LYD_NAME(node), "none"));
2573
romanba93eac2023-07-18 14:36:48 +02002574 /* LOCK */
2575 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002576 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002577 return 1;
2578 }
2579
roman4cb8bb12023-06-29 09:16:46 +02002580 if (nc_server_config_get_auth_client(node, &auth_client)) {
2581 ret = 1;
2582 goto cleanup;
2583 }
romanc1d2b092023-02-02 08:58:27 +01002584
roman4cb8bb12023-06-29 09:16:46 +02002585 if (op == NC_OP_CREATE) {
2586 auth_client->supports_none = 1;
2587 } else {
2588 auth_client->supports_none = 0;
romanc1d2b092023-02-02 08:58:27 +01002589 }
2590
2591cleanup:
romanba93eac2023-07-18 14:36:48 +02002592 if (is_ch(node)) {
2593 /* UNLOCK */
2594 nc_ch_client_unlock(ch_client);
2595 }
romanc1d2b092023-02-02 08:58:27 +01002596 return ret;
2597}
2598
2599static int
romanc135c6d2023-10-25 13:32:30 +02002600nc_server_config_delete_substring(const char *haystack, const char *needle, const char delim)
2601{
2602 size_t needle_len = strlen(needle);
2603 char *substr;
2604 int substr_found = 0, ret = 0;
2605
2606 while ((substr = strstr(haystack, needle))) {
2607 /* iterate over all the substrings */
2608 if (((substr == haystack) && (*(substr + needle_len) == delim)) ||
2609 ((substr != haystack) && (*(substr - 1) == delim) && (*(substr + needle_len) == delim))) {
2610 /* either the first element of the string or somewhere in the middle */
2611 memmove(substr, substr + needle_len + 1, strlen(substr + needle_len + 1));
2612 substr_found = 1;
2613 break;
2614 } else if ((*(substr - 1) == delim) && (*(substr + needle_len) == '\0')) {
2615 /* the last element of the string */
2616 *(substr - 1) = '\0';
2617 substr_found = 1;
2618 break;
2619 }
2620 haystack = substr + 1;
2621 }
2622 if (!substr_found) {
2623 ret = 1;
2624 }
2625
2626 return ret;
2627}
2628
2629static int
romana6bf6ab2023-05-26 13:26:02 +02002630nc_server_config_transport_params(const char *algorithm, char **alg_store, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002631{
romanc135c6d2023-10-25 13:32:30 +02002632 int ret = 0;
2633 char *alg = NULL;
romana6bf6ab2023-05-26 13:26:02 +02002634
2635 if (!strncmp(algorithm, "openssh-", 8)) {
2636 /* if the name starts with openssh, convert it to it's original libssh accepted form */
roman3a95bb22023-10-26 11:07:17 +02002637 ret = asprintf(&alg, "%s@openssh.com", algorithm + 8);
2638 NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; alg = NULL, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002639 } else if (!strncmp(algorithm, "libssh-", 7)) {
2640 /* if the name starts with libssh, convert it to it's original libssh accepted form */
roman3a95bb22023-10-26 11:07:17 +02002641 ret = asprintf(&alg, "%s@libssh.org", algorithm + 7);
2642 NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; alg = NULL, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002643 } else {
2644 alg = strdup(algorithm);
roman3a95bb22023-10-26 11:07:17 +02002645 NC_CHECK_ERRMEM_GOTO(!alg, ret = 1, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002646 }
2647
romanc1d2b092023-02-02 08:58:27 +01002648 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2649 if (!*alg_store) {
2650 /* first call */
2651 *alg_store = strdup(alg);
roman3a95bb22023-10-26 11:07:17 +02002652 NC_CHECK_ERRMEM_GOTO(!*alg_store, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01002653 } else {
2654 /* +1 because of ',' between algorithms */
roman3a95bb22023-10-26 11:07:17 +02002655 *alg_store = nc_realloc(*alg_store, strlen(*alg_store) + strlen(alg) + 1 + 1);
2656 NC_CHECK_ERRMEM_GOTO(!*alg_store, ret = 1, cleanup);
roman08f67f42023-06-08 13:51:54 +02002657 strcat(*alg_store, ",");
2658 strcat(*alg_store, alg);
romanc1d2b092023-02-02 08:58:27 +01002659 }
2660 } else {
2661 /* delete */
romanc135c6d2023-10-25 13:32:30 +02002662 ret = nc_server_config_delete_substring(*alg_store, alg, ',');
2663 if (ret) {
romanc1d2b092023-02-02 08:58:27 +01002664 ERR(NULL, "Unable to delete an algorithm (%s), which was not previously added.", alg);
romanc135c6d2023-10-25 13:32:30 +02002665 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002666 }
2667 }
2668
2669cleanup:
romana6bf6ab2023-05-26 13:26:02 +02002670 free(alg);
romanc1d2b092023-02-02 08:58:27 +01002671 return ret;
2672}
2673
2674/* leaf-list */
2675static int
romane028ef92023-02-24 16:33:08 +01002676nc_server_config_host_key_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002677{
roman5cbb6532023-06-22 12:53:17 +02002678 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002679 const char *alg;
2680 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002681 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002682 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002683
roman5cbb6532023-06-22 12:53:17 +02002684 assert(!strcmp(LYD_NAME(node), "host-key-alg"));
romanc1d2b092023-02-02 08:58:27 +01002685
romanba93eac2023-07-18 14:36:48 +02002686 /* LOCK */
2687 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002688 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002689 return 1;
2690 }
2691
roman4cb8bb12023-06-29 09:16:46 +02002692 if (nc_server_config_get_ssh_opts(node, &opts)) {
2693 ret = 1;
2694 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002695 }
2696
roman5cbb6532023-06-22 12:53:17 +02002697 /* get the algorithm name and compare it with algs supported by libssh */
2698 alg = ((struct lyd_node_term *)node)->value.ident->name;
romanc1d2b092023-02-02 08:58:27 +01002699 i = 0;
2700 while (supported_hostkey_algs[i]) {
2701 if (!strcmp(supported_hostkey_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002702 if (nc_server_config_transport_params(alg, &opts->hostkey_algs, op)) {
2703 ret = 1;
2704 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002705 }
2706 break;
2707 }
2708 i++;
2709 }
2710 if (!supported_hostkey_algs[i]) {
2711 /* algorithm not supported */
2712 ERR(NULL, "Public key algorithm (%s) not supported by libssh.", alg);
2713 ret = 1;
2714 }
2715
2716cleanup:
romanba93eac2023-07-18 14:36:48 +02002717 if (is_ch(node)) {
2718 /* UNLOCK */
2719 nc_ch_client_unlock(ch_client);
2720 }
romanc1d2b092023-02-02 08:58:27 +01002721 return ret;
2722}
2723
2724/* leaf-list */
2725static int
romane028ef92023-02-24 16:33:08 +01002726nc_server_config_kex_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002727{
roman5cbb6532023-06-22 12:53:17 +02002728 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002729 const char *alg;
2730 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002731 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002732 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002733
roman5cbb6532023-06-22 12:53:17 +02002734 assert(!strcmp(LYD_NAME(node), "key-exchange-alg"));
romanc1d2b092023-02-02 08:58:27 +01002735
romanba93eac2023-07-18 14:36:48 +02002736 /* LOCK */
2737 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002738 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002739 return 1;
2740 }
2741
roman4cb8bb12023-06-29 09:16:46 +02002742 if (nc_server_config_get_ssh_opts(node, &opts)) {
2743 ret = 1;
2744 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002745 }
2746
roman5cbb6532023-06-22 12:53:17 +02002747 /* get the algorithm name and compare it with algs supported by libssh */
2748 alg = ((struct lyd_node_term *)node)->value.ident->name;
romanc1d2b092023-02-02 08:58:27 +01002749 i = 0;
2750 while (supported_kex_algs[i]) {
2751 if (!strcmp(supported_kex_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002752 if (nc_server_config_transport_params(alg, &opts->kex_algs, op)) {
2753 ret = 1;
2754 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002755 }
2756 break;
2757 }
2758 i++;
2759 }
2760 if (!supported_kex_algs[i]) {
2761 /* algorithm not supported */
2762 ERR(NULL, "Key exchange algorithm (%s) not supported by libssh.", alg);
2763 ret = 1;
2764 }
2765
2766cleanup:
romanba93eac2023-07-18 14:36:48 +02002767 if (is_ch(node)) {
2768 /* UNLOCK */
2769 nc_ch_client_unlock(ch_client);
2770 }
romanc1d2b092023-02-02 08:58:27 +01002771 return ret;
2772}
2773
2774/* leaf-list */
2775static int
romane028ef92023-02-24 16:33:08 +01002776nc_server_config_encryption_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002777{
roman5cbb6532023-06-22 12:53:17 +02002778 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002779 const char *alg;
2780 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002781 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002782 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002783
roman5cbb6532023-06-22 12:53:17 +02002784 assert(!strcmp(LYD_NAME(node), "encryption-alg"));
romanc1d2b092023-02-02 08:58:27 +01002785
romanba93eac2023-07-18 14:36:48 +02002786 /* LOCK */
2787 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002788 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002789 return 1;
2790 }
2791
roman4cb8bb12023-06-29 09:16:46 +02002792 if (nc_server_config_get_ssh_opts(node, &opts)) {
2793 ret = 1;
2794 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002795 }
2796
roman5cbb6532023-06-22 12:53:17 +02002797 /* get the algorithm name and compare it with algs supported by libssh */
2798 alg = ((struct lyd_node_term *)node)->value.ident->name;
romanc1d2b092023-02-02 08:58:27 +01002799 i = 0;
2800 while (supported_encryption_algs[i]) {
2801 if (!strcmp(supported_encryption_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002802 if (nc_server_config_transport_params(alg, &opts->encryption_algs, op)) {
2803 ret = 1;
2804 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002805 }
2806 break;
2807 }
2808 i++;
2809 }
2810 if (!supported_encryption_algs[i]) {
2811 /* algorithm not supported */
2812 ERR(NULL, "Encryption algorithm (%s) not supported by libssh.", alg);
2813 ret = 1;
2814 }
2815
2816cleanup:
romanba93eac2023-07-18 14:36:48 +02002817 if (is_ch(node)) {
2818 /* UNLOCK */
2819 nc_ch_client_unlock(ch_client);
2820 }
romanc1d2b092023-02-02 08:58:27 +01002821 return ret;
2822}
2823
2824/* leaf-list */
2825static int
romane028ef92023-02-24 16:33:08 +01002826nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002827{
roman5cbb6532023-06-22 12:53:17 +02002828 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002829 const char *alg;
2830 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002831 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002832 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002833
roman5cbb6532023-06-22 12:53:17 +02002834 assert(!strcmp(LYD_NAME(node), "mac-alg"));
romanc1d2b092023-02-02 08:58:27 +01002835
romanba93eac2023-07-18 14:36:48 +02002836 /* LOCK */
2837 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002838 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002839 return 1;
2840 }
2841
roman4cb8bb12023-06-29 09:16:46 +02002842 if (nc_server_config_get_ssh_opts(node, &opts)) {
2843 ret = 1;
2844 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002845 }
2846
roman5cbb6532023-06-22 12:53:17 +02002847 /* get the algorithm name and compare it with algs supported by libssh */
2848 alg = ((struct lyd_node_term *)node)->value.ident->name;
romanc1d2b092023-02-02 08:58:27 +01002849 i = 0;
2850 while (supported_mac_algs[i]) {
2851 if (!strcmp(supported_mac_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002852 if (nc_server_config_transport_params(alg, &opts->mac_algs, op)) {
2853 ret = 1;
2854 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002855 }
2856 break;
2857 }
2858 i++;
2859 }
2860 if (!supported_mac_algs[i]) {
2861 /* algorithm not supported */
2862 ERR(NULL, "MAC algorithm (%s) not supported by libssh.", alg);
2863 ret = 1;
2864 }
2865
2866cleanup:
romanba93eac2023-07-18 14:36:48 +02002867 if (is_ch(node)) {
2868 /* UNLOCK */
2869 nc_ch_client_unlock(ch_client);
2870 }
romanc1d2b092023-02-02 08:58:27 +01002871 return ret;
2872}
2873
roman2eab4742023-06-06 10:00:26 +02002874#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02002875
romanc1d2b092023-02-02 08:58:27 +01002876static int
roman874fed12023-05-25 10:20:01 +02002877nc_server_config_create_unix_socket(struct nc_endpt *endpt)
roman83683fb2023-02-24 09:15:23 +01002878{
2879 endpt->ti = NC_TI_UNIX;
2880 endpt->opts.unixsock = calloc(1, sizeof *endpt->opts.unixsock);
roman3a95bb22023-10-26 11:07:17 +02002881 NC_CHECK_ERRMEM_RET(!endpt->opts.unixsock, 1);
roman83683fb2023-02-24 09:15:23 +01002882
2883 /* set default values */
2884 endpt->opts.unixsock->mode = -1;
2885 endpt->opts.unixsock->uid = -1;
2886 endpt->opts.unixsock->gid = -1;
2887
2888 return 0;
2889}
2890
2891static int
romane028ef92023-02-24 16:33:08 +01002892nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op)
roman83683fb2023-02-24 09:15:23 +01002893{
2894 int ret = 0;
roman84fe3252023-10-25 11:28:32 +02002895 uint32_t log_options = 0;
roman83683fb2023-02-24 09:15:23 +01002896 struct nc_endpt *endpt;
2897 struct nc_bind *bind;
2898 struct nc_server_unix_opts *opts;
2899 struct lyd_node *data = NULL;
2900
2901 assert(!strcmp(LYD_NAME(node), "unix-socket"));
2902
romanf02273a2023-05-25 09:44:11 +02002903 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
roman83683fb2023-02-24 09:15:23 +01002904 ret = 1;
2905 goto cleanup;
2906 }
2907
2908 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +02002909 if (nc_server_config_create_unix_socket(endpt)) {
roman83683fb2023-02-24 09:15:23 +01002910 ret = 1;
2911 goto cleanup;
2912 }
2913
2914 opts = endpt->opts.unixsock;
2915
2916 lyd_find_path(node, "path", 0, &data);
2917 assert(data);
2918
2919 opts->address = strdup(lyd_get_value(data));
2920 bind->address = strdup(lyd_get_value(data));
roman3a95bb22023-10-26 11:07:17 +02002921 NC_CHECK_ERRMEM_GOTO(!opts->address || !bind->address, ret = 1, cleanup);
roman83683fb2023-02-24 09:15:23 +01002922
2923 /* silently search for non-mandatory parameters */
roman84fe3252023-10-25 11:28:32 +02002924 ly_temp_log_options(&log_options);
roman83683fb2023-02-24 09:15:23 +01002925 ret = lyd_find_path(node, "mode", 0, &data);
2926 if (!ret) {
2927 opts->mode = strtol(lyd_get_value(data), NULL, 8);
2928 }
2929
2930 ret = lyd_find_path(node, "uid", 0, &data);
2931 if (!ret) {
2932 opts->uid = strtol(lyd_get_value(data), NULL, 10);
2933 }
2934
2935 ret = lyd_find_path(node, "gid", 0, &data);
2936 if (!ret) {
2937 opts->gid = strtol(lyd_get_value(data), NULL, 10);
2938 }
2939
2940 /* reset the logging options */
roman84fe3252023-10-25 11:28:32 +02002941 ly_temp_log_options(NULL);
roman83683fb2023-02-24 09:15:23 +01002942
2943 ret = nc_server_config_set_address_port(endpt, bind, NULL, 0);
2944 if (ret) {
2945 goto cleanup;
2946 }
2947 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02002948 nc_server_config_del_unix_socket_opts(bind, endpt->opts.unixsock);
roman83683fb2023-02-24 09:15:23 +01002949 }
2950
2951cleanup:
2952 return ret;
2953}
2954
roman2eab4742023-06-06 10:00:26 +02002955#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02002956
roman0bbc19c2023-05-26 09:59:09 +02002957/**
roman6430c152023-10-12 11:28:47 +02002958 * @brief Set all endpoint client auth references, which couldn't be set while parsing data.
roman0bbc19c2023-05-26 09:59:09 +02002959 *
2960 * @return 0 on success, 1 on error.
2961 */
2962static int
2963nc_server_config_fill_endpt_client_auth(void)
2964{
2965 uint16_t i, j;
2966
2967 for (i = 0; i < server_opts.endpt_count; i++) {
roman6430c152023-10-12 11:28:47 +02002968 /* go through all the endpoints */
roman0bbc19c2023-05-26 09:59:09 +02002969 if (server_opts.endpts[i].referenced_endpt_name) {
2970 /* endpt has a reference, that hasn't been set yet */
roman6430c152023-10-12 11:28:47 +02002971 for (j = 0; j < server_opts.endpt_count; j++) {
2972 /* go through all the endpts */
roman0bbc19c2023-05-26 09:59:09 +02002973 if (!strcmp(server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[j].name)) {
roman6430c152023-10-12 11:28:47 +02002974 /* found the endpoint we were looking for,
2975 * assign the server opts from the referenced endpt */
roman0bbc19c2023-05-26 09:59:09 +02002976 if (server_opts.endpts[i].ti == NC_TI_LIBSSH) {
2977 server_opts.endpts[i].opts.ssh->endpt_client_ref = &server_opts.endpts[j];
2978 break;
roman2e797ef2023-06-19 10:47:49 +02002979 } else if (server_opts.endpts[i].ti == NC_TI_OPENSSL) {
2980 server_opts.endpts[i].opts.tls->endpt_client_ref = &server_opts.endpts[j];
2981 break;
roman0bbc19c2023-05-26 09:59:09 +02002982 } else {
2983 ERRINT;
2984 return 1;
2985 }
2986 }
2987 }
2988
2989 /* didn't find the endpoint */
2990 if (j == server_opts.endpt_count) {
2991 ERR(NULL, "Endpoint \"%s\" referenced by \"%s\" not found.",
2992 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2993 return 1;
2994 }
2995 }
2996 }
2997
2998 return 0;
2999}
3000
3001static int
roman2e797ef2023-06-19 10:47:49 +02003002nc_server_config_endpoint_client_auth_has_cycle(struct nc_endpt *original, struct nc_endpt *next)
roman0bbc19c2023-05-26 09:59:09 +02003003{
roman2e797ef2023-06-19 10:47:49 +02003004 if (original->ti == NC_TI_LIBSSH) {
3005 if (!next->opts.ssh->endpt_client_ref) {
3006 /* no further reference -> no cycle */
roman0bbc19c2023-05-26 09:59:09 +02003007 return 0;
3008 }
roman2e797ef2023-06-19 10:47:49 +02003009
3010 if (next->opts.ssh->endpt_client_ref == original) {
3011 /* found cycle */
3012 return 1;
3013 } else {
3014 /* continue further */
3015 return nc_server_config_endpoint_client_auth_has_cycle(original, next->opts.ssh->endpt_client_ref);
3016 }
3017 } else if (original->ti == NC_TI_OPENSSL) {
3018 if (!next->opts.tls->endpt_client_ref) {
3019 /* no further reference -> no cycle */
3020 return 0;
3021 }
3022
3023 if (next->opts.tls->endpt_client_ref == original) {
3024 /* found cycle */
3025 return 1;
3026 } else {
3027 /* continue further */
3028 return nc_server_config_endpoint_client_auth_has_cycle(original, next->opts.tls->endpt_client_ref);
3029 }
roman0bbc19c2023-05-26 09:59:09 +02003030 } else {
3031 ERRINT;
3032 return 1;
3033 }
3034}
3035
3036static int
3037nc_server_config_endpoint_client_auth(const struct lyd_node *node, NC_OPERATION op)
3038{
3039 int ret = 0;
3040 uint16_t i;
3041 const char *endpt_name;
3042 struct nc_endpt *endpt;
3043
3044 assert(!strcmp(LYD_NAME(node), "endpoint-client-auth"));
3045
3046 /* get current endpoint */
3047 ret = nc_server_config_get_endpt(node, &endpt, NULL);
3048 if (ret) {
3049 goto cleanup;
3050 }
3051
3052 if (op == NC_OP_DELETE) {
roman2e797ef2023-06-19 10:47:49 +02003053 if (is_ssh(node)) {
3054 endpt->opts.ssh->endpt_client_ref = NULL;
3055 } else {
3056 endpt->opts.tls->endpt_client_ref = NULL;
3057 }
roman0bbc19c2023-05-26 09:59:09 +02003058 goto cleanup;
3059 }
3060
3061 /* find the endpoint leafref is referring to */
3062 endpt_name = lyd_get_value(node);
3063 for (i = 0; i < server_opts.endpt_count; i++) {
3064 if (!strcmp(endpt_name, server_opts.endpts[i].name)) {
3065 break;
3066 }
3067 }
3068
3069 if (i == server_opts.endpt_count) {
3070 /* endpt not found, save the name and try to look it up later */
roman6430c152023-10-12 11:28:47 +02003071 free(endpt->referenced_endpt_name);
roman0bbc19c2023-05-26 09:59:09 +02003072 endpt->referenced_endpt_name = strdup(endpt_name);
roman3a95bb22023-10-26 11:07:17 +02003073 NC_CHECK_ERRMEM_GOTO(!endpt->referenced_endpt_name, ret = 1, cleanup);
roman0bbc19c2023-05-26 09:59:09 +02003074 goto cleanup;
3075 }
3076
3077 /* check for self reference */
3078 if (endpt == &server_opts.endpts[i]) {
roman6430c152023-10-12 11:28:47 +02003079 ERR(NULL, "Self endpoint reference detected for endpoint \"%s\".", endpt->name);
roman0bbc19c2023-05-26 09:59:09 +02003080 ret = 1;
3081 goto cleanup;
3082 }
3083
3084 /* check for cyclic references */
roman2e797ef2023-06-19 10:47:49 +02003085 ret = nc_server_config_endpoint_client_auth_has_cycle(endpt, &server_opts.endpts[i]);
roman0bbc19c2023-05-26 09:59:09 +02003086 if (ret) {
roman6430c152023-10-12 11:28:47 +02003087 ERR(NULL, "Cyclic endpoint reference detected for endpoint \"%s\".", endpt->name);
roman0bbc19c2023-05-26 09:59:09 +02003088 goto cleanup;
3089 }
3090
3091 /* assign the current endpt the referrenced endpt */
roman2e797ef2023-06-19 10:47:49 +02003092 if (is_ssh(node)) {
3093 endpt->opts.ssh->endpt_client_ref = &server_opts.endpts[i];
3094 } else {
3095 endpt->opts.tls->endpt_client_ref = &server_opts.endpts[i];
3096 }
roman0bbc19c2023-05-26 09:59:09 +02003097
3098cleanup:
3099 return ret;
3100}
3101
roman3f9b65c2023-06-05 14:26:58 +02003102static int
roman3f9b65c2023-06-05 14:26:58 +02003103nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op)
3104{
3105 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02003106 struct nc_certificate *cert;
romanb6f44032023-06-30 15:07:56 +02003107 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02003108 struct nc_ch_client *ch_client;
roman3f9b65c2023-06-05 14:26:58 +02003109
3110 assert(!strcmp(LYD_NAME(node), "cert-data"));
3111
romanba93eac2023-07-18 14:36:48 +02003112 /* LOCK */
3113 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003114 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003115 return 1;
3116 }
3117
romanb6f44032023-06-30 15:07:56 +02003118 if (equal_parent_name(node, 3, "server-identity")) {
3119 if (nc_server_config_get_tls_opts(node, &opts)) {
3120 ret = 1;
3121 goto cleanup;
3122 }
roman3f9b65c2023-06-05 14:26:58 +02003123
roman3f9b65c2023-06-05 14:26:58 +02003124 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003125 free(opts->cert_data);
3126 opts->cert_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003127 NC_CHECK_ERRMEM_GOTO(!opts->cert_data, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003128 }
roman6430c152023-10-12 11:28:47 +02003129 } else if (equal_parent_name(node, 3, "ca-certs") || equal_parent_name(node, 3, "ee-certs")) {
3130 if (nc_server_config_get_cert(node, &cert)) {
roman3f9b65c2023-06-05 14:26:58 +02003131 ret = 1;
3132 goto cleanup;
3133 }
3134
3135 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003136 free(cert->data);
3137 cert->data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003138 NC_CHECK_ERRMEM_GOTO(!cert->data, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003139 } else {
roman6430c152023-10-12 11:28:47 +02003140 free(cert->data);
3141 cert->data = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003142 }
3143 }
3144
3145cleanup:
romanba93eac2023-07-18 14:36:48 +02003146 if (is_ch(node)) {
3147 /* UNLOCK */
3148 nc_ch_client_unlock(ch_client);
3149 }
roman3f9b65c2023-06-05 14:26:58 +02003150 return ret;
3151}
3152
3153static int
roman3f9b65c2023-06-05 14:26:58 +02003154nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op)
3155{
3156 int ret = 0;
3157 struct nc_endpt *endpt;
romanba93eac2023-07-18 14:36:48 +02003158 struct nc_ch_client *ch_client;
roman3f9b65c2023-06-05 14:26:58 +02003159
3160 assert(!strcmp(LYD_NAME(node), "asymmetric-key"));
3161
romanba93eac2023-07-18 14:36:48 +02003162 /* LOCK */
3163 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003164 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003165 return 1;
3166 }
3167
roman3f9b65c2023-06-05 14:26:58 +02003168 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
3169 ret = 1;
3170 goto cleanup;
3171 }
3172
3173 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
3174 /* set to keystore */
3175 endpt->opts.tls->store = NC_STORE_KEYSTORE;
3176
roman6430c152023-10-12 11:28:47 +02003177 free(endpt->opts.tls->key_ref);
3178 endpt->opts.tls->key_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003179 NC_CHECK_ERRMEM_GOTO(!endpt->opts.tls->key_ref, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003180 } else {
roman6430c152023-10-12 11:28:47 +02003181 free(endpt->opts.tls->key_ref);
roman3f9b65c2023-06-05 14:26:58 +02003182 endpt->opts.tls->key_ref = NULL;
3183 }
3184
3185cleanup:
romanba93eac2023-07-18 14:36:48 +02003186 if (is_ch(node)) {
3187 /* UNLOCK */
3188 nc_ch_client_unlock(ch_client);
3189 }
roman3f9b65c2023-06-05 14:26:58 +02003190 return ret;
3191}
3192
3193static int
roman3f9b65c2023-06-05 14:26:58 +02003194nc_server_config_create_ca_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
3195{
3196 assert(!strcmp(LYD_NAME(node), "certificate"));
3197
3198 node = lyd_child(node);
3199 assert(!strcmp(LYD_NAME(node), "name"));
3200
3201 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ca_certs.certs, sizeof *opts->ca_certs.certs, &opts->ca_certs.cert_count);
3202}
3203
3204static int
3205nc_server_config_create_ee_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
3206{
3207 assert(!strcmp(LYD_NAME(node), "certificate"));
3208
3209 node = lyd_child(node);
3210 assert(!strcmp(LYD_NAME(node), "name"));
3211
3212 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ee_certs.certs, sizeof *opts->ee_certs.certs, &opts->ee_certs.cert_count);
3213}
3214
3215static int
3216nc_server_config_certificate(const struct lyd_node *node, NC_OPERATION op)
3217{
3218 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003219 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02003220 struct nc_ch_client *ch_client;
roman6430c152023-10-12 11:28:47 +02003221 struct nc_certificate *cert;
roman3f9b65c2023-06-05 14:26:58 +02003222
3223 assert(!strcmp(LYD_NAME(node), "certificate"));
3224
romanba93eac2023-07-18 14:36:48 +02003225 /* LOCK */
3226 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003227 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003228 return 1;
3229 }
3230
romanb6f44032023-06-30 15:07:56 +02003231 if (nc_server_config_get_tls_opts(node, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02003232 ret = 1;
3233 goto cleanup;
3234 }
3235
romanb6f44032023-06-30 15:07:56 +02003236 if (equal_parent_name(node, 1, "keystore-reference")) {
3237 /* TLS server-identity */
roman3f9b65c2023-06-05 14:26:58 +02003238 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
3239 /* set to keystore */
romanb6f44032023-06-30 15:07:56 +02003240 opts->store = NC_STORE_KEYSTORE;
roman3f9b65c2023-06-05 14:26:58 +02003241
roman6430c152023-10-12 11:28:47 +02003242 free(opts->cert_ref);
3243 opts->cert_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003244 NC_CHECK_ERRMEM_GOTO(!opts->cert_ref, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003245 } else {
roman6430c152023-10-12 11:28:47 +02003246 free(opts->cert_ref);
romanb6f44032023-06-30 15:07:56 +02003247 opts->cert_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003248 }
romanb6f44032023-06-30 15:07:56 +02003249 } else if (equal_parent_name(node, 2, "ca-certs")) {
3250 /* TLS client auth certificate authority */
roman3f9b65c2023-06-05 14:26:58 +02003251 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003252 ret = nc_server_config_create_ca_certs_certificate(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02003253 if (ret) {
3254 goto cleanup;
3255 }
3256 } else {
roman6430c152023-10-12 11:28:47 +02003257 if (nc_server_config_get_cert(node, &cert)) {
3258 ret = 1;
3259 goto cleanup;
3260 }
3261 nc_server_config_del_cert(&opts->ca_certs, cert);
roman3f9b65c2023-06-05 14:26:58 +02003262 }
romanb6f44032023-06-30 15:07:56 +02003263 } else if (equal_parent_name(node, 2, "ee-certs")) {
3264 /* TLS client auth end entity */
roman3f9b65c2023-06-05 14:26:58 +02003265 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003266 ret = nc_server_config_create_ee_certs_certificate(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02003267 if (ret) {
3268 goto cleanup;
3269 }
3270 } else {
roman6430c152023-10-12 11:28:47 +02003271 if (nc_server_config_get_cert(node, &cert)) {
3272 ret = 1;
3273 goto cleanup;
3274 }
3275 nc_server_config_del_cert(&opts->ee_certs, cert);
roman3f9b65c2023-06-05 14:26:58 +02003276 }
3277 }
3278
3279cleanup:
romanba93eac2023-07-18 14:36:48 +02003280 if (is_ch(node)) {
3281 /* UNLOCK */
3282 nc_ch_client_unlock(ch_client);
3283 }
roman3f9b65c2023-06-05 14:26:58 +02003284 return ret;
3285}
3286
3287static int
3288nc_server_config_create_cert_to_name(const struct lyd_node *node, struct nc_server_tls_opts *opts)
3289{
3290 int ret = 0;
3291 struct lyd_node *n;
3292 struct nc_ctn *new, *iter;
3293 const char *map_type, *name;
3294 uint32_t id;
3295 NC_TLS_CTN_MAPTYPE m_type;
3296
3297 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
3298
roman3f9b65c2023-06-05 14:26:58 +02003299 /* get all the data */
3300 /* find the list's key */
3301 lyd_find_path(node, "id", 0, &n);
3302 assert(n);
roman9cdb7b52023-10-25 13:59:55 +02003303 id = ((struct lyd_node_term *)n)->value.uint32;
roman3f9b65c2023-06-05 14:26:58 +02003304
3305 /* find the ctn's name */
3306 lyd_find_path(node, "name", 0, &n);
3307 assert(n);
3308 name = lyd_get_value(n);
3309
3310 /* find the ctn's map-type */
3311 lyd_find_path(node, "map-type", 0, &n);
3312 assert(n);
3313 map_type = ((struct lyd_node_term *)n)->value.ident->name;
3314 if (!strcmp(map_type, "specified")) {
3315 m_type = NC_TLS_CTN_SPECIFIED;
3316 } else if (!strcmp(map_type, "san-rfc822-name")) {
3317 m_type = NC_TLS_CTN_SAN_RFC822_NAME;
3318 } else if (!strcmp(map_type, "san-dns-name")) {
3319 m_type = NC_TLS_CTN_SAN_DNS_NAME;
3320 } else if (!strcmp(map_type, "san-ip-address")) {
3321 m_type = NC_TLS_CTN_SAN_IP_ADDRESS;
3322 } else if (!strcmp(map_type, "san-any")) {
3323 m_type = NC_TLS_CTN_SAN_ANY;
3324 } else if (!strcmp(map_type, "common-name")) {
3325 m_type = NC_TLS_CTN_COMMON_NAME;
3326 } else {
3327 ERR(NULL, "Map-type identity \"%s\" not supported.", map_type);
3328 ret = 1;
3329 goto cleanup;
3330 }
3331
roman6430c152023-10-12 11:28:47 +02003332 /* create new ctn */
3333 new = calloc(1, sizeof *new);
roman3a95bb22023-10-26 11:07:17 +02003334 NC_CHECK_ERRMEM_GOTO(!new, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02003335
roman3f9b65c2023-06-05 14:26:58 +02003336 /* find the right place for insertion */
3337 if (!opts->ctn) {
3338 /* inserting the first one */
3339 opts->ctn = new;
Roytak421eb0c2023-08-01 22:18:27 +02003340 } else if (opts->ctn->id > id) {
roman3f9b65c2023-06-05 14:26:58 +02003341 /* insert at the beginning */
3342 new->next = opts->ctn;
3343 opts->ctn = new;
3344 } else {
3345 /* have to find the right place */
Roytak421eb0c2023-08-01 22:18:27 +02003346 for (iter = opts->ctn; iter->next && iter->next->id <= id; iter = iter->next) {}
3347 if (iter->id == id) {
roman3f9b65c2023-06-05 14:26:58 +02003348 /* collision */
3349 new = iter;
3350 } else {
3351 new->next = iter->next;
3352 iter->next = new;
3353 }
3354 }
3355
3356 /* insert the right data */
3357 new->id = id;
roman6430c152023-10-12 11:28:47 +02003358 free(new->name);
roman3f9b65c2023-06-05 14:26:58 +02003359 new->name = strdup(name);
roman3a95bb22023-10-26 11:07:17 +02003360 NC_CHECK_ERRMEM_GOTO(!new->name, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003361 new->map_type = m_type;
3362
3363cleanup:
3364 return ret;
3365}
3366
3367static int
3368nc_server_config_cert_to_name(const struct lyd_node *node, NC_OPERATION op)
3369{
3370 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003371 struct nc_server_tls_opts *opts;
roman3f9b65c2023-06-05 14:26:58 +02003372 struct nc_ctn *ctn;
romanba93eac2023-07-18 14:36:48 +02003373 struct nc_ch_client *ch_client;
roman3f9b65c2023-06-05 14:26:58 +02003374
3375 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
3376
romanba93eac2023-07-18 14:36:48 +02003377 /* LOCK */
3378 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003379 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003380 return 1;
3381 }
3382
romanb6f44032023-06-30 15:07:56 +02003383 if (nc_server_config_get_tls_opts(node, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02003384 ret = 1;
3385 goto cleanup;
3386 }
3387
3388 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003389 ret = nc_server_config_create_cert_to_name(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02003390 if (ret) {
3391 goto cleanup;
3392 }
3393 } else {
3394 /* find the given ctn entry */
roman4cb8bb12023-06-29 09:16:46 +02003395 if (nc_server_config_get_ctn(node, &ctn)) {
roman3f9b65c2023-06-05 14:26:58 +02003396 ret = 1;
3397 goto cleanup;
3398 }
romanb6f44032023-06-30 15:07:56 +02003399 nc_server_config_del_ctn(opts, ctn);
roman3f9b65c2023-06-05 14:26:58 +02003400 }
3401
3402cleanup:
romanba93eac2023-07-18 14:36:48 +02003403 if (is_ch(node)) {
3404 /* UNLOCK */
3405 nc_ch_client_unlock(ch_client);
3406 }
roman3f9b65c2023-06-05 14:26:58 +02003407 return ret;
3408}
3409
3410static int
roman3f9b65c2023-06-05 14:26:58 +02003411nc_server_config_fingerprint(const struct lyd_node *node, NC_OPERATION op)
3412{
3413 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02003414 struct nc_ctn *ctn;
romanba93eac2023-07-18 14:36:48 +02003415 struct nc_ch_client *ch_client;
3416
3417 assert(!strcmp(LYD_NAME(node), "fingerprint"));
3418
3419 /* LOCK */
3420 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003421 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003422 return 1;
3423 }
roman3f9b65c2023-06-05 14:26:58 +02003424
roman4cb8bb12023-06-29 09:16:46 +02003425 if (nc_server_config_get_ctn(node, &ctn)) {
roman3f9b65c2023-06-05 14:26:58 +02003426 ret = 1;
3427 goto cleanup;
3428 }
3429
3430 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003431 free(ctn->fingerprint);
3432 ctn->fingerprint = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003433 NC_CHECK_ERRMEM_GOTO(!ctn->fingerprint, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003434 } else {
roman6430c152023-10-12 11:28:47 +02003435 free(ctn->fingerprint);
3436 ctn->fingerprint = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003437 }
3438
3439cleanup:
romanba93eac2023-07-18 14:36:48 +02003440 if (is_ch(node)) {
3441 /* UNLOCK */
3442 nc_ch_client_unlock(ch_client);
3443 }
roman3f9b65c2023-06-05 14:26:58 +02003444 return ret;
3445}
3446
roman12644fe2023-06-08 11:06:42 +02003447static int
3448nc_server_config_tls_version(const struct lyd_node *node, NC_OPERATION op)
3449{
3450 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003451 struct nc_server_tls_opts *opts;
roman12644fe2023-06-08 11:06:42 +02003452 const char *version = NULL;
romanba93eac2023-07-18 14:36:48 +02003453 struct nc_ch_client *ch_client;
roman6430c152023-10-12 11:28:47 +02003454 NC_TLS_VERSION tls_version;
roman12644fe2023-06-08 11:06:42 +02003455
3456 assert(!strcmp(LYD_NAME(node), "tls-version"));
3457
romanba93eac2023-07-18 14:36:48 +02003458 /* LOCK */
3459 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003460 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003461 return 1;
3462 }
3463
romanb6f44032023-06-30 15:07:56 +02003464 if (nc_server_config_get_tls_opts(node, &opts)) {
roman12644fe2023-06-08 11:06:42 +02003465 ret = 1;
3466 goto cleanup;
3467 }
3468
roman6430c152023-10-12 11:28:47 +02003469 /* str to tls_version */
roman12644fe2023-06-08 11:06:42 +02003470 version = ((struct lyd_node_term *)node)->value.ident->name;
3471 if (!strcmp(version, "tls10")) {
roman6430c152023-10-12 11:28:47 +02003472 tls_version = NC_TLS_VERSION_10;
roman12644fe2023-06-08 11:06:42 +02003473 } else if (!strcmp(version, "tls11")) {
roman6430c152023-10-12 11:28:47 +02003474 tls_version = NC_TLS_VERSION_11;
roman12644fe2023-06-08 11:06:42 +02003475 } else if (!strcmp(version, "tls12")) {
roman6430c152023-10-12 11:28:47 +02003476 tls_version = NC_TLS_VERSION_12;
roman12644fe2023-06-08 11:06:42 +02003477 } else if (!strcmp(version, "tls13")) {
roman6430c152023-10-12 11:28:47 +02003478 tls_version = NC_TLS_VERSION_13;
roman12644fe2023-06-08 11:06:42 +02003479 } else {
3480 ERR(NULL, "TLS version \"%s\" not supported.", version);
3481 ret = 1;
3482 goto cleanup;
3483 }
3484
roman6430c152023-10-12 11:28:47 +02003485 if (op == NC_OP_CREATE) {
3486 /* add the version if it isn't there already */
3487 opts->tls_versions |= tls_version;
3488 } else if ((op == NC_OP_DELETE) && (opts->tls_versions & tls_version)) {
3489 /* delete the version if it is there */
roman84fe3252023-10-25 11:28:32 +02003490 opts->tls_versions &= ~tls_version;
roman6430c152023-10-12 11:28:47 +02003491 }
3492
roman12644fe2023-06-08 11:06:42 +02003493cleanup:
romanba93eac2023-07-18 14:36:48 +02003494 if (is_ch(node)) {
3495 /* UNLOCK */
3496 nc_ch_client_unlock(ch_client);
3497 }
roman12644fe2023-06-08 11:06:42 +02003498 return ret;
3499}
3500
3501static int
3502nc_server_config_create_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher)
3503{
3504 int ret = 0;
3505 char *ssl_cipher = NULL;
3506 uint16_t i;
roman6430c152023-10-12 11:28:47 +02003507 void *tmp;
roman12644fe2023-06-08 11:06:42 +02003508
3509 ssl_cipher = malloc(strlen(cipher) + 1);
roman3a95bb22023-10-26 11:07:17 +02003510 NC_CHECK_ERRMEM_GOTO(!ssl_cipher, ret = 1, cleanup);
roman12644fe2023-06-08 11:06:42 +02003511
3512 for (i = 0; cipher[i]; i++) {
3513 if (cipher[i] == '-') {
3514 /* OpenSSL requires _ instead of - in cipher names */
3515 ssl_cipher[i] = '_';
3516 } else {
3517 /* and requires uppercase unlike the identities */
3518 ssl_cipher[i] = toupper(cipher[i]);
3519 }
3520 }
3521 ssl_cipher[i] = '\0';
3522
3523 if (!opts->ciphers) {
3524 /* first entry */
3525 opts->ciphers = strdup(ssl_cipher);
roman3a95bb22023-10-26 11:07:17 +02003526 NC_CHECK_ERRMEM_GOTO(!opts->ciphers, ret = 1, cleanup);
roman12644fe2023-06-08 11:06:42 +02003527 } else {
3528 /* + 1 because of : between entries */
roman6430c152023-10-12 11:28:47 +02003529 tmp = nc_realloc(opts->ciphers, strlen(opts->ciphers) + strlen(ssl_cipher) + 1 + 1);
roman3a95bb22023-10-26 11:07:17 +02003530 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02003531 opts->ciphers = tmp;
roman08f67f42023-06-08 13:51:54 +02003532 strcat(opts->ciphers, ":");
3533 strcat(opts->ciphers, ssl_cipher);
roman12644fe2023-06-08 11:06:42 +02003534 }
3535
3536cleanup:
3537 free(ssl_cipher);
3538 return ret;
3539}
3540
3541static int
romanb6f44032023-06-30 15:07:56 +02003542nc_server_config_del_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher)
roman12644fe2023-06-08 11:06:42 +02003543{
romanc135c6d2023-10-25 13:32:30 +02003544 int ret = 0;
roman12644fe2023-06-08 11:06:42 +02003545
romanc135c6d2023-10-25 13:32:30 +02003546 ret = nc_server_config_delete_substring(opts->ciphers, cipher, ':');
3547 if (ret) {
roman12644fe2023-06-08 11:06:42 +02003548 ERR(NULL, "Unable to delete a cipher (%s), which was not previously added.", cipher);
3549 return 1;
3550 }
3551
3552 return 0;
3553}
3554
3555static int
3556nc_server_config_cipher_suite(const struct lyd_node *node, NC_OPERATION op)
3557{
3558 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003559 struct nc_server_tls_opts *opts;
roman12644fe2023-06-08 11:06:42 +02003560 const char *cipher = NULL;
romanba93eac2023-07-18 14:36:48 +02003561 struct nc_ch_client *ch_client;
roman12644fe2023-06-08 11:06:42 +02003562
romanfaecc582023-06-15 16:13:31 +02003563 assert(!strcmp(LYD_NAME(node), "cipher-suite"));
3564
romanba93eac2023-07-18 14:36:48 +02003565 /* LOCK */
3566 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003567 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003568 return 1;
3569 }
3570
romanb6f44032023-06-30 15:07:56 +02003571 if (nc_server_config_get_tls_opts(node, &opts)) {
roman12644fe2023-06-08 11:06:42 +02003572 ret = 1;
3573 goto cleanup;
3574 }
3575
3576 cipher = ((struct lyd_node_term *)node)->value.ident->name;
3577 if (op == NC_OP_CREATE) {
romanb6f44032023-06-30 15:07:56 +02003578 ret = nc_server_config_create_cipher_suite(opts, cipher);
roman12644fe2023-06-08 11:06:42 +02003579 if (ret) {
3580 goto cleanup;
3581 }
3582 } else if (op == NC_OP_DELETE) {
romanb6f44032023-06-30 15:07:56 +02003583 ret = nc_server_config_del_cipher_suite(opts, cipher);
roman12644fe2023-06-08 11:06:42 +02003584 if (ret) {
3585 goto cleanup;
3586 }
3587 }
3588
3589cleanup:
romanba93eac2023-07-18 14:36:48 +02003590 if (is_ch(node)) {
3591 /* UNLOCK */
3592 nc_ch_client_unlock(ch_client);
3593 }
roman12644fe2023-06-08 11:06:42 +02003594 return ret;
3595}
3596
romanfaecc582023-06-15 16:13:31 +02003597static int
3598nc_server_config_crl_url(const struct lyd_node *node, NC_OPERATION op)
3599{
3600 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003601 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02003602 struct nc_ch_client *ch_client;
romanfaecc582023-06-15 16:13:31 +02003603
3604 assert(!strcmp(LYD_NAME(node), "crl-url"));
3605
romanba93eac2023-07-18 14:36:48 +02003606 /* LOCK */
3607 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003608 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003609 return 1;
3610 }
3611
romanb6f44032023-06-30 15:07:56 +02003612 if (nc_server_config_get_tls_opts(node, &opts)) {
romanfaecc582023-06-15 16:13:31 +02003613 ret = 1;
3614 goto cleanup;
3615 }
3616
3617 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003618 free(opts->crl_url);
romanb6f44032023-06-30 15:07:56 +02003619 opts->crl_url = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003620 NC_CHECK_ERRMEM_GOTO(!opts->crl_url, ret = 1, cleanup);
romanfaecc582023-06-15 16:13:31 +02003621 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02003622 free(opts->crl_url);
3623 opts->crl_url = NULL;
romanfaecc582023-06-15 16:13:31 +02003624 }
3625
3626cleanup:
romanba93eac2023-07-18 14:36:48 +02003627 if (is_ch(node)) {
3628 /* UNLOCK */
3629 nc_ch_client_unlock(ch_client);
3630 }
romanfaecc582023-06-15 16:13:31 +02003631 return ret;
3632}
3633
3634static int
3635nc_server_config_crl_path(const struct lyd_node *node, NC_OPERATION op)
3636{
3637 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003638 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02003639 struct nc_ch_client *ch_client;
romanfaecc582023-06-15 16:13:31 +02003640
3641 assert(!strcmp(LYD_NAME(node), "crl-path"));
3642
romanba93eac2023-07-18 14:36:48 +02003643 /* LOCK */
3644 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003645 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003646 return 1;
3647 }
3648
romanb6f44032023-06-30 15:07:56 +02003649 if (nc_server_config_get_tls_opts(node, &opts)) {
romanfaecc582023-06-15 16:13:31 +02003650 ret = 1;
3651 goto cleanup;
3652 }
3653
3654 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003655 free(opts->crl_path);
romanb6f44032023-06-30 15:07:56 +02003656 opts->crl_path = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003657 NC_CHECK_ERRMEM_GOTO(!opts->crl_path, ret = 1, cleanup);
romanfaecc582023-06-15 16:13:31 +02003658 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02003659 free(opts->crl_path);
3660 opts->crl_path = NULL;
romanfaecc582023-06-15 16:13:31 +02003661 }
3662
3663cleanup:
romanba93eac2023-07-18 14:36:48 +02003664 if (is_ch(node)) {
3665 /* UNLOCK */
3666 nc_ch_client_unlock(ch_client);
3667 }
romanfaecc582023-06-15 16:13:31 +02003668 return ret;
3669}
3670
3671static int
3672nc_server_config_crl_cert_ext(const struct lyd_node *node, NC_OPERATION op)
3673{
3674 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003675 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02003676 struct nc_ch_client *ch_client;
romanfaecc582023-06-15 16:13:31 +02003677
3678 assert(!strcmp(LYD_NAME(node), "crl-cert-ext"));
3679
romanba93eac2023-07-18 14:36:48 +02003680 /* LOCK */
3681 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003682 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003683 return 1;
3684 }
3685
romanb6f44032023-06-30 15:07:56 +02003686 if (nc_server_config_get_tls_opts(node, &opts)) {
romanfaecc582023-06-15 16:13:31 +02003687 ret = 1;
3688 goto cleanup;
3689 }
3690
3691 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003692 opts->crl_cert_ext = 1;
romanfaecc582023-06-15 16:13:31 +02003693 } else if (op == NC_OP_DELETE) {
romanb6f44032023-06-30 15:07:56 +02003694 opts->crl_cert_ext = 0;
romanfaecc582023-06-15 16:13:31 +02003695 }
3696
3697cleanup:
romanba93eac2023-07-18 14:36:48 +02003698 if (is_ch(node)) {
3699 /* UNLOCK */
3700 nc_ch_client_unlock(ch_client);
3701 }
romanfaecc582023-06-15 16:13:31 +02003702 return ret;
3703}
3704
roman2eab4742023-06-06 10:00:26 +02003705#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02003706
roman83683fb2023-02-24 09:15:23 +01003707static int
roman5cbb6532023-06-22 12:53:17 +02003708nc_server_config_create_netconf_client(const struct lyd_node *node)
3709{
3710 int ret = 0;
3711
3712 node = lyd_child(node);
3713 assert(!strcmp(LYD_NAME(node), "name"));
3714
3715 /* LOCK */
3716 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
3717
3718 ret = nc_server_config_realloc(lyd_get_value(node), (void **)&server_opts.ch_clients, sizeof *server_opts.ch_clients, &server_opts.ch_client_count);
3719 if (ret) {
3720 goto cleanup;
3721 }
3722
3723 server_opts.ch_clients[server_opts.ch_client_count - 1].id = ATOMIC_INC_RELAXED(server_opts.new_client_id);
3724 server_opts.ch_clients[server_opts.ch_client_count - 1].start_with = NC_CH_FIRST_LISTED;
roman6430c152023-10-12 11:28:47 +02003725 server_opts.ch_clients[server_opts.ch_client_count - 1].max_attempts = 3;
roman5cbb6532023-06-22 12:53:17 +02003726
3727 pthread_mutex_init(&server_opts.ch_clients[server_opts.ch_client_count - 1].lock, NULL);
3728
3729cleanup:
3730 /* UNLOCK */
3731 pthread_rwlock_unlock(&server_opts.ch_client_lock);
3732 return ret;
3733}
3734
3735static int
3736nc_server_config_netconf_client(const struct lyd_node *node, NC_OPERATION op)
3737{
3738 int ret = 0;
3739 struct nc_ch_client *ch_client;
3740
3741 assert(!strcmp(LYD_NAME(node), "netconf-client"));
3742
3743 if (op == NC_OP_CREATE) {
3744 ret = nc_server_config_create_netconf_client(node);
3745 if (ret) {
3746 goto cleanup;
3747 }
3748 } else if (op == NC_OP_DELETE) {
3749 if (nc_server_config_get_ch_client(node, &ch_client)) {
3750 ret = 1;
3751 goto cleanup;
3752 }
3753
3754 nc_server_config_ch_del_client(ch_client);
3755 }
3756
3757cleanup:
3758 return ret;
3759}
3760
3761#ifdef NC_ENABLED_SSH_TLS
3762
3763static int
3764nc_server_config_remote_address(const struct lyd_node *node, NC_OPERATION op)
3765{
3766 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02003767 struct nc_ch_endpt *ch_endpt;
romanba93eac2023-07-18 14:36:48 +02003768 struct nc_ch_client *ch_client;
roman5cbb6532023-06-22 12:53:17 +02003769
romanb6f44032023-06-30 15:07:56 +02003770 assert(!strcmp(LYD_NAME(node), "remote-address"));
3771
romanba93eac2023-07-18 14:36:48 +02003772 /* LOCK */
3773 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003774 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003775 return 1;
3776 }
3777
roman4cb8bb12023-06-29 09:16:46 +02003778 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02003779 ret = 1;
3780 goto cleanup;
3781 }
3782
3783 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003784 free(ch_endpt->address);
roman5cbb6532023-06-22 12:53:17 +02003785 ch_endpt->address = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003786 NC_CHECK_ERRMEM_GOTO(!ch_endpt->address, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02003787 } else {
roman6430c152023-10-12 11:28:47 +02003788 free(ch_endpt->address);
3789 ch_endpt->address = NULL;
roman5cbb6532023-06-22 12:53:17 +02003790 }
3791
3792cleanup:
romanba93eac2023-07-18 14:36:48 +02003793 /* UNLOCK */
3794 nc_ch_client_unlock(ch_client);
roman5cbb6532023-06-22 12:53:17 +02003795 return ret;
3796}
3797
3798static int
3799nc_server_config_remote_port(const struct lyd_node *node, NC_OPERATION op)
3800{
3801 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02003802 struct nc_ch_endpt *ch_endpt;
romanba93eac2023-07-18 14:36:48 +02003803 struct nc_ch_client *ch_client;
roman5cbb6532023-06-22 12:53:17 +02003804
romanb6f44032023-06-30 15:07:56 +02003805 assert(!strcmp(LYD_NAME(node), "remote-port"));
3806
romanba93eac2023-07-18 14:36:48 +02003807 /* LOCK */
3808 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003809 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003810 return 1;
3811 }
3812
roman4cb8bb12023-06-29 09:16:46 +02003813 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02003814 ret = 1;
3815 goto cleanup;
3816 }
3817
3818 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02003819 ch_endpt->port = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02003820 } else {
3821 ch_endpt->port = 0;
3822 }
3823
3824cleanup:
romanba93eac2023-07-18 14:36:48 +02003825 /* UNLOCK */
3826 nc_ch_client_unlock(ch_client);
roman5cbb6532023-06-22 12:53:17 +02003827 return ret;
3828}
3829
3830#endif /* NC_ENABLED_SSH_TLS */
3831
3832static int
romanb6f44032023-06-30 15:07:56 +02003833nc_server_config_persistent(const struct lyd_node *node, NC_OPERATION op)
3834{
3835 int ret = 0;
3836 struct nc_ch_client *ch_client;
3837
3838 assert(!strcmp(LYD_NAME(node), "persistent"));
3839
3840 (void) op;
3841
romanba93eac2023-07-18 14:36:48 +02003842 /* LOCK */
3843 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003844 /* to avoid unlock on fail */
3845 return 1;
romanb6f44032023-06-30 15:07:56 +02003846 }
3847
3848 ch_client->conn_type = NC_CH_PERSIST;
3849
romanba93eac2023-07-18 14:36:48 +02003850 /* UNLOCK */
3851 nc_ch_client_unlock(ch_client);
3852
romanb6f44032023-06-30 15:07:56 +02003853 return ret;
3854}
3855
3856static int
3857nc_server_config_periodic(const struct lyd_node *node, NC_OPERATION op)
3858{
3859 int ret = 0;
3860 struct nc_ch_client *ch_client;
3861
3862 assert(!strcmp(LYD_NAME(node), "periodic"));
3863
3864 (void) op;
3865
romanba93eac2023-07-18 14:36:48 +02003866 /* LOCK */
3867 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003868 /* to avoid unlock on fail */
3869 return 1;
romanb6f44032023-06-30 15:07:56 +02003870 }
3871
3872 ch_client->conn_type = NC_CH_PERIOD;
3873 /* set default values */
3874 ch_client->period = 60;
3875 ch_client->anchor_time = 0;
3876 ch_client->idle_timeout = 180;
3877
romanba93eac2023-07-18 14:36:48 +02003878 /* UNLOCK */
3879 nc_ch_client_unlock(ch_client);
3880
romanb6f44032023-06-30 15:07:56 +02003881 return ret;
3882}
3883
3884static int
3885nc_server_config_period(const struct lyd_node *node, NC_OPERATION op)
3886{
3887 int ret = 0;
3888 struct nc_ch_client *ch_client;
3889
3890 assert(!strcmp(LYD_NAME(node), "period"));
3891
romanba93eac2023-07-18 14:36:48 +02003892 /* LOCK */
3893 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003894 /* to avoid unlock on fail */
3895 return 1;
romanb6f44032023-06-30 15:07:56 +02003896 }
3897
3898 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02003899 ch_client->period = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02003900 } else if (op == NC_OP_DELETE) {
3901 ch_client->period = 60;
3902 }
3903
romanba93eac2023-07-18 14:36:48 +02003904 /* UNLOCK */
3905 nc_ch_client_unlock(ch_client);
3906
romanb6f44032023-06-30 15:07:56 +02003907 return ret;
3908}
3909
3910static int
3911nc_server_config_anchor_time(const struct lyd_node *node, NC_OPERATION op)
3912{
3913 int ret = 0;
3914 struct nc_ch_client *ch_client;
romana3c95c72023-10-26 11:15:53 +02003915 struct lyd_value_date_and_time *anchor_time;
romanb6f44032023-06-30 15:07:56 +02003916
3917 assert(!strcmp(LYD_NAME(node), "anchor-time"));
3918
romanba93eac2023-07-18 14:36:48 +02003919 /* LOCK */
3920 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003921 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003922 return 1;
romanb6f44032023-06-30 15:07:56 +02003923 }
3924
romana3c95c72023-10-26 11:15:53 +02003925 /* get the value of time from the node directly */
3926 LYD_VALUE_GET(&((struct lyd_node_term *)node)->value, anchor_time);
romanb6f44032023-06-30 15:07:56 +02003927
3928 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romana3c95c72023-10-26 11:15:53 +02003929 ch_client->anchor_time = anchor_time->time;
romanb6f44032023-06-30 15:07:56 +02003930 } else if (op == NC_OP_DELETE) {
3931 ch_client->anchor_time = 0;
3932 }
3933
romanba93eac2023-07-18 14:36:48 +02003934 /* UNLOCK */
3935 nc_ch_client_unlock(ch_client);
romanb6f44032023-06-30 15:07:56 +02003936 return ret;
3937}
3938
3939static int
3940nc_server_config_reconnect_strategy(const struct lyd_node *node, NC_OPERATION op)
3941{
3942 int ret = 0;
3943 struct nc_ch_client *ch_client;
3944
3945 assert(!strcmp(LYD_NAME(node), "reconnect-strategy"));
3946
3947 (void) op;
3948
romanba93eac2023-07-18 14:36:48 +02003949 /* LOCK */
3950 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003951 /* to avoid unlock on fail */
3952 return 1;
romanb6f44032023-06-30 15:07:56 +02003953 }
3954
3955 /* set to default values */
3956 ch_client->start_with = NC_CH_FIRST_LISTED;
3957 ch_client->max_wait = 5;
3958 ch_client->max_attempts = 3;
3959
romanba93eac2023-07-18 14:36:48 +02003960 /* UNLOCK */
3961 nc_ch_client_unlock(ch_client);
3962
romanb6f44032023-06-30 15:07:56 +02003963 return ret;
3964}
3965
3966static int
3967nc_server_config_start_with(const struct lyd_node *node, NC_OPERATION op)
3968{
3969 int ret = 0;
3970 struct nc_ch_client *ch_client;
3971 const char *value;
3972
3973 assert(!strcmp(LYD_NAME(node), "start-with"));
3974
romanba93eac2023-07-18 14:36:48 +02003975 /* LOCK */
3976 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003977 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003978 return 1;
romanb6f44032023-06-30 15:07:56 +02003979 }
3980
3981 if (op == NC_OP_DELETE) {
3982 ch_client->start_with = NC_CH_FIRST_LISTED;
3983 goto cleanup;
3984 }
3985
3986 value = lyd_get_value(node);
3987 if (!strcmp(value, "first-listed")) {
3988 ch_client->start_with = NC_CH_FIRST_LISTED;
3989 } else if (!strcmp(value, "last-connected")) {
3990 ch_client->start_with = NC_CH_LAST_CONNECTED;
3991 } else if (!strcmp(value, "random-selection")) {
3992 ch_client->start_with = NC_CH_RANDOM;
3993 } else {
3994 ERR(NULL, "Unexpected start-with value \"%s\".", value);
3995 ret = 1;
3996 goto cleanup;
3997 }
3998
3999cleanup:
romanba93eac2023-07-18 14:36:48 +02004000 /* UNLOCK */
4001 nc_ch_client_unlock(ch_client);
romanb6f44032023-06-30 15:07:56 +02004002 return ret;
4003}
4004
4005static int
4006nc_server_config_max_wait(const struct lyd_node *node, NC_OPERATION op)
4007{
4008 int ret = 0;
4009 struct nc_ch_client *ch_client;
4010
4011 assert(!strcmp(LYD_NAME(node), "max-wait"));
4012
romanba93eac2023-07-18 14:36:48 +02004013 /* LOCK */
4014 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02004015 /* to avoid unlock on fail */
4016 return 1;
romanb6f44032023-06-30 15:07:56 +02004017 }
4018
4019 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02004020 ch_client->max_wait = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02004021 } else {
4022 ch_client->max_wait = 5;
4023 }
4024
romanba93eac2023-07-18 14:36:48 +02004025 /* UNLOCK */
4026 nc_ch_client_unlock(ch_client);
4027
romanb6f44032023-06-30 15:07:56 +02004028 return ret;
4029}
4030
4031static int
4032nc_server_config_max_attempts(const struct lyd_node *node, NC_OPERATION op)
4033{
4034 int ret = 0;
4035 struct nc_ch_client *ch_client;
4036
4037 assert(!strcmp(LYD_NAME(node), "max-attempts"));
4038
romanba93eac2023-07-18 14:36:48 +02004039 /* LOCK */
4040 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02004041 /* to avoid unlock on fail */
4042 return 1;
romanb6f44032023-06-30 15:07:56 +02004043 }
4044
4045 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02004046 ch_client->max_attempts = ((struct lyd_node_term *)node)->value.uint8;
romanb6f44032023-06-30 15:07:56 +02004047 } else {
4048 ch_client->max_attempts = 3;
4049 }
4050
romanba93eac2023-07-18 14:36:48 +02004051 /* UNLOCK */
4052 nc_ch_client_unlock(ch_client);
4053
romanb6f44032023-06-30 15:07:56 +02004054 return ret;
4055}
4056
4057static int
romanf02273a2023-05-25 09:44:11 +02004058nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01004059{
4060 const char *name = LYD_NAME(node);
roman6430c152023-10-12 11:28:47 +02004061 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01004062
4063 if (!strcmp(name, "listen")) {
roman6430c152023-10-12 11:28:47 +02004064 ret = nc_server_config_listen(node, op);
4065 } else if (!strcmp(name, "call-home")) {
4066 ret = nc_server_config_ch(node, op);
romaneaf84c72023-10-19 14:38:05 +02004067 } else if (!strcmp(name, "hello-timeout")) {
4068 ret = nc_server_config_hello_timeout(node, op);
romanc1d2b092023-02-02 08:58:27 +01004069 } else if (!strcmp(name, "endpoint")) {
roman6430c152023-10-12 11:28:47 +02004070 ret = nc_server_config_endpoint(node, op);
roman2eab4742023-06-06 10:00:26 +02004071 } else if (!strcmp(name, "unix-socket")) {
roman6430c152023-10-12 11:28:47 +02004072 ret = nc_server_config_unix_socket(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004073 }
roman2eab4742023-06-06 10:00:26 +02004074#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02004075 else if (!strcmp(name, "ssh")) {
roman6430c152023-10-12 11:28:47 +02004076 ret = nc_server_config_ssh(node, op);
roman2eab4742023-06-06 10:00:26 +02004077 } else if (!strcmp(name, "local-address")) {
roman6430c152023-10-12 11:28:47 +02004078 ret = nc_server_config_local_address(node, op);
romanc1d2b092023-02-02 08:58:27 +01004079 } else if (!strcmp(name, "local-port")) {
roman6430c152023-10-12 11:28:47 +02004080 ret = nc_server_config_local_port(node, op);
romanc1d2b092023-02-02 08:58:27 +01004081 } else if (!strcmp(name, "keepalives")) {
roman6430c152023-10-12 11:28:47 +02004082 ret = nc_server_config_keepalives(node, op);
romanc1d2b092023-02-02 08:58:27 +01004083 } else if (!strcmp(name, "idle-time")) {
roman6430c152023-10-12 11:28:47 +02004084 ret = nc_server_config_idle_time(node, op);
romanc1d2b092023-02-02 08:58:27 +01004085 } else if (!strcmp(name, "max-probes")) {
roman6430c152023-10-12 11:28:47 +02004086 ret = nc_server_config_max_probes(node, op);
romanc1d2b092023-02-02 08:58:27 +01004087 } else if (!strcmp(name, "probe-interval")) {
roman6430c152023-10-12 11:28:47 +02004088 ret = nc_server_config_probe_interval(node, op);
roman2eab4742023-06-06 10:00:26 +02004089 } else if (!strcmp(name, "host-key")) {
roman6430c152023-10-12 11:28:47 +02004090 ret = nc_server_config_host_key(node, op);
roman2eab4742023-06-06 10:00:26 +02004091 } else if (!strcmp(name, "public-key-format")) {
roman6430c152023-10-12 11:28:47 +02004092 ret = nc_server_config_public_key_format(node, op);
romanc1d2b092023-02-02 08:58:27 +01004093 } else if (!strcmp(name, "public-key")) {
roman6430c152023-10-12 11:28:47 +02004094 ret = nc_server_config_public_key(node, op);
romanc1d2b092023-02-02 08:58:27 +01004095 } else if (!strcmp(name, "private-key-format")) {
roman6430c152023-10-12 11:28:47 +02004096 ret = nc_server_config_private_key_format(node, op);
romanc1d2b092023-02-02 08:58:27 +01004097 } else if (!strcmp(name, "cleartext-private-key")) {
roman6430c152023-10-12 11:28:47 +02004098 ret = nc_server_config_cleartext_private_key(node, op);
roman2eab4742023-06-06 10:00:26 +02004099 } else if (!strcmp(name, "keystore-reference")) {
roman6430c152023-10-12 11:28:47 +02004100 ret = nc_server_config_keystore_reference(node, op);
romanc1d2b092023-02-02 08:58:27 +01004101 } else if (!strcmp(name, "user")) {
roman6430c152023-10-12 11:28:47 +02004102 ret = nc_server_config_user(node, op);
romanc1d2b092023-02-02 08:58:27 +01004103 } else if (!strcmp(name, "auth-attempts")) {
roman6430c152023-10-12 11:28:47 +02004104 ret = nc_server_config_auth_attempts(node, op);
romanc1d2b092023-02-02 08:58:27 +01004105 } else if (!strcmp(name, "auth-timeout")) {
roman6430c152023-10-12 11:28:47 +02004106 ret = nc_server_config_auth_timeout(node, op);
roman2eab4742023-06-06 10:00:26 +02004107 } else if (!strcmp(name, "truststore-reference")) {
roman6430c152023-10-12 11:28:47 +02004108 ret = nc_server_config_truststore_reference(node, op);
roman2eab4742023-06-06 10:00:26 +02004109 } else if (!strcmp(name, "password")) {
roman6430c152023-10-12 11:28:47 +02004110 ret = nc_server_config_password(node, op);
romanc1d2b092023-02-02 08:58:27 +01004111 } else if (!strcmp(name, "pam-config-file-name")) {
roman6430c152023-10-12 11:28:47 +02004112 ret = nc_server_config_pam_name(node, op);
romanc1d2b092023-02-02 08:58:27 +01004113 } else if (!strcmp(name, "pam-config-file-dir")) {
roman6430c152023-10-12 11:28:47 +02004114 ret = nc_server_config_pam_dir(node, op);
romanc1d2b092023-02-02 08:58:27 +01004115 } else if (!strcmp(name, "none")) {
roman6430c152023-10-12 11:28:47 +02004116 ret = nc_server_config_none(node, op);
romanc1d2b092023-02-02 08:58:27 +01004117 } else if (!strcmp(name, "host-key-alg")) {
roman6430c152023-10-12 11:28:47 +02004118 ret = nc_server_config_host_key_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01004119 } else if (!strcmp(name, "key-exchange-alg")) {
roman6430c152023-10-12 11:28:47 +02004120 ret = nc_server_config_kex_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01004121 } else if (!strcmp(name, "encryption-alg")) {
roman6430c152023-10-12 11:28:47 +02004122 ret = nc_server_config_encryption_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01004123 } else if (!strcmp(name, "mac-alg")) {
roman6430c152023-10-12 11:28:47 +02004124 ret = nc_server_config_mac_alg(node, op);
roman2eab4742023-06-06 10:00:26 +02004125 } else if (!strcmp(name, "endpoint-client-auth")) {
roman6430c152023-10-12 11:28:47 +02004126 ret = nc_server_config_endpoint_client_auth(node, op);
roman2eab4742023-06-06 10:00:26 +02004127 } else if (!strcmp(name, "tls")) {
roman6430c152023-10-12 11:28:47 +02004128 ret = nc_server_config_tls(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004129 } else if (!strcmp(name, "cert-data")) {
roman6430c152023-10-12 11:28:47 +02004130 ret = nc_server_config_cert_data(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004131 } else if (!strcmp(name, "asymmetric-key")) {
roman6430c152023-10-12 11:28:47 +02004132 ret = nc_server_config_asymmetric_key(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004133 } else if (!strcmp(name, "certificate")) {
roman6430c152023-10-12 11:28:47 +02004134 ret = nc_server_config_certificate(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004135 } else if (!strcmp(name, "cert-to-name")) {
roman6430c152023-10-12 11:28:47 +02004136 ret = nc_server_config_cert_to_name(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004137 } else if (!strcmp(name, "fingerprint")) {
roman6430c152023-10-12 11:28:47 +02004138 ret = nc_server_config_fingerprint(node, op);
roman12644fe2023-06-08 11:06:42 +02004139 } else if (!strcmp(name, "tls-version")) {
roman6430c152023-10-12 11:28:47 +02004140 ret = nc_server_config_tls_version(node, op);
roman12644fe2023-06-08 11:06:42 +02004141 } else if (!strcmp(name, "cipher-suite")) {
roman6430c152023-10-12 11:28:47 +02004142 ret = nc_server_config_cipher_suite(node, op);
romanfaecc582023-06-15 16:13:31 +02004143 } else if (!strcmp(name, "crl-url")) {
roman6430c152023-10-12 11:28:47 +02004144 ret = nc_server_config_crl_url(node, op);
romanfaecc582023-06-15 16:13:31 +02004145 } else if (!strcmp(name, "crl-path")) {
roman6430c152023-10-12 11:28:47 +02004146 ret = nc_server_config_crl_path(node, op);
romanfaecc582023-06-15 16:13:31 +02004147 } else if (!strcmp(name, "crl-cert-ext")) {
roman6430c152023-10-12 11:28:47 +02004148 ret = nc_server_config_crl_cert_ext(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004149 }
roman2eab4742023-06-06 10:00:26 +02004150#endif /* NC_ENABLED_SSH_TLS */
roman5cbb6532023-06-22 12:53:17 +02004151 else if (!strcmp(name, "netconf-client")) {
roman6430c152023-10-12 11:28:47 +02004152 ret = nc_server_config_netconf_client(node, op);
roman5cbb6532023-06-22 12:53:17 +02004153 }
4154#ifdef NC_ENABLED_SSH_TLS
4155 else if (!strcmp(name, "remote-address")) {
roman6430c152023-10-12 11:28:47 +02004156 ret = nc_server_config_remote_address(node, op);
roman5cbb6532023-06-22 12:53:17 +02004157 } else if (!strcmp(name, "remote-port")) {
roman6430c152023-10-12 11:28:47 +02004158 ret = nc_server_config_remote_port(node, op);
roman5cbb6532023-06-22 12:53:17 +02004159 }
4160#endif /* NC_ENABLED_SSH_TLS */
romanb6f44032023-06-30 15:07:56 +02004161 else if (!strcmp(name, "persistent")) {
roman6430c152023-10-12 11:28:47 +02004162 ret = nc_server_config_persistent(node, op);
romanb6f44032023-06-30 15:07:56 +02004163 } else if (!strcmp(name, "periodic")) {
roman6430c152023-10-12 11:28:47 +02004164 ret = nc_server_config_periodic(node, op);
romanb6f44032023-06-30 15:07:56 +02004165 } else if (!strcmp(name, "period")) {
roman6430c152023-10-12 11:28:47 +02004166 ret = nc_server_config_period(node, op);
romanb6f44032023-06-30 15:07:56 +02004167 } else if (!strcmp(name, "anchor-time")) {
roman6430c152023-10-12 11:28:47 +02004168 ret = nc_server_config_anchor_time(node, op);
romaneaf84c72023-10-19 14:38:05 +02004169 } else if (!strcmp(name, "idle-timeout")) {
4170 ret = nc_server_config_idle_timeout(node, op);
romanb6f44032023-06-30 15:07:56 +02004171 } else if (!strcmp(name, "reconnect-strategy")) {
roman6430c152023-10-12 11:28:47 +02004172 ret = nc_server_config_reconnect_strategy(node, op);
romanb6f44032023-06-30 15:07:56 +02004173 } else if (!strcmp(name, "start-with")) {
roman6430c152023-10-12 11:28:47 +02004174 ret = nc_server_config_start_with(node, op);
romanb6f44032023-06-30 15:07:56 +02004175 } else if (!strcmp(name, "max-wait")) {
roman6430c152023-10-12 11:28:47 +02004176 ret = nc_server_config_max_wait(node, op);
romanb6f44032023-06-30 15:07:56 +02004177 } else if (!strcmp(name, "max-attempts")) {
roman6430c152023-10-12 11:28:47 +02004178 ret = nc_server_config_max_attempts(node, op);
4179 }
4180
4181 if (ret) {
4182 ERR(NULL, "Configuring node \"%s\" failed.", LYD_NAME(node));
4183 return 1;
romanb6f44032023-06-30 15:07:56 +02004184 }
romanc1d2b092023-02-02 08:58:27 +01004185
4186 return 0;
romanc1d2b092023-02-02 08:58:27 +01004187}
4188
4189int
roman0bbc19c2023-05-26 09:59:09 +02004190nc_server_config_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, NC_MODULE module)
romanc1d2b092023-02-02 08:58:27 +01004191{
4192 struct lyd_node *child;
4193 struct lyd_meta *m;
romanf9906b42023-05-22 14:04:29 +02004194 NC_OPERATION current_op = NC_OP_UNKNOWN;
romanf02273a2023-05-25 09:44:11 +02004195 int ret;
romanc1d2b092023-02-02 08:58:27 +01004196
4197 assert(node);
4198
romanf9906b42023-05-22 14:04:29 +02004199 /* get current op if there is any */
4200 if ((m = lyd_find_meta(node->meta, NULL, "yang:operation"))) {
4201 if (!strcmp(lyd_get_meta_value(m), "create")) {
4202 current_op = NC_OP_CREATE;
4203 } else if (!strcmp(lyd_get_meta_value(m), "delete")) {
4204 current_op = NC_OP_DELETE;
4205 } else if (!strcmp(lyd_get_meta_value(m), "replace")) {
4206 current_op = NC_OP_REPLACE;
4207 } else if (!strcmp(lyd_get_meta_value(m), "none")) {
4208 current_op = NC_OP_NONE;
romanc1d2b092023-02-02 08:58:27 +01004209 }
4210 }
4211
4212 /* node has no op, inherit from the parent */
romanf9906b42023-05-22 14:04:29 +02004213 if (!current_op) {
4214 if (!parent_op) {
4215 ERR(NULL, "Unknown operation for node \"%s\".", LYD_NAME(node));
4216 return 1;
4217 }
4218
romanc1d2b092023-02-02 08:58:27 +01004219 current_op = parent_op;
4220 }
4221
4222 switch (current_op) {
4223 case NC_OP_NONE:
4224 break;
4225 case NC_OP_CREATE:
4226 case NC_OP_DELETE:
4227 case NC_OP_REPLACE:
roman2eab4742023-06-06 10:00:26 +02004228#ifdef NC_ENABLED_SSH_TLS
4229 if (module == NC_MODULE_KEYSTORE) {
romanf02273a2023-05-25 09:44:11 +02004230 ret = nc_server_config_parse_keystore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02004231 } else if (module == NC_MODULE_TRUSTSTORE) {
romanf02273a2023-05-25 09:44:11 +02004232 ret = nc_server_config_parse_truststore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02004233 } else
4234#endif /* NC_ENABLED_SSH_TLS */
4235 {
4236 ret = nc_server_config_parse_netconf_server(node, current_op);
romanf02273a2023-05-25 09:44:11 +02004237 }
4238 if (ret) {
4239 return ret;
romanc1d2b092023-02-02 08:58:27 +01004240 }
4241 break;
4242 default:
4243 break;
4244 }
4245
4246 if (current_op != NC_OP_DELETE) {
4247 LY_LIST_FOR(lyd_child(node), child) {
roman0bbc19c2023-05-26 09:59:09 +02004248 if (nc_server_config_parse_tree(child, current_op, module)) {
romanc1d2b092023-02-02 08:58:27 +01004249 return 1;
4250 }
4251 }
4252 }
4253 return 0;
4254}
4255
romanc1d2b092023-02-02 08:58:27 +01004256API int
4257nc_server_config_load_modules(struct ly_ctx **ctx)
4258{
4259 int i, new_ctx = 0;
4260
4261 if (!*ctx) {
4262 if (ly_ctx_new(NC_SERVER_SEARCH_DIR, 0, ctx)) {
4263 ERR(NULL, "Couldn't create new libyang context.\n");
4264 goto error;
4265 }
4266 new_ctx = 1;
4267 }
4268
4269 /* all features */
4270 const char *ietf_nectonf_server[] = {"ssh-listen", "tls-listen", "ssh-call-home", "tls-call-home", "central-netconf-server-supported", NULL};
4271 /* all features */
4272 const char *ietf_x509_cert_to_name[] = {NULL};
roman7fdc84d2023-06-06 13:14:53 +02004273 /* no private-key-encryption, csr-generation, p10-csr-format, certificate-expiration-notification,
roman3c6c7e62023-09-14 10:19:19 +02004274 * encrypted-passwords, hidden-symmetric-keys, encrypted-symmetric-keys, hidden-private-keys, encrypted-private-keys,
4275 * one-symmetric-key-format, one-asymmetric-key-format, symmetrically-encrypted-value-format,
4276 * asymmetrically-encrypted-value-format, cms-enveloped-data-format, cms-encrypted-data-format,
Roytakb2794852023-10-18 14:30:22 +02004277 * cleartext-symmetric-keys */
roman3c6c7e62023-09-14 10:19:19 +02004278 const char *ietf_crypto_types[] = {"cleartext-passwords", "cleartext-private-keys", NULL};
romanc1d2b092023-02-02 08:58:27 +01004279 /* all features */
4280 const char *ietf_tcp_common[] = {"keepalives-supported", NULL};
roman7fdc84d2023-06-06 13:14:53 +02004281 /* all features */
4282 const char *ietf_tcp_server[] = {"tcp-server-keepalives", NULL};
Roytakb2794852023-10-18 14:30:22 +02004283 /* no proxy-connect, socks5-gss-api, socks5-username-password, local-binding-supported ? */
4284 const char *ietf_tcp_client[] = {"tcp-client-keepalives", NULL};
roman3c6c7e62023-09-14 10:19:19 +02004285 /* no ssh-x509-certs, public-key-generation */
4286 const char *ietf_ssh_common[] = {"transport-params", NULL};
roman7fdc84d2023-06-06 13:14:53 +02004287 /* no ssh-server-keepalives and local-user-auth-hostbased */
4288 const char *ietf_ssh_server[] = {"local-users-supported", "local-user-auth-publickey", "local-user-auth-password", "local-user-auth-none", NULL};
romanc1d2b092023-02-02 08:58:27 +01004289 /* all features */
4290 const char *iana_ssh_encryption_algs[] = {NULL};
4291 /* all features */
4292 const char *iana_ssh_key_exchange_algs[] = {NULL};
4293 /* all features */
4294 const char *iana_ssh_mac_algs[] = {NULL};
4295 /* all features */
4296 const char *iana_ssh_public_key_algs[] = {NULL};
romanc1d2b092023-02-02 08:58:27 +01004297 /* all features */
roman7fdc84d2023-06-06 13:14:53 +02004298 const char *iana_crypt_hash[] = {"crypt-hash-md5", "crypt-hash-sha-256", "crypt-hash-sha-512", NULL};
4299 /* no symmetric-keys */
4300 const char *ietf_keystore[] = {"central-keystore-supported", "inline-definitions-supported", "asymmetric-keys", NULL};
4301 /* all features */
4302 const char *ietf_truststore[] = {"central-truststore-supported", "inline-definitions-supported", "certificates", "public-keys", NULL};
roman3c6c7e62023-09-14 10:19:19 +02004303 /* no public-key-generation */
4304 const char *ietf_tls_common[] = {"tls10", "tls11", "tls12", "tls13", "hello-params", NULL};
4305 /* no tls-server-keepalives, server-ident-raw-public-key, server-ident-tls12-psk, server-ident-tls13-epsk,
4306 * client-auth-raw-public-key, client-auth-tls12-psk, client-auth-tls13-epsk */
4307 const char *ietf_tls_server[] = {"server-ident-x509-cert", "client-auth-supported", "client-auth-x509-cert", NULL};
roman7fdc84d2023-06-06 13:14:53 +02004308 /* all features */
roman12644fe2023-06-08 11:06:42 +02004309 const char *iana_tls_cipher_suite_algs[] = {NULL};
romanc1d2b092023-02-02 08:58:27 +01004310 /* all features */
4311 const char *libnetconf2_netconf_server[] = {NULL};
4312
4313 const char *module_names[] = {
roman7fdc84d2023-06-06 13:14:53 +02004314 "ietf-netconf-server", "ietf-x509-cert-to-name", "ietf-crypto-types", "ietf-tcp-common", "ietf-tcp-server",
4315 "ietf-tcp-client", "ietf-ssh-common", "ietf-ssh-server", "iana-ssh-encryption-algs",
4316 "iana-ssh-key-exchange-algs", "iana-ssh-mac-algs", "iana-ssh-public-key-algs", "iana-crypt-hash",
roman12644fe2023-06-08 11:06:42 +02004317 "ietf-keystore", "ietf-truststore", "ietf-tls-common", "ietf-tls-server", "iana-tls-cipher-suite-algs",
4318 "libnetconf2-netconf-server", NULL
romanc1d2b092023-02-02 08:58:27 +01004319 };
4320
4321 const char **module_features[] = {
roman7fdc84d2023-06-06 13:14:53 +02004322 ietf_nectonf_server, ietf_x509_cert_to_name, ietf_crypto_types, ietf_tcp_common,
4323 ietf_tcp_server, ietf_tcp_client, ietf_ssh_common, ietf_ssh_server, iana_ssh_encryption_algs,
4324 iana_ssh_key_exchange_algs, iana_ssh_mac_algs, iana_ssh_public_key_algs, iana_crypt_hash,
roman12644fe2023-06-08 11:06:42 +02004325 ietf_keystore, ietf_truststore, ietf_tls_common, ietf_tls_server, iana_tls_cipher_suite_algs,
4326 libnetconf2_netconf_server, NULL
romanc1d2b092023-02-02 08:58:27 +01004327 };
4328
4329 for (i = 0; module_names[i] != NULL; i++) {
4330 if (!ly_ctx_load_module(*ctx, module_names[i], NULL, module_features[i])) {
4331 ERR(NULL, "Loading module \"%s\" failed.\n", module_names[i]);
4332 goto error;
4333 }
4334 }
4335
4336 return 0;
4337
4338error:
4339 if (new_ctx) {
4340 ly_ctx_destroy(*ctx);
4341 *ctx = NULL;
4342 }
4343 return 1;
4344}
4345
romanf9906b42023-05-22 14:04:29 +02004346static int
4347nc_server_config_fill_nectonf_server(const struct lyd_node *data, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01004348{
4349 int ret = 0;
roman84fe3252023-10-25 11:28:32 +02004350 uint32_t log_options = 0;
romanc1d2b092023-02-02 08:58:27 +01004351 struct lyd_node *tree;
romand57b3722023-04-05 11:26:25 +02004352
romanc9b62d62023-09-14 10:19:50 +02004353 /* silently search for ietf-netconf-server, it may not be present */
roman84fe3252023-10-25 11:28:32 +02004354 ly_temp_log_options(&log_options);
romanc9b62d62023-09-14 10:19:50 +02004355
romanc1d2b092023-02-02 08:58:27 +01004356 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &tree);
romanc9b62d62023-09-14 10:19:50 +02004357 if (ret || (tree->flags & LYD_DEFAULT)) {
4358 /* not found */
4359 ret = 0;
romanc1d2b092023-02-02 08:58:27 +01004360 goto cleanup;
4361 }
4362
roman0bbc19c2023-05-26 09:59:09 +02004363 if (nc_server_config_parse_tree(tree, op, NC_MODULE_NETCONF_SERVER)) {
4364 ret = 1;
4365 goto cleanup;
4366 }
4367
roman2eab4742023-06-06 10:00:26 +02004368#ifdef NC_ENABLED_SSH_TLS
4369 /* backward check of client auth reference */
roman0bbc19c2023-05-26 09:59:09 +02004370 if (nc_server_config_fill_endpt_client_auth()) {
romanf9906b42023-05-22 14:04:29 +02004371 ret = 1;
4372 goto cleanup;
4373 }
roman2eab4742023-06-06 10:00:26 +02004374#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004375
4376cleanup:
romanc9b62d62023-09-14 10:19:50 +02004377 /* reset the logging options back to what they were */
roman84fe3252023-10-25 11:28:32 +02004378 ly_temp_log_options(NULL);
romanf9906b42023-05-22 14:04:29 +02004379 return ret;
4380}
4381
4382API int
romanf6f37a52023-05-25 14:27:51 +02004383nc_server_config_setup_diff(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02004384{
4385 int ret = 0;
4386
romanc9b62d62023-09-14 10:19:50 +02004387 NC_CHECK_ARG_RET(NULL, data, 1);
4388
romanf9906b42023-05-22 14:04:29 +02004389 /* LOCK */
4390 pthread_rwlock_wrlock(&server_opts.config_lock);
4391
roman2eab4742023-06-06 10:00:26 +02004392#ifdef NC_ENABLED_SSH_TLS
romanf9906b42023-05-22 14:04:29 +02004393 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02004394 ret = nc_server_config_fill_keystore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02004395 if (ret) {
4396 ERR(NULL, "Filling keystore failed.");
4397 goto cleanup;
4398 }
4399
4400 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02004401 ret = nc_server_config_fill_truststore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02004402 if (ret) {
4403 ERR(NULL, "Filling truststore failed.");
4404 goto cleanup;
4405 }
roman2eab4742023-06-06 10:00:26 +02004406#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004407
4408 /* configure netconf-server */
4409 ret = nc_server_config_fill_nectonf_server(data, NC_OP_UNKNOWN);
4410 if (ret) {
4411 ERR(NULL, "Filling netconf-server failed.");
4412 goto cleanup;
4413 }
4414
4415cleanup:
4416 /* UNLOCK */
4417 pthread_rwlock_unlock(&server_opts.config_lock);
4418 return ret;
4419}
4420
4421API int
romanf6f37a52023-05-25 14:27:51 +02004422nc_server_config_setup_data(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02004423{
4424 int ret = 0;
4425 struct lyd_node *tree, *iter, *root;
4426
romanc9b62d62023-09-14 10:19:50 +02004427 NC_CHECK_ARG_RET(NULL, data, 1);
4428
romanf9906b42023-05-22 14:04:29 +02004429 /* LOCK */
4430 pthread_rwlock_wrlock(&server_opts.config_lock);
4431
4432 /* find the netconf-server node */
4433 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &root);
4434 if (ret) {
4435 ERR(NULL, "Unable to find the netconf-server container in the YANG data.");
4436 goto cleanup;
4437 }
4438
4439 /* iterate through all the nodes and make sure there is no operation attribute */
4440 LY_LIST_FOR(root, tree) {
4441 LYD_TREE_DFS_BEGIN(tree, iter) {
4442 if (lyd_find_meta(iter->meta, NULL, "yang:operation")) {
4443 ERR(NULL, "Unexpected operation attribute in the YANG data.");
romanc1d2b092023-02-02 08:58:27 +01004444 ret = 1;
4445 goto cleanup;
4446 }
romanf9906b42023-05-22 14:04:29 +02004447 LYD_TREE_DFS_END(tree, iter);
romanc1d2b092023-02-02 08:58:27 +01004448 }
4449 }
4450
romanf9906b42023-05-22 14:04:29 +02004451 /* delete the current configuration */
romanf02273a2023-05-25 09:44:11 +02004452 nc_server_config_listen(NULL, NC_OP_DELETE);
roman4cb8bb12023-06-29 09:16:46 +02004453 nc_server_config_ch(NULL, NC_OP_DELETE);
roman2eab4742023-06-06 10:00:26 +02004454#ifdef NC_ENABLED_SSH_TLS
romanf02273a2023-05-25 09:44:11 +02004455 nc_server_config_ks_keystore(NULL, NC_OP_DELETE);
4456 nc_server_config_ts_truststore(NULL, NC_OP_DELETE);
romanf9906b42023-05-22 14:04:29 +02004457
4458 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02004459 ret = nc_server_config_fill_keystore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02004460 if (ret) {
4461 ERR(NULL, "Filling keystore failed.");
4462 goto cleanup;
4463 }
4464
4465 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02004466 ret = nc_server_config_fill_truststore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02004467 if (ret) {
4468 ERR(NULL, "Filling truststore failed.");
4469 goto cleanup;
4470 }
roman2eab4742023-06-06 10:00:26 +02004471#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004472
4473 /* configure netconf-server */
4474 ret = nc_server_config_fill_nectonf_server(data, NC_OP_CREATE);
4475 if (ret) {
4476 ERR(NULL, "Filling netconf-server failed.");
romanc1d2b092023-02-02 08:58:27 +01004477 goto cleanup;
4478 }
4479
4480cleanup:
4481 /* UNLOCK */
4482 pthread_rwlock_unlock(&server_opts.config_lock);
4483 return ret;
4484}
roman3f9b65c2023-06-05 14:26:58 +02004485
4486API int
4487nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path)
4488{
4489 struct lyd_node *tree = NULL;
4490 int ret = 0;
4491
4492 NC_CHECK_ARG_RET(NULL, path, 1);
4493
4494 ret = lyd_parse_data_path(ctx, path, LYD_UNKNOWN, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree);
4495 if (ret) {
4496 goto cleanup;
4497 }
4498
4499 ret = nc_server_config_setup_data(tree);
4500 if (ret) {
4501 goto cleanup;
4502 }
4503
4504cleanup:
4505 lyd_free_all(tree);
4506 return ret;
4507}