blob: d41ea21167f764604359beba569d27bcb417edcd [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
roman5ae78282023-11-02 13:34:34 +0100755 if (bind) {
756 free(bind->address);
757 if (bind->sock > -1) {
758 close(bind->sock);
759 }
romanc1d2b092023-02-02 08:58:27 +0100760 }
761
762 /* store in variable because it gets decremented in the function call */
763 hostkey_count = opts->hostkey_count;
764 for (i = 0; i < hostkey_count; i++) {
roman874fed12023-05-25 10:20:01 +0200765 nc_server_config_del_hostkey(opts, &opts->hostkeys[i]);
romanc1d2b092023-02-02 08:58:27 +0100766 }
767
768 client_count = opts->client_count;
769 for (i = 0; i < client_count; i++) {
roman874fed12023-05-25 10:20:01 +0200770 nc_server_config_del_auth_client(opts, &opts->auth_clients[i]);
romanc1d2b092023-02-02 08:58:27 +0100771 }
772
roman6430c152023-10-12 11:28:47 +0200773 free(opts->hostkey_algs);
774 free(opts->kex_algs);
775 free(opts->encryption_algs);
776 free(opts->mac_algs);
romanc1d2b092023-02-02 08:58:27 +0100777
778 free(opts);
romanc1d2b092023-02-02 08:58:27 +0100779}
780
roman78df0fa2023-11-02 10:33:57 +0100781static void
782nc_server_config_del_endpt_references(const char *referenced_endpt_name)
783{
784 uint16_t i, j;
785
786 for (i = 0; i < server_opts.endpt_count; i++) {
787 if (server_opts.endpts[i].referenced_endpt_name) {
788 if (!strcmp(server_opts.endpts[i].referenced_endpt_name, referenced_endpt_name)) {
789 free(server_opts.endpts[i].referenced_endpt_name);
790 server_opts.endpts[i].referenced_endpt_name = NULL;
791
792 if (server_opts.endpts[i].ti == NC_TI_LIBSSH) {
793 server_opts.endpts[i].opts.ssh->referenced_endpt_name = NULL;
794 } else {
795 server_opts.endpts[i].opts.tls->referenced_endpt_name = NULL;
796 }
797 }
798 }
799 }
800
801 /* LOCK */
802 pthread_rwlock_rdlock(&server_opts.ch_client_lock);
803 for (i = 0; i < server_opts.ch_client_count; i++) {
804 /* LOCK */
805 pthread_mutex_lock(&server_opts.ch_clients[i].lock);
806 for (j = 0; j < server_opts.ch_clients[i].ch_endpt_count; j++) {
807 if (server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name) {
808 if (!strcmp(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, referenced_endpt_name)) {
809 free(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name);
810 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name = NULL;
811
812 if (server_opts.ch_clients[i].ch_endpts[j].ti == NC_TI_LIBSSH) {
813 server_opts.ch_clients[i].ch_endpts[j].opts.ssh->referenced_endpt_name = NULL;
814 } else {
815 server_opts.ch_clients[i].ch_endpts[j].opts.tls->referenced_endpt_name = NULL;
816 }
817 }
818 }
819 }
820 /* UNLOCK */
821 pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
822 }
823
824 /* UNLOCK */
825 pthread_rwlock_unlock(&server_opts.ch_client_lock);
826}
827
romanc1d2b092023-02-02 08:58:27 +0100828void
roman874fed12023-05-25 10:20:01 +0200829nc_server_config_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind)
romanc1d2b092023-02-02 08:58:27 +0100830{
roman78df0fa2023-11-02 10:33:57 +0100831 /* delete any references to this endpoint */
832 nc_server_config_del_endpt_references(endpt->name);
roman6430c152023-10-12 11:28:47 +0200833 free(endpt->name);
roman78df0fa2023-11-02 10:33:57 +0100834
roman6430c152023-10-12 11:28:47 +0200835 free(endpt->referenced_endpt_name);
836 nc_server_config_del_ssh_opts(bind, endpt->opts.ssh);
romanc1d2b092023-02-02 08:58:27 +0100837
838 server_opts.endpt_count--;
839 if (!server_opts.endpt_count) {
840 free(server_opts.endpts);
841 free(server_opts.binds);
842 server_opts.endpts = NULL;
843 server_opts.binds = NULL;
roman6430c152023-10-12 11:28:47 +0200844 } else if (endpt != &server_opts.endpts[server_opts.endpt_count]) {
roman33981232023-07-08 11:55:13 +0200845 memcpy(endpt, &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts);
846 memcpy(bind, &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds);
romanc1d2b092023-02-02 08:58:27 +0100847 }
848}
849
roman2eab4742023-06-06 10:00:26 +0200850#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200851
roman45cec4e2023-02-17 10:21:39 +0100852void
roman6430c152023-10-12 11:28:47 +0200853nc_server_config_del_unix_socket_opts(struct nc_bind *bind, struct nc_server_unix_opts *opts)
roman83683fb2023-02-24 09:15:23 +0100854{
855 if (bind->sock > -1) {
856 close(bind->sock);
857 }
858
romand0b78372023-09-14 10:06:03 +0200859 unlink(bind->address);
roman83683fb2023-02-24 09:15:23 +0100860 free(bind->address);
861 free(opts->address);
862
863 free(opts);
roman83683fb2023-02-24 09:15:23 +0100864}
865
866void
roman874fed12023-05-25 10:20:01 +0200867nc_server_config_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *bind)
roman83683fb2023-02-24 09:15:23 +0100868{
roman6430c152023-10-12 11:28:47 +0200869 free(endpt->name);
870 nc_server_config_del_unix_socket_opts(bind, endpt->opts.unixsock);
roman83683fb2023-02-24 09:15:23 +0100871
872 server_opts.endpt_count--;
873 if (!server_opts.endpt_count) {
874 free(server_opts.endpts);
875 free(server_opts.binds);
876 server_opts.endpts = NULL;
877 server_opts.binds = NULL;
roman6430c152023-10-12 11:28:47 +0200878 } else if (endpt != &server_opts.endpts[server_opts.endpt_count]) {
roman33981232023-07-08 11:55:13 +0200879 memcpy(endpt, &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts);
880 memcpy(bind, &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds);
roman83683fb2023-02-24 09:15:23 +0100881 }
882}
883
roman2eab4742023-06-06 10:00:26 +0200884#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +0200885
886static void
roman3f9b65c2023-06-05 14:26:58 +0200887nc_server_config_del_cert(struct nc_cert_grouping *certs, struct nc_certificate *cert)
888{
889 free(cert->name);
roman3f9b65c2023-06-05 14:26:58 +0200890 free(cert->data);
roman3f9b65c2023-06-05 14:26:58 +0200891
892 certs->cert_count--;
893 if (!certs->cert_count) {
894 free(certs->certs);
895 certs->certs = NULL;
roman6430c152023-10-12 11:28:47 +0200896 } else if (cert != &certs->certs[certs->cert_count]) {
roman33981232023-07-08 11:55:13 +0200897 memcpy(cert, &certs->certs[certs->cert_count], sizeof *certs->certs);
roman3f9b65c2023-06-05 14:26:58 +0200898 }
899}
900
901static void
roman6430c152023-10-12 11:28:47 +0200902nc_server_config_del_certs(struct nc_cert_grouping *certs_grp)
roman3f9b65c2023-06-05 14:26:58 +0200903{
roman6430c152023-10-12 11:28:47 +0200904 uint16_t i;
roman3f9b65c2023-06-05 14:26:58 +0200905
roman6430c152023-10-12 11:28:47 +0200906 if (certs_grp->store == NC_STORE_LOCAL) {
907 for (i = 0; i < certs_grp->cert_count; i++) {
908 free(certs_grp->certs[i].name);
909 free(certs_grp->certs[i].data);
roman3f9b65c2023-06-05 14:26:58 +0200910 }
roman6430c152023-10-12 11:28:47 +0200911 free(certs_grp->certs);
912 certs_grp->certs = NULL;
913 } else {
914 free(certs_grp->ts_ref);
roman3f9b65c2023-06-05 14:26:58 +0200915 }
916}
917
918static void
919nc_server_config_del_ctn(struct nc_server_tls_opts *opts, struct nc_ctn *ctn)
920{
921 struct nc_ctn *iter;
922
roman3f9b65c2023-06-05 14:26:58 +0200923 free(ctn->name);
roman6430c152023-10-12 11:28:47 +0200924 free(ctn->fingerprint);
roman3f9b65c2023-06-05 14:26:58 +0200925
926 if (opts->ctn == ctn) {
927 /* it's the first in the list */
928 opts->ctn = ctn->next;
929 free(ctn);
930 return;
931 }
932
roman84fe3252023-10-25 11:28:32 +0200933 for (iter = opts->ctn; iter; iter = iter->next) {
roman3f9b65c2023-06-05 14:26:58 +0200934 if (iter->next == ctn) {
935 /* found the ctn */
936 break;
937 }
roman3f9b65c2023-06-05 14:26:58 +0200938 }
939
940 iter->next = ctn->next;
941 free(ctn);
942}
943
944static void
roman6430c152023-10-12 11:28:47 +0200945nc_server_config_del_ctns(struct nc_server_tls_opts *opts)
roman3f9b65c2023-06-05 14:26:58 +0200946{
947 struct nc_ctn *cur, *next;
948
roman84fe3252023-10-25 11:28:32 +0200949 for (cur = opts->ctn; cur; cur = next) {
roman3f9b65c2023-06-05 14:26:58 +0200950 next = cur->next;
roman3f9b65c2023-06-05 14:26:58 +0200951 free(cur->name);
roman6430c152023-10-12 11:28:47 +0200952 free(cur->fingerprint);
roman3f9b65c2023-06-05 14:26:58 +0200953 free(cur);
roman3f9b65c2023-06-05 14:26:58 +0200954 }
roman3a95bb22023-10-26 11:07:17 +0200955
roman3f9b65c2023-06-05 14:26:58 +0200956 opts->ctn = NULL;
957}
958
959static void
roman6430c152023-10-12 11:28:47 +0200960nc_server_config_del_tls_opts(struct nc_bind *bind, struct nc_server_tls_opts *opts)
roman3f9b65c2023-06-05 14:26:58 +0200961{
roman5ae78282023-11-02 13:34:34 +0100962 if (bind) {
963 free(bind->address);
964 if (bind->sock > -1) {
965 close(bind->sock);
966 }
roman3f9b65c2023-06-05 14:26:58 +0200967 }
968
969 if (opts->store == NC_STORE_LOCAL) {
roman6430c152023-10-12 11:28:47 +0200970 free(opts->pubkey_data);
971 free(opts->privkey_data);
972 free(opts->cert_data);
973 } else {
974 free(opts->key_ref);
975 free(opts->cert_ref);
roman3f9b65c2023-06-05 14:26:58 +0200976 }
977
roman6430c152023-10-12 11:28:47 +0200978 nc_server_config_del_certs(&opts->ca_certs);
979 nc_server_config_del_certs(&opts->ee_certs);
roman3f9b65c2023-06-05 14:26:58 +0200980
roman6430c152023-10-12 11:28:47 +0200981 free(opts->crl_path);
982 free(opts->crl_url);
romanfaecc582023-06-15 16:13:31 +0200983 X509_STORE_free(opts->crl_store);
romanfaecc582023-06-15 16:13:31 +0200984
roman6430c152023-10-12 11:28:47 +0200985 nc_server_config_del_ctns(opts);
986 free(opts->ciphers);
roman3f9b65c2023-06-05 14:26:58 +0200987 free(opts);
988}
989
990static void
991nc_server_config_del_endpt_tls(struct nc_endpt *endpt, struct nc_bind *bind)
992{
roman78df0fa2023-11-02 10:33:57 +0100993 /* delete any references to this endpoint */
994 nc_server_config_del_endpt_references(endpt->name);
roman6430c152023-10-12 11:28:47 +0200995 free(endpt->name);
roman78df0fa2023-11-02 10:33:57 +0100996
roman6430c152023-10-12 11:28:47 +0200997 free(endpt->referenced_endpt_name);
998
999 nc_server_config_del_tls_opts(bind, endpt->opts.tls);
roman3f9b65c2023-06-05 14:26:58 +02001000
1001 server_opts.endpt_count--;
1002 if (!server_opts.endpt_count) {
1003 free(server_opts.endpts);
1004 free(server_opts.binds);
1005 server_opts.endpts = NULL;
1006 server_opts.binds = NULL;
roman6430c152023-10-12 11:28:47 +02001007 } else if (endpt != &server_opts.endpts[server_opts.endpt_count]) {
roman33981232023-07-08 11:55:13 +02001008 memcpy(endpt, &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts);
1009 memcpy(bind, &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds);
roman3f9b65c2023-06-05 14:26:58 +02001010 }
1011}
1012
roman2eab4742023-06-06 10:00:26 +02001013#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02001014
romanc1d2b092023-02-02 08:58:27 +01001015/* presence container */
1016int
roman6430c152023-10-12 11:28:47 +02001017nc_server_config_listen(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001018{
roman0bbc19c2023-05-26 09:59:09 +02001019 uint16_t i, endpt_count;
romanc1d2b092023-02-02 08:58:27 +01001020
romanf02273a2023-05-25 09:44:11 +02001021 (void) node;
1022
romanc1d2b092023-02-02 08:58:27 +01001023 assert(op == NC_OP_CREATE || op == NC_OP_DELETE);
1024
1025 if (op == NC_OP_DELETE) {
roman0bbc19c2023-05-26 09:59:09 +02001026 endpt_count = server_opts.endpt_count;
1027 for (i = 0; i < endpt_count; i++) {
roman456f92d2023-04-28 10:28:12 +02001028 switch (server_opts.endpts[i].ti) {
roman2eab4742023-06-06 10:00:26 +02001029#ifdef NC_ENABLED_SSH_TLS
roman456f92d2023-04-28 10:28:12 +02001030 case NC_TI_LIBSSH:
roman874fed12023-05-25 10:20:01 +02001031 nc_server_config_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]);
roman456f92d2023-04-28 10:28:12 +02001032 break;
roman456f92d2023-04-28 10:28:12 +02001033 case NC_TI_OPENSSL:
roman3f9b65c2023-06-05 14:26:58 +02001034 nc_server_config_del_endpt_tls(&server_opts.endpts[i], &server_opts.binds[i]);
roman456f92d2023-04-28 10:28:12 +02001035 break;
roman2eab4742023-06-06 10:00:26 +02001036#endif /* NC_ENABLED_SSH_TLS */
roman456f92d2023-04-28 10:28:12 +02001037 case NC_TI_UNIX:
roman874fed12023-05-25 10:20:01 +02001038 nc_server_config_del_endpt_unix_socket(&server_opts.endpts[i], &server_opts.binds[i]);
roman456f92d2023-04-28 10:28:12 +02001039 break;
1040 case NC_TI_NONE:
1041 case NC_TI_FD:
1042 ERRINT;
1043 return 1;
roman83683fb2023-02-24 09:15:23 +01001044 }
romanc1d2b092023-02-02 08:58:27 +01001045 }
1046 }
1047
1048 return 0;
1049}
1050
roman5cbb6532023-06-22 12:53:17 +02001051static void
1052nc_server_config_ch_del_endpt(struct nc_ch_client *ch_client, struct nc_ch_endpt *ch_endpt)
1053{
1054 free(ch_endpt->name);
roman5cbb6532023-06-22 12:53:17 +02001055
1056#ifdef NC_ENABLED_SSH_TLS
roman6430c152023-10-12 11:28:47 +02001057 free(ch_endpt->address);
roman5cbb6532023-06-22 12:53:17 +02001058 if (ch_endpt->sock_pending > -1) {
1059 close(ch_endpt->sock_pending);
1060 ch_endpt->sock_pending = -1;
1061 }
roman5ae78282023-11-02 13:34:34 +01001062 free(ch_endpt->referenced_endpt_name);
roman5cbb6532023-06-22 12:53:17 +02001063#endif /* NC_ENABLED_SSH_TLS */
1064
1065 switch (ch_endpt->ti) {
1066#ifdef NC_ENABLED_SSH_TLS
1067 case NC_TI_LIBSSH:
roman5ae78282023-11-02 13:34:34 +01001068 nc_server_config_del_ssh_opts(NULL, ch_endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +02001069 break;
romanb6f44032023-06-30 15:07:56 +02001070 case NC_TI_OPENSSL:
roman5ae78282023-11-02 13:34:34 +01001071 nc_server_config_del_tls_opts(NULL, ch_endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +02001072 break;
roman5cbb6532023-06-22 12:53:17 +02001073#endif /* NC_ENABLED_SSH_TLS */
1074 default:
1075 ERRINT;
1076 break;
1077 }
1078
1079 ch_client->ch_endpt_count--;
1080 if (!ch_client->ch_endpt_count) {
1081 free(ch_client->ch_endpts);
1082 ch_client->ch_endpts = NULL;
1083 }
1084}
1085
1086static void
1087nc_server_config_ch_del_client(struct nc_ch_client *ch_client)
1088{
1089 uint16_t i, ch_endpt_count;
romanba93eac2023-07-18 14:36:48 +02001090 struct nc_ch_client client;
1091 pthread_t tid;
roman5cbb6532023-06-22 12:53:17 +02001092
romanba93eac2023-07-18 14:36:48 +02001093 /* WR LOCK */
roman5cbb6532023-06-22 12:53:17 +02001094 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
1095
romanba93eac2023-07-18 14:36:48 +02001096 /* copy the client we want to delete into a local variable */
1097 memcpy(&client, ch_client, sizeof *ch_client);
1098 /* get his tid */
1099 tid = client.tid;
roman5cbb6532023-06-22 12:53:17 +02001100
romanba93eac2023-07-18 14:36:48 +02001101 /* delete the client */
roman5cbb6532023-06-22 12:53:17 +02001102 server_opts.ch_client_count--;
1103 if (!server_opts.ch_client_count) {
1104 free(server_opts.ch_clients);
1105 server_opts.ch_clients = NULL;
romanba93eac2023-07-18 14:36:48 +02001106 } else {
1107 memcpy(ch_client, &server_opts.ch_clients[server_opts.ch_client_count], sizeof *server_opts.ch_clients);
roman5cbb6532023-06-22 12:53:17 +02001108 }
1109
romanba93eac2023-07-18 14:36:48 +02001110 /* WR UNLOCK */
roman5cbb6532023-06-22 12:53:17 +02001111 pthread_rwlock_unlock(&server_opts.ch_client_lock);
romanba93eac2023-07-18 14:36:48 +02001112
1113 /* RD LOCK */
1114 pthread_rwlock_rdlock(&server_opts.ch_client_lock);
roman84fe3252023-10-25 11:28:32 +02001115 /* MUTEX LOCK */
1116 pthread_mutex_lock(&client.lock);
romanba93eac2023-07-18 14:36:48 +02001117
1118 if (client.thread_data->thread_running) {
1119 /* CH COND LOCK */
1120 pthread_mutex_lock(&client.thread_data->cond_lock);
1121 client.thread_data->thread_running = 0;
1122 pthread_cond_signal(&client.thread_data->cond);
1123 /* CH COND UNLOCK */
1124 pthread_mutex_unlock(&client.thread_data->cond_lock);
1125
roman84fe3252023-10-25 11:28:32 +02001126 /* MUTEX UNLOCK */
1127 pthread_mutex_unlock(&client.lock);
romanba93eac2023-07-18 14:36:48 +02001128 /* RD UNLOCK */
1129 pthread_rwlock_unlock(&server_opts.ch_client_lock);
1130
1131 /* wait for the thread to terminate */
1132 pthread_join(tid, NULL);
1133 }
1134
1135 /* free its members */
1136 free(client.name);
1137
1138 ch_endpt_count = client.ch_endpt_count;
1139 for (i = 0; i < ch_endpt_count; i++) {
1140 nc_server_config_ch_del_endpt(&client, &client.ch_endpts[i]);
1141 }
roman5cbb6532023-06-22 12:53:17 +02001142}
1143
roman6430c152023-10-12 11:28:47 +02001144int
roman5cbb6532023-06-22 12:53:17 +02001145nc_server_config_ch(const struct lyd_node *node, NC_OPERATION op)
1146{
1147 uint16_t i, ch_client_count;
1148
1149 (void) node;
1150
1151 if (op == NC_OP_DELETE) {
1152 ch_client_count = server_opts.ch_client_count;
1153 for (i = 0; i < ch_client_count; i++) {
1154 nc_server_config_ch_del_client(&server_opts.ch_clients[i]);
1155 }
1156 }
roman6430c152023-10-12 11:28:47 +02001157
1158 return 0;
roman5cbb6532023-06-22 12:53:17 +02001159}
1160
romanc1d2b092023-02-02 08:58:27 +01001161/* default leaf */
1162static int
romaneaf84c72023-10-19 14:38:05 +02001163nc_server_config_hello_timeout(const struct lyd_node *node, NC_OPERATION op)
1164{
1165 assert(!strcmp(LYD_NAME(node), "hello-timeout"));
1166
1167 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001168 server_opts.hello_timeout = ((struct lyd_node_term *)node)->value.uint16;
romaneaf84c72023-10-19 14:38:05 +02001169 } else {
1170 /* default value */
1171 server_opts.hello_timeout = 60;
1172 }
1173
1174 return 0;
1175}
1176
1177/* default leaf */
1178static int
romane028ef92023-02-24 16:33:08 +01001179nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001180{
romanb6f44032023-06-30 15:07:56 +02001181 struct nc_ch_client *ch_client;
1182
romanc1d2b092023-02-02 08:58:27 +01001183 assert(!strcmp(LYD_NAME(node), "idle-timeout"));
1184
romaneaf84c72023-10-19 14:38:05 +02001185 if (is_ch(node)) {
romanb6f44032023-06-30 15:07:56 +02001186 /* call-home idle timeout */
roman6430c152023-10-12 11:28:47 +02001187 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
1188 /* to avoid unlock on fail */
romanb6f44032023-06-30 15:07:56 +02001189 return 1;
1190 }
1191
1192 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001193 ch_client->idle_timeout = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02001194 } else if (op == NC_OP_DELETE) {
1195 ch_client->idle_timeout = 180;
1196 }
roman6430c152023-10-12 11:28:47 +02001197
1198 nc_ch_client_unlock(ch_client);
romaneaf84c72023-10-19 14:38:05 +02001199 } else {
1200 /* whole server idle timeout */
1201 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001202 server_opts.idle_timeout = ((struct lyd_node_term *)node)->value.uint16;
romaneaf84c72023-10-19 14:38:05 +02001203 } else {
1204 /* default value */
1205 server_opts.idle_timeout = 0;
1206 }
romanc1d2b092023-02-02 08:58:27 +01001207 }
1208
1209 return 0;
1210}
1211
1212static int
roman874fed12023-05-25 10:20:01 +02001213nc_server_config_create_bind(void)
romanc1d2b092023-02-02 08:58:27 +01001214{
1215 int ret = 0;
1216 void *tmp;
1217
1218 tmp = realloc(server_opts.binds, (server_opts.endpt_count + 1) * sizeof *server_opts.binds);
roman3a95bb22023-10-26 11:07:17 +02001219 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01001220 server_opts.binds = tmp;
1221 memset(&server_opts.binds[server_opts.endpt_count], 0, sizeof *server_opts.binds);
1222
1223 server_opts.binds[server_opts.endpt_count].sock = -1;
1224
1225cleanup:
1226 return ret;
1227}
1228
1229static int
roman874fed12023-05-25 10:20:01 +02001230nc_server_config_create_endpoint(const struct lyd_node *node)
romanc1d2b092023-02-02 08:58:27 +01001231{
roman874fed12023-05-25 10:20:01 +02001232 if (nc_server_config_create_bind()) {
romanf02273a2023-05-25 09:44:11 +02001233 return 1;
romanc1d2b092023-02-02 08:58:27 +01001234 }
romanc1d2b092023-02-02 08:58:27 +01001235
1236 node = lyd_child(node);
1237 assert(!strcmp(LYD_NAME(node), "name"));
1238
romanf02273a2023-05-25 09:44:11 +02001239 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 +01001240}
1241
roman5cbb6532023-06-22 12:53:17 +02001242static int
1243nc_server_config_ch_create_endpoint(const struct lyd_node *node, struct nc_ch_client *ch_client)
1244{
1245 node = lyd_child(node);
1246 assert(!strcmp(LYD_NAME(node), "name"));
1247
1248 return nc_server_config_realloc(lyd_get_value(node), (void **)&ch_client->ch_endpts, sizeof *ch_client->ch_endpts, &ch_client->ch_endpt_count);
1249}
1250
romanc1d2b092023-02-02 08:58:27 +01001251/* list */
1252static int
romane028ef92023-02-24 16:33:08 +01001253nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001254{
1255 int ret = 0;
1256 struct nc_endpt *endpt;
1257 struct nc_bind *bind;
roman6430c152023-10-12 11:28:47 +02001258 struct nc_ch_endpt *ch_endpt;
roman5cbb6532023-06-22 12:53:17 +02001259 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001260
1261 assert(!strcmp(LYD_NAME(node), "endpoint"));
1262
roman5cbb6532023-06-22 12:53:17 +02001263 if (is_listen(node)) {
1264 /* listen */
1265 if (op == NC_OP_CREATE) {
1266 ret = nc_server_config_create_endpoint(node);
1267 if (ret) {
1268 goto cleanup;
1269 }
1270 } else if (op == NC_OP_DELETE) {
1271 /* free all children */
1272 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1273 ret = 1;
1274 goto cleanup;
1275 }
1276
1277 switch (endpt->ti) {
1278#ifdef NC_ENABLED_SSH_TLS
1279 case NC_TI_LIBSSH:
1280 nc_server_config_del_endpt_ssh(endpt, bind);
1281 break;
1282 case NC_TI_OPENSSL:
1283 nc_server_config_del_endpt_tls(endpt, bind);
1284 break;
1285#endif /* NC_ENABLED_SSH_TLS */
1286 case NC_TI_UNIX:
1287 nc_server_config_del_endpt_unix_socket(endpt, bind);
1288 break;
1289 case NC_TI_NONE:
1290 case NC_TI_FD:
1291 ERRINT;
1292 ret = 1;
1293 goto cleanup;
1294 }
romanc1d2b092023-02-02 08:58:27 +01001295 }
roman5cbb6532023-06-22 12:53:17 +02001296 } else if (is_ch(node)) {
romanba93eac2023-07-18 14:36:48 +02001297 /* LOCK */
1298 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001299 /* to avoid unlock on fail */
1300 return 1;
romanc1d2b092023-02-02 08:58:27 +01001301 }
roman3f9b65c2023-06-05 14:26:58 +02001302
roman5cbb6532023-06-22 12:53:17 +02001303 if (op == NC_OP_CREATE) {
1304 ret = nc_server_config_ch_create_endpoint(node, ch_client);
1305 if (ret) {
1306 goto cleanup;
1307 }
1308
1309 /* init ch sock */
1310 ch_client->ch_endpts[ch_client->ch_endpt_count - 1].sock_pending = -1;
roman6430c152023-10-12 11:28:47 +02001311 } else if (op == NC_OP_DELETE) {
1312 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
1313 ret = 1;
1314 goto cleanup;
1315 }
1316
1317 nc_server_config_ch_del_endpt(ch_client, ch_endpt);
roman3f9b65c2023-06-05 14:26:58 +02001318 }
romanc1d2b092023-02-02 08:58:27 +01001319 }
1320
1321cleanup:
romanba93eac2023-07-18 14:36:48 +02001322 if (is_ch(node)) {
1323 /* UNLOCK */
1324 nc_ch_client_unlock(ch_client);
1325 }
romanc1d2b092023-02-02 08:58:27 +01001326 return ret;
1327}
1328
roman2eab4742023-06-06 10:00:26 +02001329#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02001330
romanc1d2b092023-02-02 08:58:27 +01001331static int
roman874fed12023-05-25 10:20:01 +02001332nc_server_config_create_ssh(struct nc_endpt *endpt)
romanc1d2b092023-02-02 08:58:27 +01001333{
1334 endpt->ti = NC_TI_LIBSSH;
1335 endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
roman3a95bb22023-10-26 11:07:17 +02001336 NC_CHECK_ERRMEM_RET(!endpt->opts.ssh, 1);
romanc1d2b092023-02-02 08:58:27 +01001337
1338 return 0;
1339}
1340
roman5cbb6532023-06-22 12:53:17 +02001341static int
1342nc_server_config_ch_create_ssh(struct nc_ch_endpt *ch_endpt)
1343{
1344 ch_endpt->ti = NC_TI_LIBSSH;
1345 ch_endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
roman3a95bb22023-10-26 11:07:17 +02001346 NC_CHECK_ERRMEM_RET(!ch_endpt->opts.ssh, 1);
roman5cbb6532023-06-22 12:53:17 +02001347
1348 return 0;
1349}
1350
romanc1d2b092023-02-02 08:58:27 +01001351/* NP container */
1352static int
romane028ef92023-02-24 16:33:08 +01001353nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001354{
1355 struct nc_endpt *endpt;
1356 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001357 struct nc_ch_endpt *ch_endpt;
romanba93eac2023-07-18 14:36:48 +02001358 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001359 int ret = 0;
1360
1361 assert(!strcmp(LYD_NAME(node), "ssh"));
1362
roman5cbb6532023-06-22 12:53:17 +02001363 if (is_listen(node)) {
1364 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1365 ret = 1;
romanc1d2b092023-02-02 08:58:27 +01001366 goto cleanup;
1367 }
roman5cbb6532023-06-22 12:53:17 +02001368
1369 if (op == NC_OP_CREATE) {
1370 ret = nc_server_config_create_ssh(endpt);
1371 if (ret) {
1372 goto cleanup;
1373 }
1374 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02001375 nc_server_config_del_ssh_opts(bind, endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +02001376 }
1377 } else {
romanba93eac2023-07-18 14:36:48 +02001378 /* LOCK */
1379 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001380 /* to avoid unlock on fail */
1381 return 1;
romanba93eac2023-07-18 14:36:48 +02001382 }
1383
roman4cb8bb12023-06-29 09:16:46 +02001384 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001385 ret = 1;
1386 goto cleanup;
1387 }
1388
1389 if (op == NC_OP_CREATE) {
1390 ret = nc_server_config_ch_create_ssh(ch_endpt);
1391 if (ret) {
1392 goto cleanup;
1393 }
romanb6f44032023-06-30 15:07:56 +02001394 } else if (op == NC_OP_DELETE) {
roman5ae78282023-11-02 13:34:34 +01001395 nc_server_config_del_ssh_opts(NULL, ch_endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +02001396 }
romanc1d2b092023-02-02 08:58:27 +01001397 }
1398
1399cleanup:
romanba93eac2023-07-18 14:36:48 +02001400 if (is_ch(node)) {
1401 /* UNLOCK */
1402 nc_ch_client_unlock(ch_client);
1403 }
romanc1d2b092023-02-02 08:58:27 +01001404 return ret;
1405}
1406
roman3f9b65c2023-06-05 14:26:58 +02001407static int
1408nc_server_config_create_tls(struct nc_endpt *endpt)
1409{
1410 endpt->ti = NC_TI_OPENSSL;
1411 endpt->opts.tls = calloc(1, sizeof *endpt->opts.tls);
roman3a95bb22023-10-26 11:07:17 +02001412 NC_CHECK_ERRMEM_RET(!endpt->opts.tls, 1);
roman3f9b65c2023-06-05 14:26:58 +02001413
1414 return 0;
1415}
1416
1417static int
romanb6f44032023-06-30 15:07:56 +02001418nc_server_config_ch_create_tls(struct nc_ch_endpt *ch_endpt)
1419{
1420 ch_endpt->ti = NC_TI_OPENSSL;
1421 ch_endpt->opts.tls = calloc(1, sizeof(struct nc_server_tls_opts));
roman3a95bb22023-10-26 11:07:17 +02001422 NC_CHECK_ERRMEM_RET(!ch_endpt->opts.tls, 1);
romanb6f44032023-06-30 15:07:56 +02001423
1424 return 0;
1425}
1426
1427static int
roman3f9b65c2023-06-05 14:26:58 +02001428nc_server_config_tls(const struct lyd_node *node, NC_OPERATION op)
1429{
1430 struct nc_endpt *endpt;
1431 struct nc_bind *bind;
romanb6f44032023-06-30 15:07:56 +02001432 struct nc_ch_endpt *ch_endpt;
romanba93eac2023-07-18 14:36:48 +02001433 struct nc_ch_client *ch_client;
roman3f9b65c2023-06-05 14:26:58 +02001434 int ret = 0;
1435
1436 assert(!strcmp(LYD_NAME(node), "tls"));
1437
romanb6f44032023-06-30 15:07:56 +02001438 if (is_listen(node)) {
1439 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1440 ret = 1;
roman3f9b65c2023-06-05 14:26:58 +02001441 goto cleanup;
1442 }
romanb6f44032023-06-30 15:07:56 +02001443
1444 if (op == NC_OP_CREATE) {
1445 ret = nc_server_config_create_tls(endpt);
1446 if (ret) {
1447 goto cleanup;
1448 }
1449 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02001450 nc_server_config_del_tls_opts(bind, endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +02001451 }
1452 } else {
romanba93eac2023-07-18 14:36:48 +02001453 /* LOCK */
1454 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001455 /* to avoid unlock on fail */
1456 return 1;
romanba93eac2023-07-18 14:36:48 +02001457 }
1458
romanb6f44032023-06-30 15:07:56 +02001459 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
1460 ret = 1;
1461 goto cleanup;
1462 }
1463
1464 if (op == NC_OP_CREATE) {
1465 ret = nc_server_config_ch_create_tls(ch_endpt);
1466 if (ret) {
1467 goto cleanup;
1468 }
roman6430c152023-10-12 11:28:47 +02001469 } else if (op == NC_OP_DELETE) {
roman5ae78282023-11-02 13:34:34 +01001470 nc_server_config_del_tls_opts(NULL, ch_endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +02001471 }
roman3f9b65c2023-06-05 14:26:58 +02001472 }
1473
1474cleanup:
romanba93eac2023-07-18 14:36:48 +02001475 if (is_ch(node)) {
1476 /* UNLOCK */
1477 nc_ch_client_unlock(ch_client);
1478 }
roman3f9b65c2023-06-05 14:26:58 +02001479 return ret;
1480}
1481
roman2eab4742023-06-06 10:00:26 +02001482#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02001483
romanc1d2b092023-02-02 08:58:27 +01001484static int
1485nc_server_config_set_address_port(struct nc_endpt *endpt, struct nc_bind *bind, const char *address, uint16_t port)
1486{
1487 int sock = -1, set_addr, ret = 0;
1488
roman83683fb2023-02-24 09:15:23 +01001489 assert((address && !port) || (!address && port) || (endpt->ti == NC_TI_UNIX));
romanc1d2b092023-02-02 08:58:27 +01001490
1491 if (address) {
1492 set_addr = 1;
1493 } else {
1494 set_addr = 0;
1495 }
1496
1497 if (set_addr) {
1498 port = bind->port;
1499 } else {
1500 address = bind->address;
1501 }
1502
romanc1d2b092023-02-02 08:58:27 +01001503 /* we have all the information we need to create a listening socket */
roman83683fb2023-02-24 09:15:23 +01001504 if ((address && port) || (endpt->ti == NC_TI_UNIX)) {
romanc1d2b092023-02-02 08:58:27 +01001505 /* create new socket, close the old one */
roman83683fb2023-02-24 09:15:23 +01001506 if (endpt->ti == NC_TI_UNIX) {
1507 sock = nc_sock_listen_unix(endpt->opts.unixsock);
1508 } else {
1509 sock = nc_sock_listen_inet(address, port, &endpt->ka);
1510 }
1511
romanc1d2b092023-02-02 08:58:27 +01001512 if (sock == -1) {
1513 ret = 1;
1514 goto cleanup;
1515 }
1516
1517 if (bind->sock > -1) {
1518 close(bind->sock);
1519 }
1520 bind->sock = sock;
1521 }
1522
1523 if (sock > -1) {
1524 switch (endpt->ti) {
roman83683fb2023-02-24 09:15:23 +01001525 case NC_TI_UNIX:
1526 VRB(NULL, "Listening on %s for UNIX connections.", endpt->opts.unixsock->address);
1527 break;
roman2eab4742023-06-06 10:00:26 +02001528#ifdef NC_ENABLED_SSH_TLS
romanc1d2b092023-02-02 08:58:27 +01001529 case NC_TI_LIBSSH:
1530 VRB(NULL, "Listening on %s:%u for SSH connections.", address, port);
1531 break;
romanc1d2b092023-02-02 08:58:27 +01001532 case NC_TI_OPENSSL:
1533 VRB(NULL, "Listening on %s:%u for TLS connections.", address, port);
1534 break;
roman2eab4742023-06-06 10:00:26 +02001535#endif /* NC_ENABLED_SSH_TLS */
romanc1d2b092023-02-02 08:58:27 +01001536 default:
1537 ERRINT;
1538 ret = 1;
1539 break;
1540 }
1541 }
1542
1543cleanup:
1544 return ret;
1545}
1546
roman2eab4742023-06-06 10:00:26 +02001547#ifdef NC_ENABLED_SSH_TLS
1548
romanc1d2b092023-02-02 08:58:27 +01001549/* mandatory leaf */
1550static int
romane028ef92023-02-24 16:33:08 +01001551nc_server_config_local_address(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001552{
1553 struct nc_endpt *endpt;
1554 struct nc_bind *bind;
1555 int ret = 0;
1556
1557 (void) op;
1558
1559 assert(!strcmp(LYD_NAME(node), "local-address"));
1560
1561 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001562 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001563 ret = 1;
1564 goto cleanup;
1565 }
1566
roman6430c152023-10-12 11:28:47 +02001567 free(bind->address);
romanc1d2b092023-02-02 08:58:27 +01001568 bind->address = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001569 NC_CHECK_ERRMEM_GOTO(!bind->address, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01001570
1571 ret = nc_server_config_set_address_port(endpt, bind, lyd_get_value(node), 0);
1572 if (ret) {
1573 goto cleanup;
1574 }
1575 }
1576
1577cleanup:
1578 return ret;
1579}
1580
1581/* leaf with default value */
1582static int
romane028ef92023-02-24 16:33:08 +01001583nc_server_config_local_port(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001584{
1585 struct nc_endpt *endpt;
1586 struct nc_bind *bind;
1587 int ret = 0;
1588
1589 assert(!strcmp(LYD_NAME(node), "local-port"));
1590
1591 if (equal_parent_name(node, 4, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001592 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001593 ret = 1;
1594 goto cleanup;
1595 }
1596
1597 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001598 bind->port = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001599 } else {
1600 /* delete -> set to default */
1601 bind->port = 0;
1602 }
1603
1604 ret = nc_server_config_set_address_port(endpt, bind, NULL, bind->port);
1605 if (ret) {
1606 goto cleanup;
1607 }
1608 }
1609
1610cleanup:
1611 return ret;
1612}
1613
1614/* P container */
1615static int
romane028ef92023-02-24 16:33:08 +01001616nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001617{
roman5cbb6532023-06-22 12:53:17 +02001618 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001619 struct nc_endpt *endpt;
1620 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001621 struct nc_ch_endpt *ch_endpt;
romanba93eac2023-07-18 14:36:48 +02001622 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001623
1624 assert(!strcmp(LYD_NAME(node), "keepalives"));
1625
roman5cbb6532023-06-22 12:53:17 +02001626 if (is_listen(node) && equal_parent_name(node, 1, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001627 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001628 ret = 1;
1629 goto cleanup;
1630 }
1631
1632 if (op == NC_OP_CREATE) {
1633 endpt->ka.enabled = 1;
1634 } else {
1635 endpt->ka.enabled = 0;
1636 }
1637 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1638 if (ret) {
1639 goto cleanup;
1640 }
roman5cbb6532023-06-22 12:53:17 +02001641 } else if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001642 /* LOCK */
1643 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001644 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001645 return 1;
1646 }
1647
roman4cb8bb12023-06-29 09:16:46 +02001648 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001649 ret = 1;
1650 goto cleanup;
1651 }
1652
1653 if (op == NC_OP_CREATE) {
1654 ch_endpt->ka.enabled = 1;
1655 } else {
1656 ch_endpt->ka.enabled = 0;
1657 }
romanc1d2b092023-02-02 08:58:27 +01001658 }
1659
1660cleanup:
romanba93eac2023-07-18 14:36:48 +02001661 if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) {
1662 /* UNLOCK */
1663 nc_ch_client_unlock(ch_client);
1664 }
romanc1d2b092023-02-02 08:58:27 +01001665 return ret;
1666}
1667
1668/* mandatory leaf */
1669static int
romane028ef92023-02-24 16:33:08 +01001670nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001671{
roman5cbb6532023-06-22 12:53:17 +02001672 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001673 struct nc_endpt *endpt;
1674 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001675 struct nc_ch_endpt *ch_endpt;
romanba93eac2023-07-18 14:36:48 +02001676 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001677
1678 assert(!strcmp(LYD_NAME(node), "idle-time"));
1679
roman5cbb6532023-06-22 12:53:17 +02001680 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001681 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001682 ret = 1;
1683 goto cleanup;
1684 }
1685
1686 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001687 endpt->ka.idle_time = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001688 } else {
1689 endpt->ka.idle_time = 0;
1690 }
1691 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1692 if (ret) {
1693 goto cleanup;
1694 }
roman5cbb6532023-06-22 12:53:17 +02001695 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001696 /* LOCK */
1697 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001698 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001699 return 1;
1700 }
1701
roman4cb8bb12023-06-29 09:16:46 +02001702 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001703 ret = 1;
1704 goto cleanup;
1705 }
1706
1707 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001708 ch_endpt->ka.idle_time = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001709 } else {
1710 ch_endpt->ka.idle_time = 0;
1711 }
romanc1d2b092023-02-02 08:58:27 +01001712 }
1713
1714cleanup:
roman6430c152023-10-12 11:28:47 +02001715 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001716 /* UNLOCK */
1717 nc_ch_client_unlock(ch_client);
1718 }
romanc1d2b092023-02-02 08:58:27 +01001719 return ret;
1720}
1721
1722/* mandatory leaf */
1723static int
romane028ef92023-02-24 16:33:08 +01001724nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001725{
roman5cbb6532023-06-22 12:53:17 +02001726 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001727 struct nc_endpt *endpt;
1728 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001729 struct nc_ch_endpt *ch_endpt;
romanba93eac2023-07-18 14:36:48 +02001730 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001731
1732 assert(!strcmp(LYD_NAME(node), "max-probes"));
1733
roman5cbb6532023-06-22 12:53:17 +02001734 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001735 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001736 ret = 1;
1737 goto cleanup;
1738 }
1739
1740 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001741 endpt->ka.max_probes = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001742 } else {
1743 endpt->ka.max_probes = 0;
1744 }
1745 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1746 if (ret) {
1747 goto cleanup;
1748 }
roman5cbb6532023-06-22 12:53:17 +02001749 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001750 /* LOCK */
1751 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001752 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001753 return 1;
1754 }
1755
roman4cb8bb12023-06-29 09:16:46 +02001756 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001757 ret = 1;
1758 goto cleanup;
1759 }
1760
1761 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001762 ch_endpt->ka.max_probes = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001763 } else {
1764 ch_endpt->ka.max_probes = 0;
1765 }
romanc1d2b092023-02-02 08:58:27 +01001766 }
1767
1768cleanup:
roman6430c152023-10-12 11:28:47 +02001769 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001770 /* UNLOCK */
1771 nc_ch_client_unlock(ch_client);
1772 }
romanc1d2b092023-02-02 08:58:27 +01001773 return ret;
1774}
1775
1776/* mandatory leaf */
1777static int
romane028ef92023-02-24 16:33:08 +01001778nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001779{
roman5cbb6532023-06-22 12:53:17 +02001780 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001781 struct nc_endpt *endpt;
1782 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001783 struct nc_ch_endpt *ch_endpt;
romanba93eac2023-07-18 14:36:48 +02001784 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001785
1786 assert(!strcmp(LYD_NAME(node), "probe-interval"));
1787
roman5cbb6532023-06-22 12:53:17 +02001788 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001789 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001790 ret = 1;
1791 goto cleanup;
1792 }
1793
1794 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001795 endpt->ka.probe_interval = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001796 } else {
1797 endpt->ka.probe_interval = 0;
1798 }
1799 ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka);
1800 if (ret) {
1801 goto cleanup;
1802 }
roman5cbb6532023-06-22 12:53:17 +02001803 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001804 /* LOCK */
1805 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001806 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001807 return 1;
1808 }
1809
roman4cb8bb12023-06-29 09:16:46 +02001810 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001811 ret = 1;
1812 goto cleanup;
1813 }
1814
1815 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001816 ch_endpt->ka.probe_interval = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001817 } else {
1818 ch_endpt->ka.max_probes = 0;
1819 }
romanc1d2b092023-02-02 08:58:27 +01001820 }
1821
1822cleanup:
roman6430c152023-10-12 11:28:47 +02001823 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001824 /* UNLOCK */
1825 nc_ch_client_unlock(ch_client);
1826 }
romanc1d2b092023-02-02 08:58:27 +01001827 return ret;
1828}
1829
1830static int
roman874fed12023-05-25 10:20:01 +02001831nc_server_config_create_host_key(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01001832{
romanf02273a2023-05-25 09:44:11 +02001833 node = lyd_child(node);
1834 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01001835
romanf02273a2023-05-25 09:44:11 +02001836 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->hostkeys, sizeof *opts->hostkeys, &opts->hostkey_count);
romanc1d2b092023-02-02 08:58:27 +01001837}
1838
1839/* list */
1840static int
romane028ef92023-02-24 16:33:08 +01001841nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001842{
roman5cbb6532023-06-22 12:53:17 +02001843 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001844 struct nc_hostkey *hostkey;
roman4cb8bb12023-06-29 09:16:46 +02001845 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02001846 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001847
1848 assert(!strcmp(LYD_NAME(node), "host-key"));
1849
roman4cb8bb12023-06-29 09:16:46 +02001850 if (nc_server_config_get_ssh_opts(node, &opts)) {
1851 ret = 1;
1852 goto cleanup;
1853 }
romanc1d2b092023-02-02 08:58:27 +01001854
roman4cb8bb12023-06-29 09:16:46 +02001855 if (equal_parent_name(node, 1, "server-identity")) {
romanba93eac2023-07-18 14:36:48 +02001856 /* LOCK */
1857 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001858 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001859 return 1;
1860 }
1861
romanc1d2b092023-02-02 08:58:27 +01001862 if (op == NC_OP_CREATE) {
roman4cb8bb12023-06-29 09:16:46 +02001863 ret = nc_server_config_create_host_key(node, opts);
romanc1d2b092023-02-02 08:58:27 +01001864 if (ret) {
1865 goto cleanup;
1866 }
1867 } else if (op == NC_OP_DELETE) {
roman4cb8bb12023-06-29 09:16:46 +02001868 if (nc_server_config_get_hostkey(node, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001869 ret = 1;
1870 goto cleanup;
1871 }
roman4cb8bb12023-06-29 09:16:46 +02001872 nc_server_config_del_hostkey(opts, hostkey);
roman5cbb6532023-06-22 12:53:17 +02001873 }
romanc1d2b092023-02-02 08:58:27 +01001874 }
1875
1876cleanup:
romanba93eac2023-07-18 14:36:48 +02001877 if (is_ch(node) && equal_parent_name(node, 1, "server-identity")) {
1878 /* UNLOCK */
1879 nc_ch_client_unlock(ch_client);
1880 }
romanc1d2b092023-02-02 08:58:27 +01001881 return ret;
1882}
1883
1884/* mandatory leaf */
romane028ef92023-02-24 16:33:08 +01001885static int
1886nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001887{
roman3f9b65c2023-06-05 14:26:58 +02001888 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02001889 const char *format;
roman3f9b65c2023-06-05 14:26:58 +02001890 NC_PUBKEY_FORMAT pubkey_type;
roman8edee342023-03-31 13:25:48 +02001891 struct nc_public_key *pubkey;
romanc1d2b092023-02-02 08:58:27 +01001892 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02001893 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02001894 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01001895
1896 assert(!strcmp(LYD_NAME(node), "public-key-format"));
1897
1898 format = ((struct lyd_node_term *)node)->value.ident->name;
roman3f9b65c2023-06-05 14:26:58 +02001899 if (!strcmp(format, "ssh-public-key-format")) {
roman13145912023-08-17 15:36:54 +02001900 pubkey_type = NC_PUBKEY_FORMAT_SSH;
roman3f9b65c2023-06-05 14:26:58 +02001901 } else if (!strcmp(format, "subject-public-key-info-format")) {
1902 pubkey_type = NC_PUBKEY_FORMAT_X509;
1903 } else {
1904 ERR(NULL, "Public key format (%s) not supported.", format);
1905 ret = 1;
1906 goto cleanup;
1907 }
romanc1d2b092023-02-02 08:58:27 +01001908
romanba93eac2023-07-18 14:36:48 +02001909 /* LOCK */
1910 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001911 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001912 return 1;
1913 }
1914
roman4cb8bb12023-06-29 09:16:46 +02001915 if (is_ssh(node) && equal_parent_name(node, 4, "server-identity")) {
roman5cbb6532023-06-22 12:53:17 +02001916 /* SSH hostkey public key fmt */
roman4cb8bb12023-06-29 09:16:46 +02001917 if (nc_server_config_get_hostkey(node, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02001918 ret = 1;
1919 goto cleanup;
1920 }
1921
1922 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1923 hostkey->key.pubkey_type = pubkey_type;
1924 }
roman4cb8bb12023-06-29 09:16:46 +02001925 } else if (is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) {
roman5cbb6532023-06-22 12:53:17 +02001926 /* SSH client auth public key fmt */
roman4cb8bb12023-06-29 09:16:46 +02001927 if (nc_server_config_get_pubkey(node, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001928 ret = 1;
1929 goto cleanup;
1930 }
1931
1932 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman3f9b65c2023-06-05 14:26:58 +02001933 pubkey->type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001934 }
romanb6f44032023-06-30 15:07:56 +02001935 } else if (is_tls(node) && equal_parent_name(node, 3, "server-identity")) {
1936 /* TLS server-identity */
1937 if (nc_server_config_get_tls_opts(node, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02001938 ret = 1;
1939 goto cleanup;
1940 }
1941
roman5cbb6532023-06-22 12:53:17 +02001942 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02001943 opts->pubkey_type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001944 }
romanc1d2b092023-02-02 08:58:27 +01001945 }
1946
1947cleanup:
romanba93eac2023-07-18 14:36:48 +02001948 if (is_ch(node)) {
1949 /* UNLOCK */
1950 nc_ch_client_unlock(ch_client);
1951 }
romanc1d2b092023-02-02 08:58:27 +01001952 return ret;
1953}
1954
1955static int
roman58f79d02023-10-06 10:20:31 +02001956nc_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 +01001957{
romanc1d2b092023-02-02 08:58:27 +01001958 assert(!strcmp(LYD_NAME(node), "public-key"));
1959
romanc1d2b092023-02-02 08:58:27 +01001960 node = lyd_child(node);
1961 assert(!strcmp(LYD_NAME(node), "name"));
1962
romanf02273a2023-05-25 09:44:11 +02001963 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 +01001964}
1965
1966static int
roman874fed12023-05-25 10:20:01 +02001967nc_server_config_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +01001968{
roman6430c152023-10-12 11:28:47 +02001969 free(pubkey->data);
roman3f9b65c2023-06-05 14:26:58 +02001970 pubkey->data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001971 NC_CHECK_ERRMEM_RET(!pubkey->data, 1);
romanc1d2b092023-02-02 08:58:27 +01001972
1973 return 0;
1974}
1975
1976static int
roman874fed12023-05-25 10:20:01 +02001977nc_server_config_replace_host_key_public_key(const struct lyd_node *node, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +01001978{
roman6430c152023-10-12 11:28:47 +02001979 free(hostkey->key.pubkey_data);
roman3f9b65c2023-06-05 14:26:58 +02001980 hostkey->key.pubkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001981 NC_CHECK_ERRMEM_RET(!hostkey->key.pubkey_data, 1);
romanc1d2b092023-02-02 08:58:27 +01001982
1983 return 0;
1984}
1985
roman3f9b65c2023-06-05 14:26:58 +02001986static int
1987nc_server_config_tls_replace_server_public_key(const struct lyd_node *node, struct nc_server_tls_opts *opts)
1988{
roman6430c152023-10-12 11:28:47 +02001989 free(opts->pubkey_data);
roman3f9b65c2023-06-05 14:26:58 +02001990 opts->pubkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001991 NC_CHECK_ERRMEM_RET(!opts->pubkey_data, 1);
roman3f9b65c2023-06-05 14:26:58 +02001992
1993 return 0;
1994}
1995
romanc1d2b092023-02-02 08:58:27 +01001996static int
romane028ef92023-02-24 16:33:08 +01001997nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001998{
roman3f9b65c2023-06-05 14:26:58 +02001999 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002000 struct nc_hostkey *hostkey;
roman58f79d02023-10-06 10:20:31 +02002001 struct nc_auth_client *auth_client;
roman8edee342023-03-31 13:25:48 +02002002 struct nc_public_key *pubkey;
romanb6f44032023-06-30 15:07:56 +02002003 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002004 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002005
2006 assert(!strcmp(LYD_NAME(node), "public-key"));
2007
romanba93eac2023-07-18 14:36:48 +02002008 /* LOCK */
2009 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002010 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002011 return 1;
2012 }
2013
roman4cb8bb12023-06-29 09:16:46 +02002014 if (is_ssh(node) && equal_parent_name(node, 3, "host-key")) {
roman3f9b65c2023-06-05 14:26:58 +02002015 /* server's public-key, mandatory leaf */
roman4cb8bb12023-06-29 09:16:46 +02002016 if (nc_server_config_get_hostkey(node, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01002017 ret = 1;
2018 goto cleanup;
2019 }
2020
roman13145912023-08-17 15:36:54 +02002021 /* the public key must not be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
roman51a1e192023-09-14 10:13:45 +02002022 if (nc_is_pk_subject_public_key_info(lyd_get_value(node))) {
roman13145912023-08-17 15:36:54 +02002023 ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH hostkey is forbidden!");
2024 ret = 1;
2025 goto cleanup;
2026 }
2027
romanc1d2b092023-02-02 08:58:27 +01002028 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02002029 /* set to local */
roman874fed12023-05-25 10:20:01 +02002030 hostkey->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02002031
roman874fed12023-05-25 10:20:01 +02002032 ret = nc_server_config_replace_host_key_public_key(node, hostkey);
romanc1d2b092023-02-02 08:58:27 +01002033 if (ret) {
2034 goto cleanup;
2035 }
2036 }
roman4cb8bb12023-06-29 09:16:46 +02002037 } else if (is_ssh(node) && equal_parent_name(node, 5, "client-authentication")) {
romanc1d2b092023-02-02 08:58:27 +01002038 /* client auth pubkeys, list */
roman4cb8bb12023-06-29 09:16:46 +02002039 if (nc_server_config_get_auth_client(node, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002040 ret = 1;
2041 goto cleanup;
2042 }
2043
2044 if (op == NC_OP_CREATE) {
romanf02273a2023-05-25 09:44:11 +02002045 /* set to local */
roman874fed12023-05-25 10:20:01 +02002046 auth_client->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02002047
roman874fed12023-05-25 10:20:01 +02002048 ret = nc_server_config_create_auth_key_public_key_list(node, auth_client);
romanc1d2b092023-02-02 08:58:27 +01002049 if (ret) {
2050 goto cleanup;
2051 }
2052 } else if (op == NC_OP_DELETE) {
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
roman874fed12023-05-25 10:20:01 +02002058 nc_server_config_del_auth_client_pubkey(auth_client, pubkey);
romanc1d2b092023-02-02 08:58:27 +01002059 }
roman4cb8bb12023-06-29 09:16:46 +02002060 } else if (is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) {
romanc1d2b092023-02-02 08:58:27 +01002061 /* client auth pubkey, leaf */
roman4cb8bb12023-06-29 09:16:46 +02002062 if (nc_server_config_get_pubkey(node, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01002063 ret = 1;
2064 goto cleanup;
2065 }
2066
roman13145912023-08-17 15:36:54 +02002067 /* the public key must not be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
roman51a1e192023-09-14 10:13:45 +02002068 if (nc_is_pk_subject_public_key_info(lyd_get_value(node))) {
roman13145912023-08-17 15:36:54 +02002069 ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH user's key is forbidden!");
2070 ret = 1;
2071 goto cleanup;
2072 }
2073
romanc1d2b092023-02-02 08:58:27 +01002074 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02002075 ret = nc_server_config_replace_auth_key_public_key_leaf(node, pubkey);
romanc1d2b092023-02-02 08:58:27 +01002076 if (ret) {
2077 goto cleanup;
2078 }
roman6430c152023-10-12 11:28:47 +02002079 } else if (op == NC_OP_DELETE) {
2080 free(pubkey->data);
2081 pubkey->data = NULL;
romanc1d2b092023-02-02 08:58:27 +01002082 }
romanb6f44032023-06-30 15:07:56 +02002083 } else if (is_tls(node) && equal_parent_name(node, 3, "server-identity")) {
2084 /* TLS server-identity */
2085 if (nc_server_config_get_tls_opts(node, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002086 ret = 1;
2087 goto cleanup;
2088 }
2089
roman13145912023-08-17 15:36:54 +02002090 /* the public key must be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
roman51a1e192023-09-14 10:13:45 +02002091 if (!nc_is_pk_subject_public_key_info(lyd_get_value(node))) {
roman13145912023-08-17 15:36:54 +02002092 ERR(NULL, "TLS server certificate's Public Key must be in the SubjectPublicKeyInfo format!");
2093 ret = 1;
2094 goto cleanup;
2095 }
2096
roman3f9b65c2023-06-05 14:26:58 +02002097 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2098 /* set to local */
romanb6f44032023-06-30 15:07:56 +02002099 opts->store = NC_STORE_LOCAL;
roman3f9b65c2023-06-05 14:26:58 +02002100
romanb6f44032023-06-30 15:07:56 +02002101 ret = nc_server_config_tls_replace_server_public_key(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02002102 if (ret) {
2103 goto cleanup;
2104 }
2105 }
roman5cbb6532023-06-22 12:53:17 +02002106 }
2107
2108cleanup:
romanba93eac2023-07-18 14:36:48 +02002109 if (is_ch(node)) {
2110 /* UNLOCK */
2111 nc_ch_client_unlock(ch_client);
2112 }
roman5cbb6532023-06-22 12:53:17 +02002113 return ret;
2114}
2115
2116/* leaf */
2117static int
2118nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op)
2119{
2120 int ret = 0;
2121 const char *format;
2122 NC_PRIVKEY_FORMAT privkey_type;
roman5cbb6532023-06-22 12:53:17 +02002123 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02002124 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002125 struct nc_ch_client *ch_client;
roman5cbb6532023-06-22 12:53:17 +02002126
2127 (void) op;
2128
2129 assert(!strcmp(LYD_NAME(node), "private-key-format"));
2130
2131 format = ((struct lyd_node_term *)node)->value.ident->name;
2132 if (!format) {
2133 ret = 1;
2134 goto cleanup;
2135 }
2136
2137 privkey_type = nc_server_config_get_private_key_type(format);
2138 if (privkey_type == NC_PRIVKEY_FORMAT_UNKNOWN) {
2139 ERR(NULL, "Unknown private key format.");
2140 ret = 1;
2141 goto cleanup;
2142 }
2143
romanba93eac2023-07-18 14:36:48 +02002144 /* LOCK */
2145 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002146 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002147 return 1;
2148 }
2149
roman4cb8bb12023-06-29 09:16:46 +02002150 if (is_ssh(node)) {
2151 /* ssh */
2152 if (nc_server_config_get_hostkey(node, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02002153 ret = 1;
2154 goto cleanup;
2155 }
2156
2157 hostkey->key.privkey_type = privkey_type;
romanb6f44032023-06-30 15:07:56 +02002158 } else if (is_tls(node)) {
2159 /* tls */
2160 if (nc_server_config_get_tls_opts(node, &opts)) {
roman5cbb6532023-06-22 12:53:17 +02002161 ret = 1;
2162 goto cleanup;
2163 }
2164
romanb6f44032023-06-30 15:07:56 +02002165 opts->privkey_type = privkey_type;
roman5cbb6532023-06-22 12:53:17 +02002166 }
2167
2168cleanup:
romanba93eac2023-07-18 14:36:48 +02002169 if (is_ch(node)) {
2170 /* UNLOCK */
2171 nc_ch_client_unlock(ch_client);
2172 }
roman5cbb6532023-06-22 12:53:17 +02002173 return ret;
2174}
2175
2176static int
roman5cbb6532023-06-22 12:53:17 +02002177nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op)
2178{
2179 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02002180 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02002181 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002182 struct nc_ch_client *ch_client;
roman5cbb6532023-06-22 12:53:17 +02002183
2184 assert(!strcmp(LYD_NAME(node), "cleartext-private-key"));
2185
romanba93eac2023-07-18 14:36:48 +02002186 /* LOCK */
2187 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002188 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002189 return 1;
2190 }
2191
roman4cb8bb12023-06-29 09:16:46 +02002192 if (is_ssh(node)) {
2193 /* ssh */
2194 if (nc_server_config_get_hostkey(node, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02002195 ret = 1;
2196 goto cleanup;
2197 }
2198
2199 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002200 free(hostkey->key.privkey_data);
2201 hostkey->key.privkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002202 NC_CHECK_ERRMEM_GOTO(!hostkey->key.privkey_data, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02002203 } else {
roman6430c152023-10-12 11:28:47 +02002204 free(hostkey->key.privkey_data);
2205 hostkey->key.privkey_data = NULL;
roman5cbb6532023-06-22 12:53:17 +02002206 }
romanb6f44032023-06-30 15:07:56 +02002207 } else if (is_tls(node)) {
2208 /* tls */
2209 if (nc_server_config_get_tls_opts(node, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002210 ret = 1;
2211 goto cleanup;
2212 }
2213
roman5cbb6532023-06-22 12:53:17 +02002214 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002215 free(opts->privkey_data);
2216 opts->privkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002217 NC_CHECK_ERRMEM_GOTO(!opts->privkey_data, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02002218 } else {
roman6430c152023-10-12 11:28:47 +02002219 free(opts->privkey_data);
2220 opts->privkey_data = NULL;
roman5cbb6532023-06-22 12:53:17 +02002221 }
roman5cbb6532023-06-22 12:53:17 +02002222 }
2223
2224cleanup:
romanba93eac2023-07-18 14:36:48 +02002225 if (is_ch(node)) {
2226 /* UNLOCK */
2227 nc_ch_client_unlock(ch_client);
2228 }
roman5cbb6532023-06-22 12:53:17 +02002229 return ret;
2230}
2231
roman5cbb6532023-06-22 12:53:17 +02002232/* leaf */
2233static int
2234nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op)
2235{
2236 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02002237 struct nc_hostkey *hostkey;
romanba93eac2023-07-18 14:36:48 +02002238 struct nc_ch_client *ch_client;
roman5cbb6532023-06-22 12:53:17 +02002239
2240 assert(!strcmp(LYD_NAME(node), "keystore-reference"));
2241
romanba93eac2023-07-18 14:36:48 +02002242 /* LOCK */
2243 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002244 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002245 return 1;
2246 }
2247
roman4cb8bb12023-06-29 09:16:46 +02002248 if (is_ssh(node) && equal_parent_name(node, 3, "server-identity")) {
2249 if (nc_server_config_get_hostkey(node, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02002250 ret = 1;
2251 goto cleanup;
2252 }
2253
2254 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2255 /* set to keystore */
2256 hostkey->store = NC_STORE_KEYSTORE;
2257
roman6430c152023-10-12 11:28:47 +02002258 free(hostkey->ks_ref);
romandd019a92023-09-14 10:17:07 +02002259 hostkey->ks_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002260 NC_CHECK_ERRMEM_GOTO(!hostkey->ks_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002261 } else if (op == NC_OP_DELETE) {
2262 free(hostkey->ks_ref);
roman5cbb6532023-06-22 12:53:17 +02002263 hostkey->ks_ref = NULL;
2264 }
roman3f9b65c2023-06-05 14:26:58 +02002265 }
romanc1d2b092023-02-02 08:58:27 +01002266
2267cleanup:
romanba93eac2023-07-18 14:36:48 +02002268 if (is_ch(node)) {
2269 /* UNLOCK */
2270 nc_ch_client_unlock(ch_client);
2271 }
romanc1d2b092023-02-02 08:58:27 +01002272 return ret;
2273}
2274
2275static int
roman6430c152023-10-12 11:28:47 +02002276nc_server_config_create_auth_client(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01002277{
romanf02273a2023-05-25 09:44:11 +02002278 node = lyd_child(node);
2279 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01002280
romanf02273a2023-05-25 09:44:11 +02002281 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 +01002282}
2283
2284/* list */
2285static int
romane028ef92023-02-24 16:33:08 +01002286nc_server_config_user(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002287{
roman5cbb6532023-06-22 12:53:17 +02002288 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002289 struct nc_auth_client *auth_client;
roman4cb8bb12023-06-29 09:16:46 +02002290 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002291 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002292
2293 assert(!strcmp(LYD_NAME(node), "user"));
2294
romanba93eac2023-07-18 14:36:48 +02002295 /* LOCK */
2296 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002297 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002298 return 1;
2299 }
2300
roman4cb8bb12023-06-29 09:16:46 +02002301 if (nc_server_config_get_ssh_opts(node, &opts)) {
2302 ret = 1;
2303 goto cleanup;
2304 }
2305
2306 if (op == NC_OP_CREATE) {
roman6430c152023-10-12 11:28:47 +02002307 ret = nc_server_config_create_auth_client(node, opts);
roman4cb8bb12023-06-29 09:16:46 +02002308 if (ret) {
2309 goto cleanup;
2310 }
2311 } else if (op == NC_OP_DELETE) {
2312 if (nc_server_config_get_auth_client(node, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002313 ret = 1;
2314 goto cleanup;
2315 }
2316
roman4cb8bb12023-06-29 09:16:46 +02002317 nc_server_config_del_auth_client(opts, auth_client);
romanc1d2b092023-02-02 08:58:27 +01002318 }
2319
2320cleanup:
romanba93eac2023-07-18 14:36:48 +02002321 if (is_ch(node)) {
2322 /* UNLOCK */
2323 nc_ch_client_unlock(ch_client);
2324 }
romanc1d2b092023-02-02 08:58:27 +01002325 return ret;
2326}
2327
2328static int
romane028ef92023-02-24 16:33:08 +01002329nc_server_config_auth_attempts(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002330{
romanc1d2b092023-02-02 08:58:27 +01002331 int ret = 0;
roman4cb8bb12023-06-29 09:16:46 +02002332 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002333 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002334
2335 assert(!strcmp(LYD_NAME(node), "auth-attempts"));
2336
romanba93eac2023-07-18 14:36:48 +02002337 /* LOCK */
2338 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002339 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002340 return 1;
2341 }
2342
roman4cb8bb12023-06-29 09:16:46 +02002343 if (nc_server_config_get_ssh_opts(node, &opts)) {
2344 ret = 1;
2345 goto cleanup;
2346 }
romanc1d2b092023-02-02 08:58:27 +01002347
roman4cb8bb12023-06-29 09:16:46 +02002348 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02002349 opts->auth_attempts = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01002350 }
2351
2352cleanup:
romanba93eac2023-07-18 14:36:48 +02002353 if (is_ch(node)) {
2354 /* UNLOCK */
2355 nc_ch_client_unlock(ch_client);
2356 }
romanc1d2b092023-02-02 08:58:27 +01002357 return ret;
2358}
2359
2360static int
romane028ef92023-02-24 16:33:08 +01002361nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002362{
romanc1d2b092023-02-02 08:58:27 +01002363 int ret = 0;
roman4cb8bb12023-06-29 09:16:46 +02002364 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002365 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002366
2367 assert(!strcmp(LYD_NAME(node), "auth-timeout"));
2368
romanba93eac2023-07-18 14:36:48 +02002369 /* LOCK */
2370 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002371 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002372 return 1;
2373 }
2374
roman4cb8bb12023-06-29 09:16:46 +02002375 if (nc_server_config_get_ssh_opts(node, &opts)) {
2376 ret = 1;
2377 goto cleanup;
2378 }
romanc1d2b092023-02-02 08:58:27 +01002379
roman4cb8bb12023-06-29 09:16:46 +02002380 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02002381 opts->auth_timeout = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01002382 }
2383
2384cleanup:
romanba93eac2023-07-18 14:36:48 +02002385 if (is_ch(node)) {
2386 /* UNLOCK */
2387 nc_ch_client_unlock(ch_client);
2388 }
romanc1d2b092023-02-02 08:58:27 +01002389 return ret;
2390}
2391
romanc1d2b092023-02-02 08:58:27 +01002392/* leaf */
2393static int
romane028ef92023-02-24 16:33:08 +01002394nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002395{
romanc1d2b092023-02-02 08:58:27 +01002396 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002397 struct nc_auth_client *auth_client;
romanba93eac2023-07-18 14:36:48 +02002398 struct nc_ch_client *ch_client;
roman6430c152023-10-12 11:28:47 +02002399 struct nc_server_tls_opts *opts;
2400 struct nc_cert_grouping *certs_grp;
romanc1d2b092023-02-02 08:58:27 +01002401
2402 assert(!strcmp(LYD_NAME(node), "truststore-reference"));
2403
romanba93eac2023-07-18 14:36:48 +02002404 /* LOCK */
2405 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002406 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002407 return 1;
2408 }
2409
roman4cb8bb12023-06-29 09:16:46 +02002410 if (is_ssh(node) && equal_parent_name(node, 1, "public-keys")) {
2411 if (nc_server_config_get_auth_client(node, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002412 ret = 1;
2413 goto cleanup;
2414 }
2415
2416 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02002417 /* set to truststore */
roman874fed12023-05-25 10:20:01 +02002418 auth_client->store = NC_STORE_TRUSTSTORE;
romanf02273a2023-05-25 09:44:11 +02002419
roman6430c152023-10-12 11:28:47 +02002420 free(auth_client->ts_ref);
2421 auth_client->ts_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002422 NC_CHECK_ERRMEM_GOTO(!auth_client->ts_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002423 } else if (op == NC_OP_DELETE) {
2424 free(auth_client->ts_ref);
romand57b3722023-04-05 11:26:25 +02002425 auth_client->ts_ref = NULL;
romanc1d2b092023-02-02 08:58:27 +01002426 }
roman6430c152023-10-12 11:28:47 +02002427 } else if (is_tls(node) && (equal_parent_name(node, 1, "ca-certs") || equal_parent_name(node, 1, "ee-certs"))) {
2428 /* ee-certs or ca-certs */
2429 if (nc_server_config_get_tls_opts(node, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002430 ret = 1;
2431 goto cleanup;
2432 }
2433
roman6430c152023-10-12 11:28:47 +02002434 if (equal_parent_name(node, 1, "ca-certs")) {
2435 certs_grp = &opts->ca_certs;
roman3f9b65c2023-06-05 14:26:58 +02002436 } else {
roman6430c152023-10-12 11:28:47 +02002437 certs_grp = &opts->ee_certs;
roman4cb8bb12023-06-29 09:16:46 +02002438 }
2439
roman3f9b65c2023-06-05 14:26:58 +02002440 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2441 /* set to truststore */
roman6430c152023-10-12 11:28:47 +02002442 certs_grp->store = NC_STORE_TRUSTSTORE;
roman3f9b65c2023-06-05 14:26:58 +02002443
roman6430c152023-10-12 11:28:47 +02002444 free(certs_grp->ts_ref);
2445 certs_grp->ts_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002446 NC_CHECK_ERRMEM_GOTO(!certs_grp->ts_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002447 } else if (op == NC_OP_DELETE) {
2448 free(certs_grp->ts_ref);
2449 certs_grp->ts_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002450 }
2451 }
romanc1d2b092023-02-02 08:58:27 +01002452
2453cleanup:
romanba93eac2023-07-18 14:36:48 +02002454 if (is_ch(node)) {
2455 /* UNLOCK */
2456 nc_ch_client_unlock(ch_client);
2457 }
romanc1d2b092023-02-02 08:58:27 +01002458 return ret;
2459}
2460
romanc1d2b092023-02-02 08:58:27 +01002461/* leaf */
2462static int
romane028ef92023-02-24 16:33:08 +01002463nc_server_config_password(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002464{
roman5cbb6532023-06-22 12:53:17 +02002465 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002466 struct nc_auth_client *auth_client;
romanba93eac2023-07-18 14:36:48 +02002467 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002468
2469 assert(!strcmp(LYD_NAME(node), "password"));
2470
romanba93eac2023-07-18 14:36:48 +02002471 /* LOCK */
2472 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002473 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002474 return 1;
2475 }
2476
roman4cb8bb12023-06-29 09:16:46 +02002477 if (nc_server_config_get_auth_client(node, &auth_client)) {
2478 ret = 1;
2479 goto cleanup;
2480 }
2481
2482 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002483 free(auth_client->password);
2484 auth_client->password = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002485 NC_CHECK_ERRMEM_GOTO(!auth_client->password, ret = 1, cleanup);
roman4cb8bb12023-06-29 09:16:46 +02002486 } else {
roman6430c152023-10-12 11:28:47 +02002487 free(auth_client->password);
2488 auth_client->password = NULL;
romanc1d2b092023-02-02 08:58:27 +01002489 }
2490
2491cleanup:
romanba93eac2023-07-18 14:36:48 +02002492 if (is_ch(node)) {
2493 /* UNLOCK */
2494 nc_ch_client_unlock(ch_client);
2495 }
romanc1d2b092023-02-02 08:58:27 +01002496 return ret;
2497}
2498
2499static int
romane028ef92023-02-24 16:33:08 +01002500nc_server_config_pam_name(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002501{
roman5cbb6532023-06-22 12:53:17 +02002502 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002503 struct nc_auth_client *auth_client;
romanba93eac2023-07-18 14:36:48 +02002504 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002505
2506 assert(!strcmp(LYD_NAME(node), "pam-config-file-name"));
2507
romanba93eac2023-07-18 14:36:48 +02002508 /* LOCK */
2509 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002510 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002511 return 1;
2512 }
2513
roman4cb8bb12023-06-29 09:16:46 +02002514 if (nc_server_config_get_auth_client(node, &auth_client)) {
2515 ret = 1;
2516 goto cleanup;
2517 }
2518
2519 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002520 free(auth_client->pam_config_name);
roman4cb8bb12023-06-29 09:16:46 +02002521 auth_client->pam_config_name = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002522 NC_CHECK_ERRMEM_GOTO(!auth_client->pam_config_name, ret = 1, cleanup);
roman4cb8bb12023-06-29 09:16:46 +02002523 } else {
roman6430c152023-10-12 11:28:47 +02002524 free(auth_client->pam_config_name);
2525 auth_client->pam_config_name = NULL;
romanc1d2b092023-02-02 08:58:27 +01002526 }
2527
2528cleanup:
romanba93eac2023-07-18 14:36:48 +02002529 if (is_ch(node)) {
2530 /* UNLOCK */
2531 nc_ch_client_unlock(ch_client);
2532 }
romanc1d2b092023-02-02 08:58:27 +01002533 return ret;
2534}
2535
2536static int
romane028ef92023-02-24 16:33:08 +01002537nc_server_config_pam_dir(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002538{
roman5cbb6532023-06-22 12:53:17 +02002539 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002540 struct nc_auth_client *auth_client;
romanba93eac2023-07-18 14:36:48 +02002541 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002542
2543 assert(!strcmp(LYD_NAME(node), "pam-config-file-dir"));
2544
romanba93eac2023-07-18 14:36:48 +02002545 /* LOCK */
2546 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002547 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002548 return 1;
2549 }
2550
roman4cb8bb12023-06-29 09:16:46 +02002551 if (nc_server_config_get_auth_client(node, &auth_client)) {
2552 ret = 1;
2553 goto cleanup;
2554 }
2555
2556 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002557 free(auth_client->pam_config_dir);
roman4cb8bb12023-06-29 09:16:46 +02002558 auth_client->pam_config_dir = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002559 NC_CHECK_ERRMEM_GOTO(!auth_client->pam_config_dir, ret = 1, cleanup);
roman4cb8bb12023-06-29 09:16:46 +02002560 } else {
roman6430c152023-10-12 11:28:47 +02002561 free(auth_client->pam_config_dir);
2562 auth_client->pam_config_dir = NULL;
romanc1d2b092023-02-02 08:58:27 +01002563 }
2564
2565cleanup:
romanba93eac2023-07-18 14:36:48 +02002566 if (is_ch(node)) {
2567 /* UNLOCK */
2568 nc_ch_client_unlock(ch_client);
2569 }
romanc1d2b092023-02-02 08:58:27 +01002570 return ret;
2571}
2572
2573/* leaf */
2574static int
romane028ef92023-02-24 16:33:08 +01002575nc_server_config_none(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002576{
roman5cbb6532023-06-22 12:53:17 +02002577 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002578 struct nc_auth_client *auth_client;
romanba93eac2023-07-18 14:36:48 +02002579 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002580
2581 assert(!strcmp(LYD_NAME(node), "none"));
2582
romanba93eac2023-07-18 14:36:48 +02002583 /* LOCK */
2584 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002585 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002586 return 1;
2587 }
2588
roman4cb8bb12023-06-29 09:16:46 +02002589 if (nc_server_config_get_auth_client(node, &auth_client)) {
2590 ret = 1;
2591 goto cleanup;
2592 }
romanc1d2b092023-02-02 08:58:27 +01002593
roman4cb8bb12023-06-29 09:16:46 +02002594 if (op == NC_OP_CREATE) {
2595 auth_client->supports_none = 1;
2596 } else {
2597 auth_client->supports_none = 0;
romanc1d2b092023-02-02 08:58:27 +01002598 }
2599
2600cleanup:
romanba93eac2023-07-18 14:36:48 +02002601 if (is_ch(node)) {
2602 /* UNLOCK */
2603 nc_ch_client_unlock(ch_client);
2604 }
romanc1d2b092023-02-02 08:58:27 +01002605 return ret;
2606}
2607
2608static int
romanc135c6d2023-10-25 13:32:30 +02002609nc_server_config_delete_substring(const char *haystack, const char *needle, const char delim)
2610{
2611 size_t needle_len = strlen(needle);
2612 char *substr;
2613 int substr_found = 0, ret = 0;
2614
2615 while ((substr = strstr(haystack, needle))) {
2616 /* iterate over all the substrings */
2617 if (((substr == haystack) && (*(substr + needle_len) == delim)) ||
2618 ((substr != haystack) && (*(substr - 1) == delim) && (*(substr + needle_len) == delim))) {
2619 /* either the first element of the string or somewhere in the middle */
2620 memmove(substr, substr + needle_len + 1, strlen(substr + needle_len + 1));
2621 substr_found = 1;
2622 break;
2623 } else if ((*(substr - 1) == delim) && (*(substr + needle_len) == '\0')) {
2624 /* the last element of the string */
2625 *(substr - 1) = '\0';
2626 substr_found = 1;
2627 break;
2628 }
2629 haystack = substr + 1;
2630 }
2631 if (!substr_found) {
2632 ret = 1;
2633 }
2634
2635 return ret;
2636}
2637
2638static int
romana6bf6ab2023-05-26 13:26:02 +02002639nc_server_config_transport_params(const char *algorithm, char **alg_store, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002640{
romanc135c6d2023-10-25 13:32:30 +02002641 int ret = 0;
2642 char *alg = NULL;
romana6bf6ab2023-05-26 13:26:02 +02002643
2644 if (!strncmp(algorithm, "openssh-", 8)) {
2645 /* if the name starts with openssh, convert it to it's original libssh accepted form */
roman3a95bb22023-10-26 11:07:17 +02002646 ret = asprintf(&alg, "%s@openssh.com", algorithm + 8);
2647 NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; alg = NULL, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002648 } else if (!strncmp(algorithm, "libssh-", 7)) {
2649 /* if the name starts with libssh, convert it to it's original libssh accepted form */
roman3a95bb22023-10-26 11:07:17 +02002650 ret = asprintf(&alg, "%s@libssh.org", algorithm + 7);
2651 NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; alg = NULL, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002652 } else {
2653 alg = strdup(algorithm);
roman3a95bb22023-10-26 11:07:17 +02002654 NC_CHECK_ERRMEM_GOTO(!alg, ret = 1, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002655 }
2656
romanc1d2b092023-02-02 08:58:27 +01002657 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2658 if (!*alg_store) {
2659 /* first call */
2660 *alg_store = strdup(alg);
roman3a95bb22023-10-26 11:07:17 +02002661 NC_CHECK_ERRMEM_GOTO(!*alg_store, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01002662 } else {
2663 /* +1 because of ',' between algorithms */
roman3a95bb22023-10-26 11:07:17 +02002664 *alg_store = nc_realloc(*alg_store, strlen(*alg_store) + strlen(alg) + 1 + 1);
2665 NC_CHECK_ERRMEM_GOTO(!*alg_store, ret = 1, cleanup);
roman08f67f42023-06-08 13:51:54 +02002666 strcat(*alg_store, ",");
2667 strcat(*alg_store, alg);
romanc1d2b092023-02-02 08:58:27 +01002668 }
2669 } else {
2670 /* delete */
romanc135c6d2023-10-25 13:32:30 +02002671 ret = nc_server_config_delete_substring(*alg_store, alg, ',');
2672 if (ret) {
romanc1d2b092023-02-02 08:58:27 +01002673 ERR(NULL, "Unable to delete an algorithm (%s), which was not previously added.", alg);
romanc135c6d2023-10-25 13:32:30 +02002674 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002675 }
2676 }
2677
2678cleanup:
romana6bf6ab2023-05-26 13:26:02 +02002679 free(alg);
romanc1d2b092023-02-02 08:58:27 +01002680 return ret;
2681}
2682
2683/* leaf-list */
2684static int
romane028ef92023-02-24 16:33:08 +01002685nc_server_config_host_key_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002686{
roman5cbb6532023-06-22 12:53:17 +02002687 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002688 const char *alg;
2689 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002690 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002691 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002692
roman5cbb6532023-06-22 12:53:17 +02002693 assert(!strcmp(LYD_NAME(node), "host-key-alg"));
romanc1d2b092023-02-02 08:58:27 +01002694
romanba93eac2023-07-18 14:36:48 +02002695 /* LOCK */
2696 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002697 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002698 return 1;
2699 }
2700
roman4cb8bb12023-06-29 09:16:46 +02002701 if (nc_server_config_get_ssh_opts(node, &opts)) {
2702 ret = 1;
2703 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002704 }
2705
roman5cbb6532023-06-22 12:53:17 +02002706 /* get the algorithm name and compare it with algs supported by libssh */
2707 alg = ((struct lyd_node_term *)node)->value.ident->name;
romanc1d2b092023-02-02 08:58:27 +01002708 i = 0;
2709 while (supported_hostkey_algs[i]) {
2710 if (!strcmp(supported_hostkey_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002711 if (nc_server_config_transport_params(alg, &opts->hostkey_algs, op)) {
2712 ret = 1;
2713 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002714 }
2715 break;
2716 }
2717 i++;
2718 }
2719 if (!supported_hostkey_algs[i]) {
2720 /* algorithm not supported */
2721 ERR(NULL, "Public key algorithm (%s) not supported by libssh.", alg);
2722 ret = 1;
2723 }
2724
2725cleanup:
romanba93eac2023-07-18 14:36:48 +02002726 if (is_ch(node)) {
2727 /* UNLOCK */
2728 nc_ch_client_unlock(ch_client);
2729 }
romanc1d2b092023-02-02 08:58:27 +01002730 return ret;
2731}
2732
2733/* leaf-list */
2734static int
romane028ef92023-02-24 16:33:08 +01002735nc_server_config_kex_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002736{
roman5cbb6532023-06-22 12:53:17 +02002737 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002738 const char *alg;
2739 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002740 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002741 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002742
roman5cbb6532023-06-22 12:53:17 +02002743 assert(!strcmp(LYD_NAME(node), "key-exchange-alg"));
romanc1d2b092023-02-02 08:58:27 +01002744
romanba93eac2023-07-18 14:36:48 +02002745 /* LOCK */
2746 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002747 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002748 return 1;
2749 }
2750
roman4cb8bb12023-06-29 09:16:46 +02002751 if (nc_server_config_get_ssh_opts(node, &opts)) {
2752 ret = 1;
2753 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002754 }
2755
roman5cbb6532023-06-22 12:53:17 +02002756 /* get the algorithm name and compare it with algs supported by libssh */
2757 alg = ((struct lyd_node_term *)node)->value.ident->name;
romanc1d2b092023-02-02 08:58:27 +01002758 i = 0;
2759 while (supported_kex_algs[i]) {
2760 if (!strcmp(supported_kex_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002761 if (nc_server_config_transport_params(alg, &opts->kex_algs, op)) {
2762 ret = 1;
2763 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002764 }
2765 break;
2766 }
2767 i++;
2768 }
2769 if (!supported_kex_algs[i]) {
2770 /* algorithm not supported */
2771 ERR(NULL, "Key exchange algorithm (%s) not supported by libssh.", alg);
2772 ret = 1;
2773 }
2774
2775cleanup:
romanba93eac2023-07-18 14:36:48 +02002776 if (is_ch(node)) {
2777 /* UNLOCK */
2778 nc_ch_client_unlock(ch_client);
2779 }
romanc1d2b092023-02-02 08:58:27 +01002780 return ret;
2781}
2782
2783/* leaf-list */
2784static int
romane028ef92023-02-24 16:33:08 +01002785nc_server_config_encryption_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002786{
roman5cbb6532023-06-22 12:53:17 +02002787 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002788 const char *alg;
2789 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002790 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002791 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002792
roman5cbb6532023-06-22 12:53:17 +02002793 assert(!strcmp(LYD_NAME(node), "encryption-alg"));
romanc1d2b092023-02-02 08:58:27 +01002794
romanba93eac2023-07-18 14:36:48 +02002795 /* LOCK */
2796 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002797 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002798 return 1;
2799 }
2800
roman4cb8bb12023-06-29 09:16:46 +02002801 if (nc_server_config_get_ssh_opts(node, &opts)) {
2802 ret = 1;
2803 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002804 }
2805
roman5cbb6532023-06-22 12:53:17 +02002806 /* get the algorithm name and compare it with algs supported by libssh */
2807 alg = ((struct lyd_node_term *)node)->value.ident->name;
romanc1d2b092023-02-02 08:58:27 +01002808 i = 0;
2809 while (supported_encryption_algs[i]) {
2810 if (!strcmp(supported_encryption_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002811 if (nc_server_config_transport_params(alg, &opts->encryption_algs, op)) {
2812 ret = 1;
2813 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002814 }
2815 break;
2816 }
2817 i++;
2818 }
2819 if (!supported_encryption_algs[i]) {
2820 /* algorithm not supported */
2821 ERR(NULL, "Encryption algorithm (%s) not supported by libssh.", alg);
2822 ret = 1;
2823 }
2824
2825cleanup:
romanba93eac2023-07-18 14:36:48 +02002826 if (is_ch(node)) {
2827 /* UNLOCK */
2828 nc_ch_client_unlock(ch_client);
2829 }
romanc1d2b092023-02-02 08:58:27 +01002830 return ret;
2831}
2832
2833/* leaf-list */
2834static int
romane028ef92023-02-24 16:33:08 +01002835nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002836{
roman5cbb6532023-06-22 12:53:17 +02002837 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002838 const char *alg;
2839 uint8_t i;
roman5cbb6532023-06-22 12:53:17 +02002840 struct nc_server_ssh_opts *opts;
romanba93eac2023-07-18 14:36:48 +02002841 struct nc_ch_client *ch_client;
romanc1d2b092023-02-02 08:58:27 +01002842
roman5cbb6532023-06-22 12:53:17 +02002843 assert(!strcmp(LYD_NAME(node), "mac-alg"));
romanc1d2b092023-02-02 08:58:27 +01002844
romanba93eac2023-07-18 14:36:48 +02002845 /* LOCK */
2846 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002847 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002848 return 1;
2849 }
2850
roman4cb8bb12023-06-29 09:16:46 +02002851 if (nc_server_config_get_ssh_opts(node, &opts)) {
2852 ret = 1;
2853 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002854 }
2855
roman5cbb6532023-06-22 12:53:17 +02002856 /* get the algorithm name and compare it with algs supported by libssh */
2857 alg = ((struct lyd_node_term *)node)->value.ident->name;
romanc1d2b092023-02-02 08:58:27 +01002858 i = 0;
2859 while (supported_mac_algs[i]) {
2860 if (!strcmp(supported_mac_algs[i], alg)) {
roman5cbb6532023-06-22 12:53:17 +02002861 if (nc_server_config_transport_params(alg, &opts->mac_algs, op)) {
2862 ret = 1;
2863 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002864 }
2865 break;
2866 }
2867 i++;
2868 }
2869 if (!supported_mac_algs[i]) {
2870 /* algorithm not supported */
2871 ERR(NULL, "MAC algorithm (%s) not supported by libssh.", alg);
2872 ret = 1;
2873 }
2874
2875cleanup:
romanba93eac2023-07-18 14:36:48 +02002876 if (is_ch(node)) {
2877 /* UNLOCK */
2878 nc_ch_client_unlock(ch_client);
2879 }
romanc1d2b092023-02-02 08:58:27 +01002880 return ret;
2881}
2882
roman2eab4742023-06-06 10:00:26 +02002883#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02002884
romanc1d2b092023-02-02 08:58:27 +01002885static int
roman874fed12023-05-25 10:20:01 +02002886nc_server_config_create_unix_socket(struct nc_endpt *endpt)
roman83683fb2023-02-24 09:15:23 +01002887{
2888 endpt->ti = NC_TI_UNIX;
2889 endpt->opts.unixsock = calloc(1, sizeof *endpt->opts.unixsock);
roman3a95bb22023-10-26 11:07:17 +02002890 NC_CHECK_ERRMEM_RET(!endpt->opts.unixsock, 1);
roman83683fb2023-02-24 09:15:23 +01002891
2892 /* set default values */
2893 endpt->opts.unixsock->mode = -1;
2894 endpt->opts.unixsock->uid = -1;
2895 endpt->opts.unixsock->gid = -1;
2896
2897 return 0;
2898}
2899
2900static int
romane028ef92023-02-24 16:33:08 +01002901nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op)
roman83683fb2023-02-24 09:15:23 +01002902{
2903 int ret = 0;
roman84fe3252023-10-25 11:28:32 +02002904 uint32_t log_options = 0;
roman83683fb2023-02-24 09:15:23 +01002905 struct nc_endpt *endpt;
2906 struct nc_bind *bind;
2907 struct nc_server_unix_opts *opts;
2908 struct lyd_node *data = NULL;
2909
2910 assert(!strcmp(LYD_NAME(node), "unix-socket"));
2911
romanf02273a2023-05-25 09:44:11 +02002912 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
roman83683fb2023-02-24 09:15:23 +01002913 ret = 1;
2914 goto cleanup;
2915 }
2916
2917 if (op == NC_OP_CREATE) {
roman874fed12023-05-25 10:20:01 +02002918 if (nc_server_config_create_unix_socket(endpt)) {
roman83683fb2023-02-24 09:15:23 +01002919 ret = 1;
2920 goto cleanup;
2921 }
2922
2923 opts = endpt->opts.unixsock;
2924
2925 lyd_find_path(node, "path", 0, &data);
2926 assert(data);
2927
2928 opts->address = strdup(lyd_get_value(data));
2929 bind->address = strdup(lyd_get_value(data));
roman3a95bb22023-10-26 11:07:17 +02002930 NC_CHECK_ERRMEM_GOTO(!opts->address || !bind->address, ret = 1, cleanup);
roman83683fb2023-02-24 09:15:23 +01002931
2932 /* silently search for non-mandatory parameters */
roman84fe3252023-10-25 11:28:32 +02002933 ly_temp_log_options(&log_options);
roman83683fb2023-02-24 09:15:23 +01002934 ret = lyd_find_path(node, "mode", 0, &data);
2935 if (!ret) {
2936 opts->mode = strtol(lyd_get_value(data), NULL, 8);
2937 }
2938
2939 ret = lyd_find_path(node, "uid", 0, &data);
2940 if (!ret) {
2941 opts->uid = strtol(lyd_get_value(data), NULL, 10);
2942 }
2943
2944 ret = lyd_find_path(node, "gid", 0, &data);
2945 if (!ret) {
2946 opts->gid = strtol(lyd_get_value(data), NULL, 10);
2947 }
2948
2949 /* reset the logging options */
roman84fe3252023-10-25 11:28:32 +02002950 ly_temp_log_options(NULL);
roman83683fb2023-02-24 09:15:23 +01002951
2952 ret = nc_server_config_set_address_port(endpt, bind, NULL, 0);
2953 if (ret) {
2954 goto cleanup;
2955 }
2956 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02002957 nc_server_config_del_unix_socket_opts(bind, endpt->opts.unixsock);
roman83683fb2023-02-24 09:15:23 +01002958 }
2959
2960cleanup:
2961 return ret;
2962}
2963
roman2eab4742023-06-06 10:00:26 +02002964#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02002965
roman78df0fa2023-11-02 10:33:57 +01002966static int
2967nc_server_config_check_endpt_reference_cycle(struct nc_endpt *original, struct nc_endpt *next)
2968{
2969 if (!next->referenced_endpt_name) {
2970 /* no further reference -> no cycle */
2971 return 0;
2972 }
2973
2974 if (!strcmp(original->name, next->referenced_endpt_name)) {
2975 /* found cycle */
2976 return 1;
2977 } else {
2978 if (nc_server_get_referenced_endpt(next->referenced_endpt_name, &next)) {
2979 /* referenced endpoint does not exist */
2980 return 1;
2981 }
2982
2983 /* continue further */
2984 return nc_server_config_check_endpt_reference_cycle(original, next);
2985 }
2986}
2987
roman0bbc19c2023-05-26 09:59:09 +02002988/**
roman78df0fa2023-11-02 10:33:57 +01002989 * @brief Set all endpoint references.
roman0bbc19c2023-05-26 09:59:09 +02002990 *
2991 * @return 0 on success, 1 on error.
2992 */
2993static int
roman78df0fa2023-11-02 10:33:57 +01002994nc_server_config_check_endpt_references(void)
roman0bbc19c2023-05-26 09:59:09 +02002995{
2996 uint16_t i, j;
roman78df0fa2023-11-02 10:33:57 +01002997 struct nc_endpt *referenced_endpt = NULL;
roman0bbc19c2023-05-26 09:59:09 +02002998
roman78df0fa2023-11-02 10:33:57 +01002999 /* first do listen endpoints */
roman0bbc19c2023-05-26 09:59:09 +02003000 for (i = 0; i < server_opts.endpt_count; i++) {
roman6430c152023-10-12 11:28:47 +02003001 /* go through all the endpoints */
roman0bbc19c2023-05-26 09:59:09 +02003002 if (server_opts.endpts[i].referenced_endpt_name) {
roman78df0fa2023-11-02 10:33:57 +01003003 /* get referenced endpt */
3004 if (nc_server_get_referenced_endpt(server_opts.endpts[i].referenced_endpt_name, &referenced_endpt)) {
3005 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" does not exist.",
roman0bbc19c2023-05-26 09:59:09 +02003006 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
3007 return 1;
3008 }
roman78df0fa2023-11-02 10:33:57 +01003009
3010 /* check if the endpoint references itself */
3011 if (&server_opts.endpts[i] == referenced_endpt) {
3012 ERR(NULL, "Endpoint \"%s\" references itself.", server_opts.endpts[i].name);
3013 return 1;
3014 }
3015
3016 /* check transport */
3017 if ((server_opts.endpts[i].ti != referenced_endpt->ti)) {
3018 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" has different transport type.",
3019 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
3020 return 1;
3021 } else if ((referenced_endpt->ti != NC_TI_LIBSSH) && (referenced_endpt->ti != NC_TI_OPENSSL)) {
3022 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" has unsupported transport type.",
3023 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
3024 return 1;
3025 }
3026
3027 /* check cyclic reference */
3028 if (nc_server_config_check_endpt_reference_cycle(&server_opts.endpts[i], referenced_endpt)) {
3029 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" creates a cycle.",
3030 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
3031 return 1;
3032 }
3033
3034 /* all went well, assign the name to the opts, so we can access it for auth */
3035 if (server_opts.endpts[i].ti == NC_TI_LIBSSH) {
3036 server_opts.endpts[i].opts.ssh->referenced_endpt_name = referenced_endpt->name;
3037 } else {
3038 server_opts.endpts[i].opts.tls->referenced_endpt_name = referenced_endpt->name;
3039 }
roman0bbc19c2023-05-26 09:59:09 +02003040 }
3041 }
3042
roman78df0fa2023-11-02 10:33:57 +01003043 /* now check all the call home endpoints */
3044 /* LOCK */
3045 pthread_rwlock_rdlock(&server_opts.ch_client_lock);
3046 for (i = 0; i < server_opts.ch_client_count; i++) {
3047 /* LOCK */
3048 pthread_mutex_lock(&server_opts.ch_clients[i].lock);
3049 for (j = 0; j < server_opts.ch_clients[i].ch_endpt_count; j++) {
3050 if (server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name) {
3051 /* get referenced endpt */
3052 if (nc_server_get_referenced_endpt(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, &referenced_endpt)) {
3053 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" does not exist.",
3054 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
3055 goto ch_fail;
3056 }
3057
3058 /* check transport */
3059 if (server_opts.ch_clients[i].ch_endpts[j].ti != referenced_endpt->ti) {
3060 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" has different transport type.",
3061 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
3062 goto ch_fail;
3063 } else if ((referenced_endpt->ti != NC_TI_LIBSSH) && (referenced_endpt->ti != NC_TI_OPENSSL)) {
3064 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" has unsupported transport type.",
3065 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
3066 goto ch_fail;
3067 }
3068
3069 /* check cyclic reference */
3070 if (nc_server_config_check_endpt_reference_cycle(referenced_endpt, referenced_endpt)) {
3071 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" creates a cycle.",
3072 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
3073 goto ch_fail;
3074 }
3075
3076 /* all went well, assign the name to the opts, so we can access it for auth */
3077 if (server_opts.ch_clients[i].ch_endpts[j].ti == NC_TI_LIBSSH) {
3078 server_opts.ch_clients[i].ch_endpts[j].opts.ssh->referenced_endpt_name = referenced_endpt->name;
3079 } else {
3080 server_opts.ch_clients[i].ch_endpts[j].opts.tls->referenced_endpt_name = referenced_endpt->name;
3081 }
3082 }
3083 }
3084 /* UNLOCK */
3085 pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
3086 }
3087
3088 /* UNLOCK */
3089 pthread_rwlock_unlock(&server_opts.ch_client_lock);
roman0bbc19c2023-05-26 09:59:09 +02003090 return 0;
roman78df0fa2023-11-02 10:33:57 +01003091
3092ch_fail:
3093 /* UNLOCK */
3094 pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
3095 /* UNLOCK */
3096 pthread_rwlock_unlock(&server_opts.ch_client_lock);
roman96c27f92023-11-02 11:09:46 +01003097 return 1;
roman0bbc19c2023-05-26 09:59:09 +02003098}
3099
3100static int
roman78df0fa2023-11-02 10:33:57 +01003101nc_server_config_endpoint_reference(const struct lyd_node *node, NC_OPERATION op)
roman0bbc19c2023-05-26 09:59:09 +02003102{
3103 int ret = 0;
roman78df0fa2023-11-02 10:33:57 +01003104 struct nc_endpt *endpt = NULL;
3105 struct nc_ch_client *ch_client;
3106 struct nc_ch_endpt *ch_endpt = NULL;
3107 struct nc_server_ssh_opts *ssh = NULL;
3108 struct nc_server_tls_opts *tls = NULL;
roman0bbc19c2023-05-26 09:59:09 +02003109
roman78df0fa2023-11-02 10:33:57 +01003110 assert(!strcmp(LYD_NAME(node), "endpoint-reference"));
roman0bbc19c2023-05-26 09:59:09 +02003111
roman78df0fa2023-11-02 10:33:57 +01003112 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
3113 /* to avoid unlock on fail */
3114 return 1;
3115 }
3116
3117 /* get endpt */
3118 if (is_listen(node)) {
3119 ret = nc_server_config_get_endpt(node, &endpt, NULL);
3120 } else {
3121 ret = nc_server_config_get_ch_endpt(node, &ch_endpt);
3122 }
roman0bbc19c2023-05-26 09:59:09 +02003123 if (ret) {
3124 goto cleanup;
3125 }
3126
3127 if (op == NC_OP_DELETE) {
roman78df0fa2023-11-02 10:33:57 +01003128 if (endpt) {
3129 free(endpt->referenced_endpt_name);
3130 endpt->referenced_endpt_name = NULL;
roman2e797ef2023-06-19 10:47:49 +02003131 } else {
roman78df0fa2023-11-02 10:33:57 +01003132 free(ch_endpt->referenced_endpt_name);
3133 ch_endpt->referenced_endpt_name = NULL;
roman2e797ef2023-06-19 10:47:49 +02003134 }
roman78df0fa2023-11-02 10:33:57 +01003135 if (is_ssh(node)) {
3136 if (nc_server_config_get_ssh_opts(node, &ssh)) {
3137 ret = 1;
3138 goto cleanup;
3139 }
roman96c27f92023-11-02 11:09:46 +01003140
roman78df0fa2023-11-02 10:33:57 +01003141 ssh->referenced_endpt_name = NULL;
3142 } else {
3143 if (nc_server_config_get_tls_opts(node, &tls)) {
3144 ret = 1;
3145 goto cleanup;
3146 }
roman0bbc19c2023-05-26 09:59:09 +02003147
roman78df0fa2023-11-02 10:33:57 +01003148 tls->referenced_endpt_name = NULL;
roman0bbc19c2023-05-26 09:59:09 +02003149 }
roman0bbc19c2023-05-26 09:59:09 +02003150
roman0bbc19c2023-05-26 09:59:09 +02003151 goto cleanup;
roman2e797ef2023-06-19 10:47:49 +02003152 } else {
roman78df0fa2023-11-02 10:33:57 +01003153 /* just set the name, check it once configuring of all nodes is done */
3154 if (endpt) {
3155 free(endpt->referenced_endpt_name);
3156 endpt->referenced_endpt_name = strdup(lyd_get_value(node));
3157 NC_CHECK_ERRMEM_GOTO(!endpt->referenced_endpt_name, ret = 1, cleanup);
3158 } else {
3159 free(ch_endpt->referenced_endpt_name);
3160 ch_endpt->referenced_endpt_name = strdup(lyd_get_value(node));
3161 NC_CHECK_ERRMEM_GOTO(!ch_endpt->referenced_endpt_name, ret = 1, cleanup);
3162 }
3163
3164 goto cleanup;
roman2e797ef2023-06-19 10:47:49 +02003165 }
roman0bbc19c2023-05-26 09:59:09 +02003166
3167cleanup:
roman78df0fa2023-11-02 10:33:57 +01003168 if (is_ch(node)) {
3169 /* UNLOCK */
3170 nc_ch_client_unlock(ch_client);
3171 }
3172
roman0bbc19c2023-05-26 09:59:09 +02003173 return ret;
3174}
3175
roman3f9b65c2023-06-05 14:26:58 +02003176static int
roman3f9b65c2023-06-05 14:26:58 +02003177nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op)
3178{
3179 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02003180 struct nc_certificate *cert;
romanb6f44032023-06-30 15:07:56 +02003181 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02003182 struct nc_ch_client *ch_client;
roman3f9b65c2023-06-05 14:26:58 +02003183
3184 assert(!strcmp(LYD_NAME(node), "cert-data"));
3185
romanba93eac2023-07-18 14:36:48 +02003186 /* LOCK */
3187 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003188 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003189 return 1;
3190 }
3191
romanb6f44032023-06-30 15:07:56 +02003192 if (equal_parent_name(node, 3, "server-identity")) {
3193 if (nc_server_config_get_tls_opts(node, &opts)) {
3194 ret = 1;
3195 goto cleanup;
3196 }
roman3f9b65c2023-06-05 14:26:58 +02003197
roman3f9b65c2023-06-05 14:26:58 +02003198 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003199 free(opts->cert_data);
3200 opts->cert_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003201 NC_CHECK_ERRMEM_GOTO(!opts->cert_data, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003202 }
roman6430c152023-10-12 11:28:47 +02003203 } else if (equal_parent_name(node, 3, "ca-certs") || equal_parent_name(node, 3, "ee-certs")) {
3204 if (nc_server_config_get_cert(node, &cert)) {
roman3f9b65c2023-06-05 14:26:58 +02003205 ret = 1;
3206 goto cleanup;
3207 }
3208
3209 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003210 free(cert->data);
3211 cert->data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003212 NC_CHECK_ERRMEM_GOTO(!cert->data, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003213 } else {
roman6430c152023-10-12 11:28:47 +02003214 free(cert->data);
3215 cert->data = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003216 }
3217 }
3218
3219cleanup:
romanba93eac2023-07-18 14:36:48 +02003220 if (is_ch(node)) {
3221 /* UNLOCK */
3222 nc_ch_client_unlock(ch_client);
3223 }
roman3f9b65c2023-06-05 14:26:58 +02003224 return ret;
3225}
3226
3227static int
roman3f9b65c2023-06-05 14:26:58 +02003228nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op)
3229{
3230 int ret = 0;
roman78df0fa2023-11-02 10:33:57 +01003231 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02003232 struct nc_ch_client *ch_client;
roman3f9b65c2023-06-05 14:26:58 +02003233
3234 assert(!strcmp(LYD_NAME(node), "asymmetric-key"));
3235
romanba93eac2023-07-18 14:36:48 +02003236 /* LOCK */
3237 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003238 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003239 return 1;
3240 }
3241
roman78df0fa2023-11-02 10:33:57 +01003242 if (nc_server_config_get_tls_opts(node, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02003243 ret = 1;
3244 goto cleanup;
3245 }
3246
3247 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
3248 /* set to keystore */
roman78df0fa2023-11-02 10:33:57 +01003249 opts->store = NC_STORE_KEYSTORE;
roman3f9b65c2023-06-05 14:26:58 +02003250
roman78df0fa2023-11-02 10:33:57 +01003251 free(opts->key_ref);
3252 opts->key_ref = strdup(lyd_get_value(node));
3253 NC_CHECK_ERRMEM_GOTO(!opts->key_ref, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003254 } else {
roman78df0fa2023-11-02 10:33:57 +01003255 free(opts->key_ref);
3256 opts->key_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003257 }
3258
3259cleanup:
romanba93eac2023-07-18 14:36:48 +02003260 if (is_ch(node)) {
3261 /* UNLOCK */
3262 nc_ch_client_unlock(ch_client);
3263 }
roman3f9b65c2023-06-05 14:26:58 +02003264 return ret;
3265}
3266
3267static int
roman3f9b65c2023-06-05 14:26:58 +02003268nc_server_config_create_ca_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
3269{
3270 assert(!strcmp(LYD_NAME(node), "certificate"));
3271
3272 node = lyd_child(node);
3273 assert(!strcmp(LYD_NAME(node), "name"));
3274
3275 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ca_certs.certs, sizeof *opts->ca_certs.certs, &opts->ca_certs.cert_count);
3276}
3277
3278static int
3279nc_server_config_create_ee_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
3280{
3281 assert(!strcmp(LYD_NAME(node), "certificate"));
3282
3283 node = lyd_child(node);
3284 assert(!strcmp(LYD_NAME(node), "name"));
3285
3286 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ee_certs.certs, sizeof *opts->ee_certs.certs, &opts->ee_certs.cert_count);
3287}
3288
3289static int
3290nc_server_config_certificate(const struct lyd_node *node, NC_OPERATION op)
3291{
3292 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003293 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02003294 struct nc_ch_client *ch_client;
roman6430c152023-10-12 11:28:47 +02003295 struct nc_certificate *cert;
roman3f9b65c2023-06-05 14:26:58 +02003296
3297 assert(!strcmp(LYD_NAME(node), "certificate"));
3298
romanba93eac2023-07-18 14:36:48 +02003299 /* LOCK */
3300 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003301 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003302 return 1;
3303 }
3304
romanb6f44032023-06-30 15:07:56 +02003305 if (nc_server_config_get_tls_opts(node, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02003306 ret = 1;
3307 goto cleanup;
3308 }
3309
romanb6f44032023-06-30 15:07:56 +02003310 if (equal_parent_name(node, 1, "keystore-reference")) {
3311 /* TLS server-identity */
roman3f9b65c2023-06-05 14:26:58 +02003312 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
3313 /* set to keystore */
romanb6f44032023-06-30 15:07:56 +02003314 opts->store = NC_STORE_KEYSTORE;
roman3f9b65c2023-06-05 14:26:58 +02003315
roman6430c152023-10-12 11:28:47 +02003316 free(opts->cert_ref);
3317 opts->cert_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003318 NC_CHECK_ERRMEM_GOTO(!opts->cert_ref, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003319 } else {
roman6430c152023-10-12 11:28:47 +02003320 free(opts->cert_ref);
romanb6f44032023-06-30 15:07:56 +02003321 opts->cert_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003322 }
romanb6f44032023-06-30 15:07:56 +02003323 } else if (equal_parent_name(node, 2, "ca-certs")) {
3324 /* TLS client auth certificate authority */
roman3f9b65c2023-06-05 14:26:58 +02003325 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003326 ret = nc_server_config_create_ca_certs_certificate(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02003327 if (ret) {
3328 goto cleanup;
3329 }
3330 } else {
roman6430c152023-10-12 11:28:47 +02003331 if (nc_server_config_get_cert(node, &cert)) {
3332 ret = 1;
3333 goto cleanup;
3334 }
3335 nc_server_config_del_cert(&opts->ca_certs, cert);
roman3f9b65c2023-06-05 14:26:58 +02003336 }
romanb6f44032023-06-30 15:07:56 +02003337 } else if (equal_parent_name(node, 2, "ee-certs")) {
3338 /* TLS client auth end entity */
roman3f9b65c2023-06-05 14:26:58 +02003339 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003340 ret = nc_server_config_create_ee_certs_certificate(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02003341 if (ret) {
3342 goto cleanup;
3343 }
3344 } else {
roman6430c152023-10-12 11:28:47 +02003345 if (nc_server_config_get_cert(node, &cert)) {
3346 ret = 1;
3347 goto cleanup;
3348 }
3349 nc_server_config_del_cert(&opts->ee_certs, cert);
roman3f9b65c2023-06-05 14:26:58 +02003350 }
3351 }
3352
3353cleanup:
romanba93eac2023-07-18 14:36:48 +02003354 if (is_ch(node)) {
3355 /* UNLOCK */
3356 nc_ch_client_unlock(ch_client);
3357 }
roman3f9b65c2023-06-05 14:26:58 +02003358 return ret;
3359}
3360
3361static int
3362nc_server_config_create_cert_to_name(const struct lyd_node *node, struct nc_server_tls_opts *opts)
3363{
3364 int ret = 0;
3365 struct lyd_node *n;
3366 struct nc_ctn *new, *iter;
3367 const char *map_type, *name;
3368 uint32_t id;
3369 NC_TLS_CTN_MAPTYPE m_type;
3370
3371 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
3372
roman3f9b65c2023-06-05 14:26:58 +02003373 /* get all the data */
3374 /* find the list's key */
3375 lyd_find_path(node, "id", 0, &n);
3376 assert(n);
roman9cdb7b52023-10-25 13:59:55 +02003377 id = ((struct lyd_node_term *)n)->value.uint32;
roman3f9b65c2023-06-05 14:26:58 +02003378
3379 /* find the ctn's name */
3380 lyd_find_path(node, "name", 0, &n);
3381 assert(n);
3382 name = lyd_get_value(n);
3383
3384 /* find the ctn's map-type */
3385 lyd_find_path(node, "map-type", 0, &n);
3386 assert(n);
3387 map_type = ((struct lyd_node_term *)n)->value.ident->name;
3388 if (!strcmp(map_type, "specified")) {
3389 m_type = NC_TLS_CTN_SPECIFIED;
3390 } else if (!strcmp(map_type, "san-rfc822-name")) {
3391 m_type = NC_TLS_CTN_SAN_RFC822_NAME;
3392 } else if (!strcmp(map_type, "san-dns-name")) {
3393 m_type = NC_TLS_CTN_SAN_DNS_NAME;
3394 } else if (!strcmp(map_type, "san-ip-address")) {
3395 m_type = NC_TLS_CTN_SAN_IP_ADDRESS;
3396 } else if (!strcmp(map_type, "san-any")) {
3397 m_type = NC_TLS_CTN_SAN_ANY;
3398 } else if (!strcmp(map_type, "common-name")) {
3399 m_type = NC_TLS_CTN_COMMON_NAME;
3400 } else {
3401 ERR(NULL, "Map-type identity \"%s\" not supported.", map_type);
3402 ret = 1;
3403 goto cleanup;
3404 }
3405
roman6430c152023-10-12 11:28:47 +02003406 /* create new ctn */
3407 new = calloc(1, sizeof *new);
roman3a95bb22023-10-26 11:07:17 +02003408 NC_CHECK_ERRMEM_GOTO(!new, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02003409
roman3f9b65c2023-06-05 14:26:58 +02003410 /* find the right place for insertion */
3411 if (!opts->ctn) {
3412 /* inserting the first one */
3413 opts->ctn = new;
Roytak421eb0c2023-08-01 22:18:27 +02003414 } else if (opts->ctn->id > id) {
roman3f9b65c2023-06-05 14:26:58 +02003415 /* insert at the beginning */
3416 new->next = opts->ctn;
3417 opts->ctn = new;
3418 } else {
3419 /* have to find the right place */
Roytak421eb0c2023-08-01 22:18:27 +02003420 for (iter = opts->ctn; iter->next && iter->next->id <= id; iter = iter->next) {}
3421 if (iter->id == id) {
roman3f9b65c2023-06-05 14:26:58 +02003422 /* collision */
3423 new = iter;
3424 } else {
3425 new->next = iter->next;
3426 iter->next = new;
3427 }
3428 }
3429
3430 /* insert the right data */
3431 new->id = id;
roman6430c152023-10-12 11:28:47 +02003432 free(new->name);
roman3f9b65c2023-06-05 14:26:58 +02003433 new->name = strdup(name);
roman3a95bb22023-10-26 11:07:17 +02003434 NC_CHECK_ERRMEM_GOTO(!new->name, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003435 new->map_type = m_type;
3436
3437cleanup:
3438 return ret;
3439}
3440
3441static int
3442nc_server_config_cert_to_name(const struct lyd_node *node, NC_OPERATION op)
3443{
3444 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003445 struct nc_server_tls_opts *opts;
roman3f9b65c2023-06-05 14:26:58 +02003446 struct nc_ctn *ctn;
romanba93eac2023-07-18 14:36:48 +02003447 struct nc_ch_client *ch_client;
roman3f9b65c2023-06-05 14:26:58 +02003448
3449 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
3450
romanba93eac2023-07-18 14:36:48 +02003451 /* LOCK */
3452 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003453 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003454 return 1;
3455 }
3456
romanb6f44032023-06-30 15:07:56 +02003457 if (nc_server_config_get_tls_opts(node, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02003458 ret = 1;
3459 goto cleanup;
3460 }
3461
3462 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003463 ret = nc_server_config_create_cert_to_name(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02003464 if (ret) {
3465 goto cleanup;
3466 }
3467 } else {
3468 /* find the given ctn entry */
roman4cb8bb12023-06-29 09:16:46 +02003469 if (nc_server_config_get_ctn(node, &ctn)) {
roman3f9b65c2023-06-05 14:26:58 +02003470 ret = 1;
3471 goto cleanup;
3472 }
romanb6f44032023-06-30 15:07:56 +02003473 nc_server_config_del_ctn(opts, ctn);
roman3f9b65c2023-06-05 14:26:58 +02003474 }
3475
3476cleanup:
romanba93eac2023-07-18 14:36:48 +02003477 if (is_ch(node)) {
3478 /* UNLOCK */
3479 nc_ch_client_unlock(ch_client);
3480 }
roman3f9b65c2023-06-05 14:26:58 +02003481 return ret;
3482}
3483
3484static int
roman3f9b65c2023-06-05 14:26:58 +02003485nc_server_config_fingerprint(const struct lyd_node *node, NC_OPERATION op)
3486{
3487 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02003488 struct nc_ctn *ctn;
romanba93eac2023-07-18 14:36:48 +02003489 struct nc_ch_client *ch_client;
3490
3491 assert(!strcmp(LYD_NAME(node), "fingerprint"));
3492
3493 /* LOCK */
3494 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003495 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003496 return 1;
3497 }
roman3f9b65c2023-06-05 14:26:58 +02003498
roman4cb8bb12023-06-29 09:16:46 +02003499 if (nc_server_config_get_ctn(node, &ctn)) {
roman3f9b65c2023-06-05 14:26:58 +02003500 ret = 1;
3501 goto cleanup;
3502 }
3503
3504 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003505 free(ctn->fingerprint);
3506 ctn->fingerprint = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003507 NC_CHECK_ERRMEM_GOTO(!ctn->fingerprint, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003508 } else {
roman6430c152023-10-12 11:28:47 +02003509 free(ctn->fingerprint);
3510 ctn->fingerprint = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003511 }
3512
3513cleanup:
romanba93eac2023-07-18 14:36:48 +02003514 if (is_ch(node)) {
3515 /* UNLOCK */
3516 nc_ch_client_unlock(ch_client);
3517 }
roman3f9b65c2023-06-05 14:26:58 +02003518 return ret;
3519}
3520
roman12644fe2023-06-08 11:06:42 +02003521static int
3522nc_server_config_tls_version(const struct lyd_node *node, NC_OPERATION op)
3523{
3524 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003525 struct nc_server_tls_opts *opts;
roman12644fe2023-06-08 11:06:42 +02003526 const char *version = NULL;
romanba93eac2023-07-18 14:36:48 +02003527 struct nc_ch_client *ch_client;
roman6430c152023-10-12 11:28:47 +02003528 NC_TLS_VERSION tls_version;
roman12644fe2023-06-08 11:06:42 +02003529
3530 assert(!strcmp(LYD_NAME(node), "tls-version"));
3531
romanba93eac2023-07-18 14:36:48 +02003532 /* LOCK */
3533 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003534 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003535 return 1;
3536 }
3537
romanb6f44032023-06-30 15:07:56 +02003538 if (nc_server_config_get_tls_opts(node, &opts)) {
roman12644fe2023-06-08 11:06:42 +02003539 ret = 1;
3540 goto cleanup;
3541 }
3542
roman6430c152023-10-12 11:28:47 +02003543 /* str to tls_version */
roman12644fe2023-06-08 11:06:42 +02003544 version = ((struct lyd_node_term *)node)->value.ident->name;
3545 if (!strcmp(version, "tls10")) {
roman6430c152023-10-12 11:28:47 +02003546 tls_version = NC_TLS_VERSION_10;
roman12644fe2023-06-08 11:06:42 +02003547 } else if (!strcmp(version, "tls11")) {
roman6430c152023-10-12 11:28:47 +02003548 tls_version = NC_TLS_VERSION_11;
roman12644fe2023-06-08 11:06:42 +02003549 } else if (!strcmp(version, "tls12")) {
roman6430c152023-10-12 11:28:47 +02003550 tls_version = NC_TLS_VERSION_12;
roman12644fe2023-06-08 11:06:42 +02003551 } else if (!strcmp(version, "tls13")) {
roman6430c152023-10-12 11:28:47 +02003552 tls_version = NC_TLS_VERSION_13;
roman12644fe2023-06-08 11:06:42 +02003553 } else {
3554 ERR(NULL, "TLS version \"%s\" not supported.", version);
3555 ret = 1;
3556 goto cleanup;
3557 }
3558
roman6430c152023-10-12 11:28:47 +02003559 if (op == NC_OP_CREATE) {
3560 /* add the version if it isn't there already */
3561 opts->tls_versions |= tls_version;
3562 } else if ((op == NC_OP_DELETE) && (opts->tls_versions & tls_version)) {
3563 /* delete the version if it is there */
roman84fe3252023-10-25 11:28:32 +02003564 opts->tls_versions &= ~tls_version;
roman6430c152023-10-12 11:28:47 +02003565 }
3566
roman12644fe2023-06-08 11:06:42 +02003567cleanup:
romanba93eac2023-07-18 14:36:48 +02003568 if (is_ch(node)) {
3569 /* UNLOCK */
3570 nc_ch_client_unlock(ch_client);
3571 }
roman12644fe2023-06-08 11:06:42 +02003572 return ret;
3573}
3574
3575static int
3576nc_server_config_create_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher)
3577{
3578 int ret = 0;
3579 char *ssl_cipher = NULL;
3580 uint16_t i;
roman6430c152023-10-12 11:28:47 +02003581 void *tmp;
roman12644fe2023-06-08 11:06:42 +02003582
3583 ssl_cipher = malloc(strlen(cipher) + 1);
roman3a95bb22023-10-26 11:07:17 +02003584 NC_CHECK_ERRMEM_GOTO(!ssl_cipher, ret = 1, cleanup);
roman12644fe2023-06-08 11:06:42 +02003585
3586 for (i = 0; cipher[i]; i++) {
3587 if (cipher[i] == '-') {
3588 /* OpenSSL requires _ instead of - in cipher names */
3589 ssl_cipher[i] = '_';
3590 } else {
3591 /* and requires uppercase unlike the identities */
3592 ssl_cipher[i] = toupper(cipher[i]);
3593 }
3594 }
3595 ssl_cipher[i] = '\0';
3596
3597 if (!opts->ciphers) {
3598 /* first entry */
3599 opts->ciphers = strdup(ssl_cipher);
roman3a95bb22023-10-26 11:07:17 +02003600 NC_CHECK_ERRMEM_GOTO(!opts->ciphers, ret = 1, cleanup);
roman12644fe2023-06-08 11:06:42 +02003601 } else {
3602 /* + 1 because of : between entries */
roman6430c152023-10-12 11:28:47 +02003603 tmp = nc_realloc(opts->ciphers, strlen(opts->ciphers) + strlen(ssl_cipher) + 1 + 1);
roman3a95bb22023-10-26 11:07:17 +02003604 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02003605 opts->ciphers = tmp;
roman08f67f42023-06-08 13:51:54 +02003606 strcat(opts->ciphers, ":");
3607 strcat(opts->ciphers, ssl_cipher);
roman12644fe2023-06-08 11:06:42 +02003608 }
3609
3610cleanup:
3611 free(ssl_cipher);
3612 return ret;
3613}
3614
3615static int
romanb6f44032023-06-30 15:07:56 +02003616nc_server_config_del_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher)
roman12644fe2023-06-08 11:06:42 +02003617{
romanc135c6d2023-10-25 13:32:30 +02003618 int ret = 0;
roman12644fe2023-06-08 11:06:42 +02003619
romanc135c6d2023-10-25 13:32:30 +02003620 ret = nc_server_config_delete_substring(opts->ciphers, cipher, ':');
3621 if (ret) {
roman12644fe2023-06-08 11:06:42 +02003622 ERR(NULL, "Unable to delete a cipher (%s), which was not previously added.", cipher);
3623 return 1;
3624 }
3625
3626 return 0;
3627}
3628
3629static int
3630nc_server_config_cipher_suite(const struct lyd_node *node, NC_OPERATION op)
3631{
3632 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003633 struct nc_server_tls_opts *opts;
roman12644fe2023-06-08 11:06:42 +02003634 const char *cipher = NULL;
romanba93eac2023-07-18 14:36:48 +02003635 struct nc_ch_client *ch_client;
roman12644fe2023-06-08 11:06:42 +02003636
romanfaecc582023-06-15 16:13:31 +02003637 assert(!strcmp(LYD_NAME(node), "cipher-suite"));
3638
romanba93eac2023-07-18 14:36:48 +02003639 /* LOCK */
3640 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003641 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003642 return 1;
3643 }
3644
romanb6f44032023-06-30 15:07:56 +02003645 if (nc_server_config_get_tls_opts(node, &opts)) {
roman12644fe2023-06-08 11:06:42 +02003646 ret = 1;
3647 goto cleanup;
3648 }
3649
3650 cipher = ((struct lyd_node_term *)node)->value.ident->name;
3651 if (op == NC_OP_CREATE) {
romanb6f44032023-06-30 15:07:56 +02003652 ret = nc_server_config_create_cipher_suite(opts, cipher);
roman12644fe2023-06-08 11:06:42 +02003653 if (ret) {
3654 goto cleanup;
3655 }
3656 } else if (op == NC_OP_DELETE) {
romanb6f44032023-06-30 15:07:56 +02003657 ret = nc_server_config_del_cipher_suite(opts, cipher);
roman12644fe2023-06-08 11:06:42 +02003658 if (ret) {
3659 goto cleanup;
3660 }
3661 }
3662
3663cleanup:
romanba93eac2023-07-18 14:36:48 +02003664 if (is_ch(node)) {
3665 /* UNLOCK */
3666 nc_ch_client_unlock(ch_client);
3667 }
roman12644fe2023-06-08 11:06:42 +02003668 return ret;
3669}
3670
romanfaecc582023-06-15 16:13:31 +02003671static int
3672nc_server_config_crl_url(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-url"));
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)) {
roman6430c152023-10-12 11:28:47 +02003692 free(opts->crl_url);
romanb6f44032023-06-30 15:07:56 +02003693 opts->crl_url = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003694 NC_CHECK_ERRMEM_GOTO(!opts->crl_url, ret = 1, cleanup);
romanfaecc582023-06-15 16:13:31 +02003695 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02003696 free(opts->crl_url);
3697 opts->crl_url = NULL;
romanfaecc582023-06-15 16:13:31 +02003698 }
3699
3700cleanup:
romanba93eac2023-07-18 14:36:48 +02003701 if (is_ch(node)) {
3702 /* UNLOCK */
3703 nc_ch_client_unlock(ch_client);
3704 }
romanfaecc582023-06-15 16:13:31 +02003705 return ret;
3706}
3707
3708static int
3709nc_server_config_crl_path(const struct lyd_node *node, NC_OPERATION op)
3710{
3711 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003712 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02003713 struct nc_ch_client *ch_client;
romanfaecc582023-06-15 16:13:31 +02003714
3715 assert(!strcmp(LYD_NAME(node), "crl-path"));
3716
romanba93eac2023-07-18 14:36:48 +02003717 /* LOCK */
3718 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003719 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003720 return 1;
3721 }
3722
romanb6f44032023-06-30 15:07:56 +02003723 if (nc_server_config_get_tls_opts(node, &opts)) {
romanfaecc582023-06-15 16:13:31 +02003724 ret = 1;
3725 goto cleanup;
3726 }
3727
3728 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003729 free(opts->crl_path);
romanb6f44032023-06-30 15:07:56 +02003730 opts->crl_path = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003731 NC_CHECK_ERRMEM_GOTO(!opts->crl_path, ret = 1, cleanup);
romanfaecc582023-06-15 16:13:31 +02003732 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02003733 free(opts->crl_path);
3734 opts->crl_path = NULL;
romanfaecc582023-06-15 16:13:31 +02003735 }
3736
3737cleanup:
romanba93eac2023-07-18 14:36:48 +02003738 if (is_ch(node)) {
3739 /* UNLOCK */
3740 nc_ch_client_unlock(ch_client);
3741 }
romanfaecc582023-06-15 16:13:31 +02003742 return ret;
3743}
3744
3745static int
3746nc_server_config_crl_cert_ext(const struct lyd_node *node, NC_OPERATION op)
3747{
3748 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003749 struct nc_server_tls_opts *opts;
romanba93eac2023-07-18 14:36:48 +02003750 struct nc_ch_client *ch_client;
romanfaecc582023-06-15 16:13:31 +02003751
3752 assert(!strcmp(LYD_NAME(node), "crl-cert-ext"));
3753
romanba93eac2023-07-18 14:36:48 +02003754 /* LOCK */
3755 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003756 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003757 return 1;
3758 }
3759
romanb6f44032023-06-30 15:07:56 +02003760 if (nc_server_config_get_tls_opts(node, &opts)) {
romanfaecc582023-06-15 16:13:31 +02003761 ret = 1;
3762 goto cleanup;
3763 }
3764
3765 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003766 opts->crl_cert_ext = 1;
romanfaecc582023-06-15 16:13:31 +02003767 } else if (op == NC_OP_DELETE) {
romanb6f44032023-06-30 15:07:56 +02003768 opts->crl_cert_ext = 0;
romanfaecc582023-06-15 16:13:31 +02003769 }
3770
3771cleanup:
romanba93eac2023-07-18 14:36:48 +02003772 if (is_ch(node)) {
3773 /* UNLOCK */
3774 nc_ch_client_unlock(ch_client);
3775 }
romanfaecc582023-06-15 16:13:31 +02003776 return ret;
3777}
3778
roman2eab4742023-06-06 10:00:26 +02003779#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02003780
roman83683fb2023-02-24 09:15:23 +01003781static int
roman5cbb6532023-06-22 12:53:17 +02003782nc_server_config_create_netconf_client(const struct lyd_node *node)
3783{
3784 int ret = 0;
3785
3786 node = lyd_child(node);
3787 assert(!strcmp(LYD_NAME(node), "name"));
3788
3789 /* LOCK */
3790 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
3791
3792 ret = nc_server_config_realloc(lyd_get_value(node), (void **)&server_opts.ch_clients, sizeof *server_opts.ch_clients, &server_opts.ch_client_count);
3793 if (ret) {
3794 goto cleanup;
3795 }
3796
3797 server_opts.ch_clients[server_opts.ch_client_count - 1].id = ATOMIC_INC_RELAXED(server_opts.new_client_id);
3798 server_opts.ch_clients[server_opts.ch_client_count - 1].start_with = NC_CH_FIRST_LISTED;
roman6430c152023-10-12 11:28:47 +02003799 server_opts.ch_clients[server_opts.ch_client_count - 1].max_attempts = 3;
roman5cbb6532023-06-22 12:53:17 +02003800
3801 pthread_mutex_init(&server_opts.ch_clients[server_opts.ch_client_count - 1].lock, NULL);
3802
3803cleanup:
3804 /* UNLOCK */
3805 pthread_rwlock_unlock(&server_opts.ch_client_lock);
3806 return ret;
3807}
3808
3809static int
3810nc_server_config_netconf_client(const struct lyd_node *node, NC_OPERATION op)
3811{
3812 int ret = 0;
3813 struct nc_ch_client *ch_client;
3814
3815 assert(!strcmp(LYD_NAME(node), "netconf-client"));
3816
3817 if (op == NC_OP_CREATE) {
3818 ret = nc_server_config_create_netconf_client(node);
3819 if (ret) {
3820 goto cleanup;
3821 }
roman450c00b2023-11-02 10:31:45 +01003822
roman96c27f92023-11-02 11:09:46 +01003823#ifdef NC_ENABLED_SSH_TLS
roman450c00b2023-11-02 10:31:45 +01003824 if (server_opts.ch_dispatch_data.acquire_ctx_cb && server_opts.ch_dispatch_data.release_ctx_cb &&
roman96c27f92023-11-02 11:09:46 +01003825 server_opts.ch_dispatch_data.new_session_cb) {
roman450c00b2023-11-02 10:31:45 +01003826 /* we have all we need for dispatching a new call home thread */
3827 ret = nc_connect_ch_client_dispatch(lyd_get_value(lyd_child(node)), server_opts.ch_dispatch_data.acquire_ctx_cb,
roman96c27f92023-11-02 11:09:46 +01003828 server_opts.ch_dispatch_data.release_ctx_cb, server_opts.ch_dispatch_data.ctx_cb_data,
3829 server_opts.ch_dispatch_data.new_session_cb, server_opts.ch_dispatch_data.new_session_cb_data);
roman450c00b2023-11-02 10:31:45 +01003830 if (ret) {
3831 ERR(NULL, "Dispatching a new Call Home thread failed for Call Home client \"%s\".", lyd_get_value(lyd_child(node)));
3832 goto cleanup;
3833 }
3834 }
roman96c27f92023-11-02 11:09:46 +01003835#endif /* NC_ENABLED_SSH_TLS */
roman5cbb6532023-06-22 12:53:17 +02003836 } else if (op == NC_OP_DELETE) {
3837 if (nc_server_config_get_ch_client(node, &ch_client)) {
3838 ret = 1;
3839 goto cleanup;
3840 }
3841
3842 nc_server_config_ch_del_client(ch_client);
3843 }
3844
3845cleanup:
3846 return ret;
3847}
3848
3849#ifdef NC_ENABLED_SSH_TLS
3850
3851static int
3852nc_server_config_remote_address(const struct lyd_node *node, NC_OPERATION op)
3853{
3854 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02003855 struct nc_ch_endpt *ch_endpt;
romanba93eac2023-07-18 14:36:48 +02003856 struct nc_ch_client *ch_client;
roman5cbb6532023-06-22 12:53:17 +02003857
romanb6f44032023-06-30 15:07:56 +02003858 assert(!strcmp(LYD_NAME(node), "remote-address"));
3859
romanba93eac2023-07-18 14:36:48 +02003860 /* LOCK */
3861 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003862 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003863 return 1;
3864 }
3865
roman4cb8bb12023-06-29 09:16:46 +02003866 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02003867 ret = 1;
3868 goto cleanup;
3869 }
3870
3871 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003872 free(ch_endpt->address);
roman5cbb6532023-06-22 12:53:17 +02003873 ch_endpt->address = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003874 NC_CHECK_ERRMEM_GOTO(!ch_endpt->address, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02003875 } else {
roman6430c152023-10-12 11:28:47 +02003876 free(ch_endpt->address);
3877 ch_endpt->address = NULL;
roman5cbb6532023-06-22 12:53:17 +02003878 }
3879
3880cleanup:
romanba93eac2023-07-18 14:36:48 +02003881 /* UNLOCK */
3882 nc_ch_client_unlock(ch_client);
roman5cbb6532023-06-22 12:53:17 +02003883 return ret;
3884}
3885
3886static int
3887nc_server_config_remote_port(const struct lyd_node *node, NC_OPERATION op)
3888{
3889 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02003890 struct nc_ch_endpt *ch_endpt;
romanba93eac2023-07-18 14:36:48 +02003891 struct nc_ch_client *ch_client;
roman5cbb6532023-06-22 12:53:17 +02003892
romanb6f44032023-06-30 15:07:56 +02003893 assert(!strcmp(LYD_NAME(node), "remote-port"));
3894
romanba93eac2023-07-18 14:36:48 +02003895 /* LOCK */
3896 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003897 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003898 return 1;
3899 }
3900
roman4cb8bb12023-06-29 09:16:46 +02003901 if (nc_server_config_get_ch_endpt(node, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02003902 ret = 1;
3903 goto cleanup;
3904 }
3905
3906 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02003907 ch_endpt->port = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02003908 } else {
3909 ch_endpt->port = 0;
3910 }
3911
3912cleanup:
romanba93eac2023-07-18 14:36:48 +02003913 /* UNLOCK */
3914 nc_ch_client_unlock(ch_client);
roman5cbb6532023-06-22 12:53:17 +02003915 return ret;
3916}
3917
3918#endif /* NC_ENABLED_SSH_TLS */
3919
3920static int
romanb6f44032023-06-30 15:07:56 +02003921nc_server_config_persistent(const struct lyd_node *node, NC_OPERATION op)
3922{
3923 int ret = 0;
3924 struct nc_ch_client *ch_client;
3925
3926 assert(!strcmp(LYD_NAME(node), "persistent"));
3927
3928 (void) op;
3929
romanba93eac2023-07-18 14:36:48 +02003930 /* LOCK */
3931 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003932 /* to avoid unlock on fail */
3933 return 1;
romanb6f44032023-06-30 15:07:56 +02003934 }
3935
3936 ch_client->conn_type = NC_CH_PERSIST;
3937
romanba93eac2023-07-18 14:36:48 +02003938 /* UNLOCK */
3939 nc_ch_client_unlock(ch_client);
3940
romanb6f44032023-06-30 15:07:56 +02003941 return ret;
3942}
3943
3944static int
3945nc_server_config_periodic(const struct lyd_node *node, NC_OPERATION op)
3946{
3947 int ret = 0;
3948 struct nc_ch_client *ch_client;
3949
3950 assert(!strcmp(LYD_NAME(node), "periodic"));
3951
3952 (void) op;
3953
romanba93eac2023-07-18 14:36:48 +02003954 /* LOCK */
3955 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003956 /* to avoid unlock on fail */
3957 return 1;
romanb6f44032023-06-30 15:07:56 +02003958 }
3959
3960 ch_client->conn_type = NC_CH_PERIOD;
3961 /* set default values */
3962 ch_client->period = 60;
3963 ch_client->anchor_time = 0;
3964 ch_client->idle_timeout = 180;
3965
romanba93eac2023-07-18 14:36:48 +02003966 /* UNLOCK */
3967 nc_ch_client_unlock(ch_client);
3968
romanb6f44032023-06-30 15:07:56 +02003969 return ret;
3970}
3971
3972static int
3973nc_server_config_period(const struct lyd_node *node, NC_OPERATION op)
3974{
3975 int ret = 0;
3976 struct nc_ch_client *ch_client;
3977
3978 assert(!strcmp(LYD_NAME(node), "period"));
3979
romanba93eac2023-07-18 14:36:48 +02003980 /* LOCK */
3981 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003982 /* to avoid unlock on fail */
3983 return 1;
romanb6f44032023-06-30 15:07:56 +02003984 }
3985
3986 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02003987 ch_client->period = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02003988 } else if (op == NC_OP_DELETE) {
3989 ch_client->period = 60;
3990 }
3991
romanba93eac2023-07-18 14:36:48 +02003992 /* UNLOCK */
3993 nc_ch_client_unlock(ch_client);
3994
romanb6f44032023-06-30 15:07:56 +02003995 return ret;
3996}
3997
3998static int
3999nc_server_config_anchor_time(const struct lyd_node *node, NC_OPERATION op)
4000{
4001 int ret = 0;
4002 struct nc_ch_client *ch_client;
romana3c95c72023-10-26 11:15:53 +02004003 struct lyd_value_date_and_time *anchor_time;
romanb6f44032023-06-30 15:07:56 +02004004
4005 assert(!strcmp(LYD_NAME(node), "anchor-time"));
4006
romanba93eac2023-07-18 14:36:48 +02004007 /* LOCK */
4008 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02004009 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02004010 return 1;
romanb6f44032023-06-30 15:07:56 +02004011 }
4012
romana3c95c72023-10-26 11:15:53 +02004013 /* get the value of time from the node directly */
4014 LYD_VALUE_GET(&((struct lyd_node_term *)node)->value, anchor_time);
romanb6f44032023-06-30 15:07:56 +02004015
4016 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romana3c95c72023-10-26 11:15:53 +02004017 ch_client->anchor_time = anchor_time->time;
romanb6f44032023-06-30 15:07:56 +02004018 } else if (op == NC_OP_DELETE) {
4019 ch_client->anchor_time = 0;
4020 }
4021
romanba93eac2023-07-18 14:36:48 +02004022 /* UNLOCK */
4023 nc_ch_client_unlock(ch_client);
romanb6f44032023-06-30 15:07:56 +02004024 return ret;
4025}
4026
4027static int
4028nc_server_config_reconnect_strategy(const struct lyd_node *node, NC_OPERATION op)
4029{
4030 int ret = 0;
4031 struct nc_ch_client *ch_client;
4032
4033 assert(!strcmp(LYD_NAME(node), "reconnect-strategy"));
4034
4035 (void) op;
4036
romanba93eac2023-07-18 14:36:48 +02004037 /* LOCK */
4038 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02004039 /* to avoid unlock on fail */
4040 return 1;
romanb6f44032023-06-30 15:07:56 +02004041 }
4042
4043 /* set to default values */
4044 ch_client->start_with = NC_CH_FIRST_LISTED;
4045 ch_client->max_wait = 5;
4046 ch_client->max_attempts = 3;
4047
romanba93eac2023-07-18 14:36:48 +02004048 /* UNLOCK */
4049 nc_ch_client_unlock(ch_client);
4050
romanb6f44032023-06-30 15:07:56 +02004051 return ret;
4052}
4053
4054static int
4055nc_server_config_start_with(const struct lyd_node *node, NC_OPERATION op)
4056{
4057 int ret = 0;
4058 struct nc_ch_client *ch_client;
4059 const char *value;
4060
4061 assert(!strcmp(LYD_NAME(node), "start-with"));
4062
romanba93eac2023-07-18 14:36:48 +02004063 /* LOCK */
4064 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02004065 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02004066 return 1;
romanb6f44032023-06-30 15:07:56 +02004067 }
4068
4069 if (op == NC_OP_DELETE) {
4070 ch_client->start_with = NC_CH_FIRST_LISTED;
4071 goto cleanup;
4072 }
4073
4074 value = lyd_get_value(node);
4075 if (!strcmp(value, "first-listed")) {
4076 ch_client->start_with = NC_CH_FIRST_LISTED;
4077 } else if (!strcmp(value, "last-connected")) {
4078 ch_client->start_with = NC_CH_LAST_CONNECTED;
4079 } else if (!strcmp(value, "random-selection")) {
4080 ch_client->start_with = NC_CH_RANDOM;
4081 } else {
4082 ERR(NULL, "Unexpected start-with value \"%s\".", value);
4083 ret = 1;
4084 goto cleanup;
4085 }
4086
4087cleanup:
romanba93eac2023-07-18 14:36:48 +02004088 /* UNLOCK */
4089 nc_ch_client_unlock(ch_client);
romanb6f44032023-06-30 15:07:56 +02004090 return ret;
4091}
4092
4093static int
4094nc_server_config_max_wait(const struct lyd_node *node, NC_OPERATION op)
4095{
4096 int ret = 0;
4097 struct nc_ch_client *ch_client;
4098
4099 assert(!strcmp(LYD_NAME(node), "max-wait"));
4100
romanba93eac2023-07-18 14:36:48 +02004101 /* LOCK */
4102 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02004103 /* to avoid unlock on fail */
4104 return 1;
romanb6f44032023-06-30 15:07:56 +02004105 }
4106
4107 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02004108 ch_client->max_wait = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02004109 } else {
4110 ch_client->max_wait = 5;
4111 }
4112
romanba93eac2023-07-18 14:36:48 +02004113 /* UNLOCK */
4114 nc_ch_client_unlock(ch_client);
4115
romanb6f44032023-06-30 15:07:56 +02004116 return ret;
4117}
4118
4119static int
4120nc_server_config_max_attempts(const struct lyd_node *node, NC_OPERATION op)
4121{
4122 int ret = 0;
4123 struct nc_ch_client *ch_client;
4124
4125 assert(!strcmp(LYD_NAME(node), "max-attempts"));
4126
romanba93eac2023-07-18 14:36:48 +02004127 /* LOCK */
4128 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02004129 /* to avoid unlock on fail */
4130 return 1;
romanb6f44032023-06-30 15:07:56 +02004131 }
4132
4133 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02004134 ch_client->max_attempts = ((struct lyd_node_term *)node)->value.uint8;
romanb6f44032023-06-30 15:07:56 +02004135 } else {
4136 ch_client->max_attempts = 3;
4137 }
4138
romanba93eac2023-07-18 14:36:48 +02004139 /* UNLOCK */
4140 nc_ch_client_unlock(ch_client);
4141
romanb6f44032023-06-30 15:07:56 +02004142 return ret;
4143}
4144
4145static int
romanf02273a2023-05-25 09:44:11 +02004146nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01004147{
4148 const char *name = LYD_NAME(node);
roman6430c152023-10-12 11:28:47 +02004149 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01004150
4151 if (!strcmp(name, "listen")) {
roman6430c152023-10-12 11:28:47 +02004152 ret = nc_server_config_listen(node, op);
4153 } else if (!strcmp(name, "call-home")) {
4154 ret = nc_server_config_ch(node, op);
romaneaf84c72023-10-19 14:38:05 +02004155 } else if (!strcmp(name, "hello-timeout")) {
4156 ret = nc_server_config_hello_timeout(node, op);
romanc1d2b092023-02-02 08:58:27 +01004157 } else if (!strcmp(name, "endpoint")) {
roman6430c152023-10-12 11:28:47 +02004158 ret = nc_server_config_endpoint(node, op);
roman2eab4742023-06-06 10:00:26 +02004159 } else if (!strcmp(name, "unix-socket")) {
roman6430c152023-10-12 11:28:47 +02004160 ret = nc_server_config_unix_socket(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004161 }
roman2eab4742023-06-06 10:00:26 +02004162#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02004163 else if (!strcmp(name, "ssh")) {
roman6430c152023-10-12 11:28:47 +02004164 ret = nc_server_config_ssh(node, op);
roman2eab4742023-06-06 10:00:26 +02004165 } else if (!strcmp(name, "local-address")) {
roman6430c152023-10-12 11:28:47 +02004166 ret = nc_server_config_local_address(node, op);
romanc1d2b092023-02-02 08:58:27 +01004167 } else if (!strcmp(name, "local-port")) {
roman6430c152023-10-12 11:28:47 +02004168 ret = nc_server_config_local_port(node, op);
romanc1d2b092023-02-02 08:58:27 +01004169 } else if (!strcmp(name, "keepalives")) {
roman6430c152023-10-12 11:28:47 +02004170 ret = nc_server_config_keepalives(node, op);
romanc1d2b092023-02-02 08:58:27 +01004171 } else if (!strcmp(name, "idle-time")) {
roman6430c152023-10-12 11:28:47 +02004172 ret = nc_server_config_idle_time(node, op);
romanc1d2b092023-02-02 08:58:27 +01004173 } else if (!strcmp(name, "max-probes")) {
roman6430c152023-10-12 11:28:47 +02004174 ret = nc_server_config_max_probes(node, op);
romanc1d2b092023-02-02 08:58:27 +01004175 } else if (!strcmp(name, "probe-interval")) {
roman6430c152023-10-12 11:28:47 +02004176 ret = nc_server_config_probe_interval(node, op);
roman2eab4742023-06-06 10:00:26 +02004177 } else if (!strcmp(name, "host-key")) {
roman6430c152023-10-12 11:28:47 +02004178 ret = nc_server_config_host_key(node, op);
roman2eab4742023-06-06 10:00:26 +02004179 } else if (!strcmp(name, "public-key-format")) {
roman6430c152023-10-12 11:28:47 +02004180 ret = nc_server_config_public_key_format(node, op);
romanc1d2b092023-02-02 08:58:27 +01004181 } else if (!strcmp(name, "public-key")) {
roman6430c152023-10-12 11:28:47 +02004182 ret = nc_server_config_public_key(node, op);
romanc1d2b092023-02-02 08:58:27 +01004183 } else if (!strcmp(name, "private-key-format")) {
roman6430c152023-10-12 11:28:47 +02004184 ret = nc_server_config_private_key_format(node, op);
romanc1d2b092023-02-02 08:58:27 +01004185 } else if (!strcmp(name, "cleartext-private-key")) {
roman6430c152023-10-12 11:28:47 +02004186 ret = nc_server_config_cleartext_private_key(node, op);
roman2eab4742023-06-06 10:00:26 +02004187 } else if (!strcmp(name, "keystore-reference")) {
roman6430c152023-10-12 11:28:47 +02004188 ret = nc_server_config_keystore_reference(node, op);
romanc1d2b092023-02-02 08:58:27 +01004189 } else if (!strcmp(name, "user")) {
roman6430c152023-10-12 11:28:47 +02004190 ret = nc_server_config_user(node, op);
romanc1d2b092023-02-02 08:58:27 +01004191 } else if (!strcmp(name, "auth-attempts")) {
roman6430c152023-10-12 11:28:47 +02004192 ret = nc_server_config_auth_attempts(node, op);
romanc1d2b092023-02-02 08:58:27 +01004193 } else if (!strcmp(name, "auth-timeout")) {
roman6430c152023-10-12 11:28:47 +02004194 ret = nc_server_config_auth_timeout(node, op);
roman2eab4742023-06-06 10:00:26 +02004195 } else if (!strcmp(name, "truststore-reference")) {
roman6430c152023-10-12 11:28:47 +02004196 ret = nc_server_config_truststore_reference(node, op);
roman2eab4742023-06-06 10:00:26 +02004197 } else if (!strcmp(name, "password")) {
roman6430c152023-10-12 11:28:47 +02004198 ret = nc_server_config_password(node, op);
romanc1d2b092023-02-02 08:58:27 +01004199 } else if (!strcmp(name, "pam-config-file-name")) {
roman6430c152023-10-12 11:28:47 +02004200 ret = nc_server_config_pam_name(node, op);
romanc1d2b092023-02-02 08:58:27 +01004201 } else if (!strcmp(name, "pam-config-file-dir")) {
roman6430c152023-10-12 11:28:47 +02004202 ret = nc_server_config_pam_dir(node, op);
romanc1d2b092023-02-02 08:58:27 +01004203 } else if (!strcmp(name, "none")) {
roman6430c152023-10-12 11:28:47 +02004204 ret = nc_server_config_none(node, op);
romanc1d2b092023-02-02 08:58:27 +01004205 } else if (!strcmp(name, "host-key-alg")) {
roman6430c152023-10-12 11:28:47 +02004206 ret = nc_server_config_host_key_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01004207 } else if (!strcmp(name, "key-exchange-alg")) {
roman6430c152023-10-12 11:28:47 +02004208 ret = nc_server_config_kex_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01004209 } else if (!strcmp(name, "encryption-alg")) {
roman6430c152023-10-12 11:28:47 +02004210 ret = nc_server_config_encryption_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01004211 } else if (!strcmp(name, "mac-alg")) {
roman6430c152023-10-12 11:28:47 +02004212 ret = nc_server_config_mac_alg(node, op);
roman78df0fa2023-11-02 10:33:57 +01004213 } else if (!strcmp(name, "endpoint-reference")) {
4214 ret = nc_server_config_endpoint_reference(node, op);
roman2eab4742023-06-06 10:00:26 +02004215 } else if (!strcmp(name, "tls")) {
roman6430c152023-10-12 11:28:47 +02004216 ret = nc_server_config_tls(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004217 } else if (!strcmp(name, "cert-data")) {
roman6430c152023-10-12 11:28:47 +02004218 ret = nc_server_config_cert_data(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004219 } else if (!strcmp(name, "asymmetric-key")) {
roman6430c152023-10-12 11:28:47 +02004220 ret = nc_server_config_asymmetric_key(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004221 } else if (!strcmp(name, "certificate")) {
roman6430c152023-10-12 11:28:47 +02004222 ret = nc_server_config_certificate(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004223 } else if (!strcmp(name, "cert-to-name")) {
roman6430c152023-10-12 11:28:47 +02004224 ret = nc_server_config_cert_to_name(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004225 } else if (!strcmp(name, "fingerprint")) {
roman6430c152023-10-12 11:28:47 +02004226 ret = nc_server_config_fingerprint(node, op);
roman12644fe2023-06-08 11:06:42 +02004227 } else if (!strcmp(name, "tls-version")) {
roman6430c152023-10-12 11:28:47 +02004228 ret = nc_server_config_tls_version(node, op);
roman12644fe2023-06-08 11:06:42 +02004229 } else if (!strcmp(name, "cipher-suite")) {
roman6430c152023-10-12 11:28:47 +02004230 ret = nc_server_config_cipher_suite(node, op);
romanfaecc582023-06-15 16:13:31 +02004231 } else if (!strcmp(name, "crl-url")) {
roman6430c152023-10-12 11:28:47 +02004232 ret = nc_server_config_crl_url(node, op);
romanfaecc582023-06-15 16:13:31 +02004233 } else if (!strcmp(name, "crl-path")) {
roman6430c152023-10-12 11:28:47 +02004234 ret = nc_server_config_crl_path(node, op);
romanfaecc582023-06-15 16:13:31 +02004235 } else if (!strcmp(name, "crl-cert-ext")) {
roman6430c152023-10-12 11:28:47 +02004236 ret = nc_server_config_crl_cert_ext(node, op);
roman3f9b65c2023-06-05 14:26:58 +02004237 }
roman2eab4742023-06-06 10:00:26 +02004238#endif /* NC_ENABLED_SSH_TLS */
roman5cbb6532023-06-22 12:53:17 +02004239 else if (!strcmp(name, "netconf-client")) {
roman6430c152023-10-12 11:28:47 +02004240 ret = nc_server_config_netconf_client(node, op);
roman5cbb6532023-06-22 12:53:17 +02004241 }
4242#ifdef NC_ENABLED_SSH_TLS
4243 else if (!strcmp(name, "remote-address")) {
roman6430c152023-10-12 11:28:47 +02004244 ret = nc_server_config_remote_address(node, op);
roman5cbb6532023-06-22 12:53:17 +02004245 } else if (!strcmp(name, "remote-port")) {
roman6430c152023-10-12 11:28:47 +02004246 ret = nc_server_config_remote_port(node, op);
roman5cbb6532023-06-22 12:53:17 +02004247 }
4248#endif /* NC_ENABLED_SSH_TLS */
romanb6f44032023-06-30 15:07:56 +02004249 else if (!strcmp(name, "persistent")) {
roman6430c152023-10-12 11:28:47 +02004250 ret = nc_server_config_persistent(node, op);
romanb6f44032023-06-30 15:07:56 +02004251 } else if (!strcmp(name, "periodic")) {
roman6430c152023-10-12 11:28:47 +02004252 ret = nc_server_config_periodic(node, op);
romanb6f44032023-06-30 15:07:56 +02004253 } else if (!strcmp(name, "period")) {
roman6430c152023-10-12 11:28:47 +02004254 ret = nc_server_config_period(node, op);
romanb6f44032023-06-30 15:07:56 +02004255 } else if (!strcmp(name, "anchor-time")) {
roman6430c152023-10-12 11:28:47 +02004256 ret = nc_server_config_anchor_time(node, op);
romaneaf84c72023-10-19 14:38:05 +02004257 } else if (!strcmp(name, "idle-timeout")) {
4258 ret = nc_server_config_idle_timeout(node, op);
romanb6f44032023-06-30 15:07:56 +02004259 } else if (!strcmp(name, "reconnect-strategy")) {
roman6430c152023-10-12 11:28:47 +02004260 ret = nc_server_config_reconnect_strategy(node, op);
romanb6f44032023-06-30 15:07:56 +02004261 } else if (!strcmp(name, "start-with")) {
roman6430c152023-10-12 11:28:47 +02004262 ret = nc_server_config_start_with(node, op);
romanb6f44032023-06-30 15:07:56 +02004263 } else if (!strcmp(name, "max-wait")) {
roman6430c152023-10-12 11:28:47 +02004264 ret = nc_server_config_max_wait(node, op);
romanb6f44032023-06-30 15:07:56 +02004265 } else if (!strcmp(name, "max-attempts")) {
roman6430c152023-10-12 11:28:47 +02004266 ret = nc_server_config_max_attempts(node, op);
4267 }
4268
4269 if (ret) {
4270 ERR(NULL, "Configuring node \"%s\" failed.", LYD_NAME(node));
4271 return 1;
romanb6f44032023-06-30 15:07:56 +02004272 }
romanc1d2b092023-02-02 08:58:27 +01004273
4274 return 0;
romanc1d2b092023-02-02 08:58:27 +01004275}
4276
4277int
roman0bbc19c2023-05-26 09:59:09 +02004278nc_server_config_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, NC_MODULE module)
romanc1d2b092023-02-02 08:58:27 +01004279{
4280 struct lyd_node *child;
4281 struct lyd_meta *m;
romanf9906b42023-05-22 14:04:29 +02004282 NC_OPERATION current_op = NC_OP_UNKNOWN;
romanf02273a2023-05-25 09:44:11 +02004283 int ret;
romanc1d2b092023-02-02 08:58:27 +01004284
4285 assert(node);
4286
romanf9906b42023-05-22 14:04:29 +02004287 /* get current op if there is any */
4288 if ((m = lyd_find_meta(node->meta, NULL, "yang:operation"))) {
4289 if (!strcmp(lyd_get_meta_value(m), "create")) {
4290 current_op = NC_OP_CREATE;
4291 } else if (!strcmp(lyd_get_meta_value(m), "delete")) {
4292 current_op = NC_OP_DELETE;
4293 } else if (!strcmp(lyd_get_meta_value(m), "replace")) {
4294 current_op = NC_OP_REPLACE;
4295 } else if (!strcmp(lyd_get_meta_value(m), "none")) {
4296 current_op = NC_OP_NONE;
romanc1d2b092023-02-02 08:58:27 +01004297 }
4298 }
4299
4300 /* node has no op, inherit from the parent */
romanf9906b42023-05-22 14:04:29 +02004301 if (!current_op) {
4302 if (!parent_op) {
4303 ERR(NULL, "Unknown operation for node \"%s\".", LYD_NAME(node));
4304 return 1;
4305 }
4306
romanc1d2b092023-02-02 08:58:27 +01004307 current_op = parent_op;
4308 }
4309
4310 switch (current_op) {
4311 case NC_OP_NONE:
4312 break;
4313 case NC_OP_CREATE:
4314 case NC_OP_DELETE:
4315 case NC_OP_REPLACE:
roman2eab4742023-06-06 10:00:26 +02004316#ifdef NC_ENABLED_SSH_TLS
4317 if (module == NC_MODULE_KEYSTORE) {
romanf02273a2023-05-25 09:44:11 +02004318 ret = nc_server_config_parse_keystore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02004319 } else if (module == NC_MODULE_TRUSTSTORE) {
romanf02273a2023-05-25 09:44:11 +02004320 ret = nc_server_config_parse_truststore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02004321 } else
4322#endif /* NC_ENABLED_SSH_TLS */
4323 {
4324 ret = nc_server_config_parse_netconf_server(node, current_op);
romanf02273a2023-05-25 09:44:11 +02004325 }
4326 if (ret) {
4327 return ret;
romanc1d2b092023-02-02 08:58:27 +01004328 }
4329 break;
4330 default:
4331 break;
4332 }
4333
4334 if (current_op != NC_OP_DELETE) {
4335 LY_LIST_FOR(lyd_child(node), child) {
roman0bbc19c2023-05-26 09:59:09 +02004336 if (nc_server_config_parse_tree(child, current_op, module)) {
romanc1d2b092023-02-02 08:58:27 +01004337 return 1;
4338 }
4339 }
4340 }
4341 return 0;
4342}
4343
romanc1d2b092023-02-02 08:58:27 +01004344API int
4345nc_server_config_load_modules(struct ly_ctx **ctx)
4346{
4347 int i, new_ctx = 0;
4348
4349 if (!*ctx) {
4350 if (ly_ctx_new(NC_SERVER_SEARCH_DIR, 0, ctx)) {
4351 ERR(NULL, "Couldn't create new libyang context.\n");
4352 goto error;
4353 }
4354 new_ctx = 1;
4355 }
4356
4357 /* all features */
4358 const char *ietf_nectonf_server[] = {"ssh-listen", "tls-listen", "ssh-call-home", "tls-call-home", "central-netconf-server-supported", NULL};
4359 /* all features */
4360 const char *ietf_x509_cert_to_name[] = {NULL};
roman7fdc84d2023-06-06 13:14:53 +02004361 /* no private-key-encryption, csr-generation, p10-csr-format, certificate-expiration-notification,
roman3c6c7e62023-09-14 10:19:19 +02004362 * encrypted-passwords, hidden-symmetric-keys, encrypted-symmetric-keys, hidden-private-keys, encrypted-private-keys,
4363 * one-symmetric-key-format, one-asymmetric-key-format, symmetrically-encrypted-value-format,
4364 * asymmetrically-encrypted-value-format, cms-enveloped-data-format, cms-encrypted-data-format,
Roytakb2794852023-10-18 14:30:22 +02004365 * cleartext-symmetric-keys */
roman3c6c7e62023-09-14 10:19:19 +02004366 const char *ietf_crypto_types[] = {"cleartext-passwords", "cleartext-private-keys", NULL};
romanc1d2b092023-02-02 08:58:27 +01004367 /* all features */
4368 const char *ietf_tcp_common[] = {"keepalives-supported", NULL};
roman7fdc84d2023-06-06 13:14:53 +02004369 /* all features */
4370 const char *ietf_tcp_server[] = {"tcp-server-keepalives", NULL};
Roytakb2794852023-10-18 14:30:22 +02004371 /* no proxy-connect, socks5-gss-api, socks5-username-password, local-binding-supported ? */
4372 const char *ietf_tcp_client[] = {"tcp-client-keepalives", NULL};
roman3c6c7e62023-09-14 10:19:19 +02004373 /* no ssh-x509-certs, public-key-generation */
4374 const char *ietf_ssh_common[] = {"transport-params", NULL};
roman7fdc84d2023-06-06 13:14:53 +02004375 /* no ssh-server-keepalives and local-user-auth-hostbased */
4376 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 +01004377 /* all features */
4378 const char *iana_ssh_encryption_algs[] = {NULL};
4379 /* all features */
4380 const char *iana_ssh_key_exchange_algs[] = {NULL};
4381 /* all features */
4382 const char *iana_ssh_mac_algs[] = {NULL};
4383 /* all features */
4384 const char *iana_ssh_public_key_algs[] = {NULL};
romanc1d2b092023-02-02 08:58:27 +01004385 /* all features */
roman7fdc84d2023-06-06 13:14:53 +02004386 const char *iana_crypt_hash[] = {"crypt-hash-md5", "crypt-hash-sha-256", "crypt-hash-sha-512", NULL};
4387 /* no symmetric-keys */
4388 const char *ietf_keystore[] = {"central-keystore-supported", "inline-definitions-supported", "asymmetric-keys", NULL};
4389 /* all features */
4390 const char *ietf_truststore[] = {"central-truststore-supported", "inline-definitions-supported", "certificates", "public-keys", NULL};
roman3c6c7e62023-09-14 10:19:19 +02004391 /* no public-key-generation */
4392 const char *ietf_tls_common[] = {"tls10", "tls11", "tls12", "tls13", "hello-params", NULL};
4393 /* no tls-server-keepalives, server-ident-raw-public-key, server-ident-tls12-psk, server-ident-tls13-epsk,
4394 * client-auth-raw-public-key, client-auth-tls12-psk, client-auth-tls13-epsk */
4395 const char *ietf_tls_server[] = {"server-ident-x509-cert", "client-auth-supported", "client-auth-x509-cert", NULL};
roman7fdc84d2023-06-06 13:14:53 +02004396 /* all features */
roman12644fe2023-06-08 11:06:42 +02004397 const char *iana_tls_cipher_suite_algs[] = {NULL};
romanc1d2b092023-02-02 08:58:27 +01004398 /* all features */
4399 const char *libnetconf2_netconf_server[] = {NULL};
4400
4401 const char *module_names[] = {
roman7fdc84d2023-06-06 13:14:53 +02004402 "ietf-netconf-server", "ietf-x509-cert-to-name", "ietf-crypto-types", "ietf-tcp-common", "ietf-tcp-server",
4403 "ietf-tcp-client", "ietf-ssh-common", "ietf-ssh-server", "iana-ssh-encryption-algs",
4404 "iana-ssh-key-exchange-algs", "iana-ssh-mac-algs", "iana-ssh-public-key-algs", "iana-crypt-hash",
roman12644fe2023-06-08 11:06:42 +02004405 "ietf-keystore", "ietf-truststore", "ietf-tls-common", "ietf-tls-server", "iana-tls-cipher-suite-algs",
4406 "libnetconf2-netconf-server", NULL
romanc1d2b092023-02-02 08:58:27 +01004407 };
4408
4409 const char **module_features[] = {
roman7fdc84d2023-06-06 13:14:53 +02004410 ietf_nectonf_server, ietf_x509_cert_to_name, ietf_crypto_types, ietf_tcp_common,
4411 ietf_tcp_server, ietf_tcp_client, ietf_ssh_common, ietf_ssh_server, iana_ssh_encryption_algs,
4412 iana_ssh_key_exchange_algs, iana_ssh_mac_algs, iana_ssh_public_key_algs, iana_crypt_hash,
roman12644fe2023-06-08 11:06:42 +02004413 ietf_keystore, ietf_truststore, ietf_tls_common, ietf_tls_server, iana_tls_cipher_suite_algs,
4414 libnetconf2_netconf_server, NULL
romanc1d2b092023-02-02 08:58:27 +01004415 };
4416
4417 for (i = 0; module_names[i] != NULL; i++) {
4418 if (!ly_ctx_load_module(*ctx, module_names[i], NULL, module_features[i])) {
4419 ERR(NULL, "Loading module \"%s\" failed.\n", module_names[i]);
4420 goto error;
4421 }
4422 }
4423
4424 return 0;
4425
4426error:
4427 if (new_ctx) {
4428 ly_ctx_destroy(*ctx);
4429 *ctx = NULL;
4430 }
4431 return 1;
4432}
4433
romanf9906b42023-05-22 14:04:29 +02004434static int
4435nc_server_config_fill_nectonf_server(const struct lyd_node *data, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01004436{
4437 int ret = 0;
roman84fe3252023-10-25 11:28:32 +02004438 uint32_t log_options = 0;
romanc1d2b092023-02-02 08:58:27 +01004439 struct lyd_node *tree;
romand57b3722023-04-05 11:26:25 +02004440
romanc9b62d62023-09-14 10:19:50 +02004441 /* silently search for ietf-netconf-server, it may not be present */
roman84fe3252023-10-25 11:28:32 +02004442 ly_temp_log_options(&log_options);
romanc9b62d62023-09-14 10:19:50 +02004443
romanc1d2b092023-02-02 08:58:27 +01004444 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &tree);
romanc9b62d62023-09-14 10:19:50 +02004445 if (ret || (tree->flags & LYD_DEFAULT)) {
4446 /* not found */
4447 ret = 0;
romanc1d2b092023-02-02 08:58:27 +01004448 goto cleanup;
4449 }
4450
roman0bbc19c2023-05-26 09:59:09 +02004451 if (nc_server_config_parse_tree(tree, op, NC_MODULE_NETCONF_SERVER)) {
4452 ret = 1;
4453 goto cleanup;
4454 }
4455
roman2eab4742023-06-06 10:00:26 +02004456#ifdef NC_ENABLED_SSH_TLS
roman78df0fa2023-11-02 10:33:57 +01004457 /* check and set all endpoint references */
4458 if (nc_server_config_check_endpt_references()) {
romanf9906b42023-05-22 14:04:29 +02004459 ret = 1;
4460 goto cleanup;
4461 }
roman2eab4742023-06-06 10:00:26 +02004462#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004463
4464cleanup:
romanc9b62d62023-09-14 10:19:50 +02004465 /* reset the logging options back to what they were */
roman84fe3252023-10-25 11:28:32 +02004466 ly_temp_log_options(NULL);
romanf9906b42023-05-22 14:04:29 +02004467 return ret;
4468}
4469
4470API int
romanf6f37a52023-05-25 14:27:51 +02004471nc_server_config_setup_diff(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02004472{
4473 int ret = 0;
4474
romanc9b62d62023-09-14 10:19:50 +02004475 NC_CHECK_ARG_RET(NULL, data, 1);
4476
romanf9906b42023-05-22 14:04:29 +02004477 /* LOCK */
4478 pthread_rwlock_wrlock(&server_opts.config_lock);
4479
roman2eab4742023-06-06 10:00:26 +02004480#ifdef NC_ENABLED_SSH_TLS
romanf9906b42023-05-22 14:04:29 +02004481 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02004482 ret = nc_server_config_fill_keystore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02004483 if (ret) {
4484 ERR(NULL, "Filling keystore failed.");
4485 goto cleanup;
4486 }
4487
4488 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02004489 ret = nc_server_config_fill_truststore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02004490 if (ret) {
4491 ERR(NULL, "Filling truststore failed.");
4492 goto cleanup;
4493 }
roman2eab4742023-06-06 10:00:26 +02004494#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004495
4496 /* configure netconf-server */
4497 ret = nc_server_config_fill_nectonf_server(data, NC_OP_UNKNOWN);
4498 if (ret) {
4499 ERR(NULL, "Filling netconf-server failed.");
4500 goto cleanup;
4501 }
4502
4503cleanup:
4504 /* UNLOCK */
4505 pthread_rwlock_unlock(&server_opts.config_lock);
4506 return ret;
4507}
4508
4509API int
romanf6f37a52023-05-25 14:27:51 +02004510nc_server_config_setup_data(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02004511{
4512 int ret = 0;
4513 struct lyd_node *tree, *iter, *root;
4514
romanc9b62d62023-09-14 10:19:50 +02004515 NC_CHECK_ARG_RET(NULL, data, 1);
4516
romanf9906b42023-05-22 14:04:29 +02004517 /* LOCK */
4518 pthread_rwlock_wrlock(&server_opts.config_lock);
4519
4520 /* find the netconf-server node */
4521 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &root);
4522 if (ret) {
4523 ERR(NULL, "Unable to find the netconf-server container in the YANG data.");
4524 goto cleanup;
4525 }
4526
4527 /* iterate through all the nodes and make sure there is no operation attribute */
4528 LY_LIST_FOR(root, tree) {
4529 LYD_TREE_DFS_BEGIN(tree, iter) {
4530 if (lyd_find_meta(iter->meta, NULL, "yang:operation")) {
4531 ERR(NULL, "Unexpected operation attribute in the YANG data.");
romanc1d2b092023-02-02 08:58:27 +01004532 ret = 1;
4533 goto cleanup;
4534 }
romanf9906b42023-05-22 14:04:29 +02004535 LYD_TREE_DFS_END(tree, iter);
romanc1d2b092023-02-02 08:58:27 +01004536 }
4537 }
4538
romanf9906b42023-05-22 14:04:29 +02004539 /* delete the current configuration */
romanf02273a2023-05-25 09:44:11 +02004540 nc_server_config_listen(NULL, NC_OP_DELETE);
roman4cb8bb12023-06-29 09:16:46 +02004541 nc_server_config_ch(NULL, NC_OP_DELETE);
roman2eab4742023-06-06 10:00:26 +02004542#ifdef NC_ENABLED_SSH_TLS
romanf02273a2023-05-25 09:44:11 +02004543 nc_server_config_ks_keystore(NULL, NC_OP_DELETE);
4544 nc_server_config_ts_truststore(NULL, NC_OP_DELETE);
romanf9906b42023-05-22 14:04:29 +02004545
4546 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02004547 ret = nc_server_config_fill_keystore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02004548 if (ret) {
4549 ERR(NULL, "Filling keystore failed.");
4550 goto cleanup;
4551 }
4552
4553 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02004554 ret = nc_server_config_fill_truststore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02004555 if (ret) {
4556 ERR(NULL, "Filling truststore failed.");
4557 goto cleanup;
4558 }
roman2eab4742023-06-06 10:00:26 +02004559#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004560
4561 /* configure netconf-server */
4562 ret = nc_server_config_fill_nectonf_server(data, NC_OP_CREATE);
4563 if (ret) {
4564 ERR(NULL, "Filling netconf-server failed.");
romanc1d2b092023-02-02 08:58:27 +01004565 goto cleanup;
4566 }
4567
4568cleanup:
4569 /* UNLOCK */
4570 pthread_rwlock_unlock(&server_opts.config_lock);
4571 return ret;
4572}
roman3f9b65c2023-06-05 14:26:58 +02004573
4574API int
4575nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path)
4576{
4577 struct lyd_node *tree = NULL;
4578 int ret = 0;
4579
4580 NC_CHECK_ARG_RET(NULL, path, 1);
4581
4582 ret = lyd_parse_data_path(ctx, path, LYD_UNKNOWN, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree);
4583 if (ret) {
4584 goto cleanup;
4585 }
4586
4587 ret = nc_server_config_setup_data(tree);
4588 if (ret) {
4589 goto cleanup;
4590 }
4591
4592cleanup:
4593 lyd_free_all(tree);
4594 return ret;
4595}