blob: e01ee50de49762545e01ecce192aec90a583ddfb [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
romanc1d2b092023-02-02 08:58:27 +010029#include "compat.h"
roman3f9b65c2023-06-05 14:26:58 +020030#include "config.h"
31#include "log_p.h"
romane028ef92023-02-24 16:33:08 +010032#include "server_config.h"
romanf02273a2023-05-25 09:44:11 +020033#include "server_config_p.h"
roman3f9b65c2023-06-05 14:26:58 +020034#include "session_p.h"
35
romanc1d2b092023-02-02 08:58:27 +010036extern struct nc_server_opts server_opts;
37
roman8341e8b2023-11-23 16:12:42 +010038/* returns a parent node of 'node' that matches the name 'name' */
39static const struct lyd_node *
40nc_server_config_get_parent(const struct lyd_node *node, const char *name)
roman4cb8bb12023-06-29 09:16:46 +020041{
roman8341e8b2023-11-23 16:12:42 +010042 NC_CHECK_ARG_RET(NULL, node, name, NULL);
roman4cb8bb12023-06-29 09:16:46 +020043
44 while (node) {
roman8341e8b2023-11-23 16:12:42 +010045 if (!strcmp(LYD_NAME(node), name)) {
46 return node;
roman4cb8bb12023-06-29 09:16:46 +020047 }
48 node = lyd_parent(node);
49 }
50
roman8341e8b2023-11-23 16:12:42 +010051 return NULL;
52}
53
54/* returns a parent list node of 'node' that matches the name 'name' */
55static const struct lyd_node *
56nc_server_config_get_parent_list(const struct lyd_node *node, const char *name)
57{
58 NC_CHECK_ARG_RET(NULL, node, name, NULL);
59
60 while (node) {
61 /* check if the node is a list and its name matches the param */
62 if ((node->schema->nodetype == LYS_LIST) && (!strcmp(LYD_NAME(node), name))) {
63 return node;
64 }
65 node = lyd_parent(node);
66 }
67
68 return NULL;
69}
70
71/* returns the key of a list node with the name 'name' */
72static const char *
73nc_server_config_get_parent_list_key_value(const struct lyd_node *node, const char *name, const char *key_name)
74{
75 const char *original_name;
76
77 NC_CHECK_ARG_RET(NULL, node, name, key_name, NULL);
78 original_name = LYD_NAME(node);
79
80 /* get the supposed parent list */
81 node = nc_server_config_get_parent_list(node, name);
82 if (!node) {
83 ERR(NULL, "Node \"%s\" not contained in \"%s\" subtree.", original_name, name);
84 return NULL;
85 }
86
87 /* child should be the key */
88 node = lyd_child(node);
89 if (!node) {
90 ERR(NULL, "Node \"%s\" has no child nodes.", name);
91 return NULL;
92 }
93 if (strcmp(LYD_NAME(node), key_name)) {
94 ERR(NULL, "Node \"%s\" child names mismatch (found:\"%s\", expected:\"%s\").", original_name, LYD_NAME(node), key_name);
95 return NULL;
96 }
97
98 return lyd_get_value(node);
99}
100
101/* returns true if a node is a part of the listen subtree */
102static int
103is_listen(const struct lyd_node *node)
104{
105 node = nc_server_config_get_parent(node, "listen");
roman4cb8bb12023-06-29 09:16:46 +0200106 return node != NULL;
107}
108
roman6430c152023-10-12 11:28:47 +0200109/* returns true if a node is a part of the Call Home subtree */
roman4cb8bb12023-06-29 09:16:46 +0200110static int
111is_ch(const struct lyd_node *node)
112{
roman8341e8b2023-11-23 16:12:42 +0100113 node = nc_server_config_get_parent(node, "call-home");
roman4cb8bb12023-06-29 09:16:46 +0200114 return node != NULL;
115}
116
117#ifdef NC_ENABLED_SSH_TLS
118
roman6430c152023-10-12 11:28:47 +0200119/* returns true if a node is a part of the ssh subtree */
roman4cb8bb12023-06-29 09:16:46 +0200120static int
121is_ssh(const struct lyd_node *node)
122{
roman8341e8b2023-11-23 16:12:42 +0100123 node = nc_server_config_get_parent(node, "ssh");
roman4cb8bb12023-06-29 09:16:46 +0200124 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{
roman8341e8b2023-11-23 16:12:42 +0100131 node = nc_server_config_get_parent(node, "tls");
roman4cb8bb12023-06-29 09:16:46 +0200132 return node != NULL;
133}
134
135#endif /* NC_ENABLED_SSH_TLS */
136
roman6430c152023-10-12 11:28:47 +0200137/* gets the endpoint struct (and optionally bind) based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200138static int
romanf02273a2023-05-25 09:44:11 +0200139nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, struct nc_bind **bind)
romanc1d2b092023-02-02 08:58:27 +0100140{
141 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200142 const char *name;
romanc1d2b092023-02-02 08:58:27 +0100143
roman8341e8b2023-11-23 16:12:42 +0100144 NC_CHECK_ARG_RET(NULL, node, endpt, 1);
romanc1d2b092023-02-02 08:58:27 +0100145
roman8341e8b2023-11-23 16:12:42 +0100146 name = nc_server_config_get_parent_list_key_value(node, "endpoint", "name");
147 if (!name) {
romanc1d2b092023-02-02 08:58:27 +0100148 return 1;
149 }
150
romanc1d2b092023-02-02 08:58:27 +0100151 for (i = 0; i < server_opts.endpt_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200152 if (!strcmp(server_opts.endpts[i].name, name)) {
romanc1d2b092023-02-02 08:58:27 +0100153 *endpt = &server_opts.endpts[i];
154 if (bind) {
155 *bind = &server_opts.binds[i];
156 }
157 return 0;
158 }
159 }
160
romanb9beb112023-07-18 09:06:58 +0200161 ERR(NULL, "Endpoint \"%s\" was not found.", name);
romanc1d2b092023-02-02 08:58:27 +0100162 return 1;
163}
164
roman8341e8b2023-11-23 16:12:42 +0100165/* gets the ch_client struct based on node's location in the YANG data tree
166 * THE ch_client_lock HAS TO BE LOCKED PRIOR TO CALLING THIS
167 */
roman4cb8bb12023-06-29 09:16:46 +0200168static int
roman5cbb6532023-06-22 12:53:17 +0200169nc_server_config_get_ch_client(const struct lyd_node *node, struct nc_ch_client **ch_client)
170{
171 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200172 const char *name;
roman5cbb6532023-06-22 12:53:17 +0200173
roman8341e8b2023-11-23 16:12:42 +0100174 NC_CHECK_ARG_RET(NULL, node, ch_client, 1);
roman4cb8bb12023-06-29 09:16:46 +0200175
roman8341e8b2023-11-23 16:12:42 +0100176 name = nc_server_config_get_parent_list_key_value(node, "netconf-client", "name");
177 if (!name) {
roman5cbb6532023-06-22 12:53:17 +0200178 return 1;
179 }
180
roman5cbb6532023-06-22 12:53:17 +0200181 for (i = 0; i < server_opts.ch_client_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200182 if (!strcmp(server_opts.ch_clients[i].name, name)) {
roman5cbb6532023-06-22 12:53:17 +0200183 *ch_client = &server_opts.ch_clients[i];
184 return 0;
185 }
186 }
187
romanb9beb112023-07-18 09:06:58 +0200188 ERR(NULL, "Call-home client \"%s\" was not found.", name);
roman5cbb6532023-06-22 12:53:17 +0200189 return 1;
190}
191
roman8341e8b2023-11-23 16:12:42 +0100192/* gets the ch_endpt struct based on node's location in the YANG data tree,
193 * ch_client has to be locked
194 */
roman4cb8bb12023-06-29 09:16:46 +0200195static int
roman8341e8b2023-11-23 16:12:42 +0100196nc_server_config_get_ch_endpt(const struct lyd_node *node, const struct nc_ch_client *ch_client,
197 struct nc_ch_endpt **ch_endpt)
roman5cbb6532023-06-22 12:53:17 +0200198{
199 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200200 const char *name;
roman4cb8bb12023-06-29 09:16:46 +0200201
roman8341e8b2023-11-23 16:12:42 +0100202 NC_CHECK_ARG_RET(NULL, node, ch_client, ch_endpt, 1);
roman4cb8bb12023-06-29 09:16:46 +0200203
roman8341e8b2023-11-23 16:12:42 +0100204 name = nc_server_config_get_parent_list_key_value(node, "endpoint", "name");
205 if (!name) {
roman4cb8bb12023-06-29 09:16:46 +0200206 return 1;
207 }
roman5cbb6532023-06-22 12:53:17 +0200208
roman5cbb6532023-06-22 12:53:17 +0200209 for (i = 0; i < ch_client->ch_endpt_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200210 if (!strcmp(ch_client->ch_endpts[i].name, name)) {
roman5cbb6532023-06-22 12:53:17 +0200211 *ch_endpt = &ch_client->ch_endpts[i];
212 return 0;
213 }
214 }
215
romanb9beb112023-07-18 09:06:58 +0200216 ERR(NULL, "Call-home client's \"%s\" endpoint \"%s\" was not found.", ch_client->name, name);
roman5cbb6532023-06-22 12:53:17 +0200217 return 1;
218}
219
roman6430c152023-10-12 11:28:47 +0200220#ifdef NC_ENABLED_SSH_TLS
221
222/* gets the ssh_opts struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200223static int
roman8341e8b2023-11-23 16:12:42 +0100224nc_server_config_get_ssh_opts(const struct lyd_node *node, const struct nc_ch_client *ch_client,
225 struct nc_server_ssh_opts **opts)
roman4cb8bb12023-06-29 09:16:46 +0200226{
227 struct nc_endpt *endpt;
228 struct nc_ch_endpt *ch_endpt;
roman3f9b65c2023-06-05 14:26:58 +0200229
roman8341e8b2023-11-23 16:12:42 +0100230 NC_CHECK_ARG_RET(NULL, node, opts, 1);
roman4cb8bb12023-06-29 09:16:46 +0200231
232 if (is_listen(node)) {
233 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
234 return 1;
235 }
236 *opts = endpt->opts.ssh;
237 } else {
roman8341e8b2023-11-23 16:12:42 +0100238 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman4cb8bb12023-06-29 09:16:46 +0200239 return 1;
240 }
241 *opts = ch_endpt->opts.ssh;
242 }
243
244 return 0;
245}
246
roman6430c152023-10-12 11:28:47 +0200247/* gets the hostkey struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200248static int
roman8341e8b2023-11-23 16:12:42 +0100249nc_server_config_get_hostkey(const struct lyd_node *node, const struct nc_ch_client *ch_client,
250 struct nc_hostkey **hostkey)
romanc1d2b092023-02-02 08:58:27 +0100251{
252 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200253 const char *name;
roman4cb8bb12023-06-29 09:16:46 +0200254 struct nc_server_ssh_opts *opts;
romanc1d2b092023-02-02 08:58:27 +0100255
roman8341e8b2023-11-23 16:12:42 +0100256 NC_CHECK_ARG_RET(NULL, node, hostkey, 1);
romanc1d2b092023-02-02 08:58:27 +0100257
roman8341e8b2023-11-23 16:12:42 +0100258 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
romanc1d2b092023-02-02 08:58:27 +0100259 return 1;
260 }
261
roman8341e8b2023-11-23 16:12:42 +0100262 name = nc_server_config_get_parent_list_key_value(node, "host-key", "name");
263 if (!name) {
romanb9beb112023-07-18 09:06:58 +0200264 return 1;
265 }
roman8341e8b2023-11-23 16:12:42 +0100266
romanc1d2b092023-02-02 08:58:27 +0100267 for (i = 0; i < opts->hostkey_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200268 if (!strcmp(opts->hostkeys[i].name, name)) {
romanc1d2b092023-02-02 08:58:27 +0100269 *hostkey = &opts->hostkeys[i];
270 return 0;
271 }
272 }
273
romanb9beb112023-07-18 09:06:58 +0200274 ERR(NULL, "Host-key \"%s\" was not found.", name);
romanc1d2b092023-02-02 08:58:27 +0100275 return 1;
276}
277
roman6430c152023-10-12 11:28:47 +0200278/* gets the client_auth struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200279static int
roman8341e8b2023-11-23 16:12:42 +0100280nc_server_config_get_auth_client(const struct lyd_node *node, const struct nc_ch_client *ch_client,
281 struct nc_auth_client **auth_client)
romanc1d2b092023-02-02 08:58:27 +0100282{
283 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200284 const char *name;
roman4cb8bb12023-06-29 09:16:46 +0200285 struct nc_server_ssh_opts *opts;
romanc1d2b092023-02-02 08:58:27 +0100286
roman8341e8b2023-11-23 16:12:42 +0100287 NC_CHECK_ARG_RET(NULL, node, auth_client, 1);
romanc1d2b092023-02-02 08:58:27 +0100288
roman8341e8b2023-11-23 16:12:42 +0100289 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
romanc1d2b092023-02-02 08:58:27 +0100290 return 1;
291 }
292
roman8341e8b2023-11-23 16:12:42 +0100293 name = nc_server_config_get_parent_list_key_value(node, "user", "name");
294 if (!name) {
romanb9beb112023-07-18 09:06:58 +0200295 return 1;
296 }
roman8341e8b2023-11-23 16:12:42 +0100297
romanc1d2b092023-02-02 08:58:27 +0100298 for (i = 0; i < opts->client_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200299 if (!strcmp(opts->auth_clients[i].username, name)) {
romanc1d2b092023-02-02 08:58:27 +0100300 *auth_client = &opts->auth_clients[i];
301 return 0;
302 }
303 }
304
romanb9beb112023-07-18 09:06:58 +0200305 ERR(NULL, "Authorized key \"%s\" was not found.", name);
romanc1d2b092023-02-02 08:58:27 +0100306 return 1;
307}
308
roman6430c152023-10-12 11:28:47 +0200309/* gets the pubkey struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200310static int
roman8341e8b2023-11-23 16:12:42 +0100311nc_server_config_get_pubkey(const struct lyd_node *node, const struct nc_ch_client *ch_client,
312 struct nc_public_key **pubkey)
romanc1d2b092023-02-02 08:58:27 +0100313{
314 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200315 const char *name;
roman6430c152023-10-12 11:28:47 +0200316 struct nc_auth_client *auth_client;
romanc1d2b092023-02-02 08:58:27 +0100317
roman8341e8b2023-11-23 16:12:42 +0100318 NC_CHECK_ARG_RET(NULL, node, pubkey, 1);
romanc1d2b092023-02-02 08:58:27 +0100319
roman8341e8b2023-11-23 16:12:42 +0100320 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +0100321 return 1;
322 }
323
roman8341e8b2023-11-23 16:12:42 +0100324 name = nc_server_config_get_parent_list_key_value(node, "public-key", "name");
325 if (!name) {
romanb9beb112023-07-18 09:06:58 +0200326 return 1;
327 }
roman8341e8b2023-11-23 16:12:42 +0100328
romanc1d2b092023-02-02 08:58:27 +0100329 for (i = 0; i < auth_client->pubkey_count; i++) {
romanb9beb112023-07-18 09:06:58 +0200330 if (!strcmp(auth_client->pubkeys[i].name, name)) {
romanc1d2b092023-02-02 08:58:27 +0100331 *pubkey = &auth_client->pubkeys[i];
332 return 0;
333 }
334 }
335
romanb9beb112023-07-18 09:06:58 +0200336 ERR(NULL, "Public key \"%s\" was not found.", name);
romanc1d2b092023-02-02 08:58:27 +0100337 return 1;
338}
339
roman6430c152023-10-12 11:28:47 +0200340/* gets the tls_opts struct based on node's location in the YANG data tree */
roman4cb8bb12023-06-29 09:16:46 +0200341static int
roman8341e8b2023-11-23 16:12:42 +0100342nc_server_config_get_tls_opts(const struct lyd_node *node, const struct nc_ch_client *ch_client,
343 struct nc_server_tls_opts **opts)
romanb6f44032023-06-30 15:07:56 +0200344{
345 struct nc_endpt *endpt;
346 struct nc_ch_endpt *ch_endpt;
347
roman8341e8b2023-11-23 16:12:42 +0100348 NC_CHECK_ARG_RET(NULL, node, opts, 1);
romanb6f44032023-06-30 15:07:56 +0200349
350 if (is_listen(node)) {
351 if (nc_server_config_get_endpt(node, &endpt, NULL)) {
352 return 1;
353 }
354 *opts = endpt->opts.tls;
355 } else {
roman8341e8b2023-11-23 16:12:42 +0100356 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
romanb6f44032023-06-30 15:07:56 +0200357 return 1;
358 }
359 *opts = ch_endpt->opts.tls;
360 }
361
362 return 0;
363}
364
roman6430c152023-10-12 11:28:47 +0200365/* gets the cert struct based on node's location in the YANG data tree */
romanb6f44032023-06-30 15:07:56 +0200366static int
roman8341e8b2023-11-23 16:12:42 +0100367nc_server_config_get_cert(const struct lyd_node *node, const struct nc_ch_client *ch_client,
368 struct nc_certificate **cert)
roman3f9b65c2023-06-05 14:26:58 +0200369{
370 uint16_t i;
romanb9beb112023-07-18 09:06:58 +0200371 const char *name;
roman8341e8b2023-11-23 16:12:42 +0100372 struct nc_cert_grouping *certs;
romanb6f44032023-06-30 15:07:56 +0200373 struct nc_server_tls_opts *opts;
roman6430c152023-10-12 11:28:47 +0200374 int is_cert_end_entity;
roman8341e8b2023-11-23 16:12:42 +0100375 const struct lyd_node *tmp;
roman3f9b65c2023-06-05 14:26:58 +0200376
roman8341e8b2023-11-23 16:12:42 +0100377 NC_CHECK_ARG_RET(NULL, node, cert, 1);
roman3f9b65c2023-06-05 14:26:58 +0200378
roman8341e8b2023-11-23 16:12:42 +0100379 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +0200380 return 1;
381 }
382
roman8341e8b2023-11-23 16:12:42 +0100383 name = nc_server_config_get_parent_list_key_value(node, "certificate", "name");
384 if (!name) {
roman6430c152023-10-12 11:28:47 +0200385 return 1;
386 }
387
roman8341e8b2023-11-23 16:12:42 +0100388 /* it's in certificate subtree, now check if it's end entity or certificate authority */
389 tmp = nc_server_config_get_parent(node, "ee-certs");
390 if (tmp) {
391 is_cert_end_entity = 1;
romanb9beb112023-07-18 09:06:58 +0200392 } else {
roman8341e8b2023-11-23 16:12:42 +0100393 tmp = nc_server_config_get_parent(node, "ca-certs");
394 if (!tmp) {
395 ERR(NULL, "Node \"%s\" is not contained in ee-certs nor ca-certs subtree.", name);
396 return 1;
397 }
398 is_cert_end_entity = 0;
romanb9beb112023-07-18 09:06:58 +0200399 }
roman3f9b65c2023-06-05 14:26:58 +0200400
roman8341e8b2023-11-23 16:12:42 +0100401 /* get the right cert stack, either ee or ca */
402 if (is_cert_end_entity) {
403 certs = &opts->ee_certs;
404 } else {
405 certs = &opts->ca_certs;
406 }
407
408 for (i = 0; i < certs->cert_count; i++) {
409 if (!strcmp(certs->certs[i].name, name)) {
410 *cert = &certs->certs[i];
roman3f9b65c2023-06-05 14:26:58 +0200411 return 0;
412 }
413 }
414
roman8341e8b2023-11-23 16:12:42 +0100415 ERR(NULL, "%s certificate \"%s\" was not found.", is_cert_end_entity ? "End-entity" : "Certificate authority", name);
roman3f9b65c2023-06-05 14:26:58 +0200416 return 1;
417}
418
roman6430c152023-10-12 11:28:47 +0200419/* gets the ctn struct based on node's location in the YANG data tree */
roman3f9b65c2023-06-05 14:26:58 +0200420static int
roman8341e8b2023-11-23 16:12:42 +0100421nc_server_config_get_ctn(const struct lyd_node *node, const struct nc_ch_client *ch_client,
422 struct nc_ctn **ctn)
roman3f9b65c2023-06-05 14:26:58 +0200423{
424 uint32_t id;
425 struct nc_ctn *iter;
romanb6f44032023-06-30 15:07:56 +0200426 struct nc_server_tls_opts *opts;
romanb9beb112023-07-18 09:06:58 +0200427 const char *name;
roman3f9b65c2023-06-05 14:26:58 +0200428
roman8341e8b2023-11-23 16:12:42 +0100429 NC_CHECK_ARG_RET(NULL, node, ctn, 1);
roman3f9b65c2023-06-05 14:26:58 +0200430
roman8341e8b2023-11-23 16:12:42 +0100431 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
432 return 1;
roman3f9b65c2023-06-05 14:26:58 +0200433 }
434
roman8341e8b2023-11-23 16:12:42 +0100435 name = LYD_NAME(node);
436 node = nc_server_config_get_parent_list(node, "cert-to-name");
roman3f9b65c2023-06-05 14:26:58 +0200437 if (!node) {
romanb9beb112023-07-18 09:06:58 +0200438 ERR(NULL, "Node \"%s\" is not contained in a cert-to-name subtree.", name);
roman3f9b65c2023-06-05 14:26:58 +0200439 return 1;
440 }
441
442 node = lyd_child(node);
443 assert(!strcmp(LYD_NAME(node), "id"));
roman91ffeb42023-10-25 13:32:03 +0200444 id = ((struct lyd_node_term *)node)->value.uint32;
roman3f9b65c2023-06-05 14:26:58 +0200445
romanb6f44032023-06-30 15:07:56 +0200446 iter = opts->ctn;
roman3f9b65c2023-06-05 14:26:58 +0200447 while (iter) {
448 if (iter->id == id) {
449 *ctn = iter;
450 return 0;
451 }
452
453 iter = iter->next;
454 }
455
456 ERR(NULL, "Cert-to-name entry with id \"%d\" was not found.", id);
457 return 1;
458}
459
roman2eab4742023-06-06 10:00:26 +0200460NC_PRIVKEY_FORMAT
461nc_server_config_get_private_key_type(const char *format)
462{
463 if (!strcmp(format, "rsa-private-key-format")) {
464 return NC_PRIVKEY_FORMAT_RSA;
465 } else if (!strcmp(format, "ec-private-key-format")) {
466 return NC_PRIVKEY_FORMAT_EC;
roman13145912023-08-17 15:36:54 +0200467 } else if (!strcmp(format, "private-key-info-format")) {
roman2eab4742023-06-06 10:00:26 +0200468 return NC_PRIVKEY_FORMAT_X509;
469 } else if (!strcmp(format, "openssh-private-key-format")) {
470 return NC_PRIVKEY_FORMAT_OPENSSH;
471 } else {
472 ERR(NULL, "Private key format (%s) not supported.", format);
473 return NC_PRIVKEY_FORMAT_UNKNOWN;
474 }
475}
476
477#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200478
roman6430c152023-10-12 11:28:47 +0200479/* 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 +0200480static int
481nc_server_config_get_ch_client_with_lock(const struct lyd_node *node, struct nc_ch_client **ch_client)
482{
483 uint16_t i;
484 const char *name;
485
roman8341e8b2023-11-23 16:12:42 +0100486 NC_CHECK_ARG_RET(NULL, node, ch_client, 1);
romanba93eac2023-07-18 14:36:48 +0200487
roman8341e8b2023-11-23 16:12:42 +0100488 name = nc_server_config_get_parent_list_key_value(node, "netconf-client", "name");
489 if (!name) {
romanba93eac2023-07-18 14:36:48 +0200490 return 1;
491 }
492
romanba93eac2023-07-18 14:36:48 +0200493 /* LOCK */
494 pthread_rwlock_rdlock(&server_opts.ch_client_lock);
495 for (i = 0; i < server_opts.ch_client_count; i++) {
496 if (!strcmp(server_opts.ch_clients[i].name, name)) {
497 /* LOCK */
498 pthread_mutex_lock(&server_opts.ch_clients[i].lock);
499 *ch_client = &server_opts.ch_clients[i];
500 return 0;
501 }
502 }
503
roman6430c152023-10-12 11:28:47 +0200504 /* UNLOCK */
505 pthread_rwlock_unlock(&server_opts.ch_client_lock);
romanba93eac2023-07-18 14:36:48 +0200506 ERR(NULL, "Call-home client \"%s\" was not found.", name);
507 return 1;
508}
509
510static void
511nc_ch_client_unlock(struct nc_ch_client *client)
512{
513 assert(client);
514
515 pthread_mutex_unlock(&client->lock);
516 pthread_rwlock_unlock(&server_opts.ch_client_lock);
517}
518
romanf02273a2023-05-25 09:44:11 +0200519int
romanc1d2b092023-02-02 08:58:27 +0100520equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char *parent_name)
521{
522 uint16_t i;
523
roman6430c152023-10-12 11:28:47 +0200524 assert(node && parent_count && parent_name);
romanc1d2b092023-02-02 08:58:27 +0100525
526 node = lyd_parent(node);
527 for (i = 1; i < parent_count; i++) {
528 node = lyd_parent(node);
529 }
530
531 if (!strcmp(LYD_NAME(node), parent_name)) {
532 return 1;
533 }
534
535 return 0;
536}
537
romanf02273a2023-05-25 09:44:11 +0200538int
539nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uint16_t *count)
540{
541 int ret = 0;
542 void *tmp;
543 char **name;
544
545 tmp = realloc(*ptr, (*count + 1) * size);
roman3a95bb22023-10-26 11:07:17 +0200546 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
romanf02273a2023-05-25 09:44:11 +0200547 *ptr = tmp;
548
549 /* set the newly allocated memory to 0 */
550 memset((char *)(*ptr) + (*count * size), 0, size);
551 (*count)++;
552
553 /* access the first member of the supposed structure */
554 name = (char **)((*ptr) + ((*count - 1) * size));
555
556 /* and set it's value */
557 *name = strdup(key_value);
roman3a95bb22023-10-26 11:07:17 +0200558 NC_CHECK_ERRMEM_GOTO(!*name, ret = 1, cleanup);
romanf02273a2023-05-25 09:44:11 +0200559
560cleanup:
561 return ret;
562}
563
roman2eab4742023-06-06 10:00:26 +0200564#ifdef NC_ENABLED_SSH_TLS
565
roman3f9b65c2023-06-05 14:26:58 +0200566static void
roman874fed12023-05-25 10:20:01 +0200567nc_server_config_del_hostkey(struct nc_server_ssh_opts *opts, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +0100568{
roman874fed12023-05-25 10:20:01 +0200569 assert(hostkey->store == NC_STORE_LOCAL || hostkey->store == NC_STORE_KEYSTORE);
romanc1d2b092023-02-02 08:58:27 +0100570
roman6430c152023-10-12 11:28:47 +0200571 free(hostkey->name);
572
roman874fed12023-05-25 10:20:01 +0200573 if (hostkey->store == NC_STORE_LOCAL) {
roman6430c152023-10-12 11:28:47 +0200574 free(hostkey->key.pubkey_data);
575 free(hostkey->key.privkey_data);
romandd019a92023-09-14 10:17:07 +0200576 } else {
roman6430c152023-10-12 11:28:47 +0200577 free(hostkey->ks_ref);
romanc1d2b092023-02-02 08:58:27 +0100578 }
579
romanc1d2b092023-02-02 08:58:27 +0100580 opts->hostkey_count--;
581 if (!opts->hostkey_count) {
582 free(opts->hostkeys);
583 opts->hostkeys = NULL;
roman6430c152023-10-12 11:28:47 +0200584 } else if (hostkey != &opts->hostkeys[opts->hostkey_count]) {
roman33981232023-07-08 11:55:13 +0200585 memcpy(hostkey, &opts->hostkeys[opts->hostkey_count], sizeof *opts->hostkeys);
romanc1d2b092023-02-02 08:58:27 +0100586 }
587}
588
589static void
roman58f79d02023-10-06 10:20:31 +0200590nc_server_config_del_auth_client_pubkey(struct nc_auth_client *auth_client, struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +0100591{
roman6430c152023-10-12 11:28:47 +0200592 free(pubkey->name);
593 free(pubkey->data);
romanc1d2b092023-02-02 08:58:27 +0100594
595 auth_client->pubkey_count--;
596 if (!auth_client->pubkey_count) {
597 free(auth_client->pubkeys);
598 auth_client->pubkeys = NULL;
roman6430c152023-10-12 11:28:47 +0200599 } else if (pubkey != &auth_client->pubkeys[auth_client->pubkey_count]) {
roman33981232023-07-08 11:55:13 +0200600 memcpy(pubkey, &auth_client->pubkeys[auth_client->pubkey_count], sizeof *auth_client->pubkeys);
romanc1d2b092023-02-02 08:58:27 +0100601 }
602}
603
604static void
roman58f79d02023-10-06 10:20:31 +0200605nc_server_config_del_auth_client(struct nc_server_ssh_opts *opts, struct nc_auth_client *auth_client)
romanc1d2b092023-02-02 08:58:27 +0100606{
607 uint16_t i, pubkey_count;
608
roman4cb8bb12023-06-29 09:16:46 +0200609 free(auth_client->username);
roman4cb8bb12023-06-29 09:16:46 +0200610
roman874fed12023-05-25 10:20:01 +0200611 if (auth_client->store == NC_STORE_LOCAL) {
romanc1d2b092023-02-02 08:58:27 +0100612 pubkey_count = auth_client->pubkey_count;
613 for (i = 0; i < pubkey_count; i++) {
roman874fed12023-05-25 10:20:01 +0200614 nc_server_config_del_auth_client_pubkey(auth_client, &auth_client->pubkeys[i]);
romanc1d2b092023-02-02 08:58:27 +0100615 }
romana9ec3362023-12-21 10:59:57 +0100616 } else if (auth_client->store == NC_STORE_TRUSTSTORE) {
roman6430c152023-10-12 11:28:47 +0200617 free(auth_client->ts_ref);
romanc1d2b092023-02-02 08:58:27 +0100618 }
619
roman6430c152023-10-12 11:28:47 +0200620 free(auth_client->password);
romanc1d2b092023-02-02 08:58:27 +0100621
622 opts->client_count--;
623 if (!opts->client_count) {
624 free(opts->auth_clients);
625 opts->auth_clients = NULL;
roman6430c152023-10-12 11:28:47 +0200626 } else if (auth_client != &opts->auth_clients[opts->client_count]) {
roman33981232023-07-08 11:55:13 +0200627 memcpy(auth_client, &opts->auth_clients[opts->client_count], sizeof *opts->auth_clients);
romanc1d2b092023-02-02 08:58:27 +0100628 }
629}
630
631static void
roman6430c152023-10-12 11:28:47 +0200632nc_server_config_del_ssh_opts(struct nc_bind *bind, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +0100633{
634 uint16_t i, hostkey_count, client_count;
635
roman5ae78282023-11-02 13:34:34 +0100636 if (bind) {
637 free(bind->address);
638 if (bind->sock > -1) {
639 close(bind->sock);
640 }
romanc1d2b092023-02-02 08:58:27 +0100641 }
642
643 /* store in variable because it gets decremented in the function call */
644 hostkey_count = opts->hostkey_count;
645 for (i = 0; i < hostkey_count; i++) {
roman874fed12023-05-25 10:20:01 +0200646 nc_server_config_del_hostkey(opts, &opts->hostkeys[i]);
romanc1d2b092023-02-02 08:58:27 +0100647 }
648
649 client_count = opts->client_count;
650 for (i = 0; i < client_count; i++) {
roman874fed12023-05-25 10:20:01 +0200651 nc_server_config_del_auth_client(opts, &opts->auth_clients[i]);
romanc1d2b092023-02-02 08:58:27 +0100652 }
653
roman6430c152023-10-12 11:28:47 +0200654 free(opts->hostkey_algs);
655 free(opts->kex_algs);
656 free(opts->encryption_algs);
657 free(opts->mac_algs);
romanc1d2b092023-02-02 08:58:27 +0100658
659 free(opts);
romanc1d2b092023-02-02 08:58:27 +0100660}
661
roman8341e8b2023-11-23 16:12:42 +0100662/* delete references to endpoint with the name 'referenced_endpt_name' from other endpts */
roman78df0fa2023-11-02 10:33:57 +0100663static void
664nc_server_config_del_endpt_references(const char *referenced_endpt_name)
665{
666 uint16_t i, j;
667
roman8341e8b2023-11-23 16:12:42 +0100668 /* first go through listen endpoints */
roman78df0fa2023-11-02 10:33:57 +0100669 for (i = 0; i < server_opts.endpt_count; i++) {
670 if (server_opts.endpts[i].referenced_endpt_name) {
671 if (!strcmp(server_opts.endpts[i].referenced_endpt_name, referenced_endpt_name)) {
672 free(server_opts.endpts[i].referenced_endpt_name);
673 server_opts.endpts[i].referenced_endpt_name = NULL;
674
roman506354a2024-04-11 09:37:22 +0200675 if (server_opts.endpts[i].ti == NC_TI_SSH) {
roman78df0fa2023-11-02 10:33:57 +0100676 server_opts.endpts[i].opts.ssh->referenced_endpt_name = NULL;
677 } else {
678 server_opts.endpts[i].opts.tls->referenced_endpt_name = NULL;
679 }
680 }
681 }
682 }
683
684 /* LOCK */
685 pthread_rwlock_rdlock(&server_opts.ch_client_lock);
roman8341e8b2023-11-23 16:12:42 +0100686 /* next go through ch endpoints */
roman78df0fa2023-11-02 10:33:57 +0100687 for (i = 0; i < server_opts.ch_client_count; i++) {
688 /* LOCK */
689 pthread_mutex_lock(&server_opts.ch_clients[i].lock);
690 for (j = 0; j < server_opts.ch_clients[i].ch_endpt_count; j++) {
691 if (server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name) {
692 if (!strcmp(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, referenced_endpt_name)) {
693 free(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name);
694 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name = NULL;
695
roman506354a2024-04-11 09:37:22 +0200696 if (server_opts.ch_clients[i].ch_endpts[j].ti == NC_TI_SSH) {
roman78df0fa2023-11-02 10:33:57 +0100697 server_opts.ch_clients[i].ch_endpts[j].opts.ssh->referenced_endpt_name = NULL;
698 } else {
699 server_opts.ch_clients[i].ch_endpts[j].opts.tls->referenced_endpt_name = NULL;
700 }
701 }
702 }
703 }
704 /* UNLOCK */
705 pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
706 }
707
708 /* UNLOCK */
709 pthread_rwlock_unlock(&server_opts.ch_client_lock);
710}
711
romanc1d2b092023-02-02 08:58:27 +0100712void
roman874fed12023-05-25 10:20:01 +0200713nc_server_config_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind)
romanc1d2b092023-02-02 08:58:27 +0100714{
roman78df0fa2023-11-02 10:33:57 +0100715 /* delete any references to this endpoint */
716 nc_server_config_del_endpt_references(endpt->name);
roman6430c152023-10-12 11:28:47 +0200717 free(endpt->name);
roman78df0fa2023-11-02 10:33:57 +0100718
roman6430c152023-10-12 11:28:47 +0200719 free(endpt->referenced_endpt_name);
720 nc_server_config_del_ssh_opts(bind, endpt->opts.ssh);
romanc1d2b092023-02-02 08:58:27 +0100721
722 server_opts.endpt_count--;
723 if (!server_opts.endpt_count) {
724 free(server_opts.endpts);
725 free(server_opts.binds);
726 server_opts.endpts = NULL;
727 server_opts.binds = NULL;
roman6430c152023-10-12 11:28:47 +0200728 } else if (endpt != &server_opts.endpts[server_opts.endpt_count]) {
roman33981232023-07-08 11:55:13 +0200729 memcpy(endpt, &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts);
730 memcpy(bind, &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds);
romanc1d2b092023-02-02 08:58:27 +0100731 }
732}
733
roman3f9b65c2023-06-05 14:26:58 +0200734static void
roman3f9b65c2023-06-05 14:26:58 +0200735nc_server_config_del_cert(struct nc_cert_grouping *certs, struct nc_certificate *cert)
736{
737 free(cert->name);
roman3f9b65c2023-06-05 14:26:58 +0200738 free(cert->data);
roman3f9b65c2023-06-05 14:26:58 +0200739
740 certs->cert_count--;
741 if (!certs->cert_count) {
742 free(certs->certs);
743 certs->certs = NULL;
roman6430c152023-10-12 11:28:47 +0200744 } else if (cert != &certs->certs[certs->cert_count]) {
roman33981232023-07-08 11:55:13 +0200745 memcpy(cert, &certs->certs[certs->cert_count], sizeof *certs->certs);
roman3f9b65c2023-06-05 14:26:58 +0200746 }
747}
748
749static void
roman6430c152023-10-12 11:28:47 +0200750nc_server_config_del_certs(struct nc_cert_grouping *certs_grp)
roman3f9b65c2023-06-05 14:26:58 +0200751{
roman6430c152023-10-12 11:28:47 +0200752 uint16_t i;
roman3f9b65c2023-06-05 14:26:58 +0200753
roman6430c152023-10-12 11:28:47 +0200754 if (certs_grp->store == NC_STORE_LOCAL) {
755 for (i = 0; i < certs_grp->cert_count; i++) {
756 free(certs_grp->certs[i].name);
757 free(certs_grp->certs[i].data);
roman3f9b65c2023-06-05 14:26:58 +0200758 }
roman6430c152023-10-12 11:28:47 +0200759 free(certs_grp->certs);
760 certs_grp->certs = NULL;
romana9ec3362023-12-21 10:59:57 +0100761 } else if (certs_grp->store == NC_STORE_TRUSTSTORE) {
roman6430c152023-10-12 11:28:47 +0200762 free(certs_grp->ts_ref);
roman3f9b65c2023-06-05 14:26:58 +0200763 }
764}
765
766static void
767nc_server_config_del_ctn(struct nc_server_tls_opts *opts, struct nc_ctn *ctn)
768{
769 struct nc_ctn *iter;
770
roman3f9b65c2023-06-05 14:26:58 +0200771 free(ctn->name);
roman6430c152023-10-12 11:28:47 +0200772 free(ctn->fingerprint);
roman3f9b65c2023-06-05 14:26:58 +0200773
774 if (opts->ctn == ctn) {
775 /* it's the first in the list */
776 opts->ctn = ctn->next;
777 free(ctn);
778 return;
779 }
780
roman84fe3252023-10-25 11:28:32 +0200781 for (iter = opts->ctn; iter; iter = iter->next) {
roman3f9b65c2023-06-05 14:26:58 +0200782 if (iter->next == ctn) {
783 /* found the ctn */
784 break;
785 }
roman3f9b65c2023-06-05 14:26:58 +0200786 }
787
romanb7bfa652023-11-09 12:36:35 +0100788 if (!iter) {
789 ERRINT;
790 return;
791 }
792
roman3f9b65c2023-06-05 14:26:58 +0200793 iter->next = ctn->next;
794 free(ctn);
795}
796
797static void
roman6430c152023-10-12 11:28:47 +0200798nc_server_config_del_ctns(struct nc_server_tls_opts *opts)
roman3f9b65c2023-06-05 14:26:58 +0200799{
800 struct nc_ctn *cur, *next;
801
roman84fe3252023-10-25 11:28:32 +0200802 for (cur = opts->ctn; cur; cur = next) {
roman3f9b65c2023-06-05 14:26:58 +0200803 next = cur->next;
roman3f9b65c2023-06-05 14:26:58 +0200804 free(cur->name);
roman6430c152023-10-12 11:28:47 +0200805 free(cur->fingerprint);
roman3f9b65c2023-06-05 14:26:58 +0200806 free(cur);
roman3f9b65c2023-06-05 14:26:58 +0200807 }
roman3a95bb22023-10-26 11:07:17 +0200808
roman3f9b65c2023-06-05 14:26:58 +0200809 opts->ctn = NULL;
810}
811
812static void
roman6430c152023-10-12 11:28:47 +0200813nc_server_config_del_tls_opts(struct nc_bind *bind, struct nc_server_tls_opts *opts)
roman3f9b65c2023-06-05 14:26:58 +0200814{
roman5ae78282023-11-02 13:34:34 +0100815 if (bind) {
816 free(bind->address);
817 if (bind->sock > -1) {
818 close(bind->sock);
819 }
roman3f9b65c2023-06-05 14:26:58 +0200820 }
821
822 if (opts->store == NC_STORE_LOCAL) {
roman6430c152023-10-12 11:28:47 +0200823 free(opts->pubkey_data);
824 free(opts->privkey_data);
825 free(opts->cert_data);
romana9ec3362023-12-21 10:59:57 +0100826 } else if (opts->store == NC_STORE_KEYSTORE) {
roman6430c152023-10-12 11:28:47 +0200827 free(opts->key_ref);
828 free(opts->cert_ref);
roman3f9b65c2023-06-05 14:26:58 +0200829 }
830
roman6430c152023-10-12 11:28:47 +0200831 nc_server_config_del_certs(&opts->ca_certs);
832 nc_server_config_del_certs(&opts->ee_certs);
roman3f9b65c2023-06-05 14:26:58 +0200833
roman6430c152023-10-12 11:28:47 +0200834 free(opts->crl_path);
835 free(opts->crl_url);
romanfaecc582023-06-15 16:13:31 +0200836
roman6430c152023-10-12 11:28:47 +0200837 nc_server_config_del_ctns(opts);
838 free(opts->ciphers);
roman3f9b65c2023-06-05 14:26:58 +0200839 free(opts);
840}
841
842static void
843nc_server_config_del_endpt_tls(struct nc_endpt *endpt, struct nc_bind *bind)
844{
roman78df0fa2023-11-02 10:33:57 +0100845 /* delete any references to this endpoint */
846 nc_server_config_del_endpt_references(endpt->name);
roman6430c152023-10-12 11:28:47 +0200847 free(endpt->name);
roman78df0fa2023-11-02 10:33:57 +0100848
roman6430c152023-10-12 11:28:47 +0200849 free(endpt->referenced_endpt_name);
850
851 nc_server_config_del_tls_opts(bind, endpt->opts.tls);
roman3f9b65c2023-06-05 14:26:58 +0200852
853 server_opts.endpt_count--;
854 if (!server_opts.endpt_count) {
855 free(server_opts.endpts);
856 free(server_opts.binds);
857 server_opts.endpts = NULL;
858 server_opts.binds = NULL;
roman6430c152023-10-12 11:28:47 +0200859 } else if (endpt != &server_opts.endpts[server_opts.endpt_count]) {
roman33981232023-07-08 11:55:13 +0200860 memcpy(endpt, &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts);
861 memcpy(bind, &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds);
roman3f9b65c2023-06-05 14:26:58 +0200862 }
863}
864
roman2eab4742023-06-06 10:00:26 +0200865#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200866
roman5cbb6532023-06-22 12:53:17 +0200867static void
868nc_server_config_ch_del_endpt(struct nc_ch_client *ch_client, struct nc_ch_endpt *ch_endpt)
869{
870 free(ch_endpt->name);
roman5cbb6532023-06-22 12:53:17 +0200871
872#ifdef NC_ENABLED_SSH_TLS
roman6430c152023-10-12 11:28:47 +0200873 free(ch_endpt->address);
roman5cbb6532023-06-22 12:53:17 +0200874 if (ch_endpt->sock_pending > -1) {
875 close(ch_endpt->sock_pending);
876 ch_endpt->sock_pending = -1;
877 }
roman5ae78282023-11-02 13:34:34 +0100878 free(ch_endpt->referenced_endpt_name);
roman5cbb6532023-06-22 12:53:17 +0200879#endif /* NC_ENABLED_SSH_TLS */
880
881 switch (ch_endpt->ti) {
882#ifdef NC_ENABLED_SSH_TLS
roman506354a2024-04-11 09:37:22 +0200883 case NC_TI_SSH:
roman5ae78282023-11-02 13:34:34 +0100884 nc_server_config_del_ssh_opts(NULL, ch_endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +0200885 break;
roman506354a2024-04-11 09:37:22 +0200886 case NC_TI_TLS:
roman5ae78282023-11-02 13:34:34 +0100887 nc_server_config_del_tls_opts(NULL, ch_endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +0200888 break;
roman5cbb6532023-06-22 12:53:17 +0200889#endif /* NC_ENABLED_SSH_TLS */
890 default:
891 ERRINT;
892 break;
893 }
894
895 ch_client->ch_endpt_count--;
896 if (!ch_client->ch_endpt_count) {
897 free(ch_client->ch_endpts);
898 ch_client->ch_endpts = NULL;
899 }
900}
901
902static void
roman8341e8b2023-11-23 16:12:42 +0100903nc_server_config_destroy_ch_client(struct nc_ch_client *ch_client)
roman5cbb6532023-06-22 12:53:17 +0200904{
romanba93eac2023-07-18 14:36:48 +0200905 pthread_t tid;
roman8341e8b2023-11-23 16:12:42 +0100906 uint16_t i, ch_endpt_count;
907
romaneaeb87e2023-12-07 13:08:01 +0100908 /* CH COND LOCK */
909 pthread_mutex_lock(&ch_client->thread_data->cond_lock);
roman8341e8b2023-11-23 16:12:42 +0100910 if (ch_client->thread_data->thread_running) {
roman8341e8b2023-11-23 16:12:42 +0100911 ch_client->thread_data->thread_running = 0;
912 pthread_cond_signal(&ch_client->thread_data->cond);
913 /* CH COND UNLOCK */
914 pthread_mutex_unlock(&ch_client->thread_data->cond_lock);
915
romaneaeb87e2023-12-07 13:08:01 +0100916 /* get tid */
917 tid = ch_client->tid;
918
roman8341e8b2023-11-23 16:12:42 +0100919 /* wait for the thread to terminate */
920 pthread_join(tid, NULL);
romaneaeb87e2023-12-07 13:08:01 +0100921 } else {
922 /* CH COND UNLOCK */
923 pthread_mutex_unlock(&ch_client->thread_data->cond_lock);
roman8341e8b2023-11-23 16:12:42 +0100924 }
925
926 /* free its members */
927 free(ch_client->name);
928
929 ch_endpt_count = ch_client->ch_endpt_count;
930 for (i = 0; i < ch_endpt_count; i++) {
931 nc_server_config_ch_del_endpt(ch_client, &ch_client->ch_endpts[i]);
932 }
933}
934
935static void
936nc_server_config_ch_del_client(const struct lyd_node *node)
937{
938 struct nc_ch_client client, *ch_client;
roman5cbb6532023-06-22 12:53:17 +0200939
romanba93eac2023-07-18 14:36:48 +0200940 /* WR LOCK */
roman5cbb6532023-06-22 12:53:17 +0200941 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
942
roman8341e8b2023-11-23 16:12:42 +0100943 if (nc_server_config_get_ch_client(node, &ch_client)) {
944 /* WR UNLOCK */
945 pthread_rwlock_unlock(&server_opts.ch_client_lock);
946 ERR(NULL, "Call-home client \"%s\" not found.", lyd_get_value(lyd_child(node)));
947 return;
948 }
949
romanba93eac2023-07-18 14:36:48 +0200950 /* copy the client we want to delete into a local variable */
951 memcpy(&client, ch_client, sizeof *ch_client);
roman5cbb6532023-06-22 12:53:17 +0200952
romanba93eac2023-07-18 14:36:48 +0200953 /* delete the client */
roman5cbb6532023-06-22 12:53:17 +0200954 server_opts.ch_client_count--;
955 if (!server_opts.ch_client_count) {
956 free(server_opts.ch_clients);
957 server_opts.ch_clients = NULL;
romanba93eac2023-07-18 14:36:48 +0200958 } else {
959 memcpy(ch_client, &server_opts.ch_clients[server_opts.ch_client_count], sizeof *server_opts.ch_clients);
roman5cbb6532023-06-22 12:53:17 +0200960 }
961
romanba93eac2023-07-18 14:36:48 +0200962 /* WR UNLOCK */
roman5cbb6532023-06-22 12:53:17 +0200963 pthread_rwlock_unlock(&server_opts.ch_client_lock);
romanba93eac2023-07-18 14:36:48 +0200964
roman8341e8b2023-11-23 16:12:42 +0100965 nc_server_config_destroy_ch_client(&client);
966}
romanba93eac2023-07-18 14:36:48 +0200967
roman8341e8b2023-11-23 16:12:42 +0100968/* presence container */
969int
970nc_server_config_listen(const struct lyd_node *node, NC_OPERATION op)
971{
972 uint16_t i, endpt_count;
romanba93eac2023-07-18 14:36:48 +0200973
roman8341e8b2023-11-23 16:12:42 +0100974 (void) node;
romanba93eac2023-07-18 14:36:48 +0200975
roman8341e8b2023-11-23 16:12:42 +0100976 assert(op == NC_OP_CREATE || op == NC_OP_DELETE);
977
978 if (op == NC_OP_DELETE) {
979 endpt_count = server_opts.endpt_count;
980 for (i = 0; i < endpt_count; i++) {
981 switch (server_opts.endpts[i].ti) {
982#ifdef NC_ENABLED_SSH_TLS
roman506354a2024-04-11 09:37:22 +0200983 case NC_TI_SSH:
roman8341e8b2023-11-23 16:12:42 +0100984 nc_server_config_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]);
985 break;
roman506354a2024-04-11 09:37:22 +0200986 case NC_TI_TLS:
roman8341e8b2023-11-23 16:12:42 +0100987 nc_server_config_del_endpt_tls(&server_opts.endpts[i], &server_opts.binds[i]);
988 break;
989#endif /* NC_ENABLED_SSH_TLS */
romana2ff4ef2024-01-19 14:41:46 +0100990 case NC_TI_UNIX:
991 break;
roman8341e8b2023-11-23 16:12:42 +0100992 case NC_TI_NONE:
993 case NC_TI_FD:
994 ERRINT;
995 return 1;
996 }
997 }
romanba93eac2023-07-18 14:36:48 +0200998 }
999
roman8341e8b2023-11-23 16:12:42 +01001000 return 0;
roman5cbb6532023-06-22 12:53:17 +02001001}
1002
roman6430c152023-10-12 11:28:47 +02001003int
roman5cbb6532023-06-22 12:53:17 +02001004nc_server_config_ch(const struct lyd_node *node, NC_OPERATION op)
1005{
1006 uint16_t i, ch_client_count;
roman8341e8b2023-11-23 16:12:42 +01001007 struct nc_ch_client *ch_clients;
roman5cbb6532023-06-22 12:53:17 +02001008
1009 (void) node;
1010
roman8341e8b2023-11-23 16:12:42 +01001011 /* don't do anything if we're not deleting */
1012 if (op != NC_OP_DELETE) {
1013 return 0;
roman5cbb6532023-06-22 12:53:17 +02001014 }
roman6430c152023-10-12 11:28:47 +02001015
roman8341e8b2023-11-23 16:12:42 +01001016 /* WR LOCK */
1017 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
1018
1019 ch_client_count = server_opts.ch_client_count;
1020 ch_clients = server_opts.ch_clients;
1021
1022 /* remove them from the server opts */
1023 server_opts.ch_client_count = 0;
1024 server_opts.ch_clients = NULL;
1025
1026 /* UNLOCK */
1027 pthread_rwlock_unlock(&server_opts.ch_client_lock);
1028
1029 for (i = 0; i < ch_client_count; i++) {
1030 /* now destroy each client */
1031 nc_server_config_destroy_ch_client(&ch_clients[i]);
1032 }
1033
1034 free(ch_clients);
roman6430c152023-10-12 11:28:47 +02001035 return 0;
roman5cbb6532023-06-22 12:53:17 +02001036}
1037
romanc1d2b092023-02-02 08:58:27 +01001038/* default leaf */
1039static int
romane028ef92023-02-24 16:33:08 +01001040nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001041{
roman8341e8b2023-11-23 16:12:42 +01001042 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02001043
romanc1d2b092023-02-02 08:58:27 +01001044 assert(!strcmp(LYD_NAME(node), "idle-timeout"));
1045
romaneaf84c72023-10-19 14:38:05 +02001046 if (is_ch(node)) {
romanb6f44032023-06-30 15:07:56 +02001047 /* call-home idle timeout */
roman6430c152023-10-12 11:28:47 +02001048 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
1049 /* to avoid unlock on fail */
romanb6f44032023-06-30 15:07:56 +02001050 return 1;
1051 }
1052
1053 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001054 ch_client->idle_timeout = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02001055 } else if (op == NC_OP_DELETE) {
1056 ch_client->idle_timeout = 180;
1057 }
roman6430c152023-10-12 11:28:47 +02001058
1059 nc_ch_client_unlock(ch_client);
romaneaf84c72023-10-19 14:38:05 +02001060 } else {
Michal Vaskocf898172024-01-15 15:04:28 +01001061 /* listen idle timeout */
romaneaf84c72023-10-19 14:38:05 +02001062 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001063 server_opts.idle_timeout = ((struct lyd_node_term *)node)->value.uint16;
romaneaf84c72023-10-19 14:38:05 +02001064 } else {
1065 /* default value */
Michal Vaskocf898172024-01-15 15:04:28 +01001066 server_opts.idle_timeout = 180;
romaneaf84c72023-10-19 14:38:05 +02001067 }
romanc1d2b092023-02-02 08:58:27 +01001068 }
1069
1070 return 0;
1071}
1072
1073static int
roman874fed12023-05-25 10:20:01 +02001074nc_server_config_create_bind(void)
romanc1d2b092023-02-02 08:58:27 +01001075{
1076 int ret = 0;
1077 void *tmp;
1078
1079 tmp = realloc(server_opts.binds, (server_opts.endpt_count + 1) * sizeof *server_opts.binds);
roman3a95bb22023-10-26 11:07:17 +02001080 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01001081 server_opts.binds = tmp;
1082 memset(&server_opts.binds[server_opts.endpt_count], 0, sizeof *server_opts.binds);
1083
1084 server_opts.binds[server_opts.endpt_count].sock = -1;
1085
1086cleanup:
1087 return ret;
1088}
1089
1090static int
roman874fed12023-05-25 10:20:01 +02001091nc_server_config_create_endpoint(const struct lyd_node *node)
romanc1d2b092023-02-02 08:58:27 +01001092{
roman874fed12023-05-25 10:20:01 +02001093 if (nc_server_config_create_bind()) {
romanf02273a2023-05-25 09:44:11 +02001094 return 1;
romanc1d2b092023-02-02 08:58:27 +01001095 }
romanc1d2b092023-02-02 08:58:27 +01001096
1097 node = lyd_child(node);
1098 assert(!strcmp(LYD_NAME(node), "name"));
1099
Michal Vaskocf898172024-01-15 15:04:28 +01001100 return nc_server_config_realloc(lyd_get_value(node), (void **)&server_opts.endpts, sizeof *server_opts.endpts,
1101 &server_opts.endpt_count);
romanc1d2b092023-02-02 08:58:27 +01001102}
1103
roman5cbb6532023-06-22 12:53:17 +02001104static int
1105nc_server_config_ch_create_endpoint(const struct lyd_node *node, struct nc_ch_client *ch_client)
1106{
1107 node = lyd_child(node);
1108 assert(!strcmp(LYD_NAME(node), "name"));
1109
Michal Vaskocf898172024-01-15 15:04:28 +01001110 return nc_server_config_realloc(lyd_get_value(node), (void **)&ch_client->ch_endpts, sizeof *ch_client->ch_endpts,
1111 &ch_client->ch_endpt_count);
roman5cbb6532023-06-22 12:53:17 +02001112}
1113
romanc1d2b092023-02-02 08:58:27 +01001114/* list */
1115static int
romane028ef92023-02-24 16:33:08 +01001116nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001117{
1118 int ret = 0;
1119 struct nc_endpt *endpt;
1120 struct nc_bind *bind;
roman6430c152023-10-12 11:28:47 +02001121 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001122 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001123
1124 assert(!strcmp(LYD_NAME(node), "endpoint"));
1125
roman5cbb6532023-06-22 12:53:17 +02001126 if (is_listen(node)) {
1127 /* listen */
1128 if (op == NC_OP_CREATE) {
1129 ret = nc_server_config_create_endpoint(node);
1130 if (ret) {
1131 goto cleanup;
1132 }
1133 } else if (op == NC_OP_DELETE) {
1134 /* free all children */
1135 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1136 ret = 1;
1137 goto cleanup;
1138 }
1139
1140 switch (endpt->ti) {
1141#ifdef NC_ENABLED_SSH_TLS
roman506354a2024-04-11 09:37:22 +02001142 case NC_TI_SSH:
roman5cbb6532023-06-22 12:53:17 +02001143 nc_server_config_del_endpt_ssh(endpt, bind);
1144 break;
roman506354a2024-04-11 09:37:22 +02001145 case NC_TI_TLS:
roman5cbb6532023-06-22 12:53:17 +02001146 nc_server_config_del_endpt_tls(endpt, bind);
1147 break;
1148#endif /* NC_ENABLED_SSH_TLS */
romana2ff4ef2024-01-19 14:41:46 +01001149 case NC_TI_UNIX:
1150 break;
roman5cbb6532023-06-22 12:53:17 +02001151 case NC_TI_NONE:
1152 case NC_TI_FD:
1153 ERRINT;
1154 ret = 1;
1155 goto cleanup;
1156 }
romanc1d2b092023-02-02 08:58:27 +01001157 }
roman5cbb6532023-06-22 12:53:17 +02001158 } else if (is_ch(node)) {
romanba93eac2023-07-18 14:36:48 +02001159 /* LOCK */
1160 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001161 /* to avoid unlock on fail */
1162 return 1;
romanc1d2b092023-02-02 08:58:27 +01001163 }
roman3f9b65c2023-06-05 14:26:58 +02001164
roman5cbb6532023-06-22 12:53:17 +02001165 if (op == NC_OP_CREATE) {
1166 ret = nc_server_config_ch_create_endpoint(node, ch_client);
1167 if (ret) {
1168 goto cleanup;
1169 }
1170
1171 /* init ch sock */
1172 ch_client->ch_endpts[ch_client->ch_endpt_count - 1].sock_pending = -1;
roman6430c152023-10-12 11:28:47 +02001173 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01001174 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman6430c152023-10-12 11:28:47 +02001175 ret = 1;
1176 goto cleanup;
1177 }
1178
1179 nc_server_config_ch_del_endpt(ch_client, ch_endpt);
roman3f9b65c2023-06-05 14:26:58 +02001180 }
romanc1d2b092023-02-02 08:58:27 +01001181 }
1182
1183cleanup:
romanba93eac2023-07-18 14:36:48 +02001184 if (is_ch(node)) {
1185 /* UNLOCK */
1186 nc_ch_client_unlock(ch_client);
1187 }
romanc1d2b092023-02-02 08:58:27 +01001188 return ret;
1189}
1190
roman2eab4742023-06-06 10:00:26 +02001191#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02001192
romanc1d2b092023-02-02 08:58:27 +01001193static int
roman874fed12023-05-25 10:20:01 +02001194nc_server_config_create_ssh(struct nc_endpt *endpt)
romanc1d2b092023-02-02 08:58:27 +01001195{
roman506354a2024-04-11 09:37:22 +02001196 endpt->ti = NC_TI_SSH;
romanc1d2b092023-02-02 08:58:27 +01001197 endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
roman3a95bb22023-10-26 11:07:17 +02001198 NC_CHECK_ERRMEM_RET(!endpt->opts.ssh, 1);
romanc1d2b092023-02-02 08:58:27 +01001199
1200 return 0;
1201}
1202
roman5cbb6532023-06-22 12:53:17 +02001203static int
1204nc_server_config_ch_create_ssh(struct nc_ch_endpt *ch_endpt)
1205{
roman506354a2024-04-11 09:37:22 +02001206 ch_endpt->ti = NC_TI_SSH;
roman5cbb6532023-06-22 12:53:17 +02001207 ch_endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
roman3a95bb22023-10-26 11:07:17 +02001208 NC_CHECK_ERRMEM_RET(!ch_endpt->opts.ssh, 1);
roman5cbb6532023-06-22 12:53:17 +02001209
1210 return 0;
1211}
1212
romanc1d2b092023-02-02 08:58:27 +01001213/* NP container */
1214static int
romane028ef92023-02-24 16:33:08 +01001215nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001216{
1217 struct nc_endpt *endpt;
1218 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001219 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001220 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001221 int ret = 0;
1222
1223 assert(!strcmp(LYD_NAME(node), "ssh"));
1224
roman5cbb6532023-06-22 12:53:17 +02001225 if (is_listen(node)) {
1226 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1227 ret = 1;
romanc1d2b092023-02-02 08:58:27 +01001228 goto cleanup;
1229 }
roman5cbb6532023-06-22 12:53:17 +02001230
1231 if (op == NC_OP_CREATE) {
1232 ret = nc_server_config_create_ssh(endpt);
1233 if (ret) {
1234 goto cleanup;
1235 }
1236 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02001237 nc_server_config_del_ssh_opts(bind, endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +02001238 }
1239 } else {
romanba93eac2023-07-18 14:36:48 +02001240 /* LOCK */
1241 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001242 /* to avoid unlock on fail */
1243 return 1;
romanba93eac2023-07-18 14:36:48 +02001244 }
1245
roman8341e8b2023-11-23 16:12:42 +01001246 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001247 ret = 1;
1248 goto cleanup;
1249 }
1250
1251 if (op == NC_OP_CREATE) {
1252 ret = nc_server_config_ch_create_ssh(ch_endpt);
1253 if (ret) {
1254 goto cleanup;
1255 }
romanb6f44032023-06-30 15:07:56 +02001256 } else if (op == NC_OP_DELETE) {
roman5ae78282023-11-02 13:34:34 +01001257 nc_server_config_del_ssh_opts(NULL, ch_endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +02001258 }
romanc1d2b092023-02-02 08:58:27 +01001259 }
1260
1261cleanup:
romanba93eac2023-07-18 14:36:48 +02001262 if (is_ch(node)) {
1263 /* UNLOCK */
1264 nc_ch_client_unlock(ch_client);
1265 }
romanc1d2b092023-02-02 08:58:27 +01001266 return ret;
1267}
1268
roman3f9b65c2023-06-05 14:26:58 +02001269static int
1270nc_server_config_create_tls(struct nc_endpt *endpt)
1271{
roman506354a2024-04-11 09:37:22 +02001272 endpt->ti = NC_TI_TLS;
roman3f9b65c2023-06-05 14:26:58 +02001273 endpt->opts.tls = calloc(1, sizeof *endpt->opts.tls);
roman3a95bb22023-10-26 11:07:17 +02001274 NC_CHECK_ERRMEM_RET(!endpt->opts.tls, 1);
roman3f9b65c2023-06-05 14:26:58 +02001275
1276 return 0;
1277}
1278
1279static int
romanb6f44032023-06-30 15:07:56 +02001280nc_server_config_ch_create_tls(struct nc_ch_endpt *ch_endpt)
1281{
roman506354a2024-04-11 09:37:22 +02001282 ch_endpt->ti = NC_TI_TLS;
romanb6f44032023-06-30 15:07:56 +02001283 ch_endpt->opts.tls = calloc(1, sizeof(struct nc_server_tls_opts));
roman3a95bb22023-10-26 11:07:17 +02001284 NC_CHECK_ERRMEM_RET(!ch_endpt->opts.tls, 1);
romanb6f44032023-06-30 15:07:56 +02001285
1286 return 0;
1287}
1288
1289static int
roman3f9b65c2023-06-05 14:26:58 +02001290nc_server_config_tls(const struct lyd_node *node, NC_OPERATION op)
1291{
1292 struct nc_endpt *endpt;
1293 struct nc_bind *bind;
romanb6f44032023-06-30 15:07:56 +02001294 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001295 struct nc_ch_client *ch_client = NULL;
roman3f9b65c2023-06-05 14:26:58 +02001296 int ret = 0;
1297
1298 assert(!strcmp(LYD_NAME(node), "tls"));
1299
romanb6f44032023-06-30 15:07:56 +02001300 if (is_listen(node)) {
1301 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1302 ret = 1;
roman3f9b65c2023-06-05 14:26:58 +02001303 goto cleanup;
1304 }
romanb6f44032023-06-30 15:07:56 +02001305
1306 if (op == NC_OP_CREATE) {
1307 ret = nc_server_config_create_tls(endpt);
1308 if (ret) {
1309 goto cleanup;
1310 }
1311 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02001312 nc_server_config_del_tls_opts(bind, endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +02001313 }
1314 } else {
romanba93eac2023-07-18 14:36:48 +02001315 /* LOCK */
1316 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001317 /* to avoid unlock on fail */
1318 return 1;
romanba93eac2023-07-18 14:36:48 +02001319 }
1320
roman8341e8b2023-11-23 16:12:42 +01001321 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
romanb6f44032023-06-30 15:07:56 +02001322 ret = 1;
1323 goto cleanup;
1324 }
1325
1326 if (op == NC_OP_CREATE) {
1327 ret = nc_server_config_ch_create_tls(ch_endpt);
1328 if (ret) {
1329 goto cleanup;
1330 }
roman6430c152023-10-12 11:28:47 +02001331 } else if (op == NC_OP_DELETE) {
roman5ae78282023-11-02 13:34:34 +01001332 nc_server_config_del_tls_opts(NULL, ch_endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +02001333 }
roman3f9b65c2023-06-05 14:26:58 +02001334 }
1335
1336cleanup:
romanba93eac2023-07-18 14:36:48 +02001337 if (is_ch(node)) {
1338 /* UNLOCK */
1339 nc_ch_client_unlock(ch_client);
1340 }
roman3f9b65c2023-06-05 14:26:58 +02001341 return ret;
1342}
1343
romanc1d2b092023-02-02 08:58:27 +01001344/* mandatory leaf */
1345static int
romane028ef92023-02-24 16:33:08 +01001346nc_server_config_local_address(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001347{
1348 struct nc_endpt *endpt;
1349 struct nc_bind *bind;
1350 int ret = 0;
1351
1352 (void) op;
1353
1354 assert(!strcmp(LYD_NAME(node), "local-address"));
1355
Michal Vaskocf898172024-01-15 15:04:28 +01001356 if (equal_parent_name(node, 5, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001357 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001358 ret = 1;
1359 goto cleanup;
1360 }
1361
roman6430c152023-10-12 11:28:47 +02001362 free(bind->address);
romanc1d2b092023-02-02 08:58:27 +01001363 bind->address = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001364 NC_CHECK_ERRMEM_GOTO(!bind->address, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01001365
romanfb3f7cf2023-11-30 16:10:09 +01001366 ret = nc_server_set_address_port(endpt, bind, lyd_get_value(node), 0);
romanc1d2b092023-02-02 08:58:27 +01001367 if (ret) {
1368 goto cleanup;
1369 }
1370 }
1371
1372cleanup:
1373 return ret;
1374}
1375
1376/* leaf with default value */
1377static int
romane028ef92023-02-24 16:33:08 +01001378nc_server_config_local_port(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001379{
1380 struct nc_endpt *endpt;
1381 struct nc_bind *bind;
1382 int ret = 0;
1383
1384 assert(!strcmp(LYD_NAME(node), "local-port"));
1385
Michal Vaskocf898172024-01-15 15:04:28 +01001386 if (equal_parent_name(node, 5, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001387 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001388 ret = 1;
1389 goto cleanup;
1390 }
1391
1392 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001393 bind->port = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001394 } else {
1395 /* delete -> set to default */
1396 bind->port = 0;
1397 }
1398
romanfb3f7cf2023-11-30 16:10:09 +01001399 ret = nc_server_set_address_port(endpt, bind, NULL, bind->port);
romanc1d2b092023-02-02 08:58:27 +01001400 if (ret) {
1401 goto cleanup;
1402 }
1403 }
1404
1405cleanup:
1406 return ret;
1407}
1408
Michal Vaskocf898172024-01-15 15:04:28 +01001409/* NP container */
romanc1d2b092023-02-02 08:58:27 +01001410static int
romane028ef92023-02-24 16:33:08 +01001411nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001412{
roman5cbb6532023-06-22 12:53:17 +02001413 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001414 struct nc_endpt *endpt;
1415 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001416 struct nc_ch_endpt *ch_endpt;
roman6cb86ea2023-11-08 15:12:05 +01001417 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001418
1419 assert(!strcmp(LYD_NAME(node), "keepalives"));
1420
roman5cbb6532023-06-22 12:53:17 +02001421 if (is_listen(node) && equal_parent_name(node, 1, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001422 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001423 ret = 1;
1424 goto cleanup;
1425 }
1426
1427 if (op == NC_OP_CREATE) {
1428 endpt->ka.enabled = 1;
1429 } else {
1430 endpt->ka.enabled = 0;
1431 }
roman5cbb6532023-06-22 12:53:17 +02001432 } else if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001433 /* LOCK */
1434 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001435 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001436 return 1;
1437 }
1438
roman8341e8b2023-11-23 16:12:42 +01001439 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001440 ret = 1;
1441 goto cleanup;
1442 }
1443
1444 if (op == NC_OP_CREATE) {
1445 ch_endpt->ka.enabled = 1;
1446 } else {
1447 ch_endpt->ka.enabled = 0;
1448 }
romanc1d2b092023-02-02 08:58:27 +01001449 }
1450
1451cleanup:
romanba93eac2023-07-18 14:36:48 +02001452 if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) {
1453 /* UNLOCK */
1454 nc_ch_client_unlock(ch_client);
1455 }
romanc1d2b092023-02-02 08:58:27 +01001456 return ret;
1457}
1458
Michal Vaskocf898172024-01-15 15:04:28 +01001459/* leaf with default value */
romanc1d2b092023-02-02 08:58:27 +01001460static int
romane028ef92023-02-24 16:33:08 +01001461nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001462{
roman5cbb6532023-06-22 12:53:17 +02001463 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001464 struct nc_endpt *endpt;
1465 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001466 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001467 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001468
1469 assert(!strcmp(LYD_NAME(node), "idle-time"));
1470
roman5cbb6532023-06-22 12:53:17 +02001471 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001472 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001473 ret = 1;
1474 goto cleanup;
1475 }
1476
1477 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001478 endpt->ka.idle_time = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001479 } else {
Michal Vaskocf898172024-01-15 15:04:28 +01001480 /* delete -> set to default */
1481 endpt->ka.idle_time = 7200;
romanc1d2b092023-02-02 08:58:27 +01001482 }
roman5cbb6532023-06-22 12:53:17 +02001483 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001484 /* LOCK */
1485 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001486 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001487 return 1;
1488 }
1489
roman8341e8b2023-11-23 16:12:42 +01001490 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001491 ret = 1;
1492 goto cleanup;
1493 }
1494
1495 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001496 ch_endpt->ka.idle_time = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001497 } else {
Michal Vaskocf898172024-01-15 15:04:28 +01001498 /* delete -> set to default */
1499 ch_endpt->ka.idle_time = 7200;
roman5cbb6532023-06-22 12:53:17 +02001500 }
romanc1d2b092023-02-02 08:58:27 +01001501 }
1502
1503cleanup:
roman6430c152023-10-12 11:28:47 +02001504 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001505 /* UNLOCK */
1506 nc_ch_client_unlock(ch_client);
1507 }
romanc1d2b092023-02-02 08:58:27 +01001508 return ret;
1509}
1510
Michal Vaskocf898172024-01-15 15:04:28 +01001511/* leaf with default value */
romanc1d2b092023-02-02 08:58:27 +01001512static int
romane028ef92023-02-24 16:33:08 +01001513nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001514{
roman5cbb6532023-06-22 12:53:17 +02001515 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001516 struct nc_endpt *endpt;
1517 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001518 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001519 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001520
1521 assert(!strcmp(LYD_NAME(node), "max-probes"));
1522
roman5cbb6532023-06-22 12:53:17 +02001523 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001524 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001525 ret = 1;
1526 goto cleanup;
1527 }
1528
1529 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001530 endpt->ka.max_probes = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001531 } else {
Michal Vaskocf898172024-01-15 15:04:28 +01001532 /* delete -> set to default */
1533 endpt->ka.max_probes = 9;
romanc1d2b092023-02-02 08:58:27 +01001534 }
roman5cbb6532023-06-22 12:53:17 +02001535 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001536 /* LOCK */
1537 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001538 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001539 return 1;
1540 }
1541
roman8341e8b2023-11-23 16:12:42 +01001542 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001543 ret = 1;
1544 goto cleanup;
1545 }
1546
1547 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001548 ch_endpt->ka.max_probes = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001549 } else {
Michal Vaskocf898172024-01-15 15:04:28 +01001550 /* delete -> set to default */
1551 ch_endpt->ka.max_probes = 9;
roman5cbb6532023-06-22 12:53:17 +02001552 }
romanc1d2b092023-02-02 08:58:27 +01001553 }
1554
1555cleanup:
roman6430c152023-10-12 11:28:47 +02001556 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001557 /* UNLOCK */
1558 nc_ch_client_unlock(ch_client);
1559 }
romanc1d2b092023-02-02 08:58:27 +01001560 return ret;
1561}
1562
Michal Vaskocf898172024-01-15 15:04:28 +01001563/* leaf with default value */
romanc1d2b092023-02-02 08:58:27 +01001564static int
romane028ef92023-02-24 16:33:08 +01001565nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001566{
roman5cbb6532023-06-22 12:53:17 +02001567 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001568 struct nc_endpt *endpt;
1569 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001570 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001571 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001572
1573 assert(!strcmp(LYD_NAME(node), "probe-interval"));
1574
roman5cbb6532023-06-22 12:53:17 +02001575 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001576 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001577 ret = 1;
1578 goto cleanup;
1579 }
1580
1581 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001582 endpt->ka.probe_interval = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001583 } else {
Michal Vaskocf898172024-01-15 15:04:28 +01001584 /* delete -> set to default */
1585 endpt->ka.probe_interval = 75;
romanc1d2b092023-02-02 08:58:27 +01001586 }
roman5cbb6532023-06-22 12:53:17 +02001587 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001588 /* LOCK */
1589 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001590 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001591 return 1;
1592 }
1593
roman8341e8b2023-11-23 16:12:42 +01001594 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001595 ret = 1;
1596 goto cleanup;
1597 }
1598
1599 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001600 ch_endpt->ka.probe_interval = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001601 } else {
Michal Vaskocf898172024-01-15 15:04:28 +01001602 /* delete -> set to default */
1603 ch_endpt->ka.probe_interval = 75;
roman5cbb6532023-06-22 12:53:17 +02001604 }
romanc1d2b092023-02-02 08:58:27 +01001605 }
1606
1607cleanup:
roman6430c152023-10-12 11:28:47 +02001608 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001609 /* UNLOCK */
1610 nc_ch_client_unlock(ch_client);
1611 }
romanc1d2b092023-02-02 08:58:27 +01001612 return ret;
1613}
1614
1615static int
roman874fed12023-05-25 10:20:01 +02001616nc_server_config_create_host_key(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01001617{
romanf02273a2023-05-25 09:44:11 +02001618 node = lyd_child(node);
1619 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01001620
romanf02273a2023-05-25 09:44:11 +02001621 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->hostkeys, sizeof *opts->hostkeys, &opts->hostkey_count);
romanc1d2b092023-02-02 08:58:27 +01001622}
1623
1624/* list */
1625static int
romane028ef92023-02-24 16:33:08 +01001626nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001627{
roman5cbb6532023-06-22 12:53:17 +02001628 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001629 struct nc_hostkey *hostkey;
roman4cb8bb12023-06-29 09:16:46 +02001630 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01001631 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001632
1633 assert(!strcmp(LYD_NAME(node), "host-key"));
1634
roman4cb8bb12023-06-29 09:16:46 +02001635 if (equal_parent_name(node, 1, "server-identity")) {
romanba93eac2023-07-18 14:36:48 +02001636 /* LOCK */
1637 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001638 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001639 return 1;
1640 }
1641
roman8341e8b2023-11-23 16:12:42 +01001642 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman6cb86ea2023-11-08 15:12:05 +01001643 ret = 1;
1644 goto cleanup;
1645 }
1646
romanc1d2b092023-02-02 08:58:27 +01001647 if (op == NC_OP_CREATE) {
roman4cb8bb12023-06-29 09:16:46 +02001648 ret = nc_server_config_create_host_key(node, opts);
romanc1d2b092023-02-02 08:58:27 +01001649 if (ret) {
1650 goto cleanup;
1651 }
1652 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01001653 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001654 ret = 1;
1655 goto cleanup;
1656 }
roman4cb8bb12023-06-29 09:16:46 +02001657 nc_server_config_del_hostkey(opts, hostkey);
roman5cbb6532023-06-22 12:53:17 +02001658 }
romanc1d2b092023-02-02 08:58:27 +01001659 }
1660
1661cleanup:
romanba93eac2023-07-18 14:36:48 +02001662 if (is_ch(node) && equal_parent_name(node, 1, "server-identity")) {
1663 /* UNLOCK */
1664 nc_ch_client_unlock(ch_client);
1665 }
romanc1d2b092023-02-02 08:58:27 +01001666 return ret;
1667}
1668
1669/* mandatory leaf */
romane028ef92023-02-24 16:33:08 +01001670static int
1671nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001672{
roman3f9b65c2023-06-05 14:26:58 +02001673 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02001674 const char *format;
roman3f9b65c2023-06-05 14:26:58 +02001675 NC_PUBKEY_FORMAT pubkey_type;
roman8edee342023-03-31 13:25:48 +02001676 struct nc_public_key *pubkey;
romanc1d2b092023-02-02 08:58:27 +01001677 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02001678 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01001679 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001680
1681 assert(!strcmp(LYD_NAME(node), "public-key-format"));
1682
roman6cb86ea2023-11-08 15:12:05 +01001683 /* LOCK */
1684 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
1685 /* to avoid unlock on fail */
1686 return 1;
1687 }
1688
romanc1d2b092023-02-02 08:58:27 +01001689 format = ((struct lyd_node_term *)node)->value.ident->name;
roman3f9b65c2023-06-05 14:26:58 +02001690 if (!strcmp(format, "ssh-public-key-format")) {
roman13145912023-08-17 15:36:54 +02001691 pubkey_type = NC_PUBKEY_FORMAT_SSH;
roman3f9b65c2023-06-05 14:26:58 +02001692 } else if (!strcmp(format, "subject-public-key-info-format")) {
1693 pubkey_type = NC_PUBKEY_FORMAT_X509;
1694 } else {
1695 ERR(NULL, "Public key format (%s) not supported.", format);
1696 ret = 1;
1697 goto cleanup;
1698 }
romanc1d2b092023-02-02 08:58:27 +01001699
roman4cb8bb12023-06-29 09:16:46 +02001700 if (is_ssh(node) && equal_parent_name(node, 4, "server-identity")) {
roman5cbb6532023-06-22 12:53:17 +02001701 /* SSH hostkey public key fmt */
roman8341e8b2023-11-23 16:12:42 +01001702 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02001703 ret = 1;
1704 goto cleanup;
1705 }
1706
1707 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1708 hostkey->key.pubkey_type = pubkey_type;
1709 }
roman4cb8bb12023-06-29 09:16:46 +02001710 } else if (is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) {
roman5cbb6532023-06-22 12:53:17 +02001711 /* SSH client auth public key fmt */
roman8341e8b2023-11-23 16:12:42 +01001712 if (nc_server_config_get_pubkey(node, ch_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001713 ret = 1;
1714 goto cleanup;
1715 }
1716
1717 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman3f9b65c2023-06-05 14:26:58 +02001718 pubkey->type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001719 }
romanb6f44032023-06-30 15:07:56 +02001720 } else if (is_tls(node) && equal_parent_name(node, 3, "server-identity")) {
1721 /* TLS server-identity */
roman8341e8b2023-11-23 16:12:42 +01001722 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02001723 ret = 1;
1724 goto cleanup;
1725 }
1726
roman5cbb6532023-06-22 12:53:17 +02001727 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02001728 opts->pubkey_type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001729 }
romanc1d2b092023-02-02 08:58:27 +01001730 }
1731
1732cleanup:
romanba93eac2023-07-18 14:36:48 +02001733 if (is_ch(node)) {
1734 /* UNLOCK */
1735 nc_ch_client_unlock(ch_client);
1736 }
romanc1d2b092023-02-02 08:58:27 +01001737 return ret;
1738}
1739
1740static int
roman58f79d02023-10-06 10:20:31 +02001741nc_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 +01001742{
romanc1d2b092023-02-02 08:58:27 +01001743 assert(!strcmp(LYD_NAME(node), "public-key"));
1744
romanc1d2b092023-02-02 08:58:27 +01001745 node = lyd_child(node);
1746 assert(!strcmp(LYD_NAME(node), "name"));
1747
Michal Vaskocf898172024-01-15 15:04:28 +01001748 return nc_server_config_realloc(lyd_get_value(node), (void **)&auth_client->pubkeys, sizeof *auth_client->pubkeys,
1749 &auth_client->pubkey_count);
romanc1d2b092023-02-02 08:58:27 +01001750}
1751
1752static int
roman874fed12023-05-25 10:20:01 +02001753nc_server_config_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +01001754{
roman6430c152023-10-12 11:28:47 +02001755 free(pubkey->data);
roman3f9b65c2023-06-05 14:26:58 +02001756 pubkey->data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001757 NC_CHECK_ERRMEM_RET(!pubkey->data, 1);
romanc1d2b092023-02-02 08:58:27 +01001758
1759 return 0;
1760}
1761
1762static int
roman874fed12023-05-25 10:20:01 +02001763nc_server_config_replace_host_key_public_key(const struct lyd_node *node, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +01001764{
roman6430c152023-10-12 11:28:47 +02001765 free(hostkey->key.pubkey_data);
roman3f9b65c2023-06-05 14:26:58 +02001766 hostkey->key.pubkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001767 NC_CHECK_ERRMEM_RET(!hostkey->key.pubkey_data, 1);
romanc1d2b092023-02-02 08:58:27 +01001768
1769 return 0;
1770}
1771
roman3f9b65c2023-06-05 14:26:58 +02001772static int
1773nc_server_config_tls_replace_server_public_key(const struct lyd_node *node, struct nc_server_tls_opts *opts)
1774{
roman6430c152023-10-12 11:28:47 +02001775 free(opts->pubkey_data);
roman3f9b65c2023-06-05 14:26:58 +02001776 opts->pubkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001777 NC_CHECK_ERRMEM_RET(!opts->pubkey_data, 1);
roman3f9b65c2023-06-05 14:26:58 +02001778
1779 return 0;
1780}
1781
romanc1d2b092023-02-02 08:58:27 +01001782static int
romane028ef92023-02-24 16:33:08 +01001783nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001784{
roman3f9b65c2023-06-05 14:26:58 +02001785 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001786 struct nc_hostkey *hostkey;
roman58f79d02023-10-06 10:20:31 +02001787 struct nc_auth_client *auth_client;
roman8edee342023-03-31 13:25:48 +02001788 struct nc_public_key *pubkey;
romanb6f44032023-06-30 15:07:56 +02001789 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01001790 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001791
1792 assert(!strcmp(LYD_NAME(node), "public-key"));
1793
romanba93eac2023-07-18 14:36:48 +02001794 /* LOCK */
1795 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02001796 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001797 return 1;
1798 }
1799
roman4cb8bb12023-06-29 09:16:46 +02001800 if (is_ssh(node) && equal_parent_name(node, 3, "host-key")) {
roman3f9b65c2023-06-05 14:26:58 +02001801 /* server's public-key, mandatory leaf */
roman8341e8b2023-11-23 16:12:42 +01001802 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001803 ret = 1;
1804 goto cleanup;
1805 }
1806
roman13145912023-08-17 15:36:54 +02001807 /* the public key must not be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
roman51a1e192023-09-14 10:13:45 +02001808 if (nc_is_pk_subject_public_key_info(lyd_get_value(node))) {
roman13145912023-08-17 15:36:54 +02001809 ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH hostkey is forbidden!");
1810 ret = 1;
1811 goto cleanup;
1812 }
1813
romanc1d2b092023-02-02 08:58:27 +01001814 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02001815 /* set to local */
roman874fed12023-05-25 10:20:01 +02001816 hostkey->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02001817
roman874fed12023-05-25 10:20:01 +02001818 ret = nc_server_config_replace_host_key_public_key(node, hostkey);
romanc1d2b092023-02-02 08:58:27 +01001819 if (ret) {
1820 goto cleanup;
1821 }
1822 }
roman4cb8bb12023-06-29 09:16:46 +02001823 } else if (is_ssh(node) && equal_parent_name(node, 5, "client-authentication")) {
romanc1d2b092023-02-02 08:58:27 +01001824 /* client auth pubkeys, list */
roman8341e8b2023-11-23 16:12:42 +01001825 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001826 ret = 1;
1827 goto cleanup;
1828 }
1829
1830 if (op == NC_OP_CREATE) {
romanf02273a2023-05-25 09:44:11 +02001831 /* set to local */
roman874fed12023-05-25 10:20:01 +02001832 auth_client->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02001833
roman874fed12023-05-25 10:20:01 +02001834 ret = nc_server_config_create_auth_key_public_key_list(node, auth_client);
romanc1d2b092023-02-02 08:58:27 +01001835 if (ret) {
1836 goto cleanup;
1837 }
1838 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01001839 if (nc_server_config_get_pubkey(node, ch_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001840 ret = 1;
1841 goto cleanup;
1842 }
1843
roman874fed12023-05-25 10:20:01 +02001844 nc_server_config_del_auth_client_pubkey(auth_client, pubkey);
romanc1d2b092023-02-02 08:58:27 +01001845 }
roman4cb8bb12023-06-29 09:16:46 +02001846 } else if (is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) {
romanc1d2b092023-02-02 08:58:27 +01001847 /* client auth pubkey, leaf */
roman8341e8b2023-11-23 16:12:42 +01001848 if (nc_server_config_get_pubkey(node, ch_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001849 ret = 1;
1850 goto cleanup;
1851 }
1852
roman13145912023-08-17 15:36:54 +02001853 /* the public key must not be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
roman51a1e192023-09-14 10:13:45 +02001854 if (nc_is_pk_subject_public_key_info(lyd_get_value(node))) {
roman13145912023-08-17 15:36:54 +02001855 ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH user's key is forbidden!");
1856 ret = 1;
1857 goto cleanup;
1858 }
1859
romanc1d2b092023-02-02 08:58:27 +01001860 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02001861 ret = nc_server_config_replace_auth_key_public_key_leaf(node, pubkey);
romanc1d2b092023-02-02 08:58:27 +01001862 if (ret) {
1863 goto cleanup;
1864 }
roman6430c152023-10-12 11:28:47 +02001865 } else if (op == NC_OP_DELETE) {
1866 free(pubkey->data);
1867 pubkey->data = NULL;
romanc1d2b092023-02-02 08:58:27 +01001868 }
romanb6f44032023-06-30 15:07:56 +02001869 } else if (is_tls(node) && equal_parent_name(node, 3, "server-identity")) {
1870 /* TLS server-identity */
roman8341e8b2023-11-23 16:12:42 +01001871 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02001872 ret = 1;
1873 goto cleanup;
1874 }
1875
roman13145912023-08-17 15:36:54 +02001876 /* the public key must be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
roman51a1e192023-09-14 10:13:45 +02001877 if (!nc_is_pk_subject_public_key_info(lyd_get_value(node))) {
roman13145912023-08-17 15:36:54 +02001878 ERR(NULL, "TLS server certificate's Public Key must be in the SubjectPublicKeyInfo format!");
1879 ret = 1;
1880 goto cleanup;
1881 }
1882
roman3f9b65c2023-06-05 14:26:58 +02001883 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1884 /* set to local */
romanb6f44032023-06-30 15:07:56 +02001885 opts->store = NC_STORE_LOCAL;
roman3f9b65c2023-06-05 14:26:58 +02001886
romanb6f44032023-06-30 15:07:56 +02001887 ret = nc_server_config_tls_replace_server_public_key(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02001888 if (ret) {
1889 goto cleanup;
1890 }
1891 }
roman5cbb6532023-06-22 12:53:17 +02001892 }
1893
1894cleanup:
romanba93eac2023-07-18 14:36:48 +02001895 if (is_ch(node)) {
1896 /* UNLOCK */
1897 nc_ch_client_unlock(ch_client);
1898 }
roman5cbb6532023-06-22 12:53:17 +02001899 return ret;
1900}
1901
1902/* leaf */
1903static int
1904nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op)
1905{
1906 int ret = 0;
1907 const char *format;
1908 NC_PRIVKEY_FORMAT privkey_type;
roman5cbb6532023-06-22 12:53:17 +02001909 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02001910 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01001911 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02001912
1913 (void) op;
1914
1915 assert(!strcmp(LYD_NAME(node), "private-key-format"));
1916
roman6cb86ea2023-11-08 15:12:05 +01001917 /* LOCK */
1918 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
1919 /* to avoid unlock on fail */
1920 return 1;
1921 }
1922
roman5cbb6532023-06-22 12:53:17 +02001923 format = ((struct lyd_node_term *)node)->value.ident->name;
1924 if (!format) {
1925 ret = 1;
1926 goto cleanup;
1927 }
1928
1929 privkey_type = nc_server_config_get_private_key_type(format);
1930 if (privkey_type == NC_PRIVKEY_FORMAT_UNKNOWN) {
1931 ERR(NULL, "Unknown private key format.");
1932 ret = 1;
1933 goto cleanup;
1934 }
1935
roman4cb8bb12023-06-29 09:16:46 +02001936 if (is_ssh(node)) {
1937 /* ssh */
roman8341e8b2023-11-23 16:12:42 +01001938 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02001939 ret = 1;
1940 goto cleanup;
1941 }
1942
1943 hostkey->key.privkey_type = privkey_type;
romanb6f44032023-06-30 15:07:56 +02001944 } else if (is_tls(node)) {
1945 /* tls */
roman8341e8b2023-11-23 16:12:42 +01001946 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman5cbb6532023-06-22 12:53:17 +02001947 ret = 1;
1948 goto cleanup;
1949 }
1950
romanb6f44032023-06-30 15:07:56 +02001951 opts->privkey_type = privkey_type;
roman5cbb6532023-06-22 12:53:17 +02001952 }
1953
1954cleanup:
romanba93eac2023-07-18 14:36:48 +02001955 if (is_ch(node)) {
1956 /* UNLOCK */
1957 nc_ch_client_unlock(ch_client);
1958 }
roman5cbb6532023-06-22 12:53:17 +02001959 return ret;
1960}
1961
1962static int
roman5cbb6532023-06-22 12:53:17 +02001963nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op)
1964{
1965 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02001966 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02001967 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01001968 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02001969
1970 assert(!strcmp(LYD_NAME(node), "cleartext-private-key"));
1971
romanba93eac2023-07-18 14:36:48 +02001972 /* LOCK */
1973 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001974 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001975 return 1;
1976 }
1977
roman4cb8bb12023-06-29 09:16:46 +02001978 if (is_ssh(node)) {
1979 /* ssh */
roman8341e8b2023-11-23 16:12:42 +01001980 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02001981 ret = 1;
1982 goto cleanup;
1983 }
1984
1985 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02001986 free(hostkey->key.privkey_data);
1987 hostkey->key.privkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001988 NC_CHECK_ERRMEM_GOTO(!hostkey->key.privkey_data, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02001989 } else {
roman6430c152023-10-12 11:28:47 +02001990 free(hostkey->key.privkey_data);
1991 hostkey->key.privkey_data = NULL;
roman5cbb6532023-06-22 12:53:17 +02001992 }
romanb6f44032023-06-30 15:07:56 +02001993 } else if (is_tls(node)) {
1994 /* tls */
roman8341e8b2023-11-23 16:12:42 +01001995 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02001996 ret = 1;
1997 goto cleanup;
1998 }
1999
roman5cbb6532023-06-22 12:53:17 +02002000 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002001 free(opts->privkey_data);
2002 opts->privkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002003 NC_CHECK_ERRMEM_GOTO(!opts->privkey_data, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02002004 } else {
roman6430c152023-10-12 11:28:47 +02002005 free(opts->privkey_data);
2006 opts->privkey_data = NULL;
roman5cbb6532023-06-22 12:53:17 +02002007 }
roman5cbb6532023-06-22 12:53:17 +02002008 }
2009
2010cleanup:
romanba93eac2023-07-18 14:36:48 +02002011 if (is_ch(node)) {
2012 /* UNLOCK */
2013 nc_ch_client_unlock(ch_client);
2014 }
roman5cbb6532023-06-22 12:53:17 +02002015 return ret;
2016}
2017
roman5cbb6532023-06-22 12:53:17 +02002018/* leaf */
2019static int
2020nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op)
2021{
2022 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02002023 struct nc_hostkey *hostkey;
roman8341e8b2023-11-23 16:12:42 +01002024 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02002025
Michal Vaskocf898172024-01-15 15:04:28 +01002026 assert(!strcmp(LYD_NAME(node), "central-keystore-reference"));
roman5cbb6532023-06-22 12:53:17 +02002027
romanba93eac2023-07-18 14:36:48 +02002028 /* LOCK */
2029 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002030 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002031 return 1;
2032 }
2033
roman4cb8bb12023-06-29 09:16:46 +02002034 if (is_ssh(node) && equal_parent_name(node, 3, "server-identity")) {
roman8341e8b2023-11-23 16:12:42 +01002035 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02002036 ret = 1;
2037 goto cleanup;
2038 }
2039
2040 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2041 /* set to keystore */
2042 hostkey->store = NC_STORE_KEYSTORE;
2043
roman6430c152023-10-12 11:28:47 +02002044 free(hostkey->ks_ref);
romandd019a92023-09-14 10:17:07 +02002045 hostkey->ks_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002046 NC_CHECK_ERRMEM_GOTO(!hostkey->ks_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002047 } else if (op == NC_OP_DELETE) {
2048 free(hostkey->ks_ref);
roman5cbb6532023-06-22 12:53:17 +02002049 hostkey->ks_ref = NULL;
2050 }
roman3f9b65c2023-06-05 14:26:58 +02002051 }
romanc1d2b092023-02-02 08:58:27 +01002052
2053cleanup:
romanba93eac2023-07-18 14:36:48 +02002054 if (is_ch(node)) {
2055 /* UNLOCK */
2056 nc_ch_client_unlock(ch_client);
2057 }
romanc1d2b092023-02-02 08:58:27 +01002058 return ret;
2059}
2060
2061static int
roman6430c152023-10-12 11:28:47 +02002062nc_server_config_create_auth_client(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01002063{
romanf02273a2023-05-25 09:44:11 +02002064 node = lyd_child(node);
2065 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01002066
romanf02273a2023-05-25 09:44:11 +02002067 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 +01002068}
2069
2070/* list */
2071static int
romane028ef92023-02-24 16:33:08 +01002072nc_server_config_user(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002073{
roman5cbb6532023-06-22 12:53:17 +02002074 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002075 struct nc_auth_client *auth_client;
roman4cb8bb12023-06-29 09:16:46 +02002076 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002077 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002078
2079 assert(!strcmp(LYD_NAME(node), "user"));
2080
romanba93eac2023-07-18 14:36:48 +02002081 /* LOCK */
2082 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002083 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002084 return 1;
2085 }
2086
roman8341e8b2023-11-23 16:12:42 +01002087 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002088 ret = 1;
2089 goto cleanup;
2090 }
2091
2092 if (op == NC_OP_CREATE) {
roman6430c152023-10-12 11:28:47 +02002093 ret = nc_server_config_create_auth_client(node, opts);
roman4cb8bb12023-06-29 09:16:46 +02002094 if (ret) {
2095 goto cleanup;
2096 }
2097 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01002098 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002099 ret = 1;
2100 goto cleanup;
2101 }
2102
roman4cb8bb12023-06-29 09:16:46 +02002103 nc_server_config_del_auth_client(opts, auth_client);
romanc1d2b092023-02-02 08:58:27 +01002104 }
2105
2106cleanup:
romanba93eac2023-07-18 14:36:48 +02002107 if (is_ch(node)) {
2108 /* UNLOCK */
2109 nc_ch_client_unlock(ch_client);
2110 }
romanc1d2b092023-02-02 08:58:27 +01002111 return ret;
2112}
2113
2114static int
romane028ef92023-02-24 16:33:08 +01002115nc_server_config_auth_attempts(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002116{
romanc1d2b092023-02-02 08:58:27 +01002117 int ret = 0;
roman4cb8bb12023-06-29 09:16:46 +02002118 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002119 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002120
2121 assert(!strcmp(LYD_NAME(node), "auth-attempts"));
2122
romanba93eac2023-07-18 14:36:48 +02002123 /* LOCK */
2124 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002125 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002126 return 1;
2127 }
2128
roman8341e8b2023-11-23 16:12:42 +01002129 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002130 ret = 1;
2131 goto cleanup;
2132 }
romanc1d2b092023-02-02 08:58:27 +01002133
roman4cb8bb12023-06-29 09:16:46 +02002134 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02002135 opts->auth_attempts = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01002136 }
2137
2138cleanup:
romanba93eac2023-07-18 14:36:48 +02002139 if (is_ch(node)) {
2140 /* UNLOCK */
2141 nc_ch_client_unlock(ch_client);
2142 }
romanc1d2b092023-02-02 08:58:27 +01002143 return ret;
2144}
2145
2146static int
romane028ef92023-02-24 16:33:08 +01002147nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002148{
romanc1d2b092023-02-02 08:58:27 +01002149 int ret = 0;
roman4cb8bb12023-06-29 09:16:46 +02002150 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002151 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002152
2153 assert(!strcmp(LYD_NAME(node), "auth-timeout"));
2154
romanba93eac2023-07-18 14:36:48 +02002155 /* LOCK */
2156 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002157 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002158 return 1;
2159 }
2160
roman8341e8b2023-11-23 16:12:42 +01002161 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002162 ret = 1;
2163 goto cleanup;
2164 }
romanc1d2b092023-02-02 08:58:27 +01002165
roman4cb8bb12023-06-29 09:16:46 +02002166 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02002167 opts->auth_timeout = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01002168 }
2169
2170cleanup:
romanba93eac2023-07-18 14:36:48 +02002171 if (is_ch(node)) {
2172 /* UNLOCK */
2173 nc_ch_client_unlock(ch_client);
2174 }
romanc1d2b092023-02-02 08:58:27 +01002175 return ret;
2176}
2177
romanc1d2b092023-02-02 08:58:27 +01002178/* leaf */
2179static int
romane028ef92023-02-24 16:33:08 +01002180nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002181{
romanc1d2b092023-02-02 08:58:27 +01002182 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002183 struct nc_auth_client *auth_client;
roman8341e8b2023-11-23 16:12:42 +01002184 struct nc_ch_client *ch_client = NULL;
roman6430c152023-10-12 11:28:47 +02002185 struct nc_server_tls_opts *opts;
2186 struct nc_cert_grouping *certs_grp;
romanc1d2b092023-02-02 08:58:27 +01002187
Michal Vaskocf898172024-01-15 15:04:28 +01002188 assert(!strcmp(LYD_NAME(node), "central-truststore-reference"));
romanc1d2b092023-02-02 08:58:27 +01002189
romanba93eac2023-07-18 14:36:48 +02002190 /* LOCK */
2191 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002192 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002193 return 1;
2194 }
2195
roman4cb8bb12023-06-29 09:16:46 +02002196 if (is_ssh(node) && equal_parent_name(node, 1, "public-keys")) {
roman8341e8b2023-11-23 16:12:42 +01002197 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002198 ret = 1;
2199 goto cleanup;
2200 }
2201
2202 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02002203 /* set to truststore */
roman874fed12023-05-25 10:20:01 +02002204 auth_client->store = NC_STORE_TRUSTSTORE;
romanf02273a2023-05-25 09:44:11 +02002205
roman6430c152023-10-12 11:28:47 +02002206 free(auth_client->ts_ref);
2207 auth_client->ts_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002208 NC_CHECK_ERRMEM_GOTO(!auth_client->ts_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002209 } else if (op == NC_OP_DELETE) {
2210 free(auth_client->ts_ref);
romand57b3722023-04-05 11:26:25 +02002211 auth_client->ts_ref = NULL;
romanc1d2b092023-02-02 08:58:27 +01002212 }
roman6430c152023-10-12 11:28:47 +02002213 } else if (is_tls(node) && (equal_parent_name(node, 1, "ca-certs") || equal_parent_name(node, 1, "ee-certs"))) {
2214 /* ee-certs or ca-certs */
roman8341e8b2023-11-23 16:12:42 +01002215 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002216 ret = 1;
2217 goto cleanup;
2218 }
2219
roman6430c152023-10-12 11:28:47 +02002220 if (equal_parent_name(node, 1, "ca-certs")) {
2221 certs_grp = &opts->ca_certs;
roman3f9b65c2023-06-05 14:26:58 +02002222 } else {
roman6430c152023-10-12 11:28:47 +02002223 certs_grp = &opts->ee_certs;
roman4cb8bb12023-06-29 09:16:46 +02002224 }
2225
roman3f9b65c2023-06-05 14:26:58 +02002226 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2227 /* set to truststore */
roman6430c152023-10-12 11:28:47 +02002228 certs_grp->store = NC_STORE_TRUSTSTORE;
roman3f9b65c2023-06-05 14:26:58 +02002229
roman6430c152023-10-12 11:28:47 +02002230 free(certs_grp->ts_ref);
2231 certs_grp->ts_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002232 NC_CHECK_ERRMEM_GOTO(!certs_grp->ts_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002233 } else if (op == NC_OP_DELETE) {
2234 free(certs_grp->ts_ref);
2235 certs_grp->ts_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002236 }
2237 }
romanc1d2b092023-02-02 08:58:27 +01002238
2239cleanup:
romanba93eac2023-07-18 14:36:48 +02002240 if (is_ch(node)) {
2241 /* UNLOCK */
2242 nc_ch_client_unlock(ch_client);
2243 }
romanc1d2b092023-02-02 08:58:27 +01002244 return ret;
2245}
2246
romana9ec3362023-12-21 10:59:57 +01002247static int
2248nc_server_config_use_system_keys(const struct lyd_node *node, NC_OPERATION op)
2249{
2250 int ret = 0;
2251 struct nc_auth_client *auth_client;
2252 struct nc_ch_client *ch_client = NULL;
2253
2254 assert(!strcmp(LYD_NAME(node), "use-system-keys"));
2255
2256 /* LOCK */
2257 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
2258 /* to avoid unlock on fail */
2259 return 1;
2260 }
2261
2262 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
2263 ret = 1;
2264 goto cleanup;
2265 }
2266
2267 if (op == NC_OP_CREATE) {
2268 auth_client->store = NC_STORE_SYSTEM;
2269 }
2270
2271cleanup:
2272 if (is_ch(node)) {
2273 /* UNLOCK */
2274 nc_ch_client_unlock(ch_client);
2275 }
2276 return ret;
2277}
2278
romanc1d2b092023-02-02 08:58:27 +01002279/* leaf */
2280static int
romane028ef92023-02-24 16:33:08 +01002281nc_server_config_password(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002282{
roman5cbb6532023-06-22 12:53:17 +02002283 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002284 struct nc_auth_client *auth_client;
roman8341e8b2023-11-23 16:12:42 +01002285 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002286
2287 assert(!strcmp(LYD_NAME(node), "password"));
2288
romanba93eac2023-07-18 14:36:48 +02002289 /* LOCK */
2290 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002291 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002292 return 1;
2293 }
2294
roman8341e8b2023-11-23 16:12:42 +01002295 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
roman4cb8bb12023-06-29 09:16:46 +02002296 ret = 1;
2297 goto cleanup;
2298 }
2299
2300 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002301 free(auth_client->password);
2302 auth_client->password = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002303 NC_CHECK_ERRMEM_GOTO(!auth_client->password, ret = 1, cleanup);
roman4cb8bb12023-06-29 09:16:46 +02002304 } else {
roman6430c152023-10-12 11:28:47 +02002305 free(auth_client->password);
2306 auth_client->password = NULL;
romanc1d2b092023-02-02 08:58:27 +01002307 }
2308
2309cleanup:
romanba93eac2023-07-18 14:36:48 +02002310 if (is_ch(node)) {
2311 /* UNLOCK */
2312 nc_ch_client_unlock(ch_client);
2313 }
romanc1d2b092023-02-02 08:58:27 +01002314 return ret;
2315}
2316
2317static int
romanc6518422023-11-30 16:39:00 +01002318nc_server_config_use_system_auth(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002319{
roman5cbb6532023-06-22 12:53:17 +02002320 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002321 struct nc_auth_client *auth_client;
roman808f3f62023-11-23 16:01:04 +01002322 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002323
romanc6518422023-11-30 16:39:00 +01002324 assert(!strcmp(LYD_NAME(node), "use-system-auth"));
romanc1d2b092023-02-02 08:58:27 +01002325
romanba93eac2023-07-18 14:36:48 +02002326 /* LOCK */
2327 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002328 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002329 return 1;
2330 }
2331
roman8341e8b2023-11-23 16:12:42 +01002332 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
roman4cb8bb12023-06-29 09:16:46 +02002333 ret = 1;
2334 goto cleanup;
2335 }
2336
roman808f3f62023-11-23 16:01:04 +01002337 if (op == NC_OP_CREATE) {
2338 auth_client->kb_int_enabled = 1;
roman4cb8bb12023-06-29 09:16:46 +02002339 } else {
roman808f3f62023-11-23 16:01:04 +01002340 auth_client->kb_int_enabled = 0;
romanc1d2b092023-02-02 08:58:27 +01002341 }
2342
2343cleanup:
romanba93eac2023-07-18 14:36:48 +02002344 if (is_ch(node)) {
2345 /* UNLOCK */
2346 nc_ch_client_unlock(ch_client);
2347 }
romanc1d2b092023-02-02 08:58:27 +01002348 return ret;
2349}
2350
2351/* leaf */
2352static int
romane028ef92023-02-24 16:33:08 +01002353nc_server_config_none(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002354{
roman5cbb6532023-06-22 12:53:17 +02002355 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002356 struct nc_auth_client *auth_client;
roman8341e8b2023-11-23 16:12:42 +01002357 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002358
2359 assert(!strcmp(LYD_NAME(node), "none"));
2360
romanba93eac2023-07-18 14:36:48 +02002361 /* LOCK */
2362 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002363 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002364 return 1;
2365 }
2366
roman8341e8b2023-11-23 16:12:42 +01002367 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
roman4cb8bb12023-06-29 09:16:46 +02002368 ret = 1;
2369 goto cleanup;
2370 }
romanc1d2b092023-02-02 08:58:27 +01002371
roman4cb8bb12023-06-29 09:16:46 +02002372 if (op == NC_OP_CREATE) {
roman808f3f62023-11-23 16:01:04 +01002373 auth_client->none_enabled = 1;
roman4cb8bb12023-06-29 09:16:46 +02002374 } else {
roman808f3f62023-11-23 16:01:04 +01002375 auth_client->none_enabled = 0;
romanc1d2b092023-02-02 08:58:27 +01002376 }
2377
2378cleanup:
romanba93eac2023-07-18 14:36:48 +02002379 if (is_ch(node)) {
2380 /* UNLOCK */
2381 nc_ch_client_unlock(ch_client);
2382 }
romanc1d2b092023-02-02 08:58:27 +01002383 return ret;
2384}
2385
2386static int
romanc135c6d2023-10-25 13:32:30 +02002387nc_server_config_delete_substring(const char *haystack, const char *needle, const char delim)
2388{
2389 size_t needle_len = strlen(needle);
2390 char *substr;
2391 int substr_found = 0, ret = 0;
2392
2393 while ((substr = strstr(haystack, needle))) {
2394 /* iterate over all the substrings */
2395 if (((substr == haystack) && (*(substr + needle_len) == delim)) ||
2396 ((substr != haystack) && (*(substr - 1) == delim) && (*(substr + needle_len) == delim))) {
2397 /* either the first element of the string or somewhere in the middle */
2398 memmove(substr, substr + needle_len + 1, strlen(substr + needle_len + 1));
2399 substr_found = 1;
2400 break;
2401 } else if ((*(substr - 1) == delim) && (*(substr + needle_len) == '\0')) {
2402 /* the last element of the string */
2403 *(substr - 1) = '\0';
2404 substr_found = 1;
2405 break;
2406 }
2407 haystack = substr + 1;
2408 }
2409 if (!substr_found) {
2410 ret = 1;
2411 }
2412
2413 return ret;
2414}
2415
2416static int
romana6bf6ab2023-05-26 13:26:02 +02002417nc_server_config_transport_params(const char *algorithm, char **alg_store, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002418{
romanc135c6d2023-10-25 13:32:30 +02002419 int ret = 0;
2420 char *alg = NULL;
romana6bf6ab2023-05-26 13:26:02 +02002421
2422 if (!strncmp(algorithm, "openssh-", 8)) {
2423 /* if the name starts with openssh, convert it to it's original libssh accepted form */
roman3a95bb22023-10-26 11:07:17 +02002424 ret = asprintf(&alg, "%s@openssh.com", algorithm + 8);
2425 NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; alg = NULL, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002426 } else if (!strncmp(algorithm, "libssh-", 7)) {
2427 /* if the name starts with libssh, convert it to it's original libssh accepted form */
roman3a95bb22023-10-26 11:07:17 +02002428 ret = asprintf(&alg, "%s@libssh.org", algorithm + 7);
2429 NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; alg = NULL, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002430 } else {
2431 alg = strdup(algorithm);
roman3a95bb22023-10-26 11:07:17 +02002432 NC_CHECK_ERRMEM_GOTO(!alg, ret = 1, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002433 }
2434
romanc1d2b092023-02-02 08:58:27 +01002435 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2436 if (!*alg_store) {
2437 /* first call */
2438 *alg_store = strdup(alg);
roman3a95bb22023-10-26 11:07:17 +02002439 NC_CHECK_ERRMEM_GOTO(!*alg_store, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01002440 } else {
2441 /* +1 because of ',' between algorithms */
roman3a95bb22023-10-26 11:07:17 +02002442 *alg_store = nc_realloc(*alg_store, strlen(*alg_store) + strlen(alg) + 1 + 1);
2443 NC_CHECK_ERRMEM_GOTO(!*alg_store, ret = 1, cleanup);
roman08f67f42023-06-08 13:51:54 +02002444 strcat(*alg_store, ",");
2445 strcat(*alg_store, alg);
romanc1d2b092023-02-02 08:58:27 +01002446 }
2447 } else {
2448 /* delete */
romanc135c6d2023-10-25 13:32:30 +02002449 ret = nc_server_config_delete_substring(*alg_store, alg, ',');
2450 if (ret) {
romanc1d2b092023-02-02 08:58:27 +01002451 ERR(NULL, "Unable to delete an algorithm (%s), which was not previously added.", alg);
romanc135c6d2023-10-25 13:32:30 +02002452 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002453 }
2454 }
2455
2456cleanup:
romana6bf6ab2023-05-26 13:26:02 +02002457 free(alg);
romanc1d2b092023-02-02 08:58:27 +01002458 return ret;
2459}
2460
2461/* leaf-list */
2462static int
romane028ef92023-02-24 16:33:08 +01002463nc_server_config_host_key_alg(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;
romanc1d2b092023-02-02 08:58:27 +01002466 const char *alg;
roman5cbb6532023-06-22 12:53:17 +02002467 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002468 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002469
roman5cbb6532023-06-22 12:53:17 +02002470 assert(!strcmp(LYD_NAME(node), "host-key-alg"));
romanc1d2b092023-02-02 08:58:27 +01002471
romanba93eac2023-07-18 14:36:48 +02002472 /* LOCK */
2473 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002474 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002475 return 1;
2476 }
2477
roman8341e8b2023-11-23 16:12:42 +01002478 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002479 ret = 1;
2480 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002481 }
2482
romand05b2ad2024-01-23 12:02:40 +01002483 /* get the algorithm name and append it to supported algs */
roman5cbb6532023-06-22 12:53:17 +02002484 alg = ((struct lyd_node_term *)node)->value.ident->name;
romand05b2ad2024-01-23 12:02:40 +01002485 if (nc_server_config_transport_params(alg, &opts->hostkey_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002486 ret = 1;
romand05b2ad2024-01-23 12:02:40 +01002487 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002488 }
2489
2490cleanup:
romanba93eac2023-07-18 14:36:48 +02002491 if (is_ch(node)) {
2492 /* UNLOCK */
2493 nc_ch_client_unlock(ch_client);
2494 }
romanc1d2b092023-02-02 08:58:27 +01002495 return ret;
2496}
2497
2498/* leaf-list */
2499static int
romane028ef92023-02-24 16:33:08 +01002500nc_server_config_kex_alg(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;
romanc1d2b092023-02-02 08:58:27 +01002503 const char *alg;
roman5cbb6532023-06-22 12:53:17 +02002504 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002505 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002506
roman5cbb6532023-06-22 12:53:17 +02002507 assert(!strcmp(LYD_NAME(node), "key-exchange-alg"));
romanc1d2b092023-02-02 08:58:27 +01002508
romanba93eac2023-07-18 14:36:48 +02002509 /* LOCK */
2510 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002511 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002512 return 1;
2513 }
2514
roman8341e8b2023-11-23 16:12:42 +01002515 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002516 ret = 1;
2517 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002518 }
2519
romand05b2ad2024-01-23 12:02:40 +01002520 /* get the algorithm name and append it to supported algs */
roman5cbb6532023-06-22 12:53:17 +02002521 alg = ((struct lyd_node_term *)node)->value.ident->name;
romand05b2ad2024-01-23 12:02:40 +01002522 if (nc_server_config_transport_params(alg, &opts->kex_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002523 ret = 1;
romand05b2ad2024-01-23 12:02:40 +01002524 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002525 }
2526
2527cleanup:
romanba93eac2023-07-18 14:36:48 +02002528 if (is_ch(node)) {
2529 /* UNLOCK */
2530 nc_ch_client_unlock(ch_client);
2531 }
romanc1d2b092023-02-02 08:58:27 +01002532 return ret;
2533}
2534
2535/* leaf-list */
2536static int
romane028ef92023-02-24 16:33:08 +01002537nc_server_config_encryption_alg(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;
romanc1d2b092023-02-02 08:58:27 +01002540 const char *alg;
roman5cbb6532023-06-22 12:53:17 +02002541 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002542 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002543
roman5cbb6532023-06-22 12:53:17 +02002544 assert(!strcmp(LYD_NAME(node), "encryption-alg"));
romanc1d2b092023-02-02 08:58:27 +01002545
romanba93eac2023-07-18 14:36:48 +02002546 /* LOCK */
2547 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002548 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002549 return 1;
2550 }
2551
roman8341e8b2023-11-23 16:12:42 +01002552 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002553 ret = 1;
2554 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002555 }
2556
romand05b2ad2024-01-23 12:02:40 +01002557 /* get the algorithm name and append it to supported algs */
roman5cbb6532023-06-22 12:53:17 +02002558 alg = ((struct lyd_node_term *)node)->value.ident->name;
romand05b2ad2024-01-23 12:02:40 +01002559 if (nc_server_config_transport_params(alg, &opts->encryption_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002560 ret = 1;
romand05b2ad2024-01-23 12:02:40 +01002561 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002562 }
2563
2564cleanup:
romanba93eac2023-07-18 14:36:48 +02002565 if (is_ch(node)) {
2566 /* UNLOCK */
2567 nc_ch_client_unlock(ch_client);
2568 }
romanc1d2b092023-02-02 08:58:27 +01002569 return ret;
2570}
2571
2572/* leaf-list */
2573static int
romane028ef92023-02-24 16:33:08 +01002574nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002575{
roman5cbb6532023-06-22 12:53:17 +02002576 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002577 const char *alg;
roman5cbb6532023-06-22 12:53:17 +02002578 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002579 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002580
roman5cbb6532023-06-22 12:53:17 +02002581 assert(!strcmp(LYD_NAME(node), "mac-alg"));
romanc1d2b092023-02-02 08:58:27 +01002582
romanba93eac2023-07-18 14:36:48 +02002583 /* LOCK */
2584 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002585 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002586 return 1;
2587 }
2588
roman8341e8b2023-11-23 16:12:42 +01002589 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002590 ret = 1;
2591 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002592 }
2593
romand05b2ad2024-01-23 12:02:40 +01002594 /* get the algorithm name and append it to supported algs */
roman5cbb6532023-06-22 12:53:17 +02002595 alg = ((struct lyd_node_term *)node)->value.ident->name;
romand05b2ad2024-01-23 12:02:40 +01002596 if (nc_server_config_transport_params(alg, &opts->mac_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002597 ret = 1;
romand05b2ad2024-01-23 12:02:40 +01002598 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002599 }
2600
2601cleanup:
romanba93eac2023-07-18 14:36:48 +02002602 if (is_ch(node)) {
2603 /* UNLOCK */
2604 nc_ch_client_unlock(ch_client);
2605 }
romanc1d2b092023-02-02 08:58:27 +01002606 return ret;
2607}
2608
roman78df0fa2023-11-02 10:33:57 +01002609static int
2610nc_server_config_check_endpt_reference_cycle(struct nc_endpt *original, struct nc_endpt *next)
2611{
2612 if (!next->referenced_endpt_name) {
2613 /* no further reference -> no cycle */
2614 return 0;
2615 }
2616
2617 if (!strcmp(original->name, next->referenced_endpt_name)) {
2618 /* found cycle */
2619 return 1;
2620 } else {
2621 if (nc_server_get_referenced_endpt(next->referenced_endpt_name, &next)) {
2622 /* referenced endpoint does not exist */
2623 return 1;
2624 }
2625
2626 /* continue further */
2627 return nc_server_config_check_endpt_reference_cycle(original, next);
2628 }
2629}
2630
roman0bbc19c2023-05-26 09:59:09 +02002631/**
roman78df0fa2023-11-02 10:33:57 +01002632 * @brief Set all endpoint references.
roman0bbc19c2023-05-26 09:59:09 +02002633 *
2634 * @return 0 on success, 1 on error.
2635 */
2636static int
roman78df0fa2023-11-02 10:33:57 +01002637nc_server_config_check_endpt_references(void)
roman0bbc19c2023-05-26 09:59:09 +02002638{
2639 uint16_t i, j;
roman78df0fa2023-11-02 10:33:57 +01002640 struct nc_endpt *referenced_endpt = NULL;
roman0bbc19c2023-05-26 09:59:09 +02002641
roman78df0fa2023-11-02 10:33:57 +01002642 /* first do listen endpoints */
roman0bbc19c2023-05-26 09:59:09 +02002643 for (i = 0; i < server_opts.endpt_count; i++) {
roman6430c152023-10-12 11:28:47 +02002644 /* go through all the endpoints */
roman0bbc19c2023-05-26 09:59:09 +02002645 if (server_opts.endpts[i].referenced_endpt_name) {
roman78df0fa2023-11-02 10:33:57 +01002646 /* get referenced endpt */
2647 if (nc_server_get_referenced_endpt(server_opts.endpts[i].referenced_endpt_name, &referenced_endpt)) {
2648 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" does not exist.",
roman0bbc19c2023-05-26 09:59:09 +02002649 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2650 return 1;
2651 }
roman78df0fa2023-11-02 10:33:57 +01002652
2653 /* check if the endpoint references itself */
2654 if (&server_opts.endpts[i] == referenced_endpt) {
2655 ERR(NULL, "Endpoint \"%s\" references itself.", server_opts.endpts[i].name);
2656 return 1;
2657 }
2658
2659 /* check transport */
2660 if ((server_opts.endpts[i].ti != referenced_endpt->ti)) {
2661 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" has different transport type.",
2662 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2663 return 1;
roman506354a2024-04-11 09:37:22 +02002664 } else if ((referenced_endpt->ti != NC_TI_SSH) && (referenced_endpt->ti != NC_TI_TLS)) {
roman78df0fa2023-11-02 10:33:57 +01002665 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" has unsupported transport type.",
2666 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2667 return 1;
2668 }
2669
2670 /* check cyclic reference */
2671 if (nc_server_config_check_endpt_reference_cycle(&server_opts.endpts[i], referenced_endpt)) {
2672 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" creates a cycle.",
2673 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2674 return 1;
2675 }
2676
2677 /* all went well, assign the name to the opts, so we can access it for auth */
roman506354a2024-04-11 09:37:22 +02002678 if (server_opts.endpts[i].ti == NC_TI_SSH) {
roman78df0fa2023-11-02 10:33:57 +01002679 server_opts.endpts[i].opts.ssh->referenced_endpt_name = referenced_endpt->name;
2680 } else {
2681 server_opts.endpts[i].opts.tls->referenced_endpt_name = referenced_endpt->name;
2682 }
roman0bbc19c2023-05-26 09:59:09 +02002683 }
2684 }
2685
roman78df0fa2023-11-02 10:33:57 +01002686 /* now check all the call home endpoints */
2687 /* LOCK */
2688 pthread_rwlock_rdlock(&server_opts.ch_client_lock);
2689 for (i = 0; i < server_opts.ch_client_count; i++) {
2690 /* LOCK */
2691 pthread_mutex_lock(&server_opts.ch_clients[i].lock);
2692 for (j = 0; j < server_opts.ch_clients[i].ch_endpt_count; j++) {
2693 if (server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name) {
2694 /* get referenced endpt */
2695 if (nc_server_get_referenced_endpt(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, &referenced_endpt)) {
2696 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" does not exist.",
2697 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
2698 goto ch_fail;
2699 }
2700
2701 /* check transport */
2702 if (server_opts.ch_clients[i].ch_endpts[j].ti != referenced_endpt->ti) {
2703 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" has different transport type.",
2704 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
2705 goto ch_fail;
roman506354a2024-04-11 09:37:22 +02002706 } else if ((referenced_endpt->ti != NC_TI_SSH) && (referenced_endpt->ti != NC_TI_TLS)) {
roman78df0fa2023-11-02 10:33:57 +01002707 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" has unsupported transport type.",
2708 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
2709 goto ch_fail;
2710 }
2711
2712 /* check cyclic reference */
2713 if (nc_server_config_check_endpt_reference_cycle(referenced_endpt, referenced_endpt)) {
2714 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" creates a cycle.",
2715 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
2716 goto ch_fail;
2717 }
2718
2719 /* all went well, assign the name to the opts, so we can access it for auth */
roman506354a2024-04-11 09:37:22 +02002720 if (server_opts.ch_clients[i].ch_endpts[j].ti == NC_TI_SSH) {
roman78df0fa2023-11-02 10:33:57 +01002721 server_opts.ch_clients[i].ch_endpts[j].opts.ssh->referenced_endpt_name = referenced_endpt->name;
2722 } else {
2723 server_opts.ch_clients[i].ch_endpts[j].opts.tls->referenced_endpt_name = referenced_endpt->name;
2724 }
2725 }
2726 }
2727 /* UNLOCK */
2728 pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
2729 }
2730
2731 /* UNLOCK */
2732 pthread_rwlock_unlock(&server_opts.ch_client_lock);
roman0bbc19c2023-05-26 09:59:09 +02002733 return 0;
roman78df0fa2023-11-02 10:33:57 +01002734
2735ch_fail:
2736 /* UNLOCK */
2737 pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
2738 /* UNLOCK */
2739 pthread_rwlock_unlock(&server_opts.ch_client_lock);
roman96c27f92023-11-02 11:09:46 +01002740 return 1;
roman0bbc19c2023-05-26 09:59:09 +02002741}
2742
2743static int
roman78df0fa2023-11-02 10:33:57 +01002744nc_server_config_endpoint_reference(const struct lyd_node *node, NC_OPERATION op)
roman0bbc19c2023-05-26 09:59:09 +02002745{
2746 int ret = 0;
roman78df0fa2023-11-02 10:33:57 +01002747 struct nc_endpt *endpt = NULL;
roman8341e8b2023-11-23 16:12:42 +01002748 struct nc_ch_client *ch_client = NULL;
roman78df0fa2023-11-02 10:33:57 +01002749 struct nc_ch_endpt *ch_endpt = NULL;
2750 struct nc_server_ssh_opts *ssh = NULL;
2751 struct nc_server_tls_opts *tls = NULL;
roman0bbc19c2023-05-26 09:59:09 +02002752
roman78df0fa2023-11-02 10:33:57 +01002753 assert(!strcmp(LYD_NAME(node), "endpoint-reference"));
roman0bbc19c2023-05-26 09:59:09 +02002754
roman78df0fa2023-11-02 10:33:57 +01002755 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
2756 /* to avoid unlock on fail */
2757 return 1;
2758 }
2759
2760 /* get endpt */
2761 if (is_listen(node)) {
2762 ret = nc_server_config_get_endpt(node, &endpt, NULL);
2763 } else {
roman8341e8b2023-11-23 16:12:42 +01002764 ret = nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt);
roman78df0fa2023-11-02 10:33:57 +01002765 }
roman0bbc19c2023-05-26 09:59:09 +02002766 if (ret) {
2767 goto cleanup;
2768 }
2769
2770 if (op == NC_OP_DELETE) {
roman78df0fa2023-11-02 10:33:57 +01002771 if (endpt) {
romanb7bfa652023-11-09 12:36:35 +01002772 /* listen */
roman78df0fa2023-11-02 10:33:57 +01002773 free(endpt->referenced_endpt_name);
2774 endpt->referenced_endpt_name = NULL;
roman2e797ef2023-06-19 10:47:49 +02002775 } else {
romanb7bfa652023-11-09 12:36:35 +01002776 /* call home */
roman78df0fa2023-11-02 10:33:57 +01002777 free(ch_endpt->referenced_endpt_name);
2778 ch_endpt->referenced_endpt_name = NULL;
roman2e797ef2023-06-19 10:47:49 +02002779 }
roman78df0fa2023-11-02 10:33:57 +01002780 if (is_ssh(node)) {
roman8341e8b2023-11-23 16:12:42 +01002781 if (nc_server_config_get_ssh_opts(node, ch_client, &ssh)) {
roman78df0fa2023-11-02 10:33:57 +01002782 ret = 1;
2783 goto cleanup;
2784 }
roman96c27f92023-11-02 11:09:46 +01002785
roman78df0fa2023-11-02 10:33:57 +01002786 ssh->referenced_endpt_name = NULL;
2787 } else {
roman8341e8b2023-11-23 16:12:42 +01002788 if (nc_server_config_get_tls_opts(node, ch_client, &tls)) {
roman78df0fa2023-11-02 10:33:57 +01002789 ret = 1;
2790 goto cleanup;
2791 }
roman0bbc19c2023-05-26 09:59:09 +02002792
roman78df0fa2023-11-02 10:33:57 +01002793 tls->referenced_endpt_name = NULL;
roman0bbc19c2023-05-26 09:59:09 +02002794 }
roman0bbc19c2023-05-26 09:59:09 +02002795
roman0bbc19c2023-05-26 09:59:09 +02002796 goto cleanup;
roman2e797ef2023-06-19 10:47:49 +02002797 } else {
roman78df0fa2023-11-02 10:33:57 +01002798 /* just set the name, check it once configuring of all nodes is done */
2799 if (endpt) {
2800 free(endpt->referenced_endpt_name);
2801 endpt->referenced_endpt_name = strdup(lyd_get_value(node));
2802 NC_CHECK_ERRMEM_GOTO(!endpt->referenced_endpt_name, ret = 1, cleanup);
2803 } else {
2804 free(ch_endpt->referenced_endpt_name);
2805 ch_endpt->referenced_endpt_name = strdup(lyd_get_value(node));
2806 NC_CHECK_ERRMEM_GOTO(!ch_endpt->referenced_endpt_name, ret = 1, cleanup);
2807 }
2808
2809 goto cleanup;
roman2e797ef2023-06-19 10:47:49 +02002810 }
roman0bbc19c2023-05-26 09:59:09 +02002811
2812cleanup:
roman78df0fa2023-11-02 10:33:57 +01002813 if (is_ch(node)) {
2814 /* UNLOCK */
2815 nc_ch_client_unlock(ch_client);
2816 }
2817
roman0bbc19c2023-05-26 09:59:09 +02002818 return ret;
2819}
2820
roman3f9b65c2023-06-05 14:26:58 +02002821static int
roman3f9b65c2023-06-05 14:26:58 +02002822nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op)
2823{
2824 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02002825 struct nc_certificate *cert;
romanb6f44032023-06-30 15:07:56 +02002826 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002827 struct nc_ch_client *ch_client = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002828
2829 assert(!strcmp(LYD_NAME(node), "cert-data"));
2830
romanba93eac2023-07-18 14:36:48 +02002831 /* LOCK */
2832 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002833 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002834 return 1;
2835 }
2836
romanb6f44032023-06-30 15:07:56 +02002837 if (equal_parent_name(node, 3, "server-identity")) {
roman8341e8b2023-11-23 16:12:42 +01002838 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
romanb6f44032023-06-30 15:07:56 +02002839 ret = 1;
2840 goto cleanup;
2841 }
roman3f9b65c2023-06-05 14:26:58 +02002842
roman3f9b65c2023-06-05 14:26:58 +02002843 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002844 free(opts->cert_data);
2845 opts->cert_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002846 NC_CHECK_ERRMEM_GOTO(!opts->cert_data, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02002847 }
roman6430c152023-10-12 11:28:47 +02002848 } else if (equal_parent_name(node, 3, "ca-certs") || equal_parent_name(node, 3, "ee-certs")) {
roman8341e8b2023-11-23 16:12:42 +01002849 if (nc_server_config_get_cert(node, ch_client, &cert)) {
roman3f9b65c2023-06-05 14:26:58 +02002850 ret = 1;
2851 goto cleanup;
2852 }
2853
2854 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002855 free(cert->data);
2856 cert->data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002857 NC_CHECK_ERRMEM_GOTO(!cert->data, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02002858 } else {
roman6430c152023-10-12 11:28:47 +02002859 free(cert->data);
2860 cert->data = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002861 }
2862 }
2863
2864cleanup:
romanba93eac2023-07-18 14:36:48 +02002865 if (is_ch(node)) {
2866 /* UNLOCK */
2867 nc_ch_client_unlock(ch_client);
2868 }
roman3f9b65c2023-06-05 14:26:58 +02002869 return ret;
2870}
2871
2872static int
roman3f9b65c2023-06-05 14:26:58 +02002873nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op)
2874{
2875 int ret = 0;
roman78df0fa2023-11-02 10:33:57 +01002876 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002877 struct nc_ch_client *ch_client = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002878
2879 assert(!strcmp(LYD_NAME(node), "asymmetric-key"));
2880
romanba93eac2023-07-18 14:36:48 +02002881 /* LOCK */
2882 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002883 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002884 return 1;
2885 }
2886
roman8341e8b2023-11-23 16:12:42 +01002887 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02002888 ret = 1;
2889 goto cleanup;
2890 }
2891
2892 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2893 /* set to keystore */
roman78df0fa2023-11-02 10:33:57 +01002894 opts->store = NC_STORE_KEYSTORE;
roman3f9b65c2023-06-05 14:26:58 +02002895
roman78df0fa2023-11-02 10:33:57 +01002896 free(opts->key_ref);
2897 opts->key_ref = strdup(lyd_get_value(node));
2898 NC_CHECK_ERRMEM_GOTO(!opts->key_ref, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02002899 } else {
roman78df0fa2023-11-02 10:33:57 +01002900 free(opts->key_ref);
2901 opts->key_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002902 }
2903
2904cleanup:
romanba93eac2023-07-18 14:36:48 +02002905 if (is_ch(node)) {
2906 /* UNLOCK */
2907 nc_ch_client_unlock(ch_client);
2908 }
roman3f9b65c2023-06-05 14:26:58 +02002909 return ret;
2910}
2911
2912static int
roman3f9b65c2023-06-05 14:26:58 +02002913nc_server_config_create_ca_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
2914{
2915 assert(!strcmp(LYD_NAME(node), "certificate"));
2916
2917 node = lyd_child(node);
2918 assert(!strcmp(LYD_NAME(node), "name"));
2919
Michal Vaskocf898172024-01-15 15:04:28 +01002920 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ca_certs.certs, sizeof *opts->ca_certs.certs,
2921 &opts->ca_certs.cert_count);
roman3f9b65c2023-06-05 14:26:58 +02002922}
2923
2924static int
2925nc_server_config_create_ee_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
2926{
2927 assert(!strcmp(LYD_NAME(node), "certificate"));
2928
2929 node = lyd_child(node);
2930 assert(!strcmp(LYD_NAME(node), "name"));
2931
Michal Vaskocf898172024-01-15 15:04:28 +01002932 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ee_certs.certs, sizeof *opts->ee_certs.certs,
2933 &opts->ee_certs.cert_count);
roman3f9b65c2023-06-05 14:26:58 +02002934}
2935
2936static int
2937nc_server_config_certificate(const struct lyd_node *node, NC_OPERATION op)
2938{
2939 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02002940 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002941 struct nc_ch_client *ch_client = NULL;
roman6430c152023-10-12 11:28:47 +02002942 struct nc_certificate *cert;
roman3f9b65c2023-06-05 14:26:58 +02002943
2944 assert(!strcmp(LYD_NAME(node), "certificate"));
2945
romanba93eac2023-07-18 14:36:48 +02002946 /* LOCK */
2947 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002948 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002949 return 1;
2950 }
2951
roman8341e8b2023-11-23 16:12:42 +01002952 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02002953 ret = 1;
2954 goto cleanup;
2955 }
2956
Michal Vaskocf898172024-01-15 15:04:28 +01002957 if (equal_parent_name(node, 1, "central-keystore-reference")) {
romanb6f44032023-06-30 15:07:56 +02002958 /* TLS server-identity */
roman3f9b65c2023-06-05 14:26:58 +02002959 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2960 /* set to keystore */
romanb6f44032023-06-30 15:07:56 +02002961 opts->store = NC_STORE_KEYSTORE;
roman3f9b65c2023-06-05 14:26:58 +02002962
roman6430c152023-10-12 11:28:47 +02002963 free(opts->cert_ref);
2964 opts->cert_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002965 NC_CHECK_ERRMEM_GOTO(!opts->cert_ref, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02002966 } else {
roman6430c152023-10-12 11:28:47 +02002967 free(opts->cert_ref);
romanb6f44032023-06-30 15:07:56 +02002968 opts->cert_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002969 }
romanb6f44032023-06-30 15:07:56 +02002970 } else if (equal_parent_name(node, 2, "ca-certs")) {
2971 /* TLS client auth certificate authority */
roman3f9b65c2023-06-05 14:26:58 +02002972 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02002973 ret = nc_server_config_create_ca_certs_certificate(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02002974 if (ret) {
2975 goto cleanup;
2976 }
2977 } else {
roman8341e8b2023-11-23 16:12:42 +01002978 if (nc_server_config_get_cert(node, ch_client, &cert)) {
roman6430c152023-10-12 11:28:47 +02002979 ret = 1;
2980 goto cleanup;
2981 }
2982 nc_server_config_del_cert(&opts->ca_certs, cert);
roman3f9b65c2023-06-05 14:26:58 +02002983 }
romanb6f44032023-06-30 15:07:56 +02002984 } else if (equal_parent_name(node, 2, "ee-certs")) {
2985 /* TLS client auth end entity */
roman3f9b65c2023-06-05 14:26:58 +02002986 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02002987 ret = nc_server_config_create_ee_certs_certificate(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02002988 if (ret) {
2989 goto cleanup;
2990 }
2991 } else {
roman8341e8b2023-11-23 16:12:42 +01002992 if (nc_server_config_get_cert(node, ch_client, &cert)) {
roman6430c152023-10-12 11:28:47 +02002993 ret = 1;
2994 goto cleanup;
2995 }
2996 nc_server_config_del_cert(&opts->ee_certs, cert);
roman3f9b65c2023-06-05 14:26:58 +02002997 }
2998 }
2999
3000cleanup:
romanba93eac2023-07-18 14:36:48 +02003001 if (is_ch(node)) {
3002 /* UNLOCK */
3003 nc_ch_client_unlock(ch_client);
3004 }
roman3f9b65c2023-06-05 14:26:58 +02003005 return ret;
3006}
3007
3008static int
3009nc_server_config_create_cert_to_name(const struct lyd_node *node, struct nc_server_tls_opts *opts)
3010{
3011 int ret = 0;
3012 struct lyd_node *n;
3013 struct nc_ctn *new, *iter;
Michal Vasko3392b4a2024-02-02 08:57:53 +01003014 const char *map_type, *name = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003015 uint32_t id;
3016 NC_TLS_CTN_MAPTYPE m_type;
3017
3018 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
3019
roman3f9b65c2023-06-05 14:26:58 +02003020 /* find the list's key */
3021 lyd_find_path(node, "id", 0, &n);
3022 assert(n);
roman9cdb7b52023-10-25 13:59:55 +02003023 id = ((struct lyd_node_term *)n)->value.uint32;
roman3f9b65c2023-06-05 14:26:58 +02003024
Michal Vasko3392b4a2024-02-02 08:57:53 +01003025 /* get CTN map-type */
3026 if (lyd_find_path(node, "map-type", 0, &n)) {
3027 ERR(NULL, "Missing CTN map-type.");
3028 ret = 1;
3029 goto cleanup;
3030 }
roman3f9b65c2023-06-05 14:26:58 +02003031 map_type = ((struct lyd_node_term *)n)->value.ident->name;
3032 if (!strcmp(map_type, "specified")) {
3033 m_type = NC_TLS_CTN_SPECIFIED;
Michal Vasko3392b4a2024-02-02 08:57:53 +01003034
3035 /* get CTN name */
3036 if (lyd_find_path(node, "name", 0, &n)) {
3037 ERR(NULL, "Missing CTN \"specified\" user name.");
3038 ret = 1;
3039 goto cleanup;
3040 }
3041 name = lyd_get_value(n);
roman3f9b65c2023-06-05 14:26:58 +02003042 } else if (!strcmp(map_type, "san-rfc822-name")) {
3043 m_type = NC_TLS_CTN_SAN_RFC822_NAME;
3044 } else if (!strcmp(map_type, "san-dns-name")) {
3045 m_type = NC_TLS_CTN_SAN_DNS_NAME;
3046 } else if (!strcmp(map_type, "san-ip-address")) {
3047 m_type = NC_TLS_CTN_SAN_IP_ADDRESS;
3048 } else if (!strcmp(map_type, "san-any")) {
3049 m_type = NC_TLS_CTN_SAN_ANY;
3050 } else if (!strcmp(map_type, "common-name")) {
3051 m_type = NC_TLS_CTN_COMMON_NAME;
3052 } else {
Michal Vasko3392b4a2024-02-02 08:57:53 +01003053 ERR(NULL, "CTN map-type \"%s\" not supported.", map_type);
roman3f9b65c2023-06-05 14:26:58 +02003054 ret = 1;
3055 goto cleanup;
3056 }
3057
roman6430c152023-10-12 11:28:47 +02003058 /* create new ctn */
3059 new = calloc(1, sizeof *new);
roman3a95bb22023-10-26 11:07:17 +02003060 NC_CHECK_ERRMEM_GOTO(!new, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02003061
roman3f9b65c2023-06-05 14:26:58 +02003062 /* find the right place for insertion */
3063 if (!opts->ctn) {
3064 /* inserting the first one */
3065 opts->ctn = new;
Roytak421eb0c2023-08-01 22:18:27 +02003066 } else if (opts->ctn->id > id) {
roman3f9b65c2023-06-05 14:26:58 +02003067 /* insert at the beginning */
3068 new->next = opts->ctn;
3069 opts->ctn = new;
3070 } else {
3071 /* have to find the right place */
Roytak421eb0c2023-08-01 22:18:27 +02003072 for (iter = opts->ctn; iter->next && iter->next->id <= id; iter = iter->next) {}
3073 if (iter->id == id) {
Michal Vasko3392b4a2024-02-02 08:57:53 +01003074 /* collision, replace */
romanb7bfa652023-11-09 12:36:35 +01003075 free(new);
roman3f9b65c2023-06-05 14:26:58 +02003076 new = iter;
Michal Vasko3392b4a2024-02-02 08:57:53 +01003077 free(new->name);
3078 new->name = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003079 } else {
3080 new->next = iter->next;
3081 iter->next = new;
3082 }
3083 }
3084
3085 /* insert the right data */
3086 new->id = id;
Michal Vasko3392b4a2024-02-02 08:57:53 +01003087 if (name) {
3088 new->name = strdup(name);
3089 NC_CHECK_ERRMEM_GOTO(!new->name, ret = 1, cleanup);
3090 }
roman3f9b65c2023-06-05 14:26:58 +02003091 new->map_type = m_type;
3092
3093cleanup:
3094 return ret;
3095}
3096
3097static int
3098nc_server_config_cert_to_name(const struct lyd_node *node, NC_OPERATION op)
3099{
3100 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003101 struct nc_server_tls_opts *opts;
roman3f9b65c2023-06-05 14:26:58 +02003102 struct nc_ctn *ctn;
roman8341e8b2023-11-23 16:12:42 +01003103 struct nc_ch_client *ch_client = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003104
3105 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
3106
romanba93eac2023-07-18 14:36:48 +02003107 /* LOCK */
3108 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003109 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003110 return 1;
3111 }
3112
roman8341e8b2023-11-23 16:12:42 +01003113 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02003114 ret = 1;
3115 goto cleanup;
3116 }
3117
3118 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003119 ret = nc_server_config_create_cert_to_name(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02003120 if (ret) {
3121 goto cleanup;
3122 }
3123 } else {
3124 /* find the given ctn entry */
roman8341e8b2023-11-23 16:12:42 +01003125 if (nc_server_config_get_ctn(node, ch_client, &ctn)) {
roman3f9b65c2023-06-05 14:26:58 +02003126 ret = 1;
3127 goto cleanup;
3128 }
romanb6f44032023-06-30 15:07:56 +02003129 nc_server_config_del_ctn(opts, ctn);
roman3f9b65c2023-06-05 14:26:58 +02003130 }
3131
3132cleanup:
romanba93eac2023-07-18 14:36:48 +02003133 if (is_ch(node)) {
3134 /* UNLOCK */
3135 nc_ch_client_unlock(ch_client);
3136 }
roman3f9b65c2023-06-05 14:26:58 +02003137 return ret;
3138}
3139
3140static int
roman3f9b65c2023-06-05 14:26:58 +02003141nc_server_config_fingerprint(const struct lyd_node *node, NC_OPERATION op)
3142{
3143 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02003144 struct nc_ctn *ctn;
roman8341e8b2023-11-23 16:12:42 +01003145 struct nc_ch_client *ch_client = NULL;
romanba93eac2023-07-18 14:36:48 +02003146
3147 assert(!strcmp(LYD_NAME(node), "fingerprint"));
3148
3149 /* LOCK */
3150 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003151 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003152 return 1;
3153 }
roman3f9b65c2023-06-05 14:26:58 +02003154
roman8341e8b2023-11-23 16:12:42 +01003155 if (nc_server_config_get_ctn(node, ch_client, &ctn)) {
roman3f9b65c2023-06-05 14:26:58 +02003156 ret = 1;
3157 goto cleanup;
3158 }
3159
3160 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003161 free(ctn->fingerprint);
3162 ctn->fingerprint = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003163 NC_CHECK_ERRMEM_GOTO(!ctn->fingerprint, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003164 } else {
roman6430c152023-10-12 11:28:47 +02003165 free(ctn->fingerprint);
3166 ctn->fingerprint = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003167 }
3168
3169cleanup:
romanba93eac2023-07-18 14:36:48 +02003170 if (is_ch(node)) {
3171 /* UNLOCK */
3172 nc_ch_client_unlock(ch_client);
3173 }
roman3f9b65c2023-06-05 14:26:58 +02003174 return ret;
3175}
3176
roman12644fe2023-06-08 11:06:42 +02003177static int
3178nc_server_config_tls_version(const struct lyd_node *node, NC_OPERATION op)
3179{
3180 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003181 struct nc_server_tls_opts *opts;
roman12644fe2023-06-08 11:06:42 +02003182 const char *version = NULL;
roman8341e8b2023-11-23 16:12:42 +01003183 struct nc_ch_client *ch_client = NULL;
roman6430c152023-10-12 11:28:47 +02003184 NC_TLS_VERSION tls_version;
roman12644fe2023-06-08 11:06:42 +02003185
3186 assert(!strcmp(LYD_NAME(node), "tls-version"));
3187
romanba93eac2023-07-18 14:36:48 +02003188 /* LOCK */
3189 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003190 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003191 return 1;
3192 }
3193
roman8341e8b2023-11-23 16:12:42 +01003194 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman12644fe2023-06-08 11:06:42 +02003195 ret = 1;
3196 goto cleanup;
3197 }
3198
roman6430c152023-10-12 11:28:47 +02003199 /* str to tls_version */
roman12644fe2023-06-08 11:06:42 +02003200 version = ((struct lyd_node_term *)node)->value.ident->name;
3201 if (!strcmp(version, "tls10")) {
roman6430c152023-10-12 11:28:47 +02003202 tls_version = NC_TLS_VERSION_10;
roman12644fe2023-06-08 11:06:42 +02003203 } else if (!strcmp(version, "tls11")) {
roman6430c152023-10-12 11:28:47 +02003204 tls_version = NC_TLS_VERSION_11;
roman12644fe2023-06-08 11:06:42 +02003205 } else if (!strcmp(version, "tls12")) {
roman6430c152023-10-12 11:28:47 +02003206 tls_version = NC_TLS_VERSION_12;
roman12644fe2023-06-08 11:06:42 +02003207 } else if (!strcmp(version, "tls13")) {
roman6430c152023-10-12 11:28:47 +02003208 tls_version = NC_TLS_VERSION_13;
roman12644fe2023-06-08 11:06:42 +02003209 } else {
3210 ERR(NULL, "TLS version \"%s\" not supported.", version);
3211 ret = 1;
3212 goto cleanup;
3213 }
3214
roman6430c152023-10-12 11:28:47 +02003215 if (op == NC_OP_CREATE) {
3216 /* add the version if it isn't there already */
3217 opts->tls_versions |= tls_version;
3218 } else if ((op == NC_OP_DELETE) && (opts->tls_versions & tls_version)) {
3219 /* delete the version if it is there */
roman84fe3252023-10-25 11:28:32 +02003220 opts->tls_versions &= ~tls_version;
roman6430c152023-10-12 11:28:47 +02003221 }
3222
roman12644fe2023-06-08 11:06:42 +02003223cleanup:
romanba93eac2023-07-18 14:36:48 +02003224 if (is_ch(node)) {
3225 /* UNLOCK */
3226 nc_ch_client_unlock(ch_client);
3227 }
roman12644fe2023-06-08 11:06:42 +02003228 return ret;
3229}
3230
3231static int
3232nc_server_config_create_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher)
3233{
3234 int ret = 0;
roman506354a2024-04-11 09:37:22 +02003235 char *processed_cipher = NULL;
roman12644fe2023-06-08 11:06:42 +02003236
roman506354a2024-04-11 09:37:22 +02003237 ret = nc_tls_process_cipher_suite_wrap(cipher, &processed_cipher);
3238 if (ret) {
3239 ERR(NULL, "Failed to process the cipher suite \"%s\".", cipher);
3240 goto cleanup;
roman12644fe2023-06-08 11:06:42 +02003241 }
roman12644fe2023-06-08 11:06:42 +02003242
roman506354a2024-04-11 09:37:22 +02003243 ret = nc_tls_append_cipher_suite_wrap(opts, processed_cipher);
3244 if (ret) {
3245 ERR(NULL, "Failed to append the cipher suite \"%s\".", cipher);
3246 goto cleanup;
roman12644fe2023-06-08 11:06:42 +02003247 }
3248
3249cleanup:
roman506354a2024-04-11 09:37:22 +02003250 free(processed_cipher);
roman12644fe2023-06-08 11:06:42 +02003251 return ret;
3252}
3253
3254static int
romanb6f44032023-06-30 15:07:56 +02003255nc_server_config_del_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher)
roman12644fe2023-06-08 11:06:42 +02003256{
romanc135c6d2023-10-25 13:32:30 +02003257 int ret = 0;
roman12644fe2023-06-08 11:06:42 +02003258
romanc135c6d2023-10-25 13:32:30 +02003259 ret = nc_server_config_delete_substring(opts->ciphers, cipher, ':');
3260 if (ret) {
roman12644fe2023-06-08 11:06:42 +02003261 ERR(NULL, "Unable to delete a cipher (%s), which was not previously added.", cipher);
3262 return 1;
3263 }
3264
3265 return 0;
3266}
3267
3268static int
3269nc_server_config_cipher_suite(const struct lyd_node *node, NC_OPERATION op)
3270{
3271 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003272 struct nc_server_tls_opts *opts;
roman12644fe2023-06-08 11:06:42 +02003273 const char *cipher = NULL;
roman8341e8b2023-11-23 16:12:42 +01003274 struct nc_ch_client *ch_client = NULL;
roman12644fe2023-06-08 11:06:42 +02003275
romanfaecc582023-06-15 16:13:31 +02003276 assert(!strcmp(LYD_NAME(node), "cipher-suite"));
3277
romanba93eac2023-07-18 14:36:48 +02003278 /* LOCK */
3279 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003280 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003281 return 1;
3282 }
3283
roman8341e8b2023-11-23 16:12:42 +01003284 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman12644fe2023-06-08 11:06:42 +02003285 ret = 1;
3286 goto cleanup;
3287 }
3288
3289 cipher = ((struct lyd_node_term *)node)->value.ident->name;
3290 if (op == NC_OP_CREATE) {
romanb6f44032023-06-30 15:07:56 +02003291 ret = nc_server_config_create_cipher_suite(opts, cipher);
roman12644fe2023-06-08 11:06:42 +02003292 if (ret) {
3293 goto cleanup;
3294 }
3295 } else if (op == NC_OP_DELETE) {
romanb6f44032023-06-30 15:07:56 +02003296 ret = nc_server_config_del_cipher_suite(opts, cipher);
roman12644fe2023-06-08 11:06:42 +02003297 if (ret) {
3298 goto cleanup;
3299 }
3300 }
3301
3302cleanup:
romanba93eac2023-07-18 14:36:48 +02003303 if (is_ch(node)) {
3304 /* UNLOCK */
3305 nc_ch_client_unlock(ch_client);
3306 }
roman12644fe2023-06-08 11:06:42 +02003307 return ret;
3308}
3309
romanfaecc582023-06-15 16:13:31 +02003310static int
3311nc_server_config_crl_url(const struct lyd_node *node, NC_OPERATION op)
3312{
3313 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003314 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01003315 struct nc_ch_client *ch_client = NULL;
romanfaecc582023-06-15 16:13:31 +02003316
3317 assert(!strcmp(LYD_NAME(node), "crl-url"));
3318
romanba93eac2023-07-18 14:36:48 +02003319 /* LOCK */
3320 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003321 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003322 return 1;
3323 }
3324
roman8341e8b2023-11-23 16:12:42 +01003325 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
romanfaecc582023-06-15 16:13:31 +02003326 ret = 1;
3327 goto cleanup;
3328 }
3329
3330 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003331 free(opts->crl_url);
romanb6f44032023-06-30 15:07:56 +02003332 opts->crl_url = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003333 NC_CHECK_ERRMEM_GOTO(!opts->crl_url, ret = 1, cleanup);
romanfaecc582023-06-15 16:13:31 +02003334 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02003335 free(opts->crl_url);
3336 opts->crl_url = NULL;
romanfaecc582023-06-15 16:13:31 +02003337 }
3338
3339cleanup:
romanba93eac2023-07-18 14:36:48 +02003340 if (is_ch(node)) {
3341 /* UNLOCK */
3342 nc_ch_client_unlock(ch_client);
3343 }
romanfaecc582023-06-15 16:13:31 +02003344 return ret;
3345}
3346
3347static int
3348nc_server_config_crl_path(const struct lyd_node *node, NC_OPERATION op)
3349{
3350 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003351 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01003352 struct nc_ch_client *ch_client = NULL;
romanfaecc582023-06-15 16:13:31 +02003353
3354 assert(!strcmp(LYD_NAME(node), "crl-path"));
3355
romanba93eac2023-07-18 14:36:48 +02003356 /* LOCK */
3357 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003358 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003359 return 1;
3360 }
3361
roman8341e8b2023-11-23 16:12:42 +01003362 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
romanfaecc582023-06-15 16:13:31 +02003363 ret = 1;
3364 goto cleanup;
3365 }
3366
3367 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003368 free(opts->crl_path);
romanb6f44032023-06-30 15:07:56 +02003369 opts->crl_path = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003370 NC_CHECK_ERRMEM_GOTO(!opts->crl_path, ret = 1, cleanup);
romanfaecc582023-06-15 16:13:31 +02003371 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02003372 free(opts->crl_path);
3373 opts->crl_path = NULL;
romanfaecc582023-06-15 16:13:31 +02003374 }
3375
3376cleanup:
romanba93eac2023-07-18 14:36:48 +02003377 if (is_ch(node)) {
3378 /* UNLOCK */
3379 nc_ch_client_unlock(ch_client);
3380 }
romanfaecc582023-06-15 16:13:31 +02003381 return ret;
3382}
3383
3384static int
3385nc_server_config_crl_cert_ext(const struct lyd_node *node, NC_OPERATION op)
3386{
3387 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003388 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01003389 struct nc_ch_client *ch_client = NULL;
romanfaecc582023-06-15 16:13:31 +02003390
3391 assert(!strcmp(LYD_NAME(node), "crl-cert-ext"));
3392
romanba93eac2023-07-18 14:36:48 +02003393 /* LOCK */
3394 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003395 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003396 return 1;
3397 }
3398
roman8341e8b2023-11-23 16:12:42 +01003399 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
romanfaecc582023-06-15 16:13:31 +02003400 ret = 1;
3401 goto cleanup;
3402 }
3403
3404 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003405 opts->crl_cert_ext = 1;
romanfaecc582023-06-15 16:13:31 +02003406 } else if (op == NC_OP_DELETE) {
romanb6f44032023-06-30 15:07:56 +02003407 opts->crl_cert_ext = 0;
romanfaecc582023-06-15 16:13:31 +02003408 }
3409
3410cleanup:
romanba93eac2023-07-18 14:36:48 +02003411 if (is_ch(node)) {
3412 /* UNLOCK */
3413 nc_ch_client_unlock(ch_client);
3414 }
romanfaecc582023-06-15 16:13:31 +02003415 return ret;
3416}
3417
roman2eab4742023-06-06 10:00:26 +02003418#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02003419
roman83683fb2023-02-24 09:15:23 +01003420static int
roman5cbb6532023-06-22 12:53:17 +02003421nc_server_config_create_netconf_client(const struct lyd_node *node)
3422{
3423 int ret = 0;
3424
3425 node = lyd_child(node);
3426 assert(!strcmp(LYD_NAME(node), "name"));
3427
3428 /* LOCK */
3429 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
3430
3431 ret = nc_server_config_realloc(lyd_get_value(node), (void **)&server_opts.ch_clients, sizeof *server_opts.ch_clients, &server_opts.ch_client_count);
3432 if (ret) {
3433 goto cleanup;
3434 }
3435
3436 server_opts.ch_clients[server_opts.ch_client_count - 1].id = ATOMIC_INC_RELAXED(server_opts.new_client_id);
3437 server_opts.ch_clients[server_opts.ch_client_count - 1].start_with = NC_CH_FIRST_LISTED;
roman6430c152023-10-12 11:28:47 +02003438 server_opts.ch_clients[server_opts.ch_client_count - 1].max_attempts = 3;
roman5cbb6532023-06-22 12:53:17 +02003439
3440 pthread_mutex_init(&server_opts.ch_clients[server_opts.ch_client_count - 1].lock, NULL);
3441
3442cleanup:
3443 /* UNLOCK */
3444 pthread_rwlock_unlock(&server_opts.ch_client_lock);
3445 return ret;
3446}
3447
3448static int
3449nc_server_config_netconf_client(const struct lyd_node *node, NC_OPERATION op)
3450{
3451 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02003452
3453 assert(!strcmp(LYD_NAME(node), "netconf-client"));
3454
3455 if (op == NC_OP_CREATE) {
3456 ret = nc_server_config_create_netconf_client(node);
3457 if (ret) {
3458 goto cleanup;
3459 }
roman450c00b2023-11-02 10:31:45 +01003460
roman96c27f92023-11-02 11:09:46 +01003461#ifdef NC_ENABLED_SSH_TLS
roman450c00b2023-11-02 10:31:45 +01003462 if (server_opts.ch_dispatch_data.acquire_ctx_cb && server_opts.ch_dispatch_data.release_ctx_cb &&
roman96c27f92023-11-02 11:09:46 +01003463 server_opts.ch_dispatch_data.new_session_cb) {
roman450c00b2023-11-02 10:31:45 +01003464 /* we have all we need for dispatching a new call home thread */
3465 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 +01003466 server_opts.ch_dispatch_data.release_ctx_cb, server_opts.ch_dispatch_data.ctx_cb_data,
3467 server_opts.ch_dispatch_data.new_session_cb, server_opts.ch_dispatch_data.new_session_cb_data);
roman450c00b2023-11-02 10:31:45 +01003468 if (ret) {
3469 ERR(NULL, "Dispatching a new Call Home thread failed for Call Home client \"%s\".", lyd_get_value(lyd_child(node)));
3470 goto cleanup;
3471 }
3472 }
roman96c27f92023-11-02 11:09:46 +01003473#endif /* NC_ENABLED_SSH_TLS */
roman5cbb6532023-06-22 12:53:17 +02003474 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01003475 nc_server_config_ch_del_client(node);
roman5cbb6532023-06-22 12:53:17 +02003476 }
3477
3478cleanup:
3479 return ret;
3480}
3481
3482#ifdef NC_ENABLED_SSH_TLS
3483
3484static int
3485nc_server_config_remote_address(const struct lyd_node *node, NC_OPERATION op)
3486{
3487 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02003488 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01003489 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02003490
romanb6f44032023-06-30 15:07:56 +02003491 assert(!strcmp(LYD_NAME(node), "remote-address"));
3492
romanba93eac2023-07-18 14:36:48 +02003493 /* LOCK */
3494 if (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 }
3498
roman8341e8b2023-11-23 16:12:42 +01003499 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +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(ch_endpt->address);
roman5cbb6532023-06-22 12:53:17 +02003506 ch_endpt->address = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003507 NC_CHECK_ERRMEM_GOTO(!ch_endpt->address, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02003508 } else {
roman6430c152023-10-12 11:28:47 +02003509 free(ch_endpt->address);
3510 ch_endpt->address = NULL;
roman5cbb6532023-06-22 12:53:17 +02003511 }
3512
3513cleanup:
romanba93eac2023-07-18 14:36:48 +02003514 /* UNLOCK */
3515 nc_ch_client_unlock(ch_client);
roman5cbb6532023-06-22 12:53:17 +02003516 return ret;
3517}
3518
3519static int
3520nc_server_config_remote_port(const struct lyd_node *node, NC_OPERATION op)
3521{
3522 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02003523 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01003524 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02003525
romanb6f44032023-06-30 15:07:56 +02003526 assert(!strcmp(LYD_NAME(node), "remote-port"));
3527
romanba93eac2023-07-18 14:36:48 +02003528 /* LOCK */
3529 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003530 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003531 return 1;
3532 }
3533
roman8341e8b2023-11-23 16:12:42 +01003534 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02003535 ret = 1;
3536 goto cleanup;
3537 }
3538
3539 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02003540 ch_endpt->port = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02003541 } else {
3542 ch_endpt->port = 0;
3543 }
3544
3545cleanup:
romanba93eac2023-07-18 14:36:48 +02003546 /* UNLOCK */
3547 nc_ch_client_unlock(ch_client);
roman5cbb6532023-06-22 12:53:17 +02003548 return ret;
3549}
3550
3551#endif /* NC_ENABLED_SSH_TLS */
3552
3553static int
romanb6f44032023-06-30 15:07:56 +02003554nc_server_config_persistent(const struct lyd_node *node, NC_OPERATION op)
3555{
3556 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003557 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003558
3559 assert(!strcmp(LYD_NAME(node), "persistent"));
3560
3561 (void) op;
3562
romanba93eac2023-07-18 14:36:48 +02003563 /* LOCK */
3564 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003565 /* to avoid unlock on fail */
3566 return 1;
romanb6f44032023-06-30 15:07:56 +02003567 }
3568
3569 ch_client->conn_type = NC_CH_PERSIST;
3570
romanba93eac2023-07-18 14:36:48 +02003571 /* UNLOCK */
3572 nc_ch_client_unlock(ch_client);
3573
romanb6f44032023-06-30 15:07:56 +02003574 return ret;
3575}
3576
3577static int
3578nc_server_config_periodic(const struct lyd_node *node, NC_OPERATION op)
3579{
3580 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003581 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003582
3583 assert(!strcmp(LYD_NAME(node), "periodic"));
3584
3585 (void) op;
3586
romanba93eac2023-07-18 14:36:48 +02003587 /* LOCK */
3588 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003589 /* to avoid unlock on fail */
3590 return 1;
romanb6f44032023-06-30 15:07:56 +02003591 }
3592
3593 ch_client->conn_type = NC_CH_PERIOD;
3594 /* set default values */
3595 ch_client->period = 60;
3596 ch_client->anchor_time = 0;
3597 ch_client->idle_timeout = 180;
3598
romanba93eac2023-07-18 14:36:48 +02003599 /* UNLOCK */
3600 nc_ch_client_unlock(ch_client);
3601
romanb6f44032023-06-30 15:07:56 +02003602 return ret;
3603}
3604
3605static int
3606nc_server_config_period(const struct lyd_node *node, NC_OPERATION op)
3607{
3608 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003609 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003610
3611 assert(!strcmp(LYD_NAME(node), "period"));
3612
romanba93eac2023-07-18 14:36:48 +02003613 /* LOCK */
3614 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003615 /* to avoid unlock on fail */
3616 return 1;
romanb6f44032023-06-30 15:07:56 +02003617 }
3618
3619 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02003620 ch_client->period = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02003621 } else if (op == NC_OP_DELETE) {
3622 ch_client->period = 60;
3623 }
3624
romanba93eac2023-07-18 14:36:48 +02003625 /* UNLOCK */
3626 nc_ch_client_unlock(ch_client);
3627
romanb6f44032023-06-30 15:07:56 +02003628 return ret;
3629}
3630
3631static int
3632nc_server_config_anchor_time(const struct lyd_node *node, NC_OPERATION op)
3633{
3634 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003635 struct nc_ch_client *ch_client = NULL;
romana3c95c72023-10-26 11:15:53 +02003636 struct lyd_value_date_and_time *anchor_time;
romanb6f44032023-06-30 15:07:56 +02003637
3638 assert(!strcmp(LYD_NAME(node), "anchor-time"));
3639
romanba93eac2023-07-18 14:36:48 +02003640 /* LOCK */
3641 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003642 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003643 return 1;
romanb6f44032023-06-30 15:07:56 +02003644 }
3645
romana3c95c72023-10-26 11:15:53 +02003646 /* get the value of time from the node directly */
3647 LYD_VALUE_GET(&((struct lyd_node_term *)node)->value, anchor_time);
romanb6f44032023-06-30 15:07:56 +02003648
3649 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romana3c95c72023-10-26 11:15:53 +02003650 ch_client->anchor_time = anchor_time->time;
romanb6f44032023-06-30 15:07:56 +02003651 } else if (op == NC_OP_DELETE) {
3652 ch_client->anchor_time = 0;
3653 }
3654
romanba93eac2023-07-18 14:36:48 +02003655 /* UNLOCK */
3656 nc_ch_client_unlock(ch_client);
romanb6f44032023-06-30 15:07:56 +02003657 return ret;
3658}
3659
3660static int
3661nc_server_config_reconnect_strategy(const struct lyd_node *node, NC_OPERATION op)
3662{
3663 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003664 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003665
3666 assert(!strcmp(LYD_NAME(node), "reconnect-strategy"));
3667
3668 (void) op;
3669
romanba93eac2023-07-18 14:36:48 +02003670 /* LOCK */
3671 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003672 /* to avoid unlock on fail */
3673 return 1;
romanb6f44032023-06-30 15:07:56 +02003674 }
3675
3676 /* set to default values */
3677 ch_client->start_with = NC_CH_FIRST_LISTED;
3678 ch_client->max_wait = 5;
3679 ch_client->max_attempts = 3;
3680
romanba93eac2023-07-18 14:36:48 +02003681 /* UNLOCK */
3682 nc_ch_client_unlock(ch_client);
3683
romanb6f44032023-06-30 15:07:56 +02003684 return ret;
3685}
3686
3687static int
3688nc_server_config_start_with(const struct lyd_node *node, NC_OPERATION op)
3689{
3690 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003691 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003692 const char *value;
3693
3694 assert(!strcmp(LYD_NAME(node), "start-with"));
3695
romanba93eac2023-07-18 14:36:48 +02003696 /* LOCK */
3697 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003698 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003699 return 1;
romanb6f44032023-06-30 15:07:56 +02003700 }
3701
3702 if (op == NC_OP_DELETE) {
3703 ch_client->start_with = NC_CH_FIRST_LISTED;
3704 goto cleanup;
3705 }
3706
3707 value = lyd_get_value(node);
3708 if (!strcmp(value, "first-listed")) {
3709 ch_client->start_with = NC_CH_FIRST_LISTED;
3710 } else if (!strcmp(value, "last-connected")) {
3711 ch_client->start_with = NC_CH_LAST_CONNECTED;
3712 } else if (!strcmp(value, "random-selection")) {
3713 ch_client->start_with = NC_CH_RANDOM;
3714 } else {
3715 ERR(NULL, "Unexpected start-with value \"%s\".", value);
3716 ret = 1;
3717 goto cleanup;
3718 }
3719
3720cleanup:
romanba93eac2023-07-18 14:36:48 +02003721 /* UNLOCK */
3722 nc_ch_client_unlock(ch_client);
romanb6f44032023-06-30 15:07:56 +02003723 return ret;
3724}
3725
3726static int
3727nc_server_config_max_wait(const struct lyd_node *node, NC_OPERATION op)
3728{
3729 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003730 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003731
3732 assert(!strcmp(LYD_NAME(node), "max-wait"));
3733
romanba93eac2023-07-18 14:36:48 +02003734 /* LOCK */
3735 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003736 /* to avoid unlock on fail */
3737 return 1;
romanb6f44032023-06-30 15:07:56 +02003738 }
3739
3740 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02003741 ch_client->max_wait = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02003742 } else {
3743 ch_client->max_wait = 5;
3744 }
3745
romanba93eac2023-07-18 14:36:48 +02003746 /* UNLOCK */
3747 nc_ch_client_unlock(ch_client);
3748
romanb6f44032023-06-30 15:07:56 +02003749 return ret;
3750}
3751
3752static int
3753nc_server_config_max_attempts(const struct lyd_node *node, NC_OPERATION op)
3754{
3755 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003756 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003757
3758 assert(!strcmp(LYD_NAME(node), "max-attempts"));
3759
romanba93eac2023-07-18 14:36:48 +02003760 /* LOCK */
3761 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003762 /* to avoid unlock on fail */
3763 return 1;
romanb6f44032023-06-30 15:07:56 +02003764 }
3765
3766 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02003767 ch_client->max_attempts = ((struct lyd_node_term *)node)->value.uint8;
romanb6f44032023-06-30 15:07:56 +02003768 } else {
3769 ch_client->max_attempts = 3;
3770 }
3771
romanba93eac2023-07-18 14:36:48 +02003772 /* UNLOCK */
3773 nc_ch_client_unlock(ch_client);
3774
romanb6f44032023-06-30 15:07:56 +02003775 return ret;
3776}
3777
3778static int
romanf02273a2023-05-25 09:44:11 +02003779nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01003780{
3781 const char *name = LYD_NAME(node);
roman6430c152023-10-12 11:28:47 +02003782 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01003783
3784 if (!strcmp(name, "listen")) {
roman6430c152023-10-12 11:28:47 +02003785 ret = nc_server_config_listen(node, op);
3786 } else if (!strcmp(name, "call-home")) {
3787 ret = nc_server_config_ch(node, op);
romanc1d2b092023-02-02 08:58:27 +01003788 } else if (!strcmp(name, "endpoint")) {
roman6430c152023-10-12 11:28:47 +02003789 ret = nc_server_config_endpoint(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003790 }
roman2eab4742023-06-06 10:00:26 +02003791#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02003792 else if (!strcmp(name, "ssh")) {
roman6430c152023-10-12 11:28:47 +02003793 ret = nc_server_config_ssh(node, op);
roman2eab4742023-06-06 10:00:26 +02003794 } else if (!strcmp(name, "local-address")) {
roman6430c152023-10-12 11:28:47 +02003795 ret = nc_server_config_local_address(node, op);
romanc1d2b092023-02-02 08:58:27 +01003796 } else if (!strcmp(name, "local-port")) {
roman6430c152023-10-12 11:28:47 +02003797 ret = nc_server_config_local_port(node, op);
romanc1d2b092023-02-02 08:58:27 +01003798 } else if (!strcmp(name, "keepalives")) {
roman6430c152023-10-12 11:28:47 +02003799 ret = nc_server_config_keepalives(node, op);
romanc1d2b092023-02-02 08:58:27 +01003800 } else if (!strcmp(name, "idle-time")) {
roman6430c152023-10-12 11:28:47 +02003801 ret = nc_server_config_idle_time(node, op);
romanc1d2b092023-02-02 08:58:27 +01003802 } else if (!strcmp(name, "max-probes")) {
roman6430c152023-10-12 11:28:47 +02003803 ret = nc_server_config_max_probes(node, op);
romanc1d2b092023-02-02 08:58:27 +01003804 } else if (!strcmp(name, "probe-interval")) {
roman6430c152023-10-12 11:28:47 +02003805 ret = nc_server_config_probe_interval(node, op);
roman2eab4742023-06-06 10:00:26 +02003806 } else if (!strcmp(name, "host-key")) {
roman6430c152023-10-12 11:28:47 +02003807 ret = nc_server_config_host_key(node, op);
roman2eab4742023-06-06 10:00:26 +02003808 } else if (!strcmp(name, "public-key-format")) {
roman6430c152023-10-12 11:28:47 +02003809 ret = nc_server_config_public_key_format(node, op);
romanc1d2b092023-02-02 08:58:27 +01003810 } else if (!strcmp(name, "public-key")) {
roman6430c152023-10-12 11:28:47 +02003811 ret = nc_server_config_public_key(node, op);
romanc1d2b092023-02-02 08:58:27 +01003812 } else if (!strcmp(name, "private-key-format")) {
roman6430c152023-10-12 11:28:47 +02003813 ret = nc_server_config_private_key_format(node, op);
romanc1d2b092023-02-02 08:58:27 +01003814 } else if (!strcmp(name, "cleartext-private-key")) {
roman6430c152023-10-12 11:28:47 +02003815 ret = nc_server_config_cleartext_private_key(node, op);
Michal Vaskocf898172024-01-15 15:04:28 +01003816 } else if (!strcmp(name, "central-keystore-reference")) {
roman6430c152023-10-12 11:28:47 +02003817 ret = nc_server_config_keystore_reference(node, op);
romanc1d2b092023-02-02 08:58:27 +01003818 } else if (!strcmp(name, "user")) {
roman6430c152023-10-12 11:28:47 +02003819 ret = nc_server_config_user(node, op);
romanc1d2b092023-02-02 08:58:27 +01003820 } else if (!strcmp(name, "auth-attempts")) {
roman6430c152023-10-12 11:28:47 +02003821 ret = nc_server_config_auth_attempts(node, op);
romanc1d2b092023-02-02 08:58:27 +01003822 } else if (!strcmp(name, "auth-timeout")) {
roman6430c152023-10-12 11:28:47 +02003823 ret = nc_server_config_auth_timeout(node, op);
Michal Vaskocf898172024-01-15 15:04:28 +01003824 } else if (!strcmp(name, "central-truststore-reference")) {
roman6430c152023-10-12 11:28:47 +02003825 ret = nc_server_config_truststore_reference(node, op);
romana9ec3362023-12-21 10:59:57 +01003826 } else if (!strcmp(name, "use-system-keys")) {
3827 ret = nc_server_config_use_system_keys(node, op);
roman2eab4742023-06-06 10:00:26 +02003828 } else if (!strcmp(name, "password")) {
roman6430c152023-10-12 11:28:47 +02003829 ret = nc_server_config_password(node, op);
romanc6518422023-11-30 16:39:00 +01003830 } else if (!strcmp(name, "use-system-auth")) {
3831 ret = nc_server_config_use_system_auth(node, op);
romanc1d2b092023-02-02 08:58:27 +01003832 } else if (!strcmp(name, "none")) {
roman6430c152023-10-12 11:28:47 +02003833 ret = nc_server_config_none(node, op);
romanc1d2b092023-02-02 08:58:27 +01003834 } else if (!strcmp(name, "host-key-alg")) {
roman6430c152023-10-12 11:28:47 +02003835 ret = nc_server_config_host_key_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01003836 } else if (!strcmp(name, "key-exchange-alg")) {
roman6430c152023-10-12 11:28:47 +02003837 ret = nc_server_config_kex_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01003838 } else if (!strcmp(name, "encryption-alg")) {
roman6430c152023-10-12 11:28:47 +02003839 ret = nc_server_config_encryption_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01003840 } else if (!strcmp(name, "mac-alg")) {
roman6430c152023-10-12 11:28:47 +02003841 ret = nc_server_config_mac_alg(node, op);
roman78df0fa2023-11-02 10:33:57 +01003842 } else if (!strcmp(name, "endpoint-reference")) {
3843 ret = nc_server_config_endpoint_reference(node, op);
roman2eab4742023-06-06 10:00:26 +02003844 } else if (!strcmp(name, "tls")) {
roman6430c152023-10-12 11:28:47 +02003845 ret = nc_server_config_tls(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003846 } else if (!strcmp(name, "cert-data")) {
roman6430c152023-10-12 11:28:47 +02003847 ret = nc_server_config_cert_data(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003848 } else if (!strcmp(name, "asymmetric-key")) {
roman6430c152023-10-12 11:28:47 +02003849 ret = nc_server_config_asymmetric_key(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003850 } else if (!strcmp(name, "certificate")) {
roman6430c152023-10-12 11:28:47 +02003851 ret = nc_server_config_certificate(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003852 } else if (!strcmp(name, "cert-to-name")) {
roman6430c152023-10-12 11:28:47 +02003853 ret = nc_server_config_cert_to_name(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003854 } else if (!strcmp(name, "fingerprint")) {
roman6430c152023-10-12 11:28:47 +02003855 ret = nc_server_config_fingerprint(node, op);
roman12644fe2023-06-08 11:06:42 +02003856 } else if (!strcmp(name, "tls-version")) {
roman6430c152023-10-12 11:28:47 +02003857 ret = nc_server_config_tls_version(node, op);
roman12644fe2023-06-08 11:06:42 +02003858 } else if (!strcmp(name, "cipher-suite")) {
roman6430c152023-10-12 11:28:47 +02003859 ret = nc_server_config_cipher_suite(node, op);
romanfaecc582023-06-15 16:13:31 +02003860 } else if (!strcmp(name, "crl-url")) {
roman6430c152023-10-12 11:28:47 +02003861 ret = nc_server_config_crl_url(node, op);
romanfaecc582023-06-15 16:13:31 +02003862 } else if (!strcmp(name, "crl-path")) {
roman6430c152023-10-12 11:28:47 +02003863 ret = nc_server_config_crl_path(node, op);
romanfaecc582023-06-15 16:13:31 +02003864 } else if (!strcmp(name, "crl-cert-ext")) {
roman6430c152023-10-12 11:28:47 +02003865 ret = nc_server_config_crl_cert_ext(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003866 }
roman2eab4742023-06-06 10:00:26 +02003867#endif /* NC_ENABLED_SSH_TLS */
roman5cbb6532023-06-22 12:53:17 +02003868 else if (!strcmp(name, "netconf-client")) {
roman6430c152023-10-12 11:28:47 +02003869 ret = nc_server_config_netconf_client(node, op);
roman5cbb6532023-06-22 12:53:17 +02003870 }
3871#ifdef NC_ENABLED_SSH_TLS
3872 else if (!strcmp(name, "remote-address")) {
roman6430c152023-10-12 11:28:47 +02003873 ret = nc_server_config_remote_address(node, op);
roman5cbb6532023-06-22 12:53:17 +02003874 } else if (!strcmp(name, "remote-port")) {
roman6430c152023-10-12 11:28:47 +02003875 ret = nc_server_config_remote_port(node, op);
roman5cbb6532023-06-22 12:53:17 +02003876 }
3877#endif /* NC_ENABLED_SSH_TLS */
romanb6f44032023-06-30 15:07:56 +02003878 else if (!strcmp(name, "persistent")) {
roman6430c152023-10-12 11:28:47 +02003879 ret = nc_server_config_persistent(node, op);
romanb6f44032023-06-30 15:07:56 +02003880 } else if (!strcmp(name, "periodic")) {
roman6430c152023-10-12 11:28:47 +02003881 ret = nc_server_config_periodic(node, op);
romanb6f44032023-06-30 15:07:56 +02003882 } else if (!strcmp(name, "period")) {
roman6430c152023-10-12 11:28:47 +02003883 ret = nc_server_config_period(node, op);
romanb6f44032023-06-30 15:07:56 +02003884 } else if (!strcmp(name, "anchor-time")) {
roman6430c152023-10-12 11:28:47 +02003885 ret = nc_server_config_anchor_time(node, op);
romaneaf84c72023-10-19 14:38:05 +02003886 } else if (!strcmp(name, "idle-timeout")) {
3887 ret = nc_server_config_idle_timeout(node, op);
romanb6f44032023-06-30 15:07:56 +02003888 } else if (!strcmp(name, "reconnect-strategy")) {
roman6430c152023-10-12 11:28:47 +02003889 ret = nc_server_config_reconnect_strategy(node, op);
romanb6f44032023-06-30 15:07:56 +02003890 } else if (!strcmp(name, "start-with")) {
roman6430c152023-10-12 11:28:47 +02003891 ret = nc_server_config_start_with(node, op);
romanb6f44032023-06-30 15:07:56 +02003892 } else if (!strcmp(name, "max-wait")) {
roman6430c152023-10-12 11:28:47 +02003893 ret = nc_server_config_max_wait(node, op);
romanb6f44032023-06-30 15:07:56 +02003894 } else if (!strcmp(name, "max-attempts")) {
roman6430c152023-10-12 11:28:47 +02003895 ret = nc_server_config_max_attempts(node, op);
3896 }
3897
3898 if (ret) {
3899 ERR(NULL, "Configuring node \"%s\" failed.", LYD_NAME(node));
3900 return 1;
romanb6f44032023-06-30 15:07:56 +02003901 }
romanc1d2b092023-02-02 08:58:27 +01003902
3903 return 0;
romanc1d2b092023-02-02 08:58:27 +01003904}
3905
3906int
roman0bbc19c2023-05-26 09:59:09 +02003907nc_server_config_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, NC_MODULE module)
romanc1d2b092023-02-02 08:58:27 +01003908{
3909 struct lyd_node *child;
3910 struct lyd_meta *m;
romanf9906b42023-05-22 14:04:29 +02003911 NC_OPERATION current_op = NC_OP_UNKNOWN;
romanf02273a2023-05-25 09:44:11 +02003912 int ret;
romanc1d2b092023-02-02 08:58:27 +01003913
3914 assert(node);
3915
romanf9906b42023-05-22 14:04:29 +02003916 /* get current op if there is any */
3917 if ((m = lyd_find_meta(node->meta, NULL, "yang:operation"))) {
3918 if (!strcmp(lyd_get_meta_value(m), "create")) {
3919 current_op = NC_OP_CREATE;
3920 } else if (!strcmp(lyd_get_meta_value(m), "delete")) {
3921 current_op = NC_OP_DELETE;
3922 } else if (!strcmp(lyd_get_meta_value(m), "replace")) {
3923 current_op = NC_OP_REPLACE;
3924 } else if (!strcmp(lyd_get_meta_value(m), "none")) {
3925 current_op = NC_OP_NONE;
romanc1d2b092023-02-02 08:58:27 +01003926 }
3927 }
3928
3929 /* node has no op, inherit from the parent */
romanf9906b42023-05-22 14:04:29 +02003930 if (!current_op) {
3931 if (!parent_op) {
3932 ERR(NULL, "Unknown operation for node \"%s\".", LYD_NAME(node));
3933 return 1;
3934 }
3935
romanc1d2b092023-02-02 08:58:27 +01003936 current_op = parent_op;
3937 }
3938
3939 switch (current_op) {
3940 case NC_OP_NONE:
3941 break;
3942 case NC_OP_CREATE:
3943 case NC_OP_DELETE:
3944 case NC_OP_REPLACE:
roman2eab4742023-06-06 10:00:26 +02003945#ifdef NC_ENABLED_SSH_TLS
3946 if (module == NC_MODULE_KEYSTORE) {
romanf02273a2023-05-25 09:44:11 +02003947 ret = nc_server_config_parse_keystore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02003948 } else if (module == NC_MODULE_TRUSTSTORE) {
romanf02273a2023-05-25 09:44:11 +02003949 ret = nc_server_config_parse_truststore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02003950 } else
3951#endif /* NC_ENABLED_SSH_TLS */
3952 {
3953 ret = nc_server_config_parse_netconf_server(node, current_op);
romanf02273a2023-05-25 09:44:11 +02003954 }
3955 if (ret) {
3956 return ret;
romanc1d2b092023-02-02 08:58:27 +01003957 }
3958 break;
3959 default:
3960 break;
3961 }
3962
3963 if (current_op != NC_OP_DELETE) {
3964 LY_LIST_FOR(lyd_child(node), child) {
roman0bbc19c2023-05-26 09:59:09 +02003965 if (nc_server_config_parse_tree(child, current_op, module)) {
romanc1d2b092023-02-02 08:58:27 +01003966 return 1;
3967 }
3968 }
3969 }
3970 return 0;
3971}
3972
romanc1d2b092023-02-02 08:58:27 +01003973API int
3974nc_server_config_load_modules(struct ly_ctx **ctx)
3975{
3976 int i, new_ctx = 0;
3977
3978 if (!*ctx) {
3979 if (ly_ctx_new(NC_SERVER_SEARCH_DIR, 0, ctx)) {
3980 ERR(NULL, "Couldn't create new libyang context.\n");
3981 goto error;
3982 }
3983 new_ctx = 1;
3984 }
3985
3986 /* all features */
3987 const char *ietf_nectonf_server[] = {"ssh-listen", "tls-listen", "ssh-call-home", "tls-call-home", "central-netconf-server-supported", NULL};
3988 /* all features */
3989 const char *ietf_x509_cert_to_name[] = {NULL};
roman7fdc84d2023-06-06 13:14:53 +02003990 /* no private-key-encryption, csr-generation, p10-csr-format, certificate-expiration-notification,
roman3c6c7e62023-09-14 10:19:19 +02003991 * encrypted-passwords, hidden-symmetric-keys, encrypted-symmetric-keys, hidden-private-keys, encrypted-private-keys,
3992 * one-symmetric-key-format, one-asymmetric-key-format, symmetrically-encrypted-value-format,
3993 * asymmetrically-encrypted-value-format, cms-enveloped-data-format, cms-encrypted-data-format,
Roytakb2794852023-10-18 14:30:22 +02003994 * cleartext-symmetric-keys */
roman3c6c7e62023-09-14 10:19:19 +02003995 const char *ietf_crypto_types[] = {"cleartext-passwords", "cleartext-private-keys", NULL};
romanc1d2b092023-02-02 08:58:27 +01003996 /* all features */
3997 const char *ietf_tcp_common[] = {"keepalives-supported", NULL};
roman7fdc84d2023-06-06 13:14:53 +02003998 /* all features */
3999 const char *ietf_tcp_server[] = {"tcp-server-keepalives", NULL};
Roytakb2794852023-10-18 14:30:22 +02004000 /* no proxy-connect, socks5-gss-api, socks5-username-password, local-binding-supported ? */
4001 const char *ietf_tcp_client[] = {"tcp-client-keepalives", NULL};
roman3c6c7e62023-09-14 10:19:19 +02004002 /* no ssh-x509-certs, public-key-generation */
4003 const char *ietf_ssh_common[] = {"transport-params", NULL};
roman7fdc84d2023-06-06 13:14:53 +02004004 /* no ssh-server-keepalives and local-user-auth-hostbased */
4005 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 +01004006 /* all features */
4007 const char *iana_ssh_encryption_algs[] = {NULL};
4008 /* all features */
4009 const char *iana_ssh_key_exchange_algs[] = {NULL};
4010 /* all features */
4011 const char *iana_ssh_mac_algs[] = {NULL};
4012 /* all features */
4013 const char *iana_ssh_public_key_algs[] = {NULL};
romanc1d2b092023-02-02 08:58:27 +01004014 /* all features */
roman7fdc84d2023-06-06 13:14:53 +02004015 const char *iana_crypt_hash[] = {"crypt-hash-md5", "crypt-hash-sha-256", "crypt-hash-sha-512", NULL};
4016 /* no symmetric-keys */
4017 const char *ietf_keystore[] = {"central-keystore-supported", "inline-definitions-supported", "asymmetric-keys", NULL};
4018 /* all features */
4019 const char *ietf_truststore[] = {"central-truststore-supported", "inline-definitions-supported", "certificates", "public-keys", NULL};
roman3c6c7e62023-09-14 10:19:19 +02004020 /* no public-key-generation */
4021 const char *ietf_tls_common[] = {"tls10", "tls11", "tls12", "tls13", "hello-params", NULL};
4022 /* no tls-server-keepalives, server-ident-raw-public-key, server-ident-tls12-psk, server-ident-tls13-epsk,
4023 * client-auth-raw-public-key, client-auth-tls12-psk, client-auth-tls13-epsk */
4024 const char *ietf_tls_server[] = {"server-ident-x509-cert", "client-auth-supported", "client-auth-x509-cert", NULL};
roman7fdc84d2023-06-06 13:14:53 +02004025 /* all features */
roman12644fe2023-06-08 11:06:42 +02004026 const char *iana_tls_cipher_suite_algs[] = {NULL};
romanc1d2b092023-02-02 08:58:27 +01004027 /* all features */
4028 const char *libnetconf2_netconf_server[] = {NULL};
4029
4030 const char *module_names[] = {
roman7fdc84d2023-06-06 13:14:53 +02004031 "ietf-netconf-server", "ietf-x509-cert-to-name", "ietf-crypto-types", "ietf-tcp-common", "ietf-tcp-server",
4032 "ietf-tcp-client", "ietf-ssh-common", "ietf-ssh-server", "iana-ssh-encryption-algs",
4033 "iana-ssh-key-exchange-algs", "iana-ssh-mac-algs", "iana-ssh-public-key-algs", "iana-crypt-hash",
roman12644fe2023-06-08 11:06:42 +02004034 "ietf-keystore", "ietf-truststore", "ietf-tls-common", "ietf-tls-server", "iana-tls-cipher-suite-algs",
4035 "libnetconf2-netconf-server", NULL
romanc1d2b092023-02-02 08:58:27 +01004036 };
4037
4038 const char **module_features[] = {
roman7fdc84d2023-06-06 13:14:53 +02004039 ietf_nectonf_server, ietf_x509_cert_to_name, ietf_crypto_types, ietf_tcp_common,
4040 ietf_tcp_server, ietf_tcp_client, ietf_ssh_common, ietf_ssh_server, iana_ssh_encryption_algs,
4041 iana_ssh_key_exchange_algs, iana_ssh_mac_algs, iana_ssh_public_key_algs, iana_crypt_hash,
roman12644fe2023-06-08 11:06:42 +02004042 ietf_keystore, ietf_truststore, ietf_tls_common, ietf_tls_server, iana_tls_cipher_suite_algs,
4043 libnetconf2_netconf_server, NULL
romanc1d2b092023-02-02 08:58:27 +01004044 };
4045
4046 for (i = 0; module_names[i] != NULL; i++) {
4047 if (!ly_ctx_load_module(*ctx, module_names[i], NULL, module_features[i])) {
4048 ERR(NULL, "Loading module \"%s\" failed.\n", module_names[i]);
4049 goto error;
4050 }
4051 }
4052
4053 return 0;
4054
4055error:
4056 if (new_ctx) {
4057 ly_ctx_destroy(*ctx);
4058 *ctx = NULL;
4059 }
4060 return 1;
4061}
4062
romanf9906b42023-05-22 14:04:29 +02004063static int
Michal Vaskocf898172024-01-15 15:04:28 +01004064nc_server_config_fill_netconf_server(const struct lyd_node *data, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01004065{
4066 int ret = 0;
roman84fe3252023-10-25 11:28:32 +02004067 uint32_t log_options = 0;
romanc1d2b092023-02-02 08:58:27 +01004068 struct lyd_node *tree;
romand57b3722023-04-05 11:26:25 +02004069
romanc9b62d62023-09-14 10:19:50 +02004070 /* silently search for ietf-netconf-server, it may not be present */
roman84fe3252023-10-25 11:28:32 +02004071 ly_temp_log_options(&log_options);
romanc9b62d62023-09-14 10:19:50 +02004072
romanc1d2b092023-02-02 08:58:27 +01004073 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &tree);
romanc9b62d62023-09-14 10:19:50 +02004074 if (ret || (tree->flags & LYD_DEFAULT)) {
4075 /* not found */
4076 ret = 0;
romanc1d2b092023-02-02 08:58:27 +01004077 goto cleanup;
4078 }
4079
roman0bbc19c2023-05-26 09:59:09 +02004080 if (nc_server_config_parse_tree(tree, op, NC_MODULE_NETCONF_SERVER)) {
4081 ret = 1;
4082 goto cleanup;
4083 }
4084
roman2eab4742023-06-06 10:00:26 +02004085#ifdef NC_ENABLED_SSH_TLS
roman78df0fa2023-11-02 10:33:57 +01004086 /* check and set all endpoint references */
4087 if (nc_server_config_check_endpt_references()) {
romanf9906b42023-05-22 14:04:29 +02004088 ret = 1;
4089 goto cleanup;
4090 }
roman2eab4742023-06-06 10:00:26 +02004091#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004092
4093cleanup:
romanc9b62d62023-09-14 10:19:50 +02004094 /* reset the logging options back to what they were */
roman84fe3252023-10-25 11:28:32 +02004095 ly_temp_log_options(NULL);
romanf9906b42023-05-22 14:04:29 +02004096 return ret;
4097}
4098
4099API int
romanf6f37a52023-05-25 14:27:51 +02004100nc_server_config_setup_diff(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02004101{
4102 int ret = 0;
4103
romanc9b62d62023-09-14 10:19:50 +02004104 NC_CHECK_ARG_RET(NULL, data, 1);
4105
romanf9906b42023-05-22 14:04:29 +02004106 /* LOCK */
4107 pthread_rwlock_wrlock(&server_opts.config_lock);
4108
roman2eab4742023-06-06 10:00:26 +02004109#ifdef NC_ENABLED_SSH_TLS
romanf9906b42023-05-22 14:04:29 +02004110 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02004111 ret = nc_server_config_fill_keystore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02004112 if (ret) {
4113 ERR(NULL, "Filling keystore failed.");
4114 goto cleanup;
4115 }
4116
4117 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02004118 ret = nc_server_config_fill_truststore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02004119 if (ret) {
4120 ERR(NULL, "Filling truststore failed.");
4121 goto cleanup;
4122 }
roman2eab4742023-06-06 10:00:26 +02004123#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004124
4125 /* configure netconf-server */
Michal Vaskocf898172024-01-15 15:04:28 +01004126 ret = nc_server_config_fill_netconf_server(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02004127 if (ret) {
4128 ERR(NULL, "Filling netconf-server failed.");
4129 goto cleanup;
4130 }
4131
4132cleanup:
4133 /* UNLOCK */
4134 pthread_rwlock_unlock(&server_opts.config_lock);
4135 return ret;
4136}
4137
4138API int
romanf6f37a52023-05-25 14:27:51 +02004139nc_server_config_setup_data(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02004140{
4141 int ret = 0;
4142 struct lyd_node *tree, *iter, *root;
4143
romanc9b62d62023-09-14 10:19:50 +02004144 NC_CHECK_ARG_RET(NULL, data, 1);
4145
romanf9906b42023-05-22 14:04:29 +02004146 /* LOCK */
4147 pthread_rwlock_wrlock(&server_opts.config_lock);
4148
4149 /* find the netconf-server node */
4150 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &root);
4151 if (ret) {
4152 ERR(NULL, "Unable to find the netconf-server container in the YANG data.");
4153 goto cleanup;
4154 }
4155
4156 /* iterate through all the nodes and make sure there is no operation attribute */
4157 LY_LIST_FOR(root, tree) {
4158 LYD_TREE_DFS_BEGIN(tree, iter) {
4159 if (lyd_find_meta(iter->meta, NULL, "yang:operation")) {
4160 ERR(NULL, "Unexpected operation attribute in the YANG data.");
romanc1d2b092023-02-02 08:58:27 +01004161 ret = 1;
4162 goto cleanup;
4163 }
romanf9906b42023-05-22 14:04:29 +02004164 LYD_TREE_DFS_END(tree, iter);
romanc1d2b092023-02-02 08:58:27 +01004165 }
4166 }
4167
romanf9906b42023-05-22 14:04:29 +02004168 /* delete the current configuration */
romanf02273a2023-05-25 09:44:11 +02004169 nc_server_config_listen(NULL, NC_OP_DELETE);
roman4cb8bb12023-06-29 09:16:46 +02004170 nc_server_config_ch(NULL, NC_OP_DELETE);
roman2eab4742023-06-06 10:00:26 +02004171#ifdef NC_ENABLED_SSH_TLS
romanf02273a2023-05-25 09:44:11 +02004172 nc_server_config_ks_keystore(NULL, NC_OP_DELETE);
4173 nc_server_config_ts_truststore(NULL, NC_OP_DELETE);
romanf9906b42023-05-22 14:04:29 +02004174
4175 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02004176 ret = nc_server_config_fill_keystore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02004177 if (ret) {
4178 ERR(NULL, "Filling keystore failed.");
4179 goto cleanup;
4180 }
4181
4182 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02004183 ret = nc_server_config_fill_truststore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02004184 if (ret) {
4185 ERR(NULL, "Filling truststore failed.");
4186 goto cleanup;
4187 }
roman2eab4742023-06-06 10:00:26 +02004188#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004189
4190 /* configure netconf-server */
Michal Vaskocf898172024-01-15 15:04:28 +01004191 ret = nc_server_config_fill_netconf_server(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02004192 if (ret) {
4193 ERR(NULL, "Filling netconf-server failed.");
romanc1d2b092023-02-02 08:58:27 +01004194 goto cleanup;
4195 }
4196
4197cleanup:
4198 /* UNLOCK */
4199 pthread_rwlock_unlock(&server_opts.config_lock);
4200 return ret;
4201}
roman3f9b65c2023-06-05 14:26:58 +02004202
4203API int
4204nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path)
4205{
4206 struct lyd_node *tree = NULL;
4207 int ret = 0;
4208
4209 NC_CHECK_ARG_RET(NULL, path, 1);
4210
4211 ret = lyd_parse_data_path(ctx, path, LYD_UNKNOWN, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree);
4212 if (ret) {
4213 goto cleanup;
4214 }
4215
4216 ret = nc_server_config_setup_data(tree);
4217 if (ret) {
4218 goto cleanup;
4219 }
4220
4221cleanup:
4222 lyd_free_all(tree);
4223 return ret;
4224}
romand05b2ad2024-01-23 12:02:40 +01004225
4226#ifdef NC_ENABLED_SSH_TLS
4227
4228static int
4229nc_server_config_oper_get_algs(const struct ly_ctx *ctx, const char *mod_name, const char *ln2_algs[],
4230 const char *mod_algs[], struct lyd_node **algs)
4231{
4232 int ret, r, i;
4233 struct lyd_node *parent = NULL;
4234 char *path = NULL;
4235
4236 NC_CHECK_ARG_RET(NULL, ctx, mod_name, ln2_algs, mod_algs, algs, 1);
4237
4238 *algs = NULL;
4239
4240 r = asprintf(&path, "/%s:supported-algorithms", mod_name);
4241 NC_CHECK_ERRMEM_RET(r == -1, 1);
4242
4243 /* create supported algorithms container */
4244 ret = lyd_new_path(NULL, ctx, path, NULL, 0, &parent);
4245 free(path);
4246 if (ret) {
4247 ERR(NULL, "Creating supported algorithms container failed.");
4248 goto cleanup;
4249 }
4250
4251 /* append algs from libnetconf2-netconf-server */
4252 for (i = 0; ln2_algs[i]; i++) {
4253 r = asprintf(&path, "libnetconf2-netconf-server:%s", ln2_algs[i]);
4254 NC_CHECK_ERRMEM_GOTO(r == -1, ret = 1, cleanup);
4255 ret = lyd_new_term(parent, NULL, "supported-algorithm", path, 0, NULL);
4256 free(path);
4257 if (ret) {
4258 ERR(NULL, "Creating new supported algorithm failed.");
4259 goto cleanup;
4260 }
4261 }
4262
4263 /* append algs from mod_name module */
4264 for (i = 0; mod_algs[i]; i++) {
4265 r = asprintf(&path, "%s:%s", mod_name, mod_algs[i]);
4266 NC_CHECK_ERRMEM_GOTO(r == -1, ret = 1, cleanup);
4267 ret = lyd_new_term(parent, NULL, "supported-algorithm", path, 0, NULL);
4268 free(path);
4269 if (ret) {
4270 ERR(NULL, "Creating new supported algorithm failed.");
4271 goto cleanup;
4272 }
4273 }
4274
4275cleanup:
4276 if (ret) {
4277 lyd_free_tree(parent);
4278 } else {
4279 *algs = parent;
4280 }
4281 return ret;
4282}
4283
4284API int
4285nc_server_config_oper_get_hostkey_algs(const struct ly_ctx *ctx, struct lyd_node **hostkey_algs)
4286{
4287 /* identities of hostkey algs supported by libssh (v0.10.5) defined in libnetconf2-netconf-server yang module */
4288 const char *libnetconf2_hostkey_algs[] = {
4289 "openssh-ssh-ed25519-cert-v01", "openssh-ecdsa-sha2-nistp521-cert-v01",
4290 "openssh-ecdsa-sha2-nistp384-cert-v01", "openssh-ecdsa-sha2-nistp256-cert-v01",
4291 "openssh-rsa-sha2-512-cert-v01", "openssh-rsa-sha2-256-cert-v01",
4292 "openssh-ssh-rsa-cert-v01", "openssh-ssh-dss-cert-v01", NULL
4293 };
4294
4295 /* identities of hostkey algs supported by libssh (v0.10.5) defined in iana-ssh-public-key-algs yang module */
4296 const char *iana_hostkey_algs[] = {
4297 "ssh-ed25519", "ecdsa-sha2-nistp521", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp256",
4298 "rsa-sha2-512", "rsa-sha2-256", "ssh-rsa", "ssh-dss", NULL
4299 };
4300
4301 NC_CHECK_ARG_RET(NULL, ctx, hostkey_algs, 1);
4302
4303 return nc_server_config_oper_get_algs(ctx, "iana-ssh-public-key-algs", libnetconf2_hostkey_algs,
4304 iana_hostkey_algs, hostkey_algs);
4305}
4306
4307API int
4308nc_server_config_oper_get_kex_algs(const struct ly_ctx *ctx, struct lyd_node **kex_algs)
4309{
4310 /* identities of kex algs supported by libssh (v0.10.5) defined in libnetconf2-netconf-server yang module */
4311 const char *libnetconf2_kex_algs[] = {
4312 "libssh-curve25519-sha256", NULL
4313 };
4314
4315 /* identities of kex algs supported by libssh (v0.10.5) defined in iana-ssh-key-exchange-algs yang module */
4316 const char *iana_kex_algs[] = {
4317 "diffie-hellman-group-exchange-sha1", "curve25519-sha256", "ecdh-sha2-nistp256", "ecdh-sha2-nistp384",
4318 "ecdh-sha2-nistp521", "diffie-hellman-group18-sha512", "diffie-hellman-group16-sha512",
4319 "diffie-hellman-group-exchange-sha256", "diffie-hellman-group14-sha256", NULL
4320 };
4321
4322 NC_CHECK_ARG_RET(NULL, ctx, kex_algs, 1);
4323
4324 return nc_server_config_oper_get_algs(ctx, "iana-ssh-key-exchange-algs", libnetconf2_kex_algs,
4325 iana_kex_algs, kex_algs);
4326}
4327
4328API int
4329nc_server_config_oper_get_encryption_algs(const struct ly_ctx *ctx, struct lyd_node **encryption_algs)
4330{
4331 /* identities of encryption algs supported by libssh (v0.10.5) defined in libnetconf2-netconf-server yang module */
4332 const char *libnetconf2_encryption_algs[] = {
4333 "openssh-chacha20-poly1305", "openssh-aes256-gcm", "openssh-aes128-gcm", NULL
4334 };
4335
4336 /* identities of encryption algs supported by libssh (v0.10.5) defined in iana-ssh-encryption-algs yang module */
4337 const char *iana_encryption_algs[] = {
4338 "aes256-ctr", "aes192-ctr", "aes128-ctr", "aes256-cbc", "aes192-cbc", "aes128-cbc",
4339 "blowfish-cbc", "triple-des-cbc", "none", NULL
4340 };
4341
4342 NC_CHECK_ARG_RET(NULL, ctx, encryption_algs, 1);
4343
4344 return nc_server_config_oper_get_algs(ctx, "iana-ssh-encryption-algs", libnetconf2_encryption_algs,
4345 iana_encryption_algs, encryption_algs);
4346}
4347
4348API int
4349nc_server_config_oper_get_mac_algs(const struct ly_ctx *ctx, struct lyd_node **mac_algs)
4350{
4351 /* identities of mac algs supported by libssh (v0.10.5) defined in libnetconf2-netconf-server yang module */
4352 const char *libnetconf2_mac_algs[] = {
4353 "openssh-hmac-sha2-256-etm", "openssh-hmac-sha2-512-etm", "openssh-hmac-sha1-etm", NULL
4354 };
4355
4356 /* identities of mac algs supported by libssh (v0.10.5) defined in iana-ssh-mac-algs yang module */
4357 const char *iana_mac_algs[] = {
4358 "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1", NULL
4359 };
4360
4361 NC_CHECK_ARG_RET(NULL, ctx, mac_algs, 1);
4362
4363 return nc_server_config_oper_get_algs(ctx, "iana-ssh-mac-algs", libnetconf2_mac_algs,
4364 iana_mac_algs, mac_algs);
4365}
4366
4367#endif /* NC_ENABLED_SSH_TLS */