blob: b60dbcf243b385b5ed27d628a4a31af64c12af23 [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 nc_server_config_del_ctns(opts);
835 free(opts->ciphers);
roman3f9b65c2023-06-05 14:26:58 +0200836 free(opts);
837}
838
839static void
840nc_server_config_del_endpt_tls(struct nc_endpt *endpt, struct nc_bind *bind)
841{
roman78df0fa2023-11-02 10:33:57 +0100842 /* delete any references to this endpoint */
843 nc_server_config_del_endpt_references(endpt->name);
roman6430c152023-10-12 11:28:47 +0200844 free(endpt->name);
roman78df0fa2023-11-02 10:33:57 +0100845
roman6430c152023-10-12 11:28:47 +0200846 free(endpt->referenced_endpt_name);
847
848 nc_server_config_del_tls_opts(bind, endpt->opts.tls);
roman3f9b65c2023-06-05 14:26:58 +0200849
850 server_opts.endpt_count--;
851 if (!server_opts.endpt_count) {
852 free(server_opts.endpts);
853 free(server_opts.binds);
854 server_opts.endpts = NULL;
855 server_opts.binds = NULL;
roman6430c152023-10-12 11:28:47 +0200856 } else if (endpt != &server_opts.endpts[server_opts.endpt_count]) {
roman33981232023-07-08 11:55:13 +0200857 memcpy(endpt, &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts);
858 memcpy(bind, &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds);
roman3f9b65c2023-06-05 14:26:58 +0200859 }
860}
861
roman2eab4742023-06-06 10:00:26 +0200862#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +0200863
roman5cbb6532023-06-22 12:53:17 +0200864static void
865nc_server_config_ch_del_endpt(struct nc_ch_client *ch_client, struct nc_ch_endpt *ch_endpt)
866{
867 free(ch_endpt->name);
roman5cbb6532023-06-22 12:53:17 +0200868
869#ifdef NC_ENABLED_SSH_TLS
roman5e5d3f22024-08-08 12:44:53 +0200870 free(ch_endpt->src_addr);
871 free(ch_endpt->dst_addr);
roman5cbb6532023-06-22 12:53:17 +0200872 if (ch_endpt->sock_pending > -1) {
873 close(ch_endpt->sock_pending);
874 ch_endpt->sock_pending = -1;
875 }
roman5ae78282023-11-02 13:34:34 +0100876 free(ch_endpt->referenced_endpt_name);
roman5cbb6532023-06-22 12:53:17 +0200877#endif /* NC_ENABLED_SSH_TLS */
878
879 switch (ch_endpt->ti) {
880#ifdef NC_ENABLED_SSH_TLS
roman506354a2024-04-11 09:37:22 +0200881 case NC_TI_SSH:
roman5ae78282023-11-02 13:34:34 +0100882 nc_server_config_del_ssh_opts(NULL, ch_endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +0200883 break;
roman506354a2024-04-11 09:37:22 +0200884 case NC_TI_TLS:
roman5ae78282023-11-02 13:34:34 +0100885 nc_server_config_del_tls_opts(NULL, ch_endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +0200886 break;
roman5cbb6532023-06-22 12:53:17 +0200887#endif /* NC_ENABLED_SSH_TLS */
888 default:
889 ERRINT;
890 break;
891 }
892
893 ch_client->ch_endpt_count--;
894 if (!ch_client->ch_endpt_count) {
895 free(ch_client->ch_endpts);
896 ch_client->ch_endpts = NULL;
897 }
898}
899
900static void
roman8341e8b2023-11-23 16:12:42 +0100901nc_server_config_destroy_ch_client(struct nc_ch_client *ch_client)
roman5cbb6532023-06-22 12:53:17 +0200902{
romanba93eac2023-07-18 14:36:48 +0200903 pthread_t tid;
roman8341e8b2023-11-23 16:12:42 +0100904 uint16_t i, ch_endpt_count;
905
romaneaeb87e2023-12-07 13:08:01 +0100906 /* CH COND LOCK */
907 pthread_mutex_lock(&ch_client->thread_data->cond_lock);
roman8341e8b2023-11-23 16:12:42 +0100908 if (ch_client->thread_data->thread_running) {
roman8341e8b2023-11-23 16:12:42 +0100909 ch_client->thread_data->thread_running = 0;
910 pthread_cond_signal(&ch_client->thread_data->cond);
911 /* CH COND UNLOCK */
912 pthread_mutex_unlock(&ch_client->thread_data->cond_lock);
913
romaneaeb87e2023-12-07 13:08:01 +0100914 /* get tid */
915 tid = ch_client->tid;
916
roman8341e8b2023-11-23 16:12:42 +0100917 /* wait for the thread to terminate */
918 pthread_join(tid, NULL);
romaneaeb87e2023-12-07 13:08:01 +0100919 } else {
920 /* CH COND UNLOCK */
921 pthread_mutex_unlock(&ch_client->thread_data->cond_lock);
roman8341e8b2023-11-23 16:12:42 +0100922 }
923
924 /* free its members */
925 free(ch_client->name);
926
927 ch_endpt_count = ch_client->ch_endpt_count;
928 for (i = 0; i < ch_endpt_count; i++) {
929 nc_server_config_ch_del_endpt(ch_client, &ch_client->ch_endpts[i]);
930 }
931}
932
933static void
934nc_server_config_ch_del_client(const struct lyd_node *node)
935{
936 struct nc_ch_client client, *ch_client;
roman5cbb6532023-06-22 12:53:17 +0200937
romanba93eac2023-07-18 14:36:48 +0200938 /* WR LOCK */
roman5cbb6532023-06-22 12:53:17 +0200939 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
940
roman8341e8b2023-11-23 16:12:42 +0100941 if (nc_server_config_get_ch_client(node, &ch_client)) {
942 /* WR UNLOCK */
943 pthread_rwlock_unlock(&server_opts.ch_client_lock);
944 ERR(NULL, "Call-home client \"%s\" not found.", lyd_get_value(lyd_child(node)));
945 return;
946 }
947
romanba93eac2023-07-18 14:36:48 +0200948 /* copy the client we want to delete into a local variable */
949 memcpy(&client, ch_client, sizeof *ch_client);
roman5cbb6532023-06-22 12:53:17 +0200950
romanba93eac2023-07-18 14:36:48 +0200951 /* delete the client */
roman5cbb6532023-06-22 12:53:17 +0200952 server_opts.ch_client_count--;
953 if (!server_opts.ch_client_count) {
954 free(server_opts.ch_clients);
955 server_opts.ch_clients = NULL;
romanba93eac2023-07-18 14:36:48 +0200956 } else {
957 memcpy(ch_client, &server_opts.ch_clients[server_opts.ch_client_count], sizeof *server_opts.ch_clients);
roman5cbb6532023-06-22 12:53:17 +0200958 }
959
romanba93eac2023-07-18 14:36:48 +0200960 /* WR UNLOCK */
roman5cbb6532023-06-22 12:53:17 +0200961 pthread_rwlock_unlock(&server_opts.ch_client_lock);
romanba93eac2023-07-18 14:36:48 +0200962
roman8341e8b2023-11-23 16:12:42 +0100963 nc_server_config_destroy_ch_client(&client);
964}
romanba93eac2023-07-18 14:36:48 +0200965
roman8341e8b2023-11-23 16:12:42 +0100966/* presence container */
967int
968nc_server_config_listen(const struct lyd_node *node, NC_OPERATION op)
969{
970 uint16_t i, endpt_count;
romanba93eac2023-07-18 14:36:48 +0200971
roman8341e8b2023-11-23 16:12:42 +0100972 (void) node;
romanba93eac2023-07-18 14:36:48 +0200973
roman8341e8b2023-11-23 16:12:42 +0100974 assert(op == NC_OP_CREATE || op == NC_OP_DELETE);
975
976 if (op == NC_OP_DELETE) {
977 endpt_count = server_opts.endpt_count;
978 for (i = 0; i < endpt_count; i++) {
979 switch (server_opts.endpts[i].ti) {
980#ifdef NC_ENABLED_SSH_TLS
roman506354a2024-04-11 09:37:22 +0200981 case NC_TI_SSH:
roman8341e8b2023-11-23 16:12:42 +0100982 nc_server_config_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]);
983 break;
roman506354a2024-04-11 09:37:22 +0200984 case NC_TI_TLS:
roman8341e8b2023-11-23 16:12:42 +0100985 nc_server_config_del_endpt_tls(&server_opts.endpts[i], &server_opts.binds[i]);
986 break;
987#endif /* NC_ENABLED_SSH_TLS */
romana2ff4ef2024-01-19 14:41:46 +0100988 case NC_TI_UNIX:
989 break;
roman8341e8b2023-11-23 16:12:42 +0100990 case NC_TI_NONE:
991 case NC_TI_FD:
992 ERRINT;
993 return 1;
994 }
995 }
romanba93eac2023-07-18 14:36:48 +0200996 }
997
roman8341e8b2023-11-23 16:12:42 +0100998 return 0;
roman5cbb6532023-06-22 12:53:17 +0200999}
1000
roman6430c152023-10-12 11:28:47 +02001001int
roman5cbb6532023-06-22 12:53:17 +02001002nc_server_config_ch(const struct lyd_node *node, NC_OPERATION op)
1003{
1004 uint16_t i, ch_client_count;
roman8341e8b2023-11-23 16:12:42 +01001005 struct nc_ch_client *ch_clients;
roman5cbb6532023-06-22 12:53:17 +02001006
1007 (void) node;
1008
roman8341e8b2023-11-23 16:12:42 +01001009 /* don't do anything if we're not deleting */
1010 if (op != NC_OP_DELETE) {
1011 return 0;
roman5cbb6532023-06-22 12:53:17 +02001012 }
roman6430c152023-10-12 11:28:47 +02001013
roman8341e8b2023-11-23 16:12:42 +01001014 /* WR LOCK */
1015 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
1016
1017 ch_client_count = server_opts.ch_client_count;
1018 ch_clients = server_opts.ch_clients;
1019
1020 /* remove them from the server opts */
1021 server_opts.ch_client_count = 0;
1022 server_opts.ch_clients = NULL;
1023
1024 /* UNLOCK */
1025 pthread_rwlock_unlock(&server_opts.ch_client_lock);
1026
1027 for (i = 0; i < ch_client_count; i++) {
1028 /* now destroy each client */
1029 nc_server_config_destroy_ch_client(&ch_clients[i]);
1030 }
1031
1032 free(ch_clients);
roman6430c152023-10-12 11:28:47 +02001033 return 0;
roman5cbb6532023-06-22 12:53:17 +02001034}
1035
romanc1d2b092023-02-02 08:58:27 +01001036/* default leaf */
1037static int
romane028ef92023-02-24 16:33:08 +01001038nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001039{
roman8341e8b2023-11-23 16:12:42 +01001040 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02001041
romanc1d2b092023-02-02 08:58:27 +01001042 assert(!strcmp(LYD_NAME(node), "idle-timeout"));
1043
romaneaf84c72023-10-19 14:38:05 +02001044 if (is_ch(node)) {
romanb6f44032023-06-30 15:07:56 +02001045 /* call-home idle timeout */
roman6430c152023-10-12 11:28:47 +02001046 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
1047 /* to avoid unlock on fail */
romanb6f44032023-06-30 15:07:56 +02001048 return 1;
1049 }
1050
1051 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001052 ch_client->idle_timeout = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02001053 } else if (op == NC_OP_DELETE) {
1054 ch_client->idle_timeout = 180;
1055 }
roman6430c152023-10-12 11:28:47 +02001056
1057 nc_ch_client_unlock(ch_client);
romaneaf84c72023-10-19 14:38:05 +02001058 } else {
Michal Vaskocf898172024-01-15 15:04:28 +01001059 /* listen idle timeout */
romaneaf84c72023-10-19 14:38:05 +02001060 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001061 server_opts.idle_timeout = ((struct lyd_node_term *)node)->value.uint16;
romaneaf84c72023-10-19 14:38:05 +02001062 } else {
1063 /* default value */
Michal Vaskocf898172024-01-15 15:04:28 +01001064 server_opts.idle_timeout = 180;
romaneaf84c72023-10-19 14:38:05 +02001065 }
romanc1d2b092023-02-02 08:58:27 +01001066 }
1067
1068 return 0;
1069}
1070
1071static int
roman874fed12023-05-25 10:20:01 +02001072nc_server_config_create_bind(void)
romanc1d2b092023-02-02 08:58:27 +01001073{
1074 int ret = 0;
1075 void *tmp;
1076
1077 tmp = realloc(server_opts.binds, (server_opts.endpt_count + 1) * sizeof *server_opts.binds);
roman3a95bb22023-10-26 11:07:17 +02001078 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01001079 server_opts.binds = tmp;
1080 memset(&server_opts.binds[server_opts.endpt_count], 0, sizeof *server_opts.binds);
1081
1082 server_opts.binds[server_opts.endpt_count].sock = -1;
1083
1084cleanup:
1085 return ret;
1086}
1087
1088static int
roman874fed12023-05-25 10:20:01 +02001089nc_server_config_create_endpoint(const struct lyd_node *node)
romanc1d2b092023-02-02 08:58:27 +01001090{
roman874fed12023-05-25 10:20:01 +02001091 if (nc_server_config_create_bind()) {
romanf02273a2023-05-25 09:44:11 +02001092 return 1;
romanc1d2b092023-02-02 08:58:27 +01001093 }
romanc1d2b092023-02-02 08:58:27 +01001094
1095 node = lyd_child(node);
1096 assert(!strcmp(LYD_NAME(node), "name"));
1097
Michal Vaskocf898172024-01-15 15:04:28 +01001098 return nc_server_config_realloc(lyd_get_value(node), (void **)&server_opts.endpts, sizeof *server_opts.endpts,
1099 &server_opts.endpt_count);
romanc1d2b092023-02-02 08:58:27 +01001100}
1101
roman5cbb6532023-06-22 12:53:17 +02001102static int
1103nc_server_config_ch_create_endpoint(const struct lyd_node *node, struct nc_ch_client *ch_client)
1104{
1105 node = lyd_child(node);
1106 assert(!strcmp(LYD_NAME(node), "name"));
1107
Michal Vaskocf898172024-01-15 15:04:28 +01001108 return nc_server_config_realloc(lyd_get_value(node), (void **)&ch_client->ch_endpts, sizeof *ch_client->ch_endpts,
1109 &ch_client->ch_endpt_count);
roman5cbb6532023-06-22 12:53:17 +02001110}
1111
romanc1d2b092023-02-02 08:58:27 +01001112/* list */
1113static int
romane028ef92023-02-24 16:33:08 +01001114nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001115{
1116 int ret = 0;
1117 struct nc_endpt *endpt;
1118 struct nc_bind *bind;
roman6430c152023-10-12 11:28:47 +02001119 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001120 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001121
1122 assert(!strcmp(LYD_NAME(node), "endpoint"));
1123
roman5cbb6532023-06-22 12:53:17 +02001124 if (is_listen(node)) {
1125 /* listen */
1126 if (op == NC_OP_CREATE) {
1127 ret = nc_server_config_create_endpoint(node);
1128 if (ret) {
1129 goto cleanup;
1130 }
1131 } else if (op == NC_OP_DELETE) {
1132 /* free all children */
1133 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1134 ret = 1;
1135 goto cleanup;
1136 }
1137
1138 switch (endpt->ti) {
1139#ifdef NC_ENABLED_SSH_TLS
roman506354a2024-04-11 09:37:22 +02001140 case NC_TI_SSH:
roman5cbb6532023-06-22 12:53:17 +02001141 nc_server_config_del_endpt_ssh(endpt, bind);
1142 break;
roman506354a2024-04-11 09:37:22 +02001143 case NC_TI_TLS:
roman5cbb6532023-06-22 12:53:17 +02001144 nc_server_config_del_endpt_tls(endpt, bind);
1145 break;
1146#endif /* NC_ENABLED_SSH_TLS */
romana2ff4ef2024-01-19 14:41:46 +01001147 case NC_TI_UNIX:
1148 break;
roman5cbb6532023-06-22 12:53:17 +02001149 case NC_TI_NONE:
1150 case NC_TI_FD:
1151 ERRINT;
1152 ret = 1;
1153 goto cleanup;
1154 }
romanc1d2b092023-02-02 08:58:27 +01001155 }
roman5cbb6532023-06-22 12:53:17 +02001156 } else if (is_ch(node)) {
romanba93eac2023-07-18 14:36:48 +02001157 /* LOCK */
1158 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001159 /* to avoid unlock on fail */
1160 return 1;
romanc1d2b092023-02-02 08:58:27 +01001161 }
roman3f9b65c2023-06-05 14:26:58 +02001162
roman5cbb6532023-06-22 12:53:17 +02001163 if (op == NC_OP_CREATE) {
1164 ret = nc_server_config_ch_create_endpoint(node, ch_client);
1165 if (ret) {
1166 goto cleanup;
1167 }
1168
1169 /* init ch sock */
1170 ch_client->ch_endpts[ch_client->ch_endpt_count - 1].sock_pending = -1;
roman6430c152023-10-12 11:28:47 +02001171 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01001172 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman6430c152023-10-12 11:28:47 +02001173 ret = 1;
1174 goto cleanup;
1175 }
1176
1177 nc_server_config_ch_del_endpt(ch_client, ch_endpt);
roman3f9b65c2023-06-05 14:26:58 +02001178 }
romanc1d2b092023-02-02 08:58:27 +01001179 }
1180
1181cleanup:
romanba93eac2023-07-18 14:36:48 +02001182 if (is_ch(node)) {
1183 /* UNLOCK */
1184 nc_ch_client_unlock(ch_client);
1185 }
romanc1d2b092023-02-02 08:58:27 +01001186 return ret;
1187}
1188
roman2eab4742023-06-06 10:00:26 +02001189#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02001190
romanc1d2b092023-02-02 08:58:27 +01001191static int
roman874fed12023-05-25 10:20:01 +02001192nc_server_config_create_ssh(struct nc_endpt *endpt)
romanc1d2b092023-02-02 08:58:27 +01001193{
roman506354a2024-04-11 09:37:22 +02001194 endpt->ti = NC_TI_SSH;
romanc1d2b092023-02-02 08:58:27 +01001195 endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
roman3a95bb22023-10-26 11:07:17 +02001196 NC_CHECK_ERRMEM_RET(!endpt->opts.ssh, 1);
romanc1d2b092023-02-02 08:58:27 +01001197
1198 return 0;
1199}
1200
roman5cbb6532023-06-22 12:53:17 +02001201static int
1202nc_server_config_ch_create_ssh(struct nc_ch_endpt *ch_endpt)
1203{
roman506354a2024-04-11 09:37:22 +02001204 ch_endpt->ti = NC_TI_SSH;
roman5cbb6532023-06-22 12:53:17 +02001205 ch_endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
roman3a95bb22023-10-26 11:07:17 +02001206 NC_CHECK_ERRMEM_RET(!ch_endpt->opts.ssh, 1);
roman5cbb6532023-06-22 12:53:17 +02001207
1208 return 0;
1209}
1210
romanc1d2b092023-02-02 08:58:27 +01001211/* NP container */
1212static int
romane028ef92023-02-24 16:33:08 +01001213nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001214{
1215 struct nc_endpt *endpt;
1216 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001217 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001218 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001219 int ret = 0;
1220
1221 assert(!strcmp(LYD_NAME(node), "ssh"));
1222
roman5cbb6532023-06-22 12:53:17 +02001223 if (is_listen(node)) {
1224 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1225 ret = 1;
romanc1d2b092023-02-02 08:58:27 +01001226 goto cleanup;
1227 }
roman5cbb6532023-06-22 12:53:17 +02001228
1229 if (op == NC_OP_CREATE) {
1230 ret = nc_server_config_create_ssh(endpt);
1231 if (ret) {
1232 goto cleanup;
1233 }
1234 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02001235 nc_server_config_del_ssh_opts(bind, endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +02001236 }
1237 } else {
romanba93eac2023-07-18 14:36:48 +02001238 /* LOCK */
1239 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001240 /* to avoid unlock on fail */
1241 return 1;
romanba93eac2023-07-18 14:36:48 +02001242 }
1243
roman8341e8b2023-11-23 16:12:42 +01001244 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001245 ret = 1;
1246 goto cleanup;
1247 }
1248
1249 if (op == NC_OP_CREATE) {
1250 ret = nc_server_config_ch_create_ssh(ch_endpt);
1251 if (ret) {
1252 goto cleanup;
1253 }
romanb6f44032023-06-30 15:07:56 +02001254 } else if (op == NC_OP_DELETE) {
roman5ae78282023-11-02 13:34:34 +01001255 nc_server_config_del_ssh_opts(NULL, ch_endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +02001256 }
romanc1d2b092023-02-02 08:58:27 +01001257 }
1258
1259cleanup:
romanba93eac2023-07-18 14:36:48 +02001260 if (is_ch(node)) {
1261 /* UNLOCK */
1262 nc_ch_client_unlock(ch_client);
1263 }
romanc1d2b092023-02-02 08:58:27 +01001264 return ret;
1265}
1266
roman3f9b65c2023-06-05 14:26:58 +02001267static int
1268nc_server_config_create_tls(struct nc_endpt *endpt)
1269{
roman506354a2024-04-11 09:37:22 +02001270 endpt->ti = NC_TI_TLS;
roman3f9b65c2023-06-05 14:26:58 +02001271 endpt->opts.tls = calloc(1, sizeof *endpt->opts.tls);
roman3a95bb22023-10-26 11:07:17 +02001272 NC_CHECK_ERRMEM_RET(!endpt->opts.tls, 1);
roman3f9b65c2023-06-05 14:26:58 +02001273
1274 return 0;
1275}
1276
1277static int
romanb6f44032023-06-30 15:07:56 +02001278nc_server_config_ch_create_tls(struct nc_ch_endpt *ch_endpt)
1279{
roman506354a2024-04-11 09:37:22 +02001280 ch_endpt->ti = NC_TI_TLS;
romanb6f44032023-06-30 15:07:56 +02001281 ch_endpt->opts.tls = calloc(1, sizeof(struct nc_server_tls_opts));
roman3a95bb22023-10-26 11:07:17 +02001282 NC_CHECK_ERRMEM_RET(!ch_endpt->opts.tls, 1);
romanb6f44032023-06-30 15:07:56 +02001283
1284 return 0;
1285}
1286
1287static int
roman3f9b65c2023-06-05 14:26:58 +02001288nc_server_config_tls(const struct lyd_node *node, NC_OPERATION op)
1289{
1290 struct nc_endpt *endpt;
1291 struct nc_bind *bind;
romanb6f44032023-06-30 15:07:56 +02001292 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001293 struct nc_ch_client *ch_client = NULL;
roman3f9b65c2023-06-05 14:26:58 +02001294 int ret = 0;
1295
1296 assert(!strcmp(LYD_NAME(node), "tls"));
1297
romanb6f44032023-06-30 15:07:56 +02001298 if (is_listen(node)) {
1299 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1300 ret = 1;
roman3f9b65c2023-06-05 14:26:58 +02001301 goto cleanup;
1302 }
romanb6f44032023-06-30 15:07:56 +02001303
1304 if (op == NC_OP_CREATE) {
1305 ret = nc_server_config_create_tls(endpt);
1306 if (ret) {
1307 goto cleanup;
1308 }
1309 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02001310 nc_server_config_del_tls_opts(bind, endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +02001311 }
1312 } else {
romanba93eac2023-07-18 14:36:48 +02001313 /* LOCK */
1314 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001315 /* to avoid unlock on fail */
1316 return 1;
romanba93eac2023-07-18 14:36:48 +02001317 }
1318
roman8341e8b2023-11-23 16:12:42 +01001319 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
romanb6f44032023-06-30 15:07:56 +02001320 ret = 1;
1321 goto cleanup;
1322 }
1323
1324 if (op == NC_OP_CREATE) {
1325 ret = nc_server_config_ch_create_tls(ch_endpt);
1326 if (ret) {
1327 goto cleanup;
1328 }
roman6430c152023-10-12 11:28:47 +02001329 } else if (op == NC_OP_DELETE) {
roman5ae78282023-11-02 13:34:34 +01001330 nc_server_config_del_tls_opts(NULL, ch_endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +02001331 }
roman3f9b65c2023-06-05 14:26:58 +02001332 }
1333
1334cleanup:
romanba93eac2023-07-18 14:36:48 +02001335 if (is_ch(node)) {
1336 /* UNLOCK */
1337 nc_ch_client_unlock(ch_client);
1338 }
roman3f9b65c2023-06-05 14:26:58 +02001339 return ret;
1340}
1341
roman5e5d3f22024-08-08 12:44:53 +02001342/* leaf */
romanc1d2b092023-02-02 08:58:27 +01001343static int
romane028ef92023-02-24 16:33:08 +01001344nc_server_config_local_address(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001345{
roman5e5d3f22024-08-08 12:44:53 +02001346 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001347 struct nc_endpt *endpt;
1348 struct nc_bind *bind;
roman5e5d3f22024-08-08 12:44:53 +02001349 struct nc_ch_client *ch_client = NULL;
1350 struct nc_ch_endpt *ch_endpt;
romanc1d2b092023-02-02 08:58:27 +01001351
1352 assert(!strcmp(LYD_NAME(node), "local-address"));
1353
roman5e5d3f22024-08-08 12:44:53 +02001354 if (is_listen(node) && equal_parent_name(node, 1, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001355 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001356 ret = 1;
1357 goto cleanup;
1358 }
1359
roman6430c152023-10-12 11:28:47 +02001360 free(bind->address);
romanc1d2b092023-02-02 08:58:27 +01001361 bind->address = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001362 NC_CHECK_ERRMEM_GOTO(!bind->address, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01001363
romanfb3f7cf2023-11-30 16:10:09 +01001364 ret = nc_server_set_address_port(endpt, bind, lyd_get_value(node), 0);
romanc1d2b092023-02-02 08:58:27 +01001365 if (ret) {
1366 goto cleanup;
1367 }
roman5e5d3f22024-08-08 12:44:53 +02001368 } else if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) {
1369 /* LOCK */
1370 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
1371 /* to avoid unlock on fail */
1372 return 1;
1373 }
1374
1375 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
1376 ret = 1;
1377 goto cleanup;
1378 }
1379
1380 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1381 free(ch_endpt->src_addr);
1382 ch_endpt->src_addr = strdup(lyd_get_value(node));
1383 NC_CHECK_ERRMEM_GOTO(!ch_endpt->src_addr, ret = 1, cleanup);
1384 } else if (op == NC_OP_DELETE) {
1385 free(ch_endpt->src_addr);
1386 ch_endpt->src_addr = NULL;
1387 }
romanc1d2b092023-02-02 08:58:27 +01001388 }
1389
1390cleanup:
roman5e5d3f22024-08-08 12:44:53 +02001391 if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) {
1392 /* UNLOCK */
1393 nc_ch_client_unlock(ch_client);
1394 }
romanc1d2b092023-02-02 08:58:27 +01001395 return ret;
1396}
1397
1398/* leaf with default value */
1399static int
romane028ef92023-02-24 16:33:08 +01001400nc_server_config_local_port(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001401{
roman5e5d3f22024-08-08 12:44:53 +02001402 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001403 struct nc_endpt *endpt;
1404 struct nc_bind *bind;
roman5e5d3f22024-08-08 12:44:53 +02001405 struct nc_ch_client *ch_client = NULL;
1406 struct nc_ch_endpt *ch_endpt;
romanc1d2b092023-02-02 08:58:27 +01001407
1408 assert(!strcmp(LYD_NAME(node), "local-port"));
1409
roman5e5d3f22024-08-08 12:44:53 +02001410 if (is_listen(node) && equal_parent_name(node, 1, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001411 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001412 ret = 1;
1413 goto cleanup;
1414 }
1415
1416 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001417 bind->port = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001418 } else {
1419 /* delete -> set to default */
1420 bind->port = 0;
1421 }
1422
romanfb3f7cf2023-11-30 16:10:09 +01001423 ret = nc_server_set_address_port(endpt, bind, NULL, bind->port);
romanc1d2b092023-02-02 08:58:27 +01001424 if (ret) {
1425 goto cleanup;
1426 }
roman5e5d3f22024-08-08 12:44:53 +02001427 } else if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) {
1428 /* LOCK */
1429 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
1430 /* to avoid unlock on fail */
1431 return 1;
1432 }
1433
1434 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
1435 ret = 1;
1436 goto cleanup;
1437 }
1438
1439 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1440 ch_endpt->src_port = ((struct lyd_node_term *)node)->value.uint16;
1441 } else if (op == NC_OP_DELETE) {
1442 /* delete -> set to default */
1443 ch_endpt->src_port = 0;
1444 }
romanc1d2b092023-02-02 08:58:27 +01001445 }
1446
1447cleanup:
roman5e5d3f22024-08-08 12:44:53 +02001448 if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) {
1449 /* UNLOCK */
1450 nc_ch_client_unlock(ch_client);
1451 }
romanc1d2b092023-02-02 08:58:27 +01001452 return ret;
1453}
1454
Michal Vaskocf898172024-01-15 15:04:28 +01001455/* NP container */
romanc1d2b092023-02-02 08:58:27 +01001456static int
romane028ef92023-02-24 16:33:08 +01001457nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001458{
roman5cbb6532023-06-22 12:53:17 +02001459 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001460 struct nc_endpt *endpt;
1461 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001462 struct nc_ch_endpt *ch_endpt;
roman6cb86ea2023-11-08 15:12:05 +01001463 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001464
1465 assert(!strcmp(LYD_NAME(node), "keepalives"));
1466
roman5cbb6532023-06-22 12:53:17 +02001467 if (is_listen(node) && equal_parent_name(node, 1, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001468 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001469 ret = 1;
1470 goto cleanup;
1471 }
1472
1473 if (op == NC_OP_CREATE) {
1474 endpt->ka.enabled = 1;
1475 } else {
1476 endpt->ka.enabled = 0;
1477 }
roman5cbb6532023-06-22 12:53:17 +02001478 } else if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001479 /* LOCK */
1480 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001481 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001482 return 1;
1483 }
1484
roman8341e8b2023-11-23 16:12:42 +01001485 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001486 ret = 1;
1487 goto cleanup;
1488 }
1489
1490 if (op == NC_OP_CREATE) {
1491 ch_endpt->ka.enabled = 1;
1492 } else {
1493 ch_endpt->ka.enabled = 0;
1494 }
romanc1d2b092023-02-02 08:58:27 +01001495 }
1496
1497cleanup:
romanba93eac2023-07-18 14:36:48 +02001498 if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) {
1499 /* UNLOCK */
1500 nc_ch_client_unlock(ch_client);
1501 }
romanc1d2b092023-02-02 08:58:27 +01001502 return ret;
1503}
1504
Michal Vaskocf898172024-01-15 15:04:28 +01001505/* leaf with default value */
romanc1d2b092023-02-02 08:58:27 +01001506static int
romane028ef92023-02-24 16:33:08 +01001507nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001508{
roman5cbb6532023-06-22 12:53:17 +02001509 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001510 struct nc_endpt *endpt;
1511 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001512 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001513 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001514
1515 assert(!strcmp(LYD_NAME(node), "idle-time"));
1516
roman5cbb6532023-06-22 12:53:17 +02001517 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001518 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001519 ret = 1;
1520 goto cleanup;
1521 }
1522
1523 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001524 endpt->ka.idle_time = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001525 } else {
Michal Vaskocf898172024-01-15 15:04:28 +01001526 /* delete -> set to default */
1527 endpt->ka.idle_time = 7200;
romanc1d2b092023-02-02 08:58:27 +01001528 }
roman5cbb6532023-06-22 12:53:17 +02001529 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001530 /* LOCK */
1531 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001532 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001533 return 1;
1534 }
1535
roman8341e8b2023-11-23 16:12:42 +01001536 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001537 ret = 1;
1538 goto cleanup;
1539 }
1540
1541 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001542 ch_endpt->ka.idle_time = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001543 } else {
Michal Vaskocf898172024-01-15 15:04:28 +01001544 /* delete -> set to default */
1545 ch_endpt->ka.idle_time = 7200;
roman5cbb6532023-06-22 12:53:17 +02001546 }
romanc1d2b092023-02-02 08:58:27 +01001547 }
1548
1549cleanup:
roman6430c152023-10-12 11:28:47 +02001550 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001551 /* UNLOCK */
1552 nc_ch_client_unlock(ch_client);
1553 }
romanc1d2b092023-02-02 08:58:27 +01001554 return ret;
1555}
1556
Michal Vaskocf898172024-01-15 15:04:28 +01001557/* leaf with default value */
romanc1d2b092023-02-02 08:58:27 +01001558static int
romane028ef92023-02-24 16:33:08 +01001559nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001560{
roman5cbb6532023-06-22 12:53:17 +02001561 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001562 struct nc_endpt *endpt;
1563 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001564 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001565 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001566
1567 assert(!strcmp(LYD_NAME(node), "max-probes"));
1568
roman5cbb6532023-06-22 12:53:17 +02001569 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001570 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001571 ret = 1;
1572 goto cleanup;
1573 }
1574
1575 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001576 endpt->ka.max_probes = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001577 } else {
Michal Vaskocf898172024-01-15 15:04:28 +01001578 /* delete -> set to default */
1579 endpt->ka.max_probes = 9;
romanc1d2b092023-02-02 08:58:27 +01001580 }
roman5cbb6532023-06-22 12:53:17 +02001581 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001582 /* LOCK */
1583 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001584 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001585 return 1;
1586 }
1587
roman8341e8b2023-11-23 16:12:42 +01001588 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001589 ret = 1;
1590 goto cleanup;
1591 }
1592
1593 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001594 ch_endpt->ka.max_probes = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001595 } else {
Michal Vaskocf898172024-01-15 15:04:28 +01001596 /* delete -> set to default */
1597 ch_endpt->ka.max_probes = 9;
roman5cbb6532023-06-22 12:53:17 +02001598 }
romanc1d2b092023-02-02 08:58:27 +01001599 }
1600
1601cleanup:
roman6430c152023-10-12 11:28:47 +02001602 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001603 /* UNLOCK */
1604 nc_ch_client_unlock(ch_client);
1605 }
romanc1d2b092023-02-02 08:58:27 +01001606 return ret;
1607}
1608
Michal Vaskocf898172024-01-15 15:04:28 +01001609/* leaf with default value */
romanc1d2b092023-02-02 08:58:27 +01001610static int
romane028ef92023-02-24 16:33:08 +01001611nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001612{
roman5cbb6532023-06-22 12:53:17 +02001613 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001614 struct nc_endpt *endpt;
1615 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001616 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001617 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001618
1619 assert(!strcmp(LYD_NAME(node), "probe-interval"));
1620
roman5cbb6532023-06-22 12:53:17 +02001621 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001622 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001623 ret = 1;
1624 goto cleanup;
1625 }
1626
1627 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001628 endpt->ka.probe_interval = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001629 } else {
Michal Vaskocf898172024-01-15 15:04:28 +01001630 /* delete -> set to default */
1631 endpt->ka.probe_interval = 75;
romanc1d2b092023-02-02 08:58:27 +01001632 }
roman5cbb6532023-06-22 12:53:17 +02001633 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001634 /* LOCK */
1635 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001636 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001637 return 1;
1638 }
1639
roman8341e8b2023-11-23 16:12:42 +01001640 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001641 ret = 1;
1642 goto cleanup;
1643 }
1644
1645 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001646 ch_endpt->ka.probe_interval = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001647 } else {
Michal Vaskocf898172024-01-15 15:04:28 +01001648 /* delete -> set to default */
1649 ch_endpt->ka.probe_interval = 75;
roman5cbb6532023-06-22 12:53:17 +02001650 }
romanc1d2b092023-02-02 08:58:27 +01001651 }
1652
1653cleanup:
roman6430c152023-10-12 11:28:47 +02001654 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001655 /* UNLOCK */
1656 nc_ch_client_unlock(ch_client);
1657 }
romanc1d2b092023-02-02 08:58:27 +01001658 return ret;
1659}
1660
1661static int
roman874fed12023-05-25 10:20:01 +02001662nc_server_config_create_host_key(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01001663{
romanf02273a2023-05-25 09:44:11 +02001664 node = lyd_child(node);
1665 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01001666
romanf02273a2023-05-25 09:44:11 +02001667 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->hostkeys, sizeof *opts->hostkeys, &opts->hostkey_count);
romanc1d2b092023-02-02 08:58:27 +01001668}
1669
1670/* list */
1671static int
romane028ef92023-02-24 16:33:08 +01001672nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001673{
roman5cbb6532023-06-22 12:53:17 +02001674 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001675 struct nc_hostkey *hostkey;
roman4cb8bb12023-06-29 09:16:46 +02001676 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01001677 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001678
1679 assert(!strcmp(LYD_NAME(node), "host-key"));
1680
roman4cb8bb12023-06-29 09:16:46 +02001681 if (equal_parent_name(node, 1, "server-identity")) {
romanba93eac2023-07-18 14:36:48 +02001682 /* LOCK */
1683 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001684 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001685 return 1;
1686 }
1687
roman8341e8b2023-11-23 16:12:42 +01001688 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman6cb86ea2023-11-08 15:12:05 +01001689 ret = 1;
1690 goto cleanup;
1691 }
1692
romanc1d2b092023-02-02 08:58:27 +01001693 if (op == NC_OP_CREATE) {
roman4cb8bb12023-06-29 09:16:46 +02001694 ret = nc_server_config_create_host_key(node, opts);
romanc1d2b092023-02-02 08:58:27 +01001695 if (ret) {
1696 goto cleanup;
1697 }
1698 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01001699 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001700 ret = 1;
1701 goto cleanup;
1702 }
roman4cb8bb12023-06-29 09:16:46 +02001703 nc_server_config_del_hostkey(opts, hostkey);
roman5cbb6532023-06-22 12:53:17 +02001704 }
romanc1d2b092023-02-02 08:58:27 +01001705 }
1706
1707cleanup:
romanba93eac2023-07-18 14:36:48 +02001708 if (is_ch(node) && equal_parent_name(node, 1, "server-identity")) {
1709 /* UNLOCK */
1710 nc_ch_client_unlock(ch_client);
1711 }
romanc1d2b092023-02-02 08:58:27 +01001712 return ret;
1713}
1714
1715/* mandatory leaf */
romane028ef92023-02-24 16:33:08 +01001716static int
1717nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001718{
roman3f9b65c2023-06-05 14:26:58 +02001719 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02001720 const char *format;
roman3f9b65c2023-06-05 14:26:58 +02001721 NC_PUBKEY_FORMAT pubkey_type;
roman8edee342023-03-31 13:25:48 +02001722 struct nc_public_key *pubkey;
romanc1d2b092023-02-02 08:58:27 +01001723 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02001724 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01001725 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001726
1727 assert(!strcmp(LYD_NAME(node), "public-key-format"));
1728
roman6cb86ea2023-11-08 15:12:05 +01001729 /* LOCK */
1730 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
1731 /* to avoid unlock on fail */
1732 return 1;
1733 }
1734
romanc1d2b092023-02-02 08:58:27 +01001735 format = ((struct lyd_node_term *)node)->value.ident->name;
roman3f9b65c2023-06-05 14:26:58 +02001736 if (!strcmp(format, "ssh-public-key-format")) {
roman13145912023-08-17 15:36:54 +02001737 pubkey_type = NC_PUBKEY_FORMAT_SSH;
roman3f9b65c2023-06-05 14:26:58 +02001738 } else if (!strcmp(format, "subject-public-key-info-format")) {
1739 pubkey_type = NC_PUBKEY_FORMAT_X509;
1740 } else {
1741 ERR(NULL, "Public key format (%s) not supported.", format);
1742 ret = 1;
1743 goto cleanup;
1744 }
romanc1d2b092023-02-02 08:58:27 +01001745
roman4cb8bb12023-06-29 09:16:46 +02001746 if (is_ssh(node) && equal_parent_name(node, 4, "server-identity")) {
roman5cbb6532023-06-22 12:53:17 +02001747 /* SSH hostkey public key fmt */
roman8341e8b2023-11-23 16:12:42 +01001748 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02001749 ret = 1;
1750 goto cleanup;
1751 }
1752
1753 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1754 hostkey->key.pubkey_type = pubkey_type;
1755 }
roman4cb8bb12023-06-29 09:16:46 +02001756 } else if (is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) {
roman5cbb6532023-06-22 12:53:17 +02001757 /* SSH client auth public key fmt */
roman8341e8b2023-11-23 16:12:42 +01001758 if (nc_server_config_get_pubkey(node, ch_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001759 ret = 1;
1760 goto cleanup;
1761 }
1762
1763 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman3f9b65c2023-06-05 14:26:58 +02001764 pubkey->type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001765 }
romanb6f44032023-06-30 15:07:56 +02001766 } else if (is_tls(node) && equal_parent_name(node, 3, "server-identity")) {
1767 /* TLS server-identity */
roman8341e8b2023-11-23 16:12:42 +01001768 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02001769 ret = 1;
1770 goto cleanup;
1771 }
1772
roman5cbb6532023-06-22 12:53:17 +02001773 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02001774 opts->pubkey_type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001775 }
romanc1d2b092023-02-02 08:58:27 +01001776 }
1777
1778cleanup:
romanba93eac2023-07-18 14:36:48 +02001779 if (is_ch(node)) {
1780 /* UNLOCK */
1781 nc_ch_client_unlock(ch_client);
1782 }
romanc1d2b092023-02-02 08:58:27 +01001783 return ret;
1784}
1785
1786static int
roman58f79d02023-10-06 10:20:31 +02001787nc_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 +01001788{
romanc1d2b092023-02-02 08:58:27 +01001789 assert(!strcmp(LYD_NAME(node), "public-key"));
1790
romanc1d2b092023-02-02 08:58:27 +01001791 node = lyd_child(node);
1792 assert(!strcmp(LYD_NAME(node), "name"));
1793
Michal Vaskocf898172024-01-15 15:04:28 +01001794 return nc_server_config_realloc(lyd_get_value(node), (void **)&auth_client->pubkeys, sizeof *auth_client->pubkeys,
1795 &auth_client->pubkey_count);
romanc1d2b092023-02-02 08:58:27 +01001796}
1797
1798static int
roman874fed12023-05-25 10:20:01 +02001799nc_server_config_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +01001800{
roman6430c152023-10-12 11:28:47 +02001801 free(pubkey->data);
roman3f9b65c2023-06-05 14:26:58 +02001802 pubkey->data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001803 NC_CHECK_ERRMEM_RET(!pubkey->data, 1);
romanc1d2b092023-02-02 08:58:27 +01001804
1805 return 0;
1806}
1807
1808static int
roman874fed12023-05-25 10:20:01 +02001809nc_server_config_replace_host_key_public_key(const struct lyd_node *node, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +01001810{
roman6430c152023-10-12 11:28:47 +02001811 free(hostkey->key.pubkey_data);
roman3f9b65c2023-06-05 14:26:58 +02001812 hostkey->key.pubkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001813 NC_CHECK_ERRMEM_RET(!hostkey->key.pubkey_data, 1);
romanc1d2b092023-02-02 08:58:27 +01001814
1815 return 0;
1816}
1817
roman3f9b65c2023-06-05 14:26:58 +02001818static int
1819nc_server_config_tls_replace_server_public_key(const struct lyd_node *node, struct nc_server_tls_opts *opts)
1820{
roman6430c152023-10-12 11:28:47 +02001821 free(opts->pubkey_data);
roman3f9b65c2023-06-05 14:26:58 +02001822 opts->pubkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001823 NC_CHECK_ERRMEM_RET(!opts->pubkey_data, 1);
roman3f9b65c2023-06-05 14:26:58 +02001824
1825 return 0;
1826}
1827
romanc1d2b092023-02-02 08:58:27 +01001828static int
romane028ef92023-02-24 16:33:08 +01001829nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001830{
roman3f9b65c2023-06-05 14:26:58 +02001831 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001832 struct nc_hostkey *hostkey;
roman58f79d02023-10-06 10:20:31 +02001833 struct nc_auth_client *auth_client;
roman8edee342023-03-31 13:25:48 +02001834 struct nc_public_key *pubkey;
romanb6f44032023-06-30 15:07:56 +02001835 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01001836 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001837
1838 assert(!strcmp(LYD_NAME(node), "public-key"));
1839
romanba93eac2023-07-18 14:36:48 +02001840 /* LOCK */
1841 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02001842 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001843 return 1;
1844 }
1845
roman4cb8bb12023-06-29 09:16:46 +02001846 if (is_ssh(node) && equal_parent_name(node, 3, "host-key")) {
roman3f9b65c2023-06-05 14:26:58 +02001847 /* server's public-key, mandatory leaf */
roman8341e8b2023-11-23 16:12:42 +01001848 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
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 hostkey 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)) {
romanf02273a2023-05-25 09:44:11 +02001861 /* set to local */
roman874fed12023-05-25 10:20:01 +02001862 hostkey->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02001863
roman874fed12023-05-25 10:20:01 +02001864 ret = nc_server_config_replace_host_key_public_key(node, hostkey);
romanc1d2b092023-02-02 08:58:27 +01001865 if (ret) {
1866 goto cleanup;
1867 }
1868 }
roman4cb8bb12023-06-29 09:16:46 +02001869 } else if (is_ssh(node) && equal_parent_name(node, 5, "client-authentication")) {
romanc1d2b092023-02-02 08:58:27 +01001870 /* client auth pubkeys, list */
roman8341e8b2023-11-23 16:12:42 +01001871 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001872 ret = 1;
1873 goto cleanup;
1874 }
1875
1876 if (op == NC_OP_CREATE) {
romanf02273a2023-05-25 09:44:11 +02001877 /* set to local */
roman874fed12023-05-25 10:20:01 +02001878 auth_client->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02001879
roman874fed12023-05-25 10:20:01 +02001880 ret = nc_server_config_create_auth_key_public_key_list(node, auth_client);
romanc1d2b092023-02-02 08:58:27 +01001881 if (ret) {
1882 goto cleanup;
1883 }
1884 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01001885 if (nc_server_config_get_pubkey(node, ch_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001886 ret = 1;
1887 goto cleanup;
1888 }
1889
roman874fed12023-05-25 10:20:01 +02001890 nc_server_config_del_auth_client_pubkey(auth_client, pubkey);
romanc1d2b092023-02-02 08:58:27 +01001891 }
roman4cb8bb12023-06-29 09:16:46 +02001892 } else if (is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) {
romanc1d2b092023-02-02 08:58:27 +01001893 /* client auth pubkey, leaf */
roman8341e8b2023-11-23 16:12:42 +01001894 if (nc_server_config_get_pubkey(node, ch_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001895 ret = 1;
1896 goto cleanup;
1897 }
1898
roman13145912023-08-17 15:36:54 +02001899 /* the public key must not be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
roman51a1e192023-09-14 10:13:45 +02001900 if (nc_is_pk_subject_public_key_info(lyd_get_value(node))) {
roman13145912023-08-17 15:36:54 +02001901 ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH user's key is forbidden!");
1902 ret = 1;
1903 goto cleanup;
1904 }
1905
romanc1d2b092023-02-02 08:58:27 +01001906 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02001907 ret = nc_server_config_replace_auth_key_public_key_leaf(node, pubkey);
romanc1d2b092023-02-02 08:58:27 +01001908 if (ret) {
1909 goto cleanup;
1910 }
roman6430c152023-10-12 11:28:47 +02001911 } else if (op == NC_OP_DELETE) {
1912 free(pubkey->data);
1913 pubkey->data = NULL;
romanc1d2b092023-02-02 08:58:27 +01001914 }
romanb6f44032023-06-30 15:07:56 +02001915 } else if (is_tls(node) && equal_parent_name(node, 3, "server-identity")) {
1916 /* TLS server-identity */
roman8341e8b2023-11-23 16:12:42 +01001917 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02001918 ret = 1;
1919 goto cleanup;
1920 }
1921
roman13145912023-08-17 15:36:54 +02001922 /* the public key must be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
roman51a1e192023-09-14 10:13:45 +02001923 if (!nc_is_pk_subject_public_key_info(lyd_get_value(node))) {
roman13145912023-08-17 15:36:54 +02001924 ERR(NULL, "TLS server certificate's Public Key must be in the SubjectPublicKeyInfo format!");
1925 ret = 1;
1926 goto cleanup;
1927 }
1928
roman3f9b65c2023-06-05 14:26:58 +02001929 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1930 /* set to local */
romanb6f44032023-06-30 15:07:56 +02001931 opts->store = NC_STORE_LOCAL;
roman3f9b65c2023-06-05 14:26:58 +02001932
romanb6f44032023-06-30 15:07:56 +02001933 ret = nc_server_config_tls_replace_server_public_key(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02001934 if (ret) {
1935 goto cleanup;
1936 }
1937 }
roman5cbb6532023-06-22 12:53:17 +02001938 }
1939
1940cleanup:
romanba93eac2023-07-18 14:36:48 +02001941 if (is_ch(node)) {
1942 /* UNLOCK */
1943 nc_ch_client_unlock(ch_client);
1944 }
roman5cbb6532023-06-22 12:53:17 +02001945 return ret;
1946}
1947
1948/* leaf */
1949static int
1950nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op)
1951{
1952 int ret = 0;
1953 const char *format;
1954 NC_PRIVKEY_FORMAT privkey_type;
roman5cbb6532023-06-22 12:53:17 +02001955 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02001956 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01001957 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02001958
1959 (void) op;
1960
1961 assert(!strcmp(LYD_NAME(node), "private-key-format"));
1962
roman6cb86ea2023-11-08 15:12:05 +01001963 /* LOCK */
1964 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
1965 /* to avoid unlock on fail */
1966 return 1;
1967 }
1968
roman5cbb6532023-06-22 12:53:17 +02001969 format = ((struct lyd_node_term *)node)->value.ident->name;
1970 if (!format) {
1971 ret = 1;
1972 goto cleanup;
1973 }
1974
1975 privkey_type = nc_server_config_get_private_key_type(format);
1976 if (privkey_type == NC_PRIVKEY_FORMAT_UNKNOWN) {
1977 ERR(NULL, "Unknown private key format.");
1978 ret = 1;
1979 goto cleanup;
1980 }
1981
roman4cb8bb12023-06-29 09:16:46 +02001982 if (is_ssh(node)) {
1983 /* ssh */
roman8341e8b2023-11-23 16:12:42 +01001984 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02001985 ret = 1;
1986 goto cleanup;
1987 }
1988
1989 hostkey->key.privkey_type = privkey_type;
romanb6f44032023-06-30 15:07:56 +02001990 } else if (is_tls(node)) {
1991 /* tls */
roman8341e8b2023-11-23 16:12:42 +01001992 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman5cbb6532023-06-22 12:53:17 +02001993 ret = 1;
1994 goto cleanup;
1995 }
1996
romanb6f44032023-06-30 15:07:56 +02001997 opts->privkey_type = privkey_type;
roman5cbb6532023-06-22 12:53:17 +02001998 }
1999
2000cleanup:
romanba93eac2023-07-18 14:36:48 +02002001 if (is_ch(node)) {
2002 /* UNLOCK */
2003 nc_ch_client_unlock(ch_client);
2004 }
roman5cbb6532023-06-22 12:53:17 +02002005 return ret;
2006}
2007
2008static int
roman5cbb6532023-06-22 12:53:17 +02002009nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op)
2010{
2011 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02002012 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02002013 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002014 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02002015
2016 assert(!strcmp(LYD_NAME(node), "cleartext-private-key"));
2017
romanba93eac2023-07-18 14:36:48 +02002018 /* LOCK */
2019 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002020 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002021 return 1;
2022 }
2023
roman4cb8bb12023-06-29 09:16:46 +02002024 if (is_ssh(node)) {
2025 /* ssh */
roman8341e8b2023-11-23 16:12:42 +01002026 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02002027 ret = 1;
2028 goto cleanup;
2029 }
2030
2031 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002032 free(hostkey->key.privkey_data);
2033 hostkey->key.privkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002034 NC_CHECK_ERRMEM_GOTO(!hostkey->key.privkey_data, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02002035 } else {
roman6430c152023-10-12 11:28:47 +02002036 free(hostkey->key.privkey_data);
2037 hostkey->key.privkey_data = NULL;
roman5cbb6532023-06-22 12:53:17 +02002038 }
romanb6f44032023-06-30 15:07:56 +02002039 } else if (is_tls(node)) {
2040 /* tls */
roman8341e8b2023-11-23 16:12:42 +01002041 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002042 ret = 1;
2043 goto cleanup;
2044 }
2045
roman5cbb6532023-06-22 12:53:17 +02002046 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002047 free(opts->privkey_data);
2048 opts->privkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002049 NC_CHECK_ERRMEM_GOTO(!opts->privkey_data, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02002050 } else {
roman6430c152023-10-12 11:28:47 +02002051 free(opts->privkey_data);
2052 opts->privkey_data = NULL;
roman5cbb6532023-06-22 12:53:17 +02002053 }
roman5cbb6532023-06-22 12:53:17 +02002054 }
2055
2056cleanup:
romanba93eac2023-07-18 14:36:48 +02002057 if (is_ch(node)) {
2058 /* UNLOCK */
2059 nc_ch_client_unlock(ch_client);
2060 }
roman5cbb6532023-06-22 12:53:17 +02002061 return ret;
2062}
2063
roman5cbb6532023-06-22 12:53:17 +02002064/* leaf */
2065static int
2066nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op)
2067{
2068 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02002069 struct nc_hostkey *hostkey;
roman8341e8b2023-11-23 16:12:42 +01002070 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02002071
Michal Vaskocf898172024-01-15 15:04:28 +01002072 assert(!strcmp(LYD_NAME(node), "central-keystore-reference"));
roman5cbb6532023-06-22 12:53:17 +02002073
romanba93eac2023-07-18 14:36:48 +02002074 /* LOCK */
2075 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002076 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002077 return 1;
2078 }
2079
roman4cb8bb12023-06-29 09:16:46 +02002080 if (is_ssh(node) && equal_parent_name(node, 3, "server-identity")) {
roman8341e8b2023-11-23 16:12:42 +01002081 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02002082 ret = 1;
2083 goto cleanup;
2084 }
2085
2086 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2087 /* set to keystore */
2088 hostkey->store = NC_STORE_KEYSTORE;
2089
roman6430c152023-10-12 11:28:47 +02002090 free(hostkey->ks_ref);
romandd019a92023-09-14 10:17:07 +02002091 hostkey->ks_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002092 NC_CHECK_ERRMEM_GOTO(!hostkey->ks_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002093 } else if (op == NC_OP_DELETE) {
2094 free(hostkey->ks_ref);
roman5cbb6532023-06-22 12:53:17 +02002095 hostkey->ks_ref = NULL;
2096 }
roman3f9b65c2023-06-05 14:26:58 +02002097 }
romanc1d2b092023-02-02 08:58:27 +01002098
2099cleanup:
romanba93eac2023-07-18 14:36:48 +02002100 if (is_ch(node)) {
2101 /* UNLOCK */
2102 nc_ch_client_unlock(ch_client);
2103 }
romanc1d2b092023-02-02 08:58:27 +01002104 return ret;
2105}
2106
2107static int
roman6430c152023-10-12 11:28:47 +02002108nc_server_config_create_auth_client(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01002109{
romanf02273a2023-05-25 09:44:11 +02002110 node = lyd_child(node);
2111 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01002112
romanf02273a2023-05-25 09:44:11 +02002113 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 +01002114}
2115
2116/* list */
2117static int
romane028ef92023-02-24 16:33:08 +01002118nc_server_config_user(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002119{
roman5cbb6532023-06-22 12:53:17 +02002120 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002121 struct nc_auth_client *auth_client;
roman4cb8bb12023-06-29 09:16:46 +02002122 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002123 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002124
2125 assert(!strcmp(LYD_NAME(node), "user"));
2126
romanba93eac2023-07-18 14:36:48 +02002127 /* LOCK */
2128 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002129 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002130 return 1;
2131 }
2132
roman8341e8b2023-11-23 16:12:42 +01002133 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002134 ret = 1;
2135 goto cleanup;
2136 }
2137
2138 if (op == NC_OP_CREATE) {
roman6430c152023-10-12 11:28:47 +02002139 ret = nc_server_config_create_auth_client(node, opts);
roman4cb8bb12023-06-29 09:16:46 +02002140 if (ret) {
2141 goto cleanup;
2142 }
2143 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01002144 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002145 ret = 1;
2146 goto cleanup;
2147 }
2148
roman4cb8bb12023-06-29 09:16:46 +02002149 nc_server_config_del_auth_client(opts, auth_client);
romanc1d2b092023-02-02 08:58:27 +01002150 }
2151
2152cleanup:
romanba93eac2023-07-18 14:36:48 +02002153 if (is_ch(node)) {
2154 /* UNLOCK */
2155 nc_ch_client_unlock(ch_client);
2156 }
romanc1d2b092023-02-02 08:58:27 +01002157 return ret;
2158}
2159
2160static int
romane028ef92023-02-24 16:33:08 +01002161nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002162{
romanc1d2b092023-02-02 08:58:27 +01002163 int ret = 0;
roman4cb8bb12023-06-29 09:16:46 +02002164 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002165 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002166
2167 assert(!strcmp(LYD_NAME(node), "auth-timeout"));
2168
romanba93eac2023-07-18 14:36:48 +02002169 /* LOCK */
2170 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002171 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002172 return 1;
2173 }
2174
roman8341e8b2023-11-23 16:12:42 +01002175 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002176 ret = 1;
2177 goto cleanup;
2178 }
romanc1d2b092023-02-02 08:58:27 +01002179
roman4cb8bb12023-06-29 09:16:46 +02002180 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02002181 opts->auth_timeout = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01002182 }
2183
2184cleanup:
romanba93eac2023-07-18 14:36:48 +02002185 if (is_ch(node)) {
2186 /* UNLOCK */
2187 nc_ch_client_unlock(ch_client);
2188 }
romanc1d2b092023-02-02 08:58:27 +01002189 return ret;
2190}
2191
romanc1d2b092023-02-02 08:58:27 +01002192/* leaf */
2193static int
romane028ef92023-02-24 16:33:08 +01002194nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002195{
romanc1d2b092023-02-02 08:58:27 +01002196 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002197 struct nc_auth_client *auth_client;
roman8341e8b2023-11-23 16:12:42 +01002198 struct nc_ch_client *ch_client = NULL;
roman6430c152023-10-12 11:28:47 +02002199 struct nc_server_tls_opts *opts;
2200 struct nc_cert_grouping *certs_grp;
romanc1d2b092023-02-02 08:58:27 +01002201
Michal Vaskocf898172024-01-15 15:04:28 +01002202 assert(!strcmp(LYD_NAME(node), "central-truststore-reference"));
romanc1d2b092023-02-02 08:58:27 +01002203
romanba93eac2023-07-18 14:36:48 +02002204 /* LOCK */
2205 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002206 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002207 return 1;
2208 }
2209
roman4cb8bb12023-06-29 09:16:46 +02002210 if (is_ssh(node) && equal_parent_name(node, 1, "public-keys")) {
roman8341e8b2023-11-23 16:12:42 +01002211 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002212 ret = 1;
2213 goto cleanup;
2214 }
2215
2216 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02002217 /* set to truststore */
roman874fed12023-05-25 10:20:01 +02002218 auth_client->store = NC_STORE_TRUSTSTORE;
romanf02273a2023-05-25 09:44:11 +02002219
roman6430c152023-10-12 11:28:47 +02002220 free(auth_client->ts_ref);
2221 auth_client->ts_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002222 NC_CHECK_ERRMEM_GOTO(!auth_client->ts_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002223 } else if (op == NC_OP_DELETE) {
2224 free(auth_client->ts_ref);
romand57b3722023-04-05 11:26:25 +02002225 auth_client->ts_ref = NULL;
romanc1d2b092023-02-02 08:58:27 +01002226 }
roman6430c152023-10-12 11:28:47 +02002227 } else if (is_tls(node) && (equal_parent_name(node, 1, "ca-certs") || equal_parent_name(node, 1, "ee-certs"))) {
2228 /* ee-certs or ca-certs */
roman8341e8b2023-11-23 16:12:42 +01002229 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002230 ret = 1;
2231 goto cleanup;
2232 }
2233
roman6430c152023-10-12 11:28:47 +02002234 if (equal_parent_name(node, 1, "ca-certs")) {
2235 certs_grp = &opts->ca_certs;
roman3f9b65c2023-06-05 14:26:58 +02002236 } else {
roman6430c152023-10-12 11:28:47 +02002237 certs_grp = &opts->ee_certs;
roman4cb8bb12023-06-29 09:16:46 +02002238 }
2239
roman3f9b65c2023-06-05 14:26:58 +02002240 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2241 /* set to truststore */
roman6430c152023-10-12 11:28:47 +02002242 certs_grp->store = NC_STORE_TRUSTSTORE;
roman3f9b65c2023-06-05 14:26:58 +02002243
roman6430c152023-10-12 11:28:47 +02002244 free(certs_grp->ts_ref);
2245 certs_grp->ts_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002246 NC_CHECK_ERRMEM_GOTO(!certs_grp->ts_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002247 } else if (op == NC_OP_DELETE) {
2248 free(certs_grp->ts_ref);
2249 certs_grp->ts_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002250 }
2251 }
romanc1d2b092023-02-02 08:58:27 +01002252
2253cleanup:
romanba93eac2023-07-18 14:36:48 +02002254 if (is_ch(node)) {
2255 /* UNLOCK */
2256 nc_ch_client_unlock(ch_client);
2257 }
romanc1d2b092023-02-02 08:58:27 +01002258 return ret;
2259}
2260
romana9ec3362023-12-21 10:59:57 +01002261static int
2262nc_server_config_use_system_keys(const struct lyd_node *node, NC_OPERATION op)
2263{
2264 int ret = 0;
2265 struct nc_auth_client *auth_client;
2266 struct nc_ch_client *ch_client = NULL;
2267
2268 assert(!strcmp(LYD_NAME(node), "use-system-keys"));
2269
2270 /* LOCK */
2271 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
2272 /* to avoid unlock on fail */
2273 return 1;
2274 }
2275
2276 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
2277 ret = 1;
2278 goto cleanup;
2279 }
2280
2281 if (op == NC_OP_CREATE) {
2282 auth_client->store = NC_STORE_SYSTEM;
2283 }
2284
2285cleanup:
2286 if (is_ch(node)) {
2287 /* UNLOCK */
2288 nc_ch_client_unlock(ch_client);
2289 }
2290 return ret;
2291}
2292
romanc1d2b092023-02-02 08:58:27 +01002293/* leaf */
2294static int
romane028ef92023-02-24 16:33:08 +01002295nc_server_config_password(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002296{
roman5cbb6532023-06-22 12:53:17 +02002297 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002298 struct nc_auth_client *auth_client;
roman8341e8b2023-11-23 16:12:42 +01002299 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002300
2301 assert(!strcmp(LYD_NAME(node), "password"));
2302
romanba93eac2023-07-18 14:36:48 +02002303 /* LOCK */
2304 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002305 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002306 return 1;
2307 }
2308
roman8341e8b2023-11-23 16:12:42 +01002309 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
roman4cb8bb12023-06-29 09:16:46 +02002310 ret = 1;
2311 goto cleanup;
2312 }
2313
2314 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002315 free(auth_client->password);
2316 auth_client->password = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002317 NC_CHECK_ERRMEM_GOTO(!auth_client->password, ret = 1, cleanup);
roman4cb8bb12023-06-29 09:16:46 +02002318 } else {
roman6430c152023-10-12 11:28:47 +02002319 free(auth_client->password);
2320 auth_client->password = NULL;
romanc1d2b092023-02-02 08:58:27 +01002321 }
2322
2323cleanup:
romanba93eac2023-07-18 14:36:48 +02002324 if (is_ch(node)) {
2325 /* UNLOCK */
2326 nc_ch_client_unlock(ch_client);
2327 }
romanc1d2b092023-02-02 08:58:27 +01002328 return ret;
2329}
2330
2331static int
romanc6518422023-11-30 16:39:00 +01002332nc_server_config_use_system_auth(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002333{
roman5cbb6532023-06-22 12:53:17 +02002334 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002335 struct nc_auth_client *auth_client;
roman808f3f62023-11-23 16:01:04 +01002336 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002337
romanc6518422023-11-30 16:39:00 +01002338 assert(!strcmp(LYD_NAME(node), "use-system-auth"));
romanc1d2b092023-02-02 08:58:27 +01002339
romanba93eac2023-07-18 14:36:48 +02002340 /* LOCK */
2341 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002342 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002343 return 1;
2344 }
2345
roman8341e8b2023-11-23 16:12:42 +01002346 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
roman4cb8bb12023-06-29 09:16:46 +02002347 ret = 1;
2348 goto cleanup;
2349 }
2350
roman808f3f62023-11-23 16:01:04 +01002351 if (op == NC_OP_CREATE) {
2352 auth_client->kb_int_enabled = 1;
roman4cb8bb12023-06-29 09:16:46 +02002353 } else {
roman808f3f62023-11-23 16:01:04 +01002354 auth_client->kb_int_enabled = 0;
romanc1d2b092023-02-02 08:58:27 +01002355 }
2356
2357cleanup:
romanba93eac2023-07-18 14:36:48 +02002358 if (is_ch(node)) {
2359 /* UNLOCK */
2360 nc_ch_client_unlock(ch_client);
2361 }
romanc1d2b092023-02-02 08:58:27 +01002362 return ret;
2363}
2364
2365/* leaf */
2366static int
romane028ef92023-02-24 16:33:08 +01002367nc_server_config_none(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002368{
roman5cbb6532023-06-22 12:53:17 +02002369 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002370 struct nc_auth_client *auth_client;
roman8341e8b2023-11-23 16:12:42 +01002371 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002372
2373 assert(!strcmp(LYD_NAME(node), "none"));
2374
romanba93eac2023-07-18 14:36:48 +02002375 /* LOCK */
2376 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002377 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002378 return 1;
2379 }
2380
roman8341e8b2023-11-23 16:12:42 +01002381 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
roman4cb8bb12023-06-29 09:16:46 +02002382 ret = 1;
2383 goto cleanup;
2384 }
romanc1d2b092023-02-02 08:58:27 +01002385
roman4cb8bb12023-06-29 09:16:46 +02002386 if (op == NC_OP_CREATE) {
roman808f3f62023-11-23 16:01:04 +01002387 auth_client->none_enabled = 1;
roman4cb8bb12023-06-29 09:16:46 +02002388 } else {
roman808f3f62023-11-23 16:01:04 +01002389 auth_client->none_enabled = 0;
romanc1d2b092023-02-02 08:58:27 +01002390 }
2391
2392cleanup:
romanba93eac2023-07-18 14:36:48 +02002393 if (is_ch(node)) {
2394 /* UNLOCK */
2395 nc_ch_client_unlock(ch_client);
2396 }
romanc1d2b092023-02-02 08:58:27 +01002397 return ret;
2398}
2399
2400static int
romanc135c6d2023-10-25 13:32:30 +02002401nc_server_config_delete_substring(const char *haystack, const char *needle, const char delim)
2402{
2403 size_t needle_len = strlen(needle);
2404 char *substr;
2405 int substr_found = 0, ret = 0;
2406
2407 while ((substr = strstr(haystack, needle))) {
2408 /* iterate over all the substrings */
2409 if (((substr == haystack) && (*(substr + needle_len) == delim)) ||
2410 ((substr != haystack) && (*(substr - 1) == delim) && (*(substr + needle_len) == delim))) {
2411 /* either the first element of the string or somewhere in the middle */
2412 memmove(substr, substr + needle_len + 1, strlen(substr + needle_len + 1));
2413 substr_found = 1;
2414 break;
2415 } else if ((*(substr - 1) == delim) && (*(substr + needle_len) == '\0')) {
2416 /* the last element of the string */
2417 *(substr - 1) = '\0';
2418 substr_found = 1;
2419 break;
2420 }
2421 haystack = substr + 1;
2422 }
2423 if (!substr_found) {
2424 ret = 1;
2425 }
2426
2427 return ret;
2428}
2429
2430static int
romana6bf6ab2023-05-26 13:26:02 +02002431nc_server_config_transport_params(const char *algorithm, char **alg_store, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002432{
romanc135c6d2023-10-25 13:32:30 +02002433 int ret = 0;
2434 char *alg = NULL;
romana6bf6ab2023-05-26 13:26:02 +02002435
2436 if (!strncmp(algorithm, "openssh-", 8)) {
2437 /* if the name starts with openssh, convert it to it's original libssh accepted form */
roman3a95bb22023-10-26 11:07:17 +02002438 ret = asprintf(&alg, "%s@openssh.com", algorithm + 8);
2439 NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; alg = NULL, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002440 } else if (!strncmp(algorithm, "libssh-", 7)) {
2441 /* if the name starts with libssh, convert it to it's original libssh accepted form */
roman3a95bb22023-10-26 11:07:17 +02002442 ret = asprintf(&alg, "%s@libssh.org", algorithm + 7);
2443 NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; alg = NULL, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002444 } else {
2445 alg = strdup(algorithm);
roman3a95bb22023-10-26 11:07:17 +02002446 NC_CHECK_ERRMEM_GOTO(!alg, ret = 1, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002447 }
2448
romanc1d2b092023-02-02 08:58:27 +01002449 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2450 if (!*alg_store) {
2451 /* first call */
2452 *alg_store = strdup(alg);
roman3a95bb22023-10-26 11:07:17 +02002453 NC_CHECK_ERRMEM_GOTO(!*alg_store, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01002454 } else {
2455 /* +1 because of ',' between algorithms */
roman3a95bb22023-10-26 11:07:17 +02002456 *alg_store = nc_realloc(*alg_store, strlen(*alg_store) + strlen(alg) + 1 + 1);
2457 NC_CHECK_ERRMEM_GOTO(!*alg_store, ret = 1, cleanup);
roman08f67f42023-06-08 13:51:54 +02002458 strcat(*alg_store, ",");
2459 strcat(*alg_store, alg);
romanc1d2b092023-02-02 08:58:27 +01002460 }
2461 } else {
2462 /* delete */
romanc135c6d2023-10-25 13:32:30 +02002463 ret = nc_server_config_delete_substring(*alg_store, alg, ',');
2464 if (ret) {
romanc1d2b092023-02-02 08:58:27 +01002465 ERR(NULL, "Unable to delete an algorithm (%s), which was not previously added.", alg);
romanc135c6d2023-10-25 13:32:30 +02002466 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002467 }
2468 }
2469
2470cleanup:
romana6bf6ab2023-05-26 13:26:02 +02002471 free(alg);
romanc1d2b092023-02-02 08:58:27 +01002472 return ret;
2473}
2474
2475/* leaf-list */
2476static int
romane028ef92023-02-24 16:33:08 +01002477nc_server_config_host_key_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002478{
roman5cbb6532023-06-22 12:53:17 +02002479 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002480 const char *alg;
roman5cbb6532023-06-22 12:53:17 +02002481 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002482 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002483
roman5cbb6532023-06-22 12:53:17 +02002484 assert(!strcmp(LYD_NAME(node), "host-key-alg"));
romanc1d2b092023-02-02 08:58:27 +01002485
romanba93eac2023-07-18 14:36:48 +02002486 /* LOCK */
2487 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002488 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002489 return 1;
2490 }
2491
roman8341e8b2023-11-23 16:12:42 +01002492 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002493 ret = 1;
2494 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002495 }
2496
romand05b2ad2024-01-23 12:02:40 +01002497 /* get the algorithm name and append it to supported algs */
roman5cbb6532023-06-22 12:53:17 +02002498 alg = ((struct lyd_node_term *)node)->value.ident->name;
romand05b2ad2024-01-23 12:02:40 +01002499 if (nc_server_config_transport_params(alg, &opts->hostkey_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002500 ret = 1;
romand05b2ad2024-01-23 12:02:40 +01002501 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002502 }
2503
2504cleanup:
romanba93eac2023-07-18 14:36:48 +02002505 if (is_ch(node)) {
2506 /* UNLOCK */
2507 nc_ch_client_unlock(ch_client);
2508 }
romanc1d2b092023-02-02 08:58:27 +01002509 return ret;
2510}
2511
2512/* leaf-list */
2513static int
romane028ef92023-02-24 16:33:08 +01002514nc_server_config_kex_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002515{
roman5cbb6532023-06-22 12:53:17 +02002516 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002517 const char *alg;
roman5cbb6532023-06-22 12:53:17 +02002518 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002519 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002520
roman5cbb6532023-06-22 12:53:17 +02002521 assert(!strcmp(LYD_NAME(node), "key-exchange-alg"));
romanc1d2b092023-02-02 08:58:27 +01002522
romanba93eac2023-07-18 14:36:48 +02002523 /* LOCK */
2524 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002525 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002526 return 1;
2527 }
2528
roman8341e8b2023-11-23 16:12:42 +01002529 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002530 ret = 1;
2531 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002532 }
2533
romand05b2ad2024-01-23 12:02:40 +01002534 /* get the algorithm name and append it to supported algs */
roman5cbb6532023-06-22 12:53:17 +02002535 alg = ((struct lyd_node_term *)node)->value.ident->name;
romand05b2ad2024-01-23 12:02:40 +01002536 if (nc_server_config_transport_params(alg, &opts->kex_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002537 ret = 1;
romand05b2ad2024-01-23 12:02:40 +01002538 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002539 }
2540
2541cleanup:
romanba93eac2023-07-18 14:36:48 +02002542 if (is_ch(node)) {
2543 /* UNLOCK */
2544 nc_ch_client_unlock(ch_client);
2545 }
romanc1d2b092023-02-02 08:58:27 +01002546 return ret;
2547}
2548
2549/* leaf-list */
2550static int
romane028ef92023-02-24 16:33:08 +01002551nc_server_config_encryption_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002552{
roman5cbb6532023-06-22 12:53:17 +02002553 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002554 const char *alg;
roman5cbb6532023-06-22 12:53:17 +02002555 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002556 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002557
roman5cbb6532023-06-22 12:53:17 +02002558 assert(!strcmp(LYD_NAME(node), "encryption-alg"));
romanc1d2b092023-02-02 08:58:27 +01002559
romanba93eac2023-07-18 14:36:48 +02002560 /* LOCK */
2561 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002562 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002563 return 1;
2564 }
2565
roman8341e8b2023-11-23 16:12:42 +01002566 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002567 ret = 1;
2568 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002569 }
2570
romand05b2ad2024-01-23 12:02:40 +01002571 /* get the algorithm name and append it to supported algs */
roman5cbb6532023-06-22 12:53:17 +02002572 alg = ((struct lyd_node_term *)node)->value.ident->name;
romand05b2ad2024-01-23 12:02:40 +01002573 if (nc_server_config_transport_params(alg, &opts->encryption_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002574 ret = 1;
romand05b2ad2024-01-23 12:02:40 +01002575 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002576 }
2577
2578cleanup:
romanba93eac2023-07-18 14:36:48 +02002579 if (is_ch(node)) {
2580 /* UNLOCK */
2581 nc_ch_client_unlock(ch_client);
2582 }
romanc1d2b092023-02-02 08:58:27 +01002583 return ret;
2584}
2585
2586/* leaf-list */
2587static int
romane028ef92023-02-24 16:33:08 +01002588nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002589{
roman5cbb6532023-06-22 12:53:17 +02002590 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002591 const char *alg;
roman5cbb6532023-06-22 12:53:17 +02002592 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002593 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002594
roman5cbb6532023-06-22 12:53:17 +02002595 assert(!strcmp(LYD_NAME(node), "mac-alg"));
romanc1d2b092023-02-02 08:58:27 +01002596
romanba93eac2023-07-18 14:36:48 +02002597 /* LOCK */
2598 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002599 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002600 return 1;
2601 }
2602
roman8341e8b2023-11-23 16:12:42 +01002603 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002604 ret = 1;
2605 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002606 }
2607
romand05b2ad2024-01-23 12:02:40 +01002608 /* get the algorithm name and append it to supported algs */
roman5cbb6532023-06-22 12:53:17 +02002609 alg = ((struct lyd_node_term *)node)->value.ident->name;
romand05b2ad2024-01-23 12:02:40 +01002610 if (nc_server_config_transport_params(alg, &opts->mac_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002611 ret = 1;
romand05b2ad2024-01-23 12:02:40 +01002612 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002613 }
2614
2615cleanup:
romanba93eac2023-07-18 14:36:48 +02002616 if (is_ch(node)) {
2617 /* UNLOCK */
2618 nc_ch_client_unlock(ch_client);
2619 }
romanc1d2b092023-02-02 08:58:27 +01002620 return ret;
2621}
2622
roman78df0fa2023-11-02 10:33:57 +01002623static int
2624nc_server_config_check_endpt_reference_cycle(struct nc_endpt *original, struct nc_endpt *next)
2625{
2626 if (!next->referenced_endpt_name) {
2627 /* no further reference -> no cycle */
2628 return 0;
2629 }
2630
2631 if (!strcmp(original->name, next->referenced_endpt_name)) {
2632 /* found cycle */
2633 return 1;
2634 } else {
2635 if (nc_server_get_referenced_endpt(next->referenced_endpt_name, &next)) {
2636 /* referenced endpoint does not exist */
2637 return 1;
2638 }
2639
2640 /* continue further */
2641 return nc_server_config_check_endpt_reference_cycle(original, next);
2642 }
2643}
2644
roman0bbc19c2023-05-26 09:59:09 +02002645/**
roman78df0fa2023-11-02 10:33:57 +01002646 * @brief Set all endpoint references.
roman0bbc19c2023-05-26 09:59:09 +02002647 *
2648 * @return 0 on success, 1 on error.
2649 */
2650static int
roman78df0fa2023-11-02 10:33:57 +01002651nc_server_config_check_endpt_references(void)
roman0bbc19c2023-05-26 09:59:09 +02002652{
2653 uint16_t i, j;
roman78df0fa2023-11-02 10:33:57 +01002654 struct nc_endpt *referenced_endpt = NULL;
roman0bbc19c2023-05-26 09:59:09 +02002655
roman78df0fa2023-11-02 10:33:57 +01002656 /* first do listen endpoints */
roman0bbc19c2023-05-26 09:59:09 +02002657 for (i = 0; i < server_opts.endpt_count; i++) {
roman6430c152023-10-12 11:28:47 +02002658 /* go through all the endpoints */
roman0bbc19c2023-05-26 09:59:09 +02002659 if (server_opts.endpts[i].referenced_endpt_name) {
roman78df0fa2023-11-02 10:33:57 +01002660 /* get referenced endpt */
2661 if (nc_server_get_referenced_endpt(server_opts.endpts[i].referenced_endpt_name, &referenced_endpt)) {
2662 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" does not exist.",
roman0bbc19c2023-05-26 09:59:09 +02002663 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2664 return 1;
2665 }
roman78df0fa2023-11-02 10:33:57 +01002666
2667 /* check if the endpoint references itself */
2668 if (&server_opts.endpts[i] == referenced_endpt) {
2669 ERR(NULL, "Endpoint \"%s\" references itself.", server_opts.endpts[i].name);
2670 return 1;
2671 }
2672
2673 /* check transport */
2674 if ((server_opts.endpts[i].ti != referenced_endpt->ti)) {
2675 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" has different transport type.",
2676 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2677 return 1;
roman506354a2024-04-11 09:37:22 +02002678 } else if ((referenced_endpt->ti != NC_TI_SSH) && (referenced_endpt->ti != NC_TI_TLS)) {
roman78df0fa2023-11-02 10:33:57 +01002679 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" has unsupported transport type.",
2680 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2681 return 1;
2682 }
2683
2684 /* check cyclic reference */
2685 if (nc_server_config_check_endpt_reference_cycle(&server_opts.endpts[i], referenced_endpt)) {
2686 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" creates a cycle.",
2687 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2688 return 1;
2689 }
2690
2691 /* all went well, assign the name to the opts, so we can access it for auth */
roman506354a2024-04-11 09:37:22 +02002692 if (server_opts.endpts[i].ti == NC_TI_SSH) {
roman78df0fa2023-11-02 10:33:57 +01002693 server_opts.endpts[i].opts.ssh->referenced_endpt_name = referenced_endpt->name;
2694 } else {
2695 server_opts.endpts[i].opts.tls->referenced_endpt_name = referenced_endpt->name;
2696 }
roman0bbc19c2023-05-26 09:59:09 +02002697 }
2698 }
2699
roman78df0fa2023-11-02 10:33:57 +01002700 /* now check all the call home endpoints */
2701 /* LOCK */
2702 pthread_rwlock_rdlock(&server_opts.ch_client_lock);
2703 for (i = 0; i < server_opts.ch_client_count; i++) {
2704 /* LOCK */
2705 pthread_mutex_lock(&server_opts.ch_clients[i].lock);
2706 for (j = 0; j < server_opts.ch_clients[i].ch_endpt_count; j++) {
2707 if (server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name) {
2708 /* get referenced endpt */
2709 if (nc_server_get_referenced_endpt(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, &referenced_endpt)) {
2710 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" does not exist.",
2711 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
2712 goto ch_fail;
2713 }
2714
2715 /* check transport */
2716 if (server_opts.ch_clients[i].ch_endpts[j].ti != referenced_endpt->ti) {
2717 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" has different transport type.",
2718 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
2719 goto ch_fail;
roman506354a2024-04-11 09:37:22 +02002720 } else if ((referenced_endpt->ti != NC_TI_SSH) && (referenced_endpt->ti != NC_TI_TLS)) {
roman78df0fa2023-11-02 10:33:57 +01002721 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" has unsupported transport type.",
2722 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
2723 goto ch_fail;
2724 }
2725
2726 /* check cyclic reference */
2727 if (nc_server_config_check_endpt_reference_cycle(referenced_endpt, referenced_endpt)) {
2728 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" creates a cycle.",
2729 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
2730 goto ch_fail;
2731 }
2732
2733 /* all went well, assign the name to the opts, so we can access it for auth */
roman506354a2024-04-11 09:37:22 +02002734 if (server_opts.ch_clients[i].ch_endpts[j].ti == NC_TI_SSH) {
roman78df0fa2023-11-02 10:33:57 +01002735 server_opts.ch_clients[i].ch_endpts[j].opts.ssh->referenced_endpt_name = referenced_endpt->name;
2736 } else {
2737 server_opts.ch_clients[i].ch_endpts[j].opts.tls->referenced_endpt_name = referenced_endpt->name;
2738 }
2739 }
2740 }
2741 /* UNLOCK */
2742 pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
2743 }
2744
2745 /* UNLOCK */
2746 pthread_rwlock_unlock(&server_opts.ch_client_lock);
roman0bbc19c2023-05-26 09:59:09 +02002747 return 0;
roman78df0fa2023-11-02 10:33:57 +01002748
2749ch_fail:
2750 /* UNLOCK */
2751 pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
2752 /* UNLOCK */
2753 pthread_rwlock_unlock(&server_opts.ch_client_lock);
roman96c27f92023-11-02 11:09:46 +01002754 return 1;
roman0bbc19c2023-05-26 09:59:09 +02002755}
2756
2757static int
roman78df0fa2023-11-02 10:33:57 +01002758nc_server_config_endpoint_reference(const struct lyd_node *node, NC_OPERATION op)
roman0bbc19c2023-05-26 09:59:09 +02002759{
2760 int ret = 0;
roman78df0fa2023-11-02 10:33:57 +01002761 struct nc_endpt *endpt = NULL;
roman8341e8b2023-11-23 16:12:42 +01002762 struct nc_ch_client *ch_client = NULL;
roman78df0fa2023-11-02 10:33:57 +01002763 struct nc_ch_endpt *ch_endpt = NULL;
2764 struct nc_server_ssh_opts *ssh = NULL;
2765 struct nc_server_tls_opts *tls = NULL;
roman0bbc19c2023-05-26 09:59:09 +02002766
roman78df0fa2023-11-02 10:33:57 +01002767 assert(!strcmp(LYD_NAME(node), "endpoint-reference"));
roman0bbc19c2023-05-26 09:59:09 +02002768
roman78df0fa2023-11-02 10:33:57 +01002769 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
2770 /* to avoid unlock on fail */
2771 return 1;
2772 }
2773
2774 /* get endpt */
2775 if (is_listen(node)) {
2776 ret = nc_server_config_get_endpt(node, &endpt, NULL);
2777 } else {
roman8341e8b2023-11-23 16:12:42 +01002778 ret = nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt);
roman78df0fa2023-11-02 10:33:57 +01002779 }
roman0bbc19c2023-05-26 09:59:09 +02002780 if (ret) {
2781 goto cleanup;
2782 }
2783
2784 if (op == NC_OP_DELETE) {
roman78df0fa2023-11-02 10:33:57 +01002785 if (endpt) {
romanb7bfa652023-11-09 12:36:35 +01002786 /* listen */
roman78df0fa2023-11-02 10:33:57 +01002787 free(endpt->referenced_endpt_name);
2788 endpt->referenced_endpt_name = NULL;
roman2e797ef2023-06-19 10:47:49 +02002789 } else {
romanb7bfa652023-11-09 12:36:35 +01002790 /* call home */
roman78df0fa2023-11-02 10:33:57 +01002791 free(ch_endpt->referenced_endpt_name);
2792 ch_endpt->referenced_endpt_name = NULL;
roman2e797ef2023-06-19 10:47:49 +02002793 }
roman78df0fa2023-11-02 10:33:57 +01002794 if (is_ssh(node)) {
roman8341e8b2023-11-23 16:12:42 +01002795 if (nc_server_config_get_ssh_opts(node, ch_client, &ssh)) {
roman78df0fa2023-11-02 10:33:57 +01002796 ret = 1;
2797 goto cleanup;
2798 }
roman96c27f92023-11-02 11:09:46 +01002799
roman78df0fa2023-11-02 10:33:57 +01002800 ssh->referenced_endpt_name = NULL;
2801 } else {
roman8341e8b2023-11-23 16:12:42 +01002802 if (nc_server_config_get_tls_opts(node, ch_client, &tls)) {
roman78df0fa2023-11-02 10:33:57 +01002803 ret = 1;
2804 goto cleanup;
2805 }
roman0bbc19c2023-05-26 09:59:09 +02002806
roman78df0fa2023-11-02 10:33:57 +01002807 tls->referenced_endpt_name = NULL;
roman0bbc19c2023-05-26 09:59:09 +02002808 }
roman0bbc19c2023-05-26 09:59:09 +02002809
roman0bbc19c2023-05-26 09:59:09 +02002810 goto cleanup;
roman2e797ef2023-06-19 10:47:49 +02002811 } else {
roman78df0fa2023-11-02 10:33:57 +01002812 /* just set the name, check it once configuring of all nodes is done */
2813 if (endpt) {
2814 free(endpt->referenced_endpt_name);
2815 endpt->referenced_endpt_name = strdup(lyd_get_value(node));
2816 NC_CHECK_ERRMEM_GOTO(!endpt->referenced_endpt_name, ret = 1, cleanup);
2817 } else {
2818 free(ch_endpt->referenced_endpt_name);
2819 ch_endpt->referenced_endpt_name = strdup(lyd_get_value(node));
2820 NC_CHECK_ERRMEM_GOTO(!ch_endpt->referenced_endpt_name, ret = 1, cleanup);
2821 }
2822
2823 goto cleanup;
roman2e797ef2023-06-19 10:47:49 +02002824 }
roman0bbc19c2023-05-26 09:59:09 +02002825
2826cleanup:
roman78df0fa2023-11-02 10:33:57 +01002827 if (is_ch(node)) {
2828 /* UNLOCK */
2829 nc_ch_client_unlock(ch_client);
2830 }
2831
roman0bbc19c2023-05-26 09:59:09 +02002832 return ret;
2833}
2834
roman3f9b65c2023-06-05 14:26:58 +02002835static int
roman3f9b65c2023-06-05 14:26:58 +02002836nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op)
2837{
2838 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02002839 struct nc_certificate *cert;
romanb6f44032023-06-30 15:07:56 +02002840 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002841 struct nc_ch_client *ch_client = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002842
2843 assert(!strcmp(LYD_NAME(node), "cert-data"));
2844
romanba93eac2023-07-18 14:36:48 +02002845 /* LOCK */
2846 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002847 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002848 return 1;
2849 }
2850
romanb6f44032023-06-30 15:07:56 +02002851 if (equal_parent_name(node, 3, "server-identity")) {
roman8341e8b2023-11-23 16:12:42 +01002852 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
romanb6f44032023-06-30 15:07:56 +02002853 ret = 1;
2854 goto cleanup;
2855 }
roman3f9b65c2023-06-05 14:26:58 +02002856
roman3f9b65c2023-06-05 14:26:58 +02002857 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002858 free(opts->cert_data);
2859 opts->cert_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002860 NC_CHECK_ERRMEM_GOTO(!opts->cert_data, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02002861 }
roman6430c152023-10-12 11:28:47 +02002862 } else if (equal_parent_name(node, 3, "ca-certs") || equal_parent_name(node, 3, "ee-certs")) {
roman8341e8b2023-11-23 16:12:42 +01002863 if (nc_server_config_get_cert(node, ch_client, &cert)) {
roman3f9b65c2023-06-05 14:26:58 +02002864 ret = 1;
2865 goto cleanup;
2866 }
2867
2868 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002869 free(cert->data);
2870 cert->data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002871 NC_CHECK_ERRMEM_GOTO(!cert->data, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02002872 } else {
roman6430c152023-10-12 11:28:47 +02002873 free(cert->data);
2874 cert->data = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002875 }
2876 }
2877
2878cleanup:
romanba93eac2023-07-18 14:36:48 +02002879 if (is_ch(node)) {
2880 /* UNLOCK */
2881 nc_ch_client_unlock(ch_client);
2882 }
roman3f9b65c2023-06-05 14:26:58 +02002883 return ret;
2884}
2885
2886static int
roman3f9b65c2023-06-05 14:26:58 +02002887nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op)
2888{
2889 int ret = 0;
roman78df0fa2023-11-02 10:33:57 +01002890 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002891 struct nc_ch_client *ch_client = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002892
2893 assert(!strcmp(LYD_NAME(node), "asymmetric-key"));
2894
romanba93eac2023-07-18 14:36:48 +02002895 /* LOCK */
2896 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002897 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002898 return 1;
2899 }
2900
roman8341e8b2023-11-23 16:12:42 +01002901 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02002902 ret = 1;
2903 goto cleanup;
2904 }
2905
2906 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2907 /* set to keystore */
roman78df0fa2023-11-02 10:33:57 +01002908 opts->store = NC_STORE_KEYSTORE;
roman3f9b65c2023-06-05 14:26:58 +02002909
roman78df0fa2023-11-02 10:33:57 +01002910 free(opts->key_ref);
2911 opts->key_ref = strdup(lyd_get_value(node));
2912 NC_CHECK_ERRMEM_GOTO(!opts->key_ref, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02002913 } else {
roman78df0fa2023-11-02 10:33:57 +01002914 free(opts->key_ref);
2915 opts->key_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002916 }
2917
2918cleanup:
romanba93eac2023-07-18 14:36:48 +02002919 if (is_ch(node)) {
2920 /* UNLOCK */
2921 nc_ch_client_unlock(ch_client);
2922 }
roman3f9b65c2023-06-05 14:26:58 +02002923 return ret;
2924}
2925
2926static int
roman3f9b65c2023-06-05 14:26:58 +02002927nc_server_config_create_ca_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
2928{
2929 assert(!strcmp(LYD_NAME(node), "certificate"));
2930
2931 node = lyd_child(node);
2932 assert(!strcmp(LYD_NAME(node), "name"));
2933
Michal Vaskocf898172024-01-15 15:04:28 +01002934 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ca_certs.certs, sizeof *opts->ca_certs.certs,
2935 &opts->ca_certs.cert_count);
roman3f9b65c2023-06-05 14:26:58 +02002936}
2937
2938static int
2939nc_server_config_create_ee_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
2940{
2941 assert(!strcmp(LYD_NAME(node), "certificate"));
2942
2943 node = lyd_child(node);
2944 assert(!strcmp(LYD_NAME(node), "name"));
2945
Michal Vaskocf898172024-01-15 15:04:28 +01002946 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ee_certs.certs, sizeof *opts->ee_certs.certs,
2947 &opts->ee_certs.cert_count);
roman3f9b65c2023-06-05 14:26:58 +02002948}
2949
2950static int
2951nc_server_config_certificate(const struct lyd_node *node, NC_OPERATION op)
2952{
2953 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02002954 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002955 struct nc_ch_client *ch_client = NULL;
roman6430c152023-10-12 11:28:47 +02002956 struct nc_certificate *cert;
roman3f9b65c2023-06-05 14:26:58 +02002957
2958 assert(!strcmp(LYD_NAME(node), "certificate"));
2959
romanba93eac2023-07-18 14:36:48 +02002960 /* LOCK */
2961 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002962 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002963 return 1;
2964 }
2965
roman8341e8b2023-11-23 16:12:42 +01002966 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02002967 ret = 1;
2968 goto cleanup;
2969 }
2970
Michal Vaskocf898172024-01-15 15:04:28 +01002971 if (equal_parent_name(node, 1, "central-keystore-reference")) {
romanb6f44032023-06-30 15:07:56 +02002972 /* TLS server-identity */
roman3f9b65c2023-06-05 14:26:58 +02002973 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2974 /* set to keystore */
romanb6f44032023-06-30 15:07:56 +02002975 opts->store = NC_STORE_KEYSTORE;
roman3f9b65c2023-06-05 14:26:58 +02002976
roman6430c152023-10-12 11:28:47 +02002977 free(opts->cert_ref);
2978 opts->cert_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002979 NC_CHECK_ERRMEM_GOTO(!opts->cert_ref, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02002980 } else {
roman6430c152023-10-12 11:28:47 +02002981 free(opts->cert_ref);
romanb6f44032023-06-30 15:07:56 +02002982 opts->cert_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002983 }
romanb6f44032023-06-30 15:07:56 +02002984 } else if (equal_parent_name(node, 2, "ca-certs")) {
2985 /* TLS client auth certificate authority */
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_ca_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->ca_certs, cert);
roman3f9b65c2023-06-05 14:26:58 +02002997 }
romanb6f44032023-06-30 15:07:56 +02002998 } else if (equal_parent_name(node, 2, "ee-certs")) {
2999 /* TLS client auth end entity */
roman3f9b65c2023-06-05 14:26:58 +02003000 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003001 ret = nc_server_config_create_ee_certs_certificate(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02003002 if (ret) {
3003 goto cleanup;
3004 }
3005 } else {
roman8341e8b2023-11-23 16:12:42 +01003006 if (nc_server_config_get_cert(node, ch_client, &cert)) {
roman6430c152023-10-12 11:28:47 +02003007 ret = 1;
3008 goto cleanup;
3009 }
3010 nc_server_config_del_cert(&opts->ee_certs, cert);
roman3f9b65c2023-06-05 14:26:58 +02003011 }
3012 }
3013
3014cleanup:
romanba93eac2023-07-18 14:36:48 +02003015 if (is_ch(node)) {
3016 /* UNLOCK */
3017 nc_ch_client_unlock(ch_client);
3018 }
roman3f9b65c2023-06-05 14:26:58 +02003019 return ret;
3020}
3021
3022static int
3023nc_server_config_create_cert_to_name(const struct lyd_node *node, struct nc_server_tls_opts *opts)
3024{
3025 int ret = 0;
3026 struct lyd_node *n;
3027 struct nc_ctn *new, *iter;
Michal Vasko3392b4a2024-02-02 08:57:53 +01003028 const char *map_type, *name = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003029 uint32_t id;
3030 NC_TLS_CTN_MAPTYPE m_type;
3031
3032 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
3033
roman3f9b65c2023-06-05 14:26:58 +02003034 /* find the list's key */
3035 lyd_find_path(node, "id", 0, &n);
3036 assert(n);
roman9cdb7b52023-10-25 13:59:55 +02003037 id = ((struct lyd_node_term *)n)->value.uint32;
roman3f9b65c2023-06-05 14:26:58 +02003038
Michal Vasko3392b4a2024-02-02 08:57:53 +01003039 /* get CTN map-type */
3040 if (lyd_find_path(node, "map-type", 0, &n)) {
3041 ERR(NULL, "Missing CTN map-type.");
3042 ret = 1;
3043 goto cleanup;
3044 }
roman3f9b65c2023-06-05 14:26:58 +02003045 map_type = ((struct lyd_node_term *)n)->value.ident->name;
3046 if (!strcmp(map_type, "specified")) {
3047 m_type = NC_TLS_CTN_SPECIFIED;
Michal Vasko3392b4a2024-02-02 08:57:53 +01003048
3049 /* get CTN name */
3050 if (lyd_find_path(node, "name", 0, &n)) {
3051 ERR(NULL, "Missing CTN \"specified\" user name.");
3052 ret = 1;
3053 goto cleanup;
3054 }
3055 name = lyd_get_value(n);
roman3f9b65c2023-06-05 14:26:58 +02003056 } else if (!strcmp(map_type, "san-rfc822-name")) {
3057 m_type = NC_TLS_CTN_SAN_RFC822_NAME;
3058 } else if (!strcmp(map_type, "san-dns-name")) {
3059 m_type = NC_TLS_CTN_SAN_DNS_NAME;
3060 } else if (!strcmp(map_type, "san-ip-address")) {
3061 m_type = NC_TLS_CTN_SAN_IP_ADDRESS;
3062 } else if (!strcmp(map_type, "san-any")) {
3063 m_type = NC_TLS_CTN_SAN_ANY;
3064 } else if (!strcmp(map_type, "common-name")) {
3065 m_type = NC_TLS_CTN_COMMON_NAME;
3066 } else {
Michal Vasko3392b4a2024-02-02 08:57:53 +01003067 ERR(NULL, "CTN map-type \"%s\" not supported.", map_type);
roman3f9b65c2023-06-05 14:26:58 +02003068 ret = 1;
3069 goto cleanup;
3070 }
3071
roman6430c152023-10-12 11:28:47 +02003072 /* create new ctn */
3073 new = calloc(1, sizeof *new);
roman3a95bb22023-10-26 11:07:17 +02003074 NC_CHECK_ERRMEM_GOTO(!new, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02003075
roman3f9b65c2023-06-05 14:26:58 +02003076 /* find the right place for insertion */
3077 if (!opts->ctn) {
3078 /* inserting the first one */
3079 opts->ctn = new;
Roytak421eb0c2023-08-01 22:18:27 +02003080 } else if (opts->ctn->id > id) {
roman3f9b65c2023-06-05 14:26:58 +02003081 /* insert at the beginning */
3082 new->next = opts->ctn;
3083 opts->ctn = new;
3084 } else {
3085 /* have to find the right place */
Roytak421eb0c2023-08-01 22:18:27 +02003086 for (iter = opts->ctn; iter->next && iter->next->id <= id; iter = iter->next) {}
3087 if (iter->id == id) {
Michal Vasko3392b4a2024-02-02 08:57:53 +01003088 /* collision, replace */
romanb7bfa652023-11-09 12:36:35 +01003089 free(new);
roman3f9b65c2023-06-05 14:26:58 +02003090 new = iter;
Michal Vasko3392b4a2024-02-02 08:57:53 +01003091 free(new->name);
3092 new->name = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003093 } else {
3094 new->next = iter->next;
3095 iter->next = new;
3096 }
3097 }
3098
3099 /* insert the right data */
3100 new->id = id;
Michal Vasko3392b4a2024-02-02 08:57:53 +01003101 if (name) {
3102 new->name = strdup(name);
3103 NC_CHECK_ERRMEM_GOTO(!new->name, ret = 1, cleanup);
3104 }
roman3f9b65c2023-06-05 14:26:58 +02003105 new->map_type = m_type;
3106
3107cleanup:
3108 return ret;
3109}
3110
3111static int
3112nc_server_config_cert_to_name(const struct lyd_node *node, NC_OPERATION op)
3113{
3114 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003115 struct nc_server_tls_opts *opts;
roman3f9b65c2023-06-05 14:26:58 +02003116 struct nc_ctn *ctn;
roman8341e8b2023-11-23 16:12:42 +01003117 struct nc_ch_client *ch_client = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003118
3119 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
3120
romanba93eac2023-07-18 14:36:48 +02003121 /* LOCK */
3122 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003123 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003124 return 1;
3125 }
3126
roman8341e8b2023-11-23 16:12:42 +01003127 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02003128 ret = 1;
3129 goto cleanup;
3130 }
3131
3132 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003133 ret = nc_server_config_create_cert_to_name(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02003134 if (ret) {
3135 goto cleanup;
3136 }
3137 } else {
3138 /* find the given ctn entry */
roman8341e8b2023-11-23 16:12:42 +01003139 if (nc_server_config_get_ctn(node, ch_client, &ctn)) {
roman3f9b65c2023-06-05 14:26:58 +02003140 ret = 1;
3141 goto cleanup;
3142 }
romanb6f44032023-06-30 15:07:56 +02003143 nc_server_config_del_ctn(opts, ctn);
roman3f9b65c2023-06-05 14:26:58 +02003144 }
3145
3146cleanup:
romanba93eac2023-07-18 14:36:48 +02003147 if (is_ch(node)) {
3148 /* UNLOCK */
3149 nc_ch_client_unlock(ch_client);
3150 }
roman3f9b65c2023-06-05 14:26:58 +02003151 return ret;
3152}
3153
3154static int
roman3f9b65c2023-06-05 14:26:58 +02003155nc_server_config_fingerprint(const struct lyd_node *node, NC_OPERATION op)
3156{
3157 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02003158 struct nc_ctn *ctn;
roman8341e8b2023-11-23 16:12:42 +01003159 struct nc_ch_client *ch_client = NULL;
romanba93eac2023-07-18 14:36:48 +02003160
3161 assert(!strcmp(LYD_NAME(node), "fingerprint"));
3162
3163 /* LOCK */
3164 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003165 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003166 return 1;
3167 }
roman3f9b65c2023-06-05 14:26:58 +02003168
roman8341e8b2023-11-23 16:12:42 +01003169 if (nc_server_config_get_ctn(node, ch_client, &ctn)) {
roman3f9b65c2023-06-05 14:26:58 +02003170 ret = 1;
3171 goto cleanup;
3172 }
3173
3174 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003175 free(ctn->fingerprint);
3176 ctn->fingerprint = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003177 NC_CHECK_ERRMEM_GOTO(!ctn->fingerprint, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003178 } else {
roman6430c152023-10-12 11:28:47 +02003179 free(ctn->fingerprint);
3180 ctn->fingerprint = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003181 }
3182
3183cleanup:
romanba93eac2023-07-18 14:36:48 +02003184 if (is_ch(node)) {
3185 /* UNLOCK */
3186 nc_ch_client_unlock(ch_client);
3187 }
roman3f9b65c2023-06-05 14:26:58 +02003188 return ret;
3189}
3190
roman12644fe2023-06-08 11:06:42 +02003191static int
3192nc_server_config_tls_version(const struct lyd_node *node, NC_OPERATION op)
3193{
3194 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003195 struct nc_server_tls_opts *opts;
roman12644fe2023-06-08 11:06:42 +02003196 const char *version = NULL;
roman8341e8b2023-11-23 16:12:42 +01003197 struct nc_ch_client *ch_client = NULL;
roman6430c152023-10-12 11:28:47 +02003198 NC_TLS_VERSION tls_version;
roman12644fe2023-06-08 11:06:42 +02003199
3200 assert(!strcmp(LYD_NAME(node), "tls-version"));
3201
romanba93eac2023-07-18 14:36:48 +02003202 /* LOCK */
3203 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003204 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003205 return 1;
3206 }
3207
roman8341e8b2023-11-23 16:12:42 +01003208 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman12644fe2023-06-08 11:06:42 +02003209 ret = 1;
3210 goto cleanup;
3211 }
3212
roman6430c152023-10-12 11:28:47 +02003213 /* str to tls_version */
roman12644fe2023-06-08 11:06:42 +02003214 version = ((struct lyd_node_term *)node)->value.ident->name;
3215 if (!strcmp(version, "tls10")) {
roman6430c152023-10-12 11:28:47 +02003216 tls_version = NC_TLS_VERSION_10;
roman12644fe2023-06-08 11:06:42 +02003217 } else if (!strcmp(version, "tls11")) {
roman6430c152023-10-12 11:28:47 +02003218 tls_version = NC_TLS_VERSION_11;
roman12644fe2023-06-08 11:06:42 +02003219 } else if (!strcmp(version, "tls12")) {
roman6430c152023-10-12 11:28:47 +02003220 tls_version = NC_TLS_VERSION_12;
roman12644fe2023-06-08 11:06:42 +02003221 } else if (!strcmp(version, "tls13")) {
roman6430c152023-10-12 11:28:47 +02003222 tls_version = NC_TLS_VERSION_13;
roman12644fe2023-06-08 11:06:42 +02003223 } else {
3224 ERR(NULL, "TLS version \"%s\" not supported.", version);
3225 ret = 1;
3226 goto cleanup;
3227 }
3228
roman6430c152023-10-12 11:28:47 +02003229 if (op == NC_OP_CREATE) {
3230 /* add the version if it isn't there already */
3231 opts->tls_versions |= tls_version;
3232 } else if ((op == NC_OP_DELETE) && (opts->tls_versions & tls_version)) {
3233 /* delete the version if it is there */
roman84fe3252023-10-25 11:28:32 +02003234 opts->tls_versions &= ~tls_version;
roman6430c152023-10-12 11:28:47 +02003235 }
3236
roman12644fe2023-06-08 11:06:42 +02003237cleanup:
romanba93eac2023-07-18 14:36:48 +02003238 if (is_ch(node)) {
3239 /* UNLOCK */
3240 nc_ch_client_unlock(ch_client);
3241 }
roman12644fe2023-06-08 11:06:42 +02003242 return ret;
3243}
3244
3245static int
3246nc_server_config_create_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher)
3247{
3248 int ret = 0;
roman506354a2024-04-11 09:37:22 +02003249 char *processed_cipher = NULL;
roman12644fe2023-06-08 11:06:42 +02003250
roman506354a2024-04-11 09:37:22 +02003251 ret = nc_tls_process_cipher_suite_wrap(cipher, &processed_cipher);
3252 if (ret) {
3253 ERR(NULL, "Failed to process the cipher suite \"%s\".", cipher);
3254 goto cleanup;
roman12644fe2023-06-08 11:06:42 +02003255 }
roman12644fe2023-06-08 11:06:42 +02003256
roman506354a2024-04-11 09:37:22 +02003257 ret = nc_tls_append_cipher_suite_wrap(opts, processed_cipher);
3258 if (ret) {
3259 ERR(NULL, "Failed to append the cipher suite \"%s\".", cipher);
3260 goto cleanup;
roman12644fe2023-06-08 11:06:42 +02003261 }
3262
3263cleanup:
roman506354a2024-04-11 09:37:22 +02003264 free(processed_cipher);
roman12644fe2023-06-08 11:06:42 +02003265 return ret;
3266}
3267
3268static int
romanb6f44032023-06-30 15:07:56 +02003269nc_server_config_del_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher)
roman12644fe2023-06-08 11:06:42 +02003270{
romanc135c6d2023-10-25 13:32:30 +02003271 int ret = 0;
roman12644fe2023-06-08 11:06:42 +02003272
romanc135c6d2023-10-25 13:32:30 +02003273 ret = nc_server_config_delete_substring(opts->ciphers, cipher, ':');
3274 if (ret) {
roman12644fe2023-06-08 11:06:42 +02003275 ERR(NULL, "Unable to delete a cipher (%s), which was not previously added.", cipher);
3276 return 1;
3277 }
3278
3279 return 0;
3280}
3281
3282static int
3283nc_server_config_cipher_suite(const struct lyd_node *node, NC_OPERATION op)
3284{
3285 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003286 struct nc_server_tls_opts *opts;
roman12644fe2023-06-08 11:06:42 +02003287 const char *cipher = NULL;
roman8341e8b2023-11-23 16:12:42 +01003288 struct nc_ch_client *ch_client = NULL;
roman12644fe2023-06-08 11:06:42 +02003289
romanfaecc582023-06-15 16:13:31 +02003290 assert(!strcmp(LYD_NAME(node), "cipher-suite"));
3291
romanba93eac2023-07-18 14:36:48 +02003292 /* LOCK */
3293 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003294 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003295 return 1;
3296 }
3297
roman8341e8b2023-11-23 16:12:42 +01003298 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman12644fe2023-06-08 11:06:42 +02003299 ret = 1;
3300 goto cleanup;
3301 }
3302
3303 cipher = ((struct lyd_node_term *)node)->value.ident->name;
3304 if (op == NC_OP_CREATE) {
romanb6f44032023-06-30 15:07:56 +02003305 ret = nc_server_config_create_cipher_suite(opts, cipher);
roman12644fe2023-06-08 11:06:42 +02003306 if (ret) {
3307 goto cleanup;
3308 }
3309 } else if (op == NC_OP_DELETE) {
romanb6f44032023-06-30 15:07:56 +02003310 ret = nc_server_config_del_cipher_suite(opts, cipher);
roman12644fe2023-06-08 11:06:42 +02003311 if (ret) {
3312 goto cleanup;
3313 }
3314 }
3315
3316cleanup:
romanba93eac2023-07-18 14:36:48 +02003317 if (is_ch(node)) {
3318 /* UNLOCK */
3319 nc_ch_client_unlock(ch_client);
3320 }
roman12644fe2023-06-08 11:06:42 +02003321 return ret;
3322}
3323
roman2eab4742023-06-06 10:00:26 +02003324#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02003325
roman83683fb2023-02-24 09:15:23 +01003326static int
roman5cbb6532023-06-22 12:53:17 +02003327nc_server_config_create_netconf_client(const struct lyd_node *node)
3328{
3329 int ret = 0;
3330
3331 node = lyd_child(node);
3332 assert(!strcmp(LYD_NAME(node), "name"));
3333
3334 /* LOCK */
3335 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
3336
3337 ret = nc_server_config_realloc(lyd_get_value(node), (void **)&server_opts.ch_clients, sizeof *server_opts.ch_clients, &server_opts.ch_client_count);
3338 if (ret) {
3339 goto cleanup;
3340 }
3341
3342 server_opts.ch_clients[server_opts.ch_client_count - 1].id = ATOMIC_INC_RELAXED(server_opts.new_client_id);
3343 server_opts.ch_clients[server_opts.ch_client_count - 1].start_with = NC_CH_FIRST_LISTED;
roman6430c152023-10-12 11:28:47 +02003344 server_opts.ch_clients[server_opts.ch_client_count - 1].max_attempts = 3;
roman5cbb6532023-06-22 12:53:17 +02003345
3346 pthread_mutex_init(&server_opts.ch_clients[server_opts.ch_client_count - 1].lock, NULL);
3347
3348cleanup:
3349 /* UNLOCK */
3350 pthread_rwlock_unlock(&server_opts.ch_client_lock);
3351 return ret;
3352}
3353
3354static int
3355nc_server_config_netconf_client(const struct lyd_node *node, NC_OPERATION op)
3356{
3357 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02003358
3359 assert(!strcmp(LYD_NAME(node), "netconf-client"));
3360
3361 if (op == NC_OP_CREATE) {
3362 ret = nc_server_config_create_netconf_client(node);
3363 if (ret) {
3364 goto cleanup;
3365 }
roman450c00b2023-11-02 10:31:45 +01003366
roman96c27f92023-11-02 11:09:46 +01003367#ifdef NC_ENABLED_SSH_TLS
roman450c00b2023-11-02 10:31:45 +01003368 if (server_opts.ch_dispatch_data.acquire_ctx_cb && server_opts.ch_dispatch_data.release_ctx_cb &&
roman96c27f92023-11-02 11:09:46 +01003369 server_opts.ch_dispatch_data.new_session_cb) {
roman450c00b2023-11-02 10:31:45 +01003370 /* we have all we need for dispatching a new call home thread */
3371 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 +01003372 server_opts.ch_dispatch_data.release_ctx_cb, server_opts.ch_dispatch_data.ctx_cb_data,
3373 server_opts.ch_dispatch_data.new_session_cb, server_opts.ch_dispatch_data.new_session_cb_data);
roman450c00b2023-11-02 10:31:45 +01003374 if (ret) {
3375 ERR(NULL, "Dispatching a new Call Home thread failed for Call Home client \"%s\".", lyd_get_value(lyd_child(node)));
3376 goto cleanup;
3377 }
3378 }
roman96c27f92023-11-02 11:09:46 +01003379#endif /* NC_ENABLED_SSH_TLS */
roman5cbb6532023-06-22 12:53:17 +02003380 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01003381 nc_server_config_ch_del_client(node);
roman5cbb6532023-06-22 12:53:17 +02003382 }
3383
3384cleanup:
3385 return ret;
3386}
3387
3388#ifdef NC_ENABLED_SSH_TLS
3389
3390static int
3391nc_server_config_remote_address(const struct lyd_node *node, NC_OPERATION op)
3392{
3393 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02003394 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01003395 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02003396
romanb6f44032023-06-30 15:07:56 +02003397 assert(!strcmp(LYD_NAME(node), "remote-address"));
3398
romanba93eac2023-07-18 14:36:48 +02003399 /* LOCK */
3400 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003401 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003402 return 1;
3403 }
3404
roman8341e8b2023-11-23 16:12:42 +01003405 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02003406 ret = 1;
3407 goto cleanup;
3408 }
3409
3410 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman5e5d3f22024-08-08 12:44:53 +02003411 free(ch_endpt->dst_addr);
3412 ch_endpt->dst_addr = strdup(lyd_get_value(node));
3413 NC_CHECK_ERRMEM_GOTO(!ch_endpt->dst_addr, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02003414 } else {
roman5e5d3f22024-08-08 12:44:53 +02003415 free(ch_endpt->dst_addr);
3416 ch_endpt->dst_addr = NULL;
roman5cbb6532023-06-22 12:53:17 +02003417 }
3418
3419cleanup:
romanba93eac2023-07-18 14:36:48 +02003420 /* UNLOCK */
3421 nc_ch_client_unlock(ch_client);
roman5cbb6532023-06-22 12:53:17 +02003422 return ret;
3423}
3424
3425static int
3426nc_server_config_remote_port(const struct lyd_node *node, NC_OPERATION op)
3427{
3428 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02003429 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01003430 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02003431
romanb6f44032023-06-30 15:07:56 +02003432 assert(!strcmp(LYD_NAME(node), "remote-port"));
3433
romanba93eac2023-07-18 14:36:48 +02003434 /* LOCK */
3435 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003436 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003437 return 1;
3438 }
3439
roman8341e8b2023-11-23 16:12:42 +01003440 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02003441 ret = 1;
3442 goto cleanup;
3443 }
3444
3445 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman5e5d3f22024-08-08 12:44:53 +02003446 ch_endpt->dst_port = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02003447 } else {
roman5e5d3f22024-08-08 12:44:53 +02003448 ch_endpt->dst_port = 0;
roman5cbb6532023-06-22 12:53:17 +02003449 }
3450
3451cleanup:
romanba93eac2023-07-18 14:36:48 +02003452 /* UNLOCK */
3453 nc_ch_client_unlock(ch_client);
roman5cbb6532023-06-22 12:53:17 +02003454 return ret;
3455}
3456
3457#endif /* NC_ENABLED_SSH_TLS */
3458
3459static int
romanb6f44032023-06-30 15:07:56 +02003460nc_server_config_persistent(const struct lyd_node *node, NC_OPERATION op)
3461{
3462 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003463 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003464
3465 assert(!strcmp(LYD_NAME(node), "persistent"));
3466
3467 (void) op;
3468
romanba93eac2023-07-18 14:36:48 +02003469 /* LOCK */
3470 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003471 /* to avoid unlock on fail */
3472 return 1;
romanb6f44032023-06-30 15:07:56 +02003473 }
3474
3475 ch_client->conn_type = NC_CH_PERSIST;
3476
romanba93eac2023-07-18 14:36:48 +02003477 /* UNLOCK */
3478 nc_ch_client_unlock(ch_client);
3479
romanb6f44032023-06-30 15:07:56 +02003480 return ret;
3481}
3482
3483static int
3484nc_server_config_periodic(const struct lyd_node *node, NC_OPERATION op)
3485{
3486 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003487 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003488
3489 assert(!strcmp(LYD_NAME(node), "periodic"));
3490
3491 (void) op;
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 */
3496 return 1;
romanb6f44032023-06-30 15:07:56 +02003497 }
3498
3499 ch_client->conn_type = NC_CH_PERIOD;
3500 /* set default values */
3501 ch_client->period = 60;
3502 ch_client->anchor_time = 0;
3503 ch_client->idle_timeout = 180;
3504
romanba93eac2023-07-18 14:36:48 +02003505 /* UNLOCK */
3506 nc_ch_client_unlock(ch_client);
3507
romanb6f44032023-06-30 15:07:56 +02003508 return ret;
3509}
3510
3511static int
3512nc_server_config_period(const struct lyd_node *node, NC_OPERATION op)
3513{
3514 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003515 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003516
3517 assert(!strcmp(LYD_NAME(node), "period"));
3518
romanba93eac2023-07-18 14:36:48 +02003519 /* LOCK */
3520 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003521 /* to avoid unlock on fail */
3522 return 1;
romanb6f44032023-06-30 15:07:56 +02003523 }
3524
3525 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02003526 ch_client->period = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02003527 } else if (op == NC_OP_DELETE) {
3528 ch_client->period = 60;
3529 }
3530
romanba93eac2023-07-18 14:36:48 +02003531 /* UNLOCK */
3532 nc_ch_client_unlock(ch_client);
3533
romanb6f44032023-06-30 15:07:56 +02003534 return ret;
3535}
3536
3537static int
3538nc_server_config_anchor_time(const struct lyd_node *node, NC_OPERATION op)
3539{
3540 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003541 struct nc_ch_client *ch_client = NULL;
romana3c95c72023-10-26 11:15:53 +02003542 struct lyd_value_date_and_time *anchor_time;
romanb6f44032023-06-30 15:07:56 +02003543
3544 assert(!strcmp(LYD_NAME(node), "anchor-time"));
3545
romanba93eac2023-07-18 14:36:48 +02003546 /* LOCK */
3547 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003548 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003549 return 1;
romanb6f44032023-06-30 15:07:56 +02003550 }
3551
romana3c95c72023-10-26 11:15:53 +02003552 /* get the value of time from the node directly */
3553 LYD_VALUE_GET(&((struct lyd_node_term *)node)->value, anchor_time);
romanb6f44032023-06-30 15:07:56 +02003554
3555 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romana3c95c72023-10-26 11:15:53 +02003556 ch_client->anchor_time = anchor_time->time;
romanb6f44032023-06-30 15:07:56 +02003557 } else if (op == NC_OP_DELETE) {
3558 ch_client->anchor_time = 0;
3559 }
3560
romanba93eac2023-07-18 14:36:48 +02003561 /* UNLOCK */
3562 nc_ch_client_unlock(ch_client);
romanb6f44032023-06-30 15:07:56 +02003563 return ret;
3564}
3565
3566static int
3567nc_server_config_reconnect_strategy(const struct lyd_node *node, NC_OPERATION op)
3568{
3569 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003570 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003571
3572 assert(!strcmp(LYD_NAME(node), "reconnect-strategy"));
3573
3574 (void) op;
3575
romanba93eac2023-07-18 14:36:48 +02003576 /* LOCK */
3577 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003578 /* to avoid unlock on fail */
3579 return 1;
romanb6f44032023-06-30 15:07:56 +02003580 }
3581
3582 /* set to default values */
3583 ch_client->start_with = NC_CH_FIRST_LISTED;
3584 ch_client->max_wait = 5;
3585 ch_client->max_attempts = 3;
3586
romanba93eac2023-07-18 14:36:48 +02003587 /* UNLOCK */
3588 nc_ch_client_unlock(ch_client);
3589
romanb6f44032023-06-30 15:07:56 +02003590 return ret;
3591}
3592
3593static int
3594nc_server_config_start_with(const struct lyd_node *node, NC_OPERATION op)
3595{
3596 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003597 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003598 const char *value;
3599
3600 assert(!strcmp(LYD_NAME(node), "start-with"));
3601
romanba93eac2023-07-18 14:36:48 +02003602 /* LOCK */
3603 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003604 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003605 return 1;
romanb6f44032023-06-30 15:07:56 +02003606 }
3607
3608 if (op == NC_OP_DELETE) {
3609 ch_client->start_with = NC_CH_FIRST_LISTED;
3610 goto cleanup;
3611 }
3612
3613 value = lyd_get_value(node);
3614 if (!strcmp(value, "first-listed")) {
3615 ch_client->start_with = NC_CH_FIRST_LISTED;
3616 } else if (!strcmp(value, "last-connected")) {
3617 ch_client->start_with = NC_CH_LAST_CONNECTED;
3618 } else if (!strcmp(value, "random-selection")) {
3619 ch_client->start_with = NC_CH_RANDOM;
3620 } else {
3621 ERR(NULL, "Unexpected start-with value \"%s\".", value);
3622 ret = 1;
3623 goto cleanup;
3624 }
3625
3626cleanup:
romanba93eac2023-07-18 14:36:48 +02003627 /* UNLOCK */
3628 nc_ch_client_unlock(ch_client);
romanb6f44032023-06-30 15:07:56 +02003629 return ret;
3630}
3631
3632static int
3633nc_server_config_max_wait(const struct lyd_node *node, NC_OPERATION op)
3634{
3635 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003636 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003637
3638 assert(!strcmp(LYD_NAME(node), "max-wait"));
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 */
3643 return 1;
romanb6f44032023-06-30 15:07:56 +02003644 }
3645
3646 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02003647 ch_client->max_wait = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02003648 } else {
3649 ch_client->max_wait = 5;
3650 }
3651
romanba93eac2023-07-18 14:36:48 +02003652 /* UNLOCK */
3653 nc_ch_client_unlock(ch_client);
3654
romanb6f44032023-06-30 15:07:56 +02003655 return ret;
3656}
3657
3658static int
3659nc_server_config_max_attempts(const struct lyd_node *node, NC_OPERATION op)
3660{
3661 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003662 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003663
3664 assert(!strcmp(LYD_NAME(node), "max-attempts"));
3665
romanba93eac2023-07-18 14:36:48 +02003666 /* LOCK */
3667 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003668 /* to avoid unlock on fail */
3669 return 1;
romanb6f44032023-06-30 15:07:56 +02003670 }
3671
3672 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02003673 ch_client->max_attempts = ((struct lyd_node_term *)node)->value.uint8;
romanb6f44032023-06-30 15:07:56 +02003674 } else {
3675 ch_client->max_attempts = 3;
3676 }
3677
romanba93eac2023-07-18 14:36:48 +02003678 /* UNLOCK */
3679 nc_ch_client_unlock(ch_client);
3680
romanb6f44032023-06-30 15:07:56 +02003681 return ret;
3682}
3683
3684static int
romanf02273a2023-05-25 09:44:11 +02003685nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01003686{
3687 const char *name = LYD_NAME(node);
roman6430c152023-10-12 11:28:47 +02003688 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01003689
3690 if (!strcmp(name, "listen")) {
roman6430c152023-10-12 11:28:47 +02003691 ret = nc_server_config_listen(node, op);
3692 } else if (!strcmp(name, "call-home")) {
3693 ret = nc_server_config_ch(node, op);
romanc1d2b092023-02-02 08:58:27 +01003694 } else if (!strcmp(name, "endpoint")) {
roman6430c152023-10-12 11:28:47 +02003695 ret = nc_server_config_endpoint(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003696 }
roman2eab4742023-06-06 10:00:26 +02003697#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02003698 else if (!strcmp(name, "ssh")) {
roman6430c152023-10-12 11:28:47 +02003699 ret = nc_server_config_ssh(node, op);
roman2eab4742023-06-06 10:00:26 +02003700 } else if (!strcmp(name, "local-address")) {
roman6430c152023-10-12 11:28:47 +02003701 ret = nc_server_config_local_address(node, op);
romanc1d2b092023-02-02 08:58:27 +01003702 } else if (!strcmp(name, "local-port")) {
roman6430c152023-10-12 11:28:47 +02003703 ret = nc_server_config_local_port(node, op);
romanc1d2b092023-02-02 08:58:27 +01003704 } else if (!strcmp(name, "keepalives")) {
roman6430c152023-10-12 11:28:47 +02003705 ret = nc_server_config_keepalives(node, op);
romanc1d2b092023-02-02 08:58:27 +01003706 } else if (!strcmp(name, "idle-time")) {
roman6430c152023-10-12 11:28:47 +02003707 ret = nc_server_config_idle_time(node, op);
romanc1d2b092023-02-02 08:58:27 +01003708 } else if (!strcmp(name, "max-probes")) {
roman6430c152023-10-12 11:28:47 +02003709 ret = nc_server_config_max_probes(node, op);
romanc1d2b092023-02-02 08:58:27 +01003710 } else if (!strcmp(name, "probe-interval")) {
roman6430c152023-10-12 11:28:47 +02003711 ret = nc_server_config_probe_interval(node, op);
roman2eab4742023-06-06 10:00:26 +02003712 } else if (!strcmp(name, "host-key")) {
roman6430c152023-10-12 11:28:47 +02003713 ret = nc_server_config_host_key(node, op);
roman2eab4742023-06-06 10:00:26 +02003714 } else if (!strcmp(name, "public-key-format")) {
roman6430c152023-10-12 11:28:47 +02003715 ret = nc_server_config_public_key_format(node, op);
romanc1d2b092023-02-02 08:58:27 +01003716 } else if (!strcmp(name, "public-key")) {
roman6430c152023-10-12 11:28:47 +02003717 ret = nc_server_config_public_key(node, op);
romanc1d2b092023-02-02 08:58:27 +01003718 } else if (!strcmp(name, "private-key-format")) {
roman6430c152023-10-12 11:28:47 +02003719 ret = nc_server_config_private_key_format(node, op);
romanc1d2b092023-02-02 08:58:27 +01003720 } else if (!strcmp(name, "cleartext-private-key")) {
roman6430c152023-10-12 11:28:47 +02003721 ret = nc_server_config_cleartext_private_key(node, op);
Michal Vaskocf898172024-01-15 15:04:28 +01003722 } else if (!strcmp(name, "central-keystore-reference")) {
roman6430c152023-10-12 11:28:47 +02003723 ret = nc_server_config_keystore_reference(node, op);
romanc1d2b092023-02-02 08:58:27 +01003724 } else if (!strcmp(name, "user")) {
roman6430c152023-10-12 11:28:47 +02003725 ret = nc_server_config_user(node, op);
romanc1d2b092023-02-02 08:58:27 +01003726 } else if (!strcmp(name, "auth-timeout")) {
roman6430c152023-10-12 11:28:47 +02003727 ret = nc_server_config_auth_timeout(node, op);
Michal Vaskocf898172024-01-15 15:04:28 +01003728 } else if (!strcmp(name, "central-truststore-reference")) {
roman6430c152023-10-12 11:28:47 +02003729 ret = nc_server_config_truststore_reference(node, op);
romana9ec3362023-12-21 10:59:57 +01003730 } else if (!strcmp(name, "use-system-keys")) {
3731 ret = nc_server_config_use_system_keys(node, op);
roman2eab4742023-06-06 10:00:26 +02003732 } else if (!strcmp(name, "password")) {
roman6430c152023-10-12 11:28:47 +02003733 ret = nc_server_config_password(node, op);
romanc6518422023-11-30 16:39:00 +01003734 } else if (!strcmp(name, "use-system-auth")) {
3735 ret = nc_server_config_use_system_auth(node, op);
romanc1d2b092023-02-02 08:58:27 +01003736 } else if (!strcmp(name, "none")) {
roman6430c152023-10-12 11:28:47 +02003737 ret = nc_server_config_none(node, op);
romanc1d2b092023-02-02 08:58:27 +01003738 } else if (!strcmp(name, "host-key-alg")) {
roman6430c152023-10-12 11:28:47 +02003739 ret = nc_server_config_host_key_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01003740 } else if (!strcmp(name, "key-exchange-alg")) {
roman6430c152023-10-12 11:28:47 +02003741 ret = nc_server_config_kex_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01003742 } else if (!strcmp(name, "encryption-alg")) {
roman6430c152023-10-12 11:28:47 +02003743 ret = nc_server_config_encryption_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01003744 } else if (!strcmp(name, "mac-alg")) {
roman6430c152023-10-12 11:28:47 +02003745 ret = nc_server_config_mac_alg(node, op);
roman78df0fa2023-11-02 10:33:57 +01003746 } else if (!strcmp(name, "endpoint-reference")) {
3747 ret = nc_server_config_endpoint_reference(node, op);
roman2eab4742023-06-06 10:00:26 +02003748 } else if (!strcmp(name, "tls")) {
roman6430c152023-10-12 11:28:47 +02003749 ret = nc_server_config_tls(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003750 } else if (!strcmp(name, "cert-data")) {
roman6430c152023-10-12 11:28:47 +02003751 ret = nc_server_config_cert_data(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003752 } else if (!strcmp(name, "asymmetric-key")) {
roman6430c152023-10-12 11:28:47 +02003753 ret = nc_server_config_asymmetric_key(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003754 } else if (!strcmp(name, "certificate")) {
roman6430c152023-10-12 11:28:47 +02003755 ret = nc_server_config_certificate(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003756 } else if (!strcmp(name, "cert-to-name")) {
roman6430c152023-10-12 11:28:47 +02003757 ret = nc_server_config_cert_to_name(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003758 } else if (!strcmp(name, "fingerprint")) {
roman6430c152023-10-12 11:28:47 +02003759 ret = nc_server_config_fingerprint(node, op);
roman12644fe2023-06-08 11:06:42 +02003760 } else if (!strcmp(name, "tls-version")) {
roman6430c152023-10-12 11:28:47 +02003761 ret = nc_server_config_tls_version(node, op);
roman12644fe2023-06-08 11:06:42 +02003762 } else if (!strcmp(name, "cipher-suite")) {
roman6430c152023-10-12 11:28:47 +02003763 ret = nc_server_config_cipher_suite(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003764 }
roman2eab4742023-06-06 10:00:26 +02003765#endif /* NC_ENABLED_SSH_TLS */
roman5cbb6532023-06-22 12:53:17 +02003766 else if (!strcmp(name, "netconf-client")) {
roman6430c152023-10-12 11:28:47 +02003767 ret = nc_server_config_netconf_client(node, op);
roman5cbb6532023-06-22 12:53:17 +02003768 }
3769#ifdef NC_ENABLED_SSH_TLS
3770 else if (!strcmp(name, "remote-address")) {
roman6430c152023-10-12 11:28:47 +02003771 ret = nc_server_config_remote_address(node, op);
roman5cbb6532023-06-22 12:53:17 +02003772 } else if (!strcmp(name, "remote-port")) {
roman6430c152023-10-12 11:28:47 +02003773 ret = nc_server_config_remote_port(node, op);
roman5cbb6532023-06-22 12:53:17 +02003774 }
3775#endif /* NC_ENABLED_SSH_TLS */
romanb6f44032023-06-30 15:07:56 +02003776 else if (!strcmp(name, "persistent")) {
roman6430c152023-10-12 11:28:47 +02003777 ret = nc_server_config_persistent(node, op);
romanb6f44032023-06-30 15:07:56 +02003778 } else if (!strcmp(name, "periodic")) {
roman6430c152023-10-12 11:28:47 +02003779 ret = nc_server_config_periodic(node, op);
romanb6f44032023-06-30 15:07:56 +02003780 } else if (!strcmp(name, "period")) {
roman6430c152023-10-12 11:28:47 +02003781 ret = nc_server_config_period(node, op);
romanb6f44032023-06-30 15:07:56 +02003782 } else if (!strcmp(name, "anchor-time")) {
roman6430c152023-10-12 11:28:47 +02003783 ret = nc_server_config_anchor_time(node, op);
romaneaf84c72023-10-19 14:38:05 +02003784 } else if (!strcmp(name, "idle-timeout")) {
3785 ret = nc_server_config_idle_timeout(node, op);
romanb6f44032023-06-30 15:07:56 +02003786 } else if (!strcmp(name, "reconnect-strategy")) {
roman6430c152023-10-12 11:28:47 +02003787 ret = nc_server_config_reconnect_strategy(node, op);
romanb6f44032023-06-30 15:07:56 +02003788 } else if (!strcmp(name, "start-with")) {
roman6430c152023-10-12 11:28:47 +02003789 ret = nc_server_config_start_with(node, op);
romanb6f44032023-06-30 15:07:56 +02003790 } else if (!strcmp(name, "max-wait")) {
roman6430c152023-10-12 11:28:47 +02003791 ret = nc_server_config_max_wait(node, op);
romanb6f44032023-06-30 15:07:56 +02003792 } else if (!strcmp(name, "max-attempts")) {
roman6430c152023-10-12 11:28:47 +02003793 ret = nc_server_config_max_attempts(node, op);
3794 }
3795
3796 if (ret) {
3797 ERR(NULL, "Configuring node \"%s\" failed.", LYD_NAME(node));
3798 return 1;
romanb6f44032023-06-30 15:07:56 +02003799 }
romanc1d2b092023-02-02 08:58:27 +01003800
3801 return 0;
romanc1d2b092023-02-02 08:58:27 +01003802}
3803
3804int
roman0bbc19c2023-05-26 09:59:09 +02003805nc_server_config_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, NC_MODULE module)
romanc1d2b092023-02-02 08:58:27 +01003806{
3807 struct lyd_node *child;
3808 struct lyd_meta *m;
romanf9906b42023-05-22 14:04:29 +02003809 NC_OPERATION current_op = NC_OP_UNKNOWN;
romanf02273a2023-05-25 09:44:11 +02003810 int ret;
romanc1d2b092023-02-02 08:58:27 +01003811
3812 assert(node);
3813
romanf9906b42023-05-22 14:04:29 +02003814 /* get current op if there is any */
3815 if ((m = lyd_find_meta(node->meta, NULL, "yang:operation"))) {
3816 if (!strcmp(lyd_get_meta_value(m), "create")) {
3817 current_op = NC_OP_CREATE;
3818 } else if (!strcmp(lyd_get_meta_value(m), "delete")) {
3819 current_op = NC_OP_DELETE;
3820 } else if (!strcmp(lyd_get_meta_value(m), "replace")) {
3821 current_op = NC_OP_REPLACE;
3822 } else if (!strcmp(lyd_get_meta_value(m), "none")) {
3823 current_op = NC_OP_NONE;
romanc1d2b092023-02-02 08:58:27 +01003824 }
3825 }
3826
3827 /* node has no op, inherit from the parent */
romanf9906b42023-05-22 14:04:29 +02003828 if (!current_op) {
3829 if (!parent_op) {
3830 ERR(NULL, "Unknown operation for node \"%s\".", LYD_NAME(node));
3831 return 1;
3832 }
3833
romanc1d2b092023-02-02 08:58:27 +01003834 current_op = parent_op;
3835 }
3836
3837 switch (current_op) {
3838 case NC_OP_NONE:
3839 break;
3840 case NC_OP_CREATE:
3841 case NC_OP_DELETE:
3842 case NC_OP_REPLACE:
roman2eab4742023-06-06 10:00:26 +02003843#ifdef NC_ENABLED_SSH_TLS
3844 if (module == NC_MODULE_KEYSTORE) {
romanf02273a2023-05-25 09:44:11 +02003845 ret = nc_server_config_parse_keystore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02003846 } else if (module == NC_MODULE_TRUSTSTORE) {
romanf02273a2023-05-25 09:44:11 +02003847 ret = nc_server_config_parse_truststore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02003848 } else
3849#endif /* NC_ENABLED_SSH_TLS */
3850 {
3851 ret = nc_server_config_parse_netconf_server(node, current_op);
romanf02273a2023-05-25 09:44:11 +02003852 }
3853 if (ret) {
3854 return ret;
romanc1d2b092023-02-02 08:58:27 +01003855 }
3856 break;
3857 default:
3858 break;
3859 }
3860
3861 if (current_op != NC_OP_DELETE) {
3862 LY_LIST_FOR(lyd_child(node), child) {
roman0bbc19c2023-05-26 09:59:09 +02003863 if (nc_server_config_parse_tree(child, current_op, module)) {
romanc1d2b092023-02-02 08:58:27 +01003864 return 1;
3865 }
3866 }
3867 }
3868 return 0;
3869}
3870
romanc1d2b092023-02-02 08:58:27 +01003871API int
3872nc_server_config_load_modules(struct ly_ctx **ctx)
3873{
3874 int i, new_ctx = 0;
3875
3876 if (!*ctx) {
3877 if (ly_ctx_new(NC_SERVER_SEARCH_DIR, 0, ctx)) {
3878 ERR(NULL, "Couldn't create new libyang context.\n");
3879 goto error;
3880 }
3881 new_ctx = 1;
3882 }
3883
3884 /* all features */
3885 const char *ietf_nectonf_server[] = {"ssh-listen", "tls-listen", "ssh-call-home", "tls-call-home", "central-netconf-server-supported", NULL};
3886 /* all features */
3887 const char *ietf_x509_cert_to_name[] = {NULL};
roman7fdc84d2023-06-06 13:14:53 +02003888 /* no private-key-encryption, csr-generation, p10-csr-format, certificate-expiration-notification,
roman3c6c7e62023-09-14 10:19:19 +02003889 * encrypted-passwords, hidden-symmetric-keys, encrypted-symmetric-keys, hidden-private-keys, encrypted-private-keys,
3890 * one-symmetric-key-format, one-asymmetric-key-format, symmetrically-encrypted-value-format,
3891 * asymmetrically-encrypted-value-format, cms-enveloped-data-format, cms-encrypted-data-format,
Roytakb2794852023-10-18 14:30:22 +02003892 * cleartext-symmetric-keys */
roman3c6c7e62023-09-14 10:19:19 +02003893 const char *ietf_crypto_types[] = {"cleartext-passwords", "cleartext-private-keys", NULL};
romanc1d2b092023-02-02 08:58:27 +01003894 /* all features */
3895 const char *ietf_tcp_common[] = {"keepalives-supported", NULL};
roman7fdc84d2023-06-06 13:14:53 +02003896 /* all features */
3897 const char *ietf_tcp_server[] = {"tcp-server-keepalives", NULL};
roman5e5d3f22024-08-08 12:44:53 +02003898 /* no proxy-connect, socks5-gss-api, socks5-username-password */
3899 const char *ietf_tcp_client[] = {"local-binding-supported", "tcp-client-keepalives", NULL};
roman3c6c7e62023-09-14 10:19:19 +02003900 /* no ssh-x509-certs, public-key-generation */
3901 const char *ietf_ssh_common[] = {"transport-params", NULL};
roman7fdc84d2023-06-06 13:14:53 +02003902 /* no ssh-server-keepalives and local-user-auth-hostbased */
3903 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 +01003904 /* all features */
3905 const char *iana_ssh_encryption_algs[] = {NULL};
3906 /* all features */
3907 const char *iana_ssh_key_exchange_algs[] = {NULL};
3908 /* all features */
3909 const char *iana_ssh_mac_algs[] = {NULL};
3910 /* all features */
3911 const char *iana_ssh_public_key_algs[] = {NULL};
romanc1d2b092023-02-02 08:58:27 +01003912 /* all features */
roman7fdc84d2023-06-06 13:14:53 +02003913 const char *iana_crypt_hash[] = {"crypt-hash-md5", "crypt-hash-sha-256", "crypt-hash-sha-512", NULL};
3914 /* no symmetric-keys */
3915 const char *ietf_keystore[] = {"central-keystore-supported", "inline-definitions-supported", "asymmetric-keys", NULL};
3916 /* all features */
3917 const char *ietf_truststore[] = {"central-truststore-supported", "inline-definitions-supported", "certificates", "public-keys", NULL};
roman3c6c7e62023-09-14 10:19:19 +02003918 /* no public-key-generation */
3919 const char *ietf_tls_common[] = {"tls10", "tls11", "tls12", "tls13", "hello-params", NULL};
3920 /* no tls-server-keepalives, server-ident-raw-public-key, server-ident-tls12-psk, server-ident-tls13-epsk,
3921 * client-auth-raw-public-key, client-auth-tls12-psk, client-auth-tls13-epsk */
3922 const char *ietf_tls_server[] = {"server-ident-x509-cert", "client-auth-supported", "client-auth-x509-cert", NULL};
roman7fdc84d2023-06-06 13:14:53 +02003923 /* all features */
roman12644fe2023-06-08 11:06:42 +02003924 const char *iana_tls_cipher_suite_algs[] = {NULL};
romanc1d2b092023-02-02 08:58:27 +01003925 /* all features */
3926 const char *libnetconf2_netconf_server[] = {NULL};
3927
3928 const char *module_names[] = {
roman7fdc84d2023-06-06 13:14:53 +02003929 "ietf-netconf-server", "ietf-x509-cert-to-name", "ietf-crypto-types", "ietf-tcp-common", "ietf-tcp-server",
3930 "ietf-tcp-client", "ietf-ssh-common", "ietf-ssh-server", "iana-ssh-encryption-algs",
3931 "iana-ssh-key-exchange-algs", "iana-ssh-mac-algs", "iana-ssh-public-key-algs", "iana-crypt-hash",
roman12644fe2023-06-08 11:06:42 +02003932 "ietf-keystore", "ietf-truststore", "ietf-tls-common", "ietf-tls-server", "iana-tls-cipher-suite-algs",
3933 "libnetconf2-netconf-server", NULL
romanc1d2b092023-02-02 08:58:27 +01003934 };
3935
3936 const char **module_features[] = {
roman7fdc84d2023-06-06 13:14:53 +02003937 ietf_nectonf_server, ietf_x509_cert_to_name, ietf_crypto_types, ietf_tcp_common,
3938 ietf_tcp_server, ietf_tcp_client, ietf_ssh_common, ietf_ssh_server, iana_ssh_encryption_algs,
3939 iana_ssh_key_exchange_algs, iana_ssh_mac_algs, iana_ssh_public_key_algs, iana_crypt_hash,
roman12644fe2023-06-08 11:06:42 +02003940 ietf_keystore, ietf_truststore, ietf_tls_common, ietf_tls_server, iana_tls_cipher_suite_algs,
3941 libnetconf2_netconf_server, NULL
romanc1d2b092023-02-02 08:58:27 +01003942 };
3943
3944 for (i = 0; module_names[i] != NULL; i++) {
3945 if (!ly_ctx_load_module(*ctx, module_names[i], NULL, module_features[i])) {
3946 ERR(NULL, "Loading module \"%s\" failed.\n", module_names[i]);
3947 goto error;
3948 }
3949 }
3950
3951 return 0;
3952
3953error:
3954 if (new_ctx) {
3955 ly_ctx_destroy(*ctx);
3956 *ctx = NULL;
3957 }
3958 return 1;
3959}
3960
romanf9906b42023-05-22 14:04:29 +02003961static int
Michal Vaskocf898172024-01-15 15:04:28 +01003962nc_server_config_fill_netconf_server(const struct lyd_node *data, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01003963{
3964 int ret = 0;
roman84fe3252023-10-25 11:28:32 +02003965 uint32_t log_options = 0;
romanc1d2b092023-02-02 08:58:27 +01003966 struct lyd_node *tree;
romand57b3722023-04-05 11:26:25 +02003967
romanc9b62d62023-09-14 10:19:50 +02003968 /* silently search for ietf-netconf-server, it may not be present */
roman84fe3252023-10-25 11:28:32 +02003969 ly_temp_log_options(&log_options);
romanc9b62d62023-09-14 10:19:50 +02003970
romanc1d2b092023-02-02 08:58:27 +01003971 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &tree);
romanc9b62d62023-09-14 10:19:50 +02003972 if (ret || (tree->flags & LYD_DEFAULT)) {
3973 /* not found */
3974 ret = 0;
romanc1d2b092023-02-02 08:58:27 +01003975 goto cleanup;
3976 }
3977
roman0bbc19c2023-05-26 09:59:09 +02003978 if (nc_server_config_parse_tree(tree, op, NC_MODULE_NETCONF_SERVER)) {
3979 ret = 1;
3980 goto cleanup;
3981 }
3982
roman2eab4742023-06-06 10:00:26 +02003983#ifdef NC_ENABLED_SSH_TLS
roman78df0fa2023-11-02 10:33:57 +01003984 /* check and set all endpoint references */
3985 if (nc_server_config_check_endpt_references()) {
romanf9906b42023-05-22 14:04:29 +02003986 ret = 1;
3987 goto cleanup;
3988 }
roman2eab4742023-06-06 10:00:26 +02003989#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02003990
3991cleanup:
romanc9b62d62023-09-14 10:19:50 +02003992 /* reset the logging options back to what they were */
roman84fe3252023-10-25 11:28:32 +02003993 ly_temp_log_options(NULL);
romanf9906b42023-05-22 14:04:29 +02003994 return ret;
3995}
3996
3997API int
romanf6f37a52023-05-25 14:27:51 +02003998nc_server_config_setup_diff(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02003999{
4000 int ret = 0;
4001
romanc9b62d62023-09-14 10:19:50 +02004002 NC_CHECK_ARG_RET(NULL, data, 1);
4003
romanf9906b42023-05-22 14:04:29 +02004004 /* LOCK */
4005 pthread_rwlock_wrlock(&server_opts.config_lock);
4006
roman2eab4742023-06-06 10:00:26 +02004007#ifdef NC_ENABLED_SSH_TLS
romanf9906b42023-05-22 14:04:29 +02004008 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02004009 ret = nc_server_config_fill_keystore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02004010 if (ret) {
4011 ERR(NULL, "Filling keystore failed.");
4012 goto cleanup;
4013 }
4014
4015 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02004016 ret = nc_server_config_fill_truststore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02004017 if (ret) {
4018 ERR(NULL, "Filling truststore failed.");
4019 goto cleanup;
4020 }
roman2eab4742023-06-06 10:00:26 +02004021#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004022
4023 /* configure netconf-server */
Michal Vaskocf898172024-01-15 15:04:28 +01004024 ret = nc_server_config_fill_netconf_server(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02004025 if (ret) {
4026 ERR(NULL, "Filling netconf-server failed.");
4027 goto cleanup;
4028 }
4029
4030cleanup:
4031 /* UNLOCK */
4032 pthread_rwlock_unlock(&server_opts.config_lock);
4033 return ret;
4034}
4035
4036API int
romanf6f37a52023-05-25 14:27:51 +02004037nc_server_config_setup_data(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02004038{
4039 int ret = 0;
4040 struct lyd_node *tree, *iter, *root;
4041
romanc9b62d62023-09-14 10:19:50 +02004042 NC_CHECK_ARG_RET(NULL, data, 1);
4043
romanf9906b42023-05-22 14:04:29 +02004044 /* LOCK */
4045 pthread_rwlock_wrlock(&server_opts.config_lock);
4046
4047 /* find the netconf-server node */
4048 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &root);
4049 if (ret) {
4050 ERR(NULL, "Unable to find the netconf-server container in the YANG data.");
4051 goto cleanup;
4052 }
4053
4054 /* iterate through all the nodes and make sure there is no operation attribute */
4055 LY_LIST_FOR(root, tree) {
4056 LYD_TREE_DFS_BEGIN(tree, iter) {
4057 if (lyd_find_meta(iter->meta, NULL, "yang:operation")) {
4058 ERR(NULL, "Unexpected operation attribute in the YANG data.");
romanc1d2b092023-02-02 08:58:27 +01004059 ret = 1;
4060 goto cleanup;
4061 }
romanf9906b42023-05-22 14:04:29 +02004062 LYD_TREE_DFS_END(tree, iter);
romanc1d2b092023-02-02 08:58:27 +01004063 }
4064 }
4065
romanf9906b42023-05-22 14:04:29 +02004066 /* delete the current configuration */
romanf02273a2023-05-25 09:44:11 +02004067 nc_server_config_listen(NULL, NC_OP_DELETE);
roman4cb8bb12023-06-29 09:16:46 +02004068 nc_server_config_ch(NULL, NC_OP_DELETE);
roman2eab4742023-06-06 10:00:26 +02004069#ifdef NC_ENABLED_SSH_TLS
romanf02273a2023-05-25 09:44:11 +02004070 nc_server_config_ks_keystore(NULL, NC_OP_DELETE);
4071 nc_server_config_ts_truststore(NULL, NC_OP_DELETE);
romanf9906b42023-05-22 14:04:29 +02004072
4073 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02004074 ret = nc_server_config_fill_keystore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02004075 if (ret) {
4076 ERR(NULL, "Filling keystore failed.");
4077 goto cleanup;
4078 }
4079
4080 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02004081 ret = nc_server_config_fill_truststore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02004082 if (ret) {
4083 ERR(NULL, "Filling truststore failed.");
4084 goto cleanup;
4085 }
roman2eab4742023-06-06 10:00:26 +02004086#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004087
4088 /* configure netconf-server */
Michal Vaskocf898172024-01-15 15:04:28 +01004089 ret = nc_server_config_fill_netconf_server(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02004090 if (ret) {
4091 ERR(NULL, "Filling netconf-server failed.");
romanc1d2b092023-02-02 08:58:27 +01004092 goto cleanup;
4093 }
4094
4095cleanup:
4096 /* UNLOCK */
4097 pthread_rwlock_unlock(&server_opts.config_lock);
4098 return ret;
4099}
roman3f9b65c2023-06-05 14:26:58 +02004100
4101API int
4102nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path)
4103{
4104 struct lyd_node *tree = NULL;
4105 int ret = 0;
4106
4107 NC_CHECK_ARG_RET(NULL, path, 1);
4108
4109 ret = lyd_parse_data_path(ctx, path, LYD_UNKNOWN, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree);
4110 if (ret) {
4111 goto cleanup;
4112 }
4113
4114 ret = nc_server_config_setup_data(tree);
4115 if (ret) {
4116 goto cleanup;
4117 }
4118
4119cleanup:
4120 lyd_free_all(tree);
4121 return ret;
4122}
romand05b2ad2024-01-23 12:02:40 +01004123
4124#ifdef NC_ENABLED_SSH_TLS
4125
4126static int
4127nc_server_config_oper_get_algs(const struct ly_ctx *ctx, const char *mod_name, const char *ln2_algs[],
4128 const char *mod_algs[], struct lyd_node **algs)
4129{
4130 int ret, r, i;
4131 struct lyd_node *parent = NULL;
4132 char *path = NULL;
4133
4134 NC_CHECK_ARG_RET(NULL, ctx, mod_name, ln2_algs, mod_algs, algs, 1);
4135
4136 *algs = NULL;
4137
4138 r = asprintf(&path, "/%s:supported-algorithms", mod_name);
4139 NC_CHECK_ERRMEM_RET(r == -1, 1);
4140
4141 /* create supported algorithms container */
4142 ret = lyd_new_path(NULL, ctx, path, NULL, 0, &parent);
4143 free(path);
4144 if (ret) {
4145 ERR(NULL, "Creating supported algorithms container failed.");
4146 goto cleanup;
4147 }
4148
4149 /* append algs from libnetconf2-netconf-server */
4150 for (i = 0; ln2_algs[i]; i++) {
4151 r = asprintf(&path, "libnetconf2-netconf-server:%s", ln2_algs[i]);
4152 NC_CHECK_ERRMEM_GOTO(r == -1, ret = 1, cleanup);
4153 ret = lyd_new_term(parent, NULL, "supported-algorithm", path, 0, NULL);
4154 free(path);
4155 if (ret) {
4156 ERR(NULL, "Creating new supported algorithm failed.");
4157 goto cleanup;
4158 }
4159 }
4160
4161 /* append algs from mod_name module */
4162 for (i = 0; mod_algs[i]; i++) {
4163 r = asprintf(&path, "%s:%s", mod_name, mod_algs[i]);
4164 NC_CHECK_ERRMEM_GOTO(r == -1, ret = 1, cleanup);
4165 ret = lyd_new_term(parent, NULL, "supported-algorithm", path, 0, NULL);
4166 free(path);
4167 if (ret) {
4168 ERR(NULL, "Creating new supported algorithm failed.");
4169 goto cleanup;
4170 }
4171 }
4172
4173cleanup:
4174 if (ret) {
4175 lyd_free_tree(parent);
4176 } else {
4177 *algs = parent;
4178 }
4179 return ret;
4180}
4181
4182API int
4183nc_server_config_oper_get_hostkey_algs(const struct ly_ctx *ctx, struct lyd_node **hostkey_algs)
4184{
4185 /* identities of hostkey algs supported by libssh (v0.10.5) defined in libnetconf2-netconf-server yang module */
4186 const char *libnetconf2_hostkey_algs[] = {
4187 "openssh-ssh-ed25519-cert-v01", "openssh-ecdsa-sha2-nistp521-cert-v01",
4188 "openssh-ecdsa-sha2-nistp384-cert-v01", "openssh-ecdsa-sha2-nistp256-cert-v01",
4189 "openssh-rsa-sha2-512-cert-v01", "openssh-rsa-sha2-256-cert-v01",
4190 "openssh-ssh-rsa-cert-v01", "openssh-ssh-dss-cert-v01", NULL
4191 };
4192
4193 /* identities of hostkey algs supported by libssh (v0.10.5) defined in iana-ssh-public-key-algs yang module */
4194 const char *iana_hostkey_algs[] = {
4195 "ssh-ed25519", "ecdsa-sha2-nistp521", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp256",
4196 "rsa-sha2-512", "rsa-sha2-256", "ssh-rsa", "ssh-dss", NULL
4197 };
4198
4199 NC_CHECK_ARG_RET(NULL, ctx, hostkey_algs, 1);
4200
4201 return nc_server_config_oper_get_algs(ctx, "iana-ssh-public-key-algs", libnetconf2_hostkey_algs,
4202 iana_hostkey_algs, hostkey_algs);
4203}
4204
4205API int
4206nc_server_config_oper_get_kex_algs(const struct ly_ctx *ctx, struct lyd_node **kex_algs)
4207{
4208 /* identities of kex algs supported by libssh (v0.10.5) defined in libnetconf2-netconf-server yang module */
4209 const char *libnetconf2_kex_algs[] = {
4210 "libssh-curve25519-sha256", NULL
4211 };
4212
4213 /* identities of kex algs supported by libssh (v0.10.5) defined in iana-ssh-key-exchange-algs yang module */
4214 const char *iana_kex_algs[] = {
4215 "diffie-hellman-group-exchange-sha1", "curve25519-sha256", "ecdh-sha2-nistp256", "ecdh-sha2-nistp384",
4216 "ecdh-sha2-nistp521", "diffie-hellman-group18-sha512", "diffie-hellman-group16-sha512",
4217 "diffie-hellman-group-exchange-sha256", "diffie-hellman-group14-sha256", NULL
4218 };
4219
4220 NC_CHECK_ARG_RET(NULL, ctx, kex_algs, 1);
4221
4222 return nc_server_config_oper_get_algs(ctx, "iana-ssh-key-exchange-algs", libnetconf2_kex_algs,
4223 iana_kex_algs, kex_algs);
4224}
4225
4226API int
4227nc_server_config_oper_get_encryption_algs(const struct ly_ctx *ctx, struct lyd_node **encryption_algs)
4228{
4229 /* identities of encryption algs supported by libssh (v0.10.5) defined in libnetconf2-netconf-server yang module */
4230 const char *libnetconf2_encryption_algs[] = {
4231 "openssh-chacha20-poly1305", "openssh-aes256-gcm", "openssh-aes128-gcm", NULL
4232 };
4233
4234 /* identities of encryption algs supported by libssh (v0.10.5) defined in iana-ssh-encryption-algs yang module */
4235 const char *iana_encryption_algs[] = {
4236 "aes256-ctr", "aes192-ctr", "aes128-ctr", "aes256-cbc", "aes192-cbc", "aes128-cbc",
4237 "blowfish-cbc", "triple-des-cbc", "none", NULL
4238 };
4239
4240 NC_CHECK_ARG_RET(NULL, ctx, encryption_algs, 1);
4241
4242 return nc_server_config_oper_get_algs(ctx, "iana-ssh-encryption-algs", libnetconf2_encryption_algs,
4243 iana_encryption_algs, encryption_algs);
4244}
4245
4246API int
4247nc_server_config_oper_get_mac_algs(const struct ly_ctx *ctx, struct lyd_node **mac_algs)
4248{
4249 /* identities of mac algs supported by libssh (v0.10.5) defined in libnetconf2-netconf-server yang module */
4250 const char *libnetconf2_mac_algs[] = {
4251 "openssh-hmac-sha2-256-etm", "openssh-hmac-sha2-512-etm", "openssh-hmac-sha1-etm", NULL
4252 };
4253
4254 /* identities of mac algs supported by libssh (v0.10.5) defined in iana-ssh-mac-algs yang module */
4255 const char *iana_mac_algs[] = {
4256 "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1", NULL
4257 };
4258
4259 NC_CHECK_ARG_RET(NULL, ctx, mac_algs, 1);
4260
4261 return nc_server_config_oper_get_algs(ctx, "iana-ssh-mac-algs", libnetconf2_mac_algs,
4262 iana_mac_algs, mac_algs);
4263}
4264
4265#endif /* NC_ENABLED_SSH_TLS */