blob: c66360ff60b594f19ce693c3407efcc1cb59906c [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
roman6430c152023-10-12 11:28:47 +0200870 free(ch_endpt->address);
roman5cbb6532023-06-22 12:53:17 +0200871 if (ch_endpt->sock_pending > -1) {
872 close(ch_endpt->sock_pending);
873 ch_endpt->sock_pending = -1;
874 }
roman5ae78282023-11-02 13:34:34 +0100875 free(ch_endpt->referenced_endpt_name);
roman5cbb6532023-06-22 12:53:17 +0200876#endif /* NC_ENABLED_SSH_TLS */
877
878 switch (ch_endpt->ti) {
879#ifdef NC_ENABLED_SSH_TLS
roman506354a2024-04-11 09:37:22 +0200880 case NC_TI_SSH:
roman5ae78282023-11-02 13:34:34 +0100881 nc_server_config_del_ssh_opts(NULL, ch_endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +0200882 break;
roman506354a2024-04-11 09:37:22 +0200883 case NC_TI_TLS:
roman5ae78282023-11-02 13:34:34 +0100884 nc_server_config_del_tls_opts(NULL, ch_endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +0200885 break;
roman5cbb6532023-06-22 12:53:17 +0200886#endif /* NC_ENABLED_SSH_TLS */
887 default:
888 ERRINT;
889 break;
890 }
891
892 ch_client->ch_endpt_count--;
893 if (!ch_client->ch_endpt_count) {
894 free(ch_client->ch_endpts);
895 ch_client->ch_endpts = NULL;
896 }
897}
898
899static void
roman8341e8b2023-11-23 16:12:42 +0100900nc_server_config_destroy_ch_client(struct nc_ch_client *ch_client)
roman5cbb6532023-06-22 12:53:17 +0200901{
romanba93eac2023-07-18 14:36:48 +0200902 pthread_t tid;
roman8341e8b2023-11-23 16:12:42 +0100903 uint16_t i, ch_endpt_count;
904
romaneaeb87e2023-12-07 13:08:01 +0100905 /* CH COND LOCK */
906 pthread_mutex_lock(&ch_client->thread_data->cond_lock);
roman8341e8b2023-11-23 16:12:42 +0100907 if (ch_client->thread_data->thread_running) {
roman8341e8b2023-11-23 16:12:42 +0100908 ch_client->thread_data->thread_running = 0;
909 pthread_cond_signal(&ch_client->thread_data->cond);
910 /* CH COND UNLOCK */
911 pthread_mutex_unlock(&ch_client->thread_data->cond_lock);
912
romaneaeb87e2023-12-07 13:08:01 +0100913 /* get tid */
914 tid = ch_client->tid;
915
roman8341e8b2023-11-23 16:12:42 +0100916 /* wait for the thread to terminate */
917 pthread_join(tid, NULL);
romaneaeb87e2023-12-07 13:08:01 +0100918 } else {
919 /* CH COND UNLOCK */
920 pthread_mutex_unlock(&ch_client->thread_data->cond_lock);
roman8341e8b2023-11-23 16:12:42 +0100921 }
922
923 /* free its members */
924 free(ch_client->name);
925
926 ch_endpt_count = ch_client->ch_endpt_count;
927 for (i = 0; i < ch_endpt_count; i++) {
928 nc_server_config_ch_del_endpt(ch_client, &ch_client->ch_endpts[i]);
929 }
930}
931
932static void
933nc_server_config_ch_del_client(const struct lyd_node *node)
934{
935 struct nc_ch_client client, *ch_client;
roman5cbb6532023-06-22 12:53:17 +0200936
romanba93eac2023-07-18 14:36:48 +0200937 /* WR LOCK */
roman5cbb6532023-06-22 12:53:17 +0200938 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
939
roman8341e8b2023-11-23 16:12:42 +0100940 if (nc_server_config_get_ch_client(node, &ch_client)) {
941 /* WR UNLOCK */
942 pthread_rwlock_unlock(&server_opts.ch_client_lock);
943 ERR(NULL, "Call-home client \"%s\" not found.", lyd_get_value(lyd_child(node)));
944 return;
945 }
946
romanba93eac2023-07-18 14:36:48 +0200947 /* copy the client we want to delete into a local variable */
948 memcpy(&client, ch_client, sizeof *ch_client);
roman5cbb6532023-06-22 12:53:17 +0200949
romanba93eac2023-07-18 14:36:48 +0200950 /* delete the client */
roman5cbb6532023-06-22 12:53:17 +0200951 server_opts.ch_client_count--;
952 if (!server_opts.ch_client_count) {
953 free(server_opts.ch_clients);
954 server_opts.ch_clients = NULL;
romanba93eac2023-07-18 14:36:48 +0200955 } else {
956 memcpy(ch_client, &server_opts.ch_clients[server_opts.ch_client_count], sizeof *server_opts.ch_clients);
roman5cbb6532023-06-22 12:53:17 +0200957 }
958
romanba93eac2023-07-18 14:36:48 +0200959 /* WR UNLOCK */
roman5cbb6532023-06-22 12:53:17 +0200960 pthread_rwlock_unlock(&server_opts.ch_client_lock);
romanba93eac2023-07-18 14:36:48 +0200961
roman8341e8b2023-11-23 16:12:42 +0100962 nc_server_config_destroy_ch_client(&client);
963}
romanba93eac2023-07-18 14:36:48 +0200964
roman8341e8b2023-11-23 16:12:42 +0100965/* presence container */
966int
967nc_server_config_listen(const struct lyd_node *node, NC_OPERATION op)
968{
969 uint16_t i, endpt_count;
romanba93eac2023-07-18 14:36:48 +0200970
roman8341e8b2023-11-23 16:12:42 +0100971 (void) node;
romanba93eac2023-07-18 14:36:48 +0200972
roman8341e8b2023-11-23 16:12:42 +0100973 assert(op == NC_OP_CREATE || op == NC_OP_DELETE);
974
975 if (op == NC_OP_DELETE) {
976 endpt_count = server_opts.endpt_count;
977 for (i = 0; i < endpt_count; i++) {
978 switch (server_opts.endpts[i].ti) {
979#ifdef NC_ENABLED_SSH_TLS
roman506354a2024-04-11 09:37:22 +0200980 case NC_TI_SSH:
roman8341e8b2023-11-23 16:12:42 +0100981 nc_server_config_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]);
982 break;
roman506354a2024-04-11 09:37:22 +0200983 case NC_TI_TLS:
roman8341e8b2023-11-23 16:12:42 +0100984 nc_server_config_del_endpt_tls(&server_opts.endpts[i], &server_opts.binds[i]);
985 break;
986#endif /* NC_ENABLED_SSH_TLS */
romana2ff4ef2024-01-19 14:41:46 +0100987 case NC_TI_UNIX:
988 break;
roman8341e8b2023-11-23 16:12:42 +0100989 case NC_TI_NONE:
990 case NC_TI_FD:
991 ERRINT;
992 return 1;
993 }
994 }
romanba93eac2023-07-18 14:36:48 +0200995 }
996
roman8341e8b2023-11-23 16:12:42 +0100997 return 0;
roman5cbb6532023-06-22 12:53:17 +0200998}
999
roman6430c152023-10-12 11:28:47 +02001000int
roman5cbb6532023-06-22 12:53:17 +02001001nc_server_config_ch(const struct lyd_node *node, NC_OPERATION op)
1002{
1003 uint16_t i, ch_client_count;
roman8341e8b2023-11-23 16:12:42 +01001004 struct nc_ch_client *ch_clients;
roman5cbb6532023-06-22 12:53:17 +02001005
1006 (void) node;
1007
roman8341e8b2023-11-23 16:12:42 +01001008 /* don't do anything if we're not deleting */
1009 if (op != NC_OP_DELETE) {
1010 return 0;
roman5cbb6532023-06-22 12:53:17 +02001011 }
roman6430c152023-10-12 11:28:47 +02001012
roman8341e8b2023-11-23 16:12:42 +01001013 /* WR LOCK */
1014 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
1015
1016 ch_client_count = server_opts.ch_client_count;
1017 ch_clients = server_opts.ch_clients;
1018
1019 /* remove them from the server opts */
1020 server_opts.ch_client_count = 0;
1021 server_opts.ch_clients = NULL;
1022
1023 /* UNLOCK */
1024 pthread_rwlock_unlock(&server_opts.ch_client_lock);
1025
1026 for (i = 0; i < ch_client_count; i++) {
1027 /* now destroy each client */
1028 nc_server_config_destroy_ch_client(&ch_clients[i]);
1029 }
1030
1031 free(ch_clients);
roman6430c152023-10-12 11:28:47 +02001032 return 0;
roman5cbb6532023-06-22 12:53:17 +02001033}
1034
romanc1d2b092023-02-02 08:58:27 +01001035/* default leaf */
1036static int
romane028ef92023-02-24 16:33:08 +01001037nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001038{
roman8341e8b2023-11-23 16:12:42 +01001039 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02001040
romanc1d2b092023-02-02 08:58:27 +01001041 assert(!strcmp(LYD_NAME(node), "idle-timeout"));
1042
romaneaf84c72023-10-19 14:38:05 +02001043 if (is_ch(node)) {
romanb6f44032023-06-30 15:07:56 +02001044 /* call-home idle timeout */
roman6430c152023-10-12 11:28:47 +02001045 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
1046 /* to avoid unlock on fail */
romanb6f44032023-06-30 15:07:56 +02001047 return 1;
1048 }
1049
1050 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001051 ch_client->idle_timeout = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02001052 } else if (op == NC_OP_DELETE) {
1053 ch_client->idle_timeout = 180;
1054 }
roman6430c152023-10-12 11:28:47 +02001055
1056 nc_ch_client_unlock(ch_client);
romaneaf84c72023-10-19 14:38:05 +02001057 } else {
Michal Vaskocf898172024-01-15 15:04:28 +01001058 /* listen idle timeout */
romaneaf84c72023-10-19 14:38:05 +02001059 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001060 server_opts.idle_timeout = ((struct lyd_node_term *)node)->value.uint16;
romaneaf84c72023-10-19 14:38:05 +02001061 } else {
1062 /* default value */
Michal Vaskocf898172024-01-15 15:04:28 +01001063 server_opts.idle_timeout = 180;
romaneaf84c72023-10-19 14:38:05 +02001064 }
romanc1d2b092023-02-02 08:58:27 +01001065 }
1066
1067 return 0;
1068}
1069
1070static int
roman874fed12023-05-25 10:20:01 +02001071nc_server_config_create_bind(void)
romanc1d2b092023-02-02 08:58:27 +01001072{
1073 int ret = 0;
1074 void *tmp;
1075
1076 tmp = realloc(server_opts.binds, (server_opts.endpt_count + 1) * sizeof *server_opts.binds);
roman3a95bb22023-10-26 11:07:17 +02001077 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01001078 server_opts.binds = tmp;
1079 memset(&server_opts.binds[server_opts.endpt_count], 0, sizeof *server_opts.binds);
1080
1081 server_opts.binds[server_opts.endpt_count].sock = -1;
1082
1083cleanup:
1084 return ret;
1085}
1086
1087static int
roman874fed12023-05-25 10:20:01 +02001088nc_server_config_create_endpoint(const struct lyd_node *node)
romanc1d2b092023-02-02 08:58:27 +01001089{
roman874fed12023-05-25 10:20:01 +02001090 if (nc_server_config_create_bind()) {
romanf02273a2023-05-25 09:44:11 +02001091 return 1;
romanc1d2b092023-02-02 08:58:27 +01001092 }
romanc1d2b092023-02-02 08:58:27 +01001093
1094 node = lyd_child(node);
1095 assert(!strcmp(LYD_NAME(node), "name"));
1096
Michal Vaskocf898172024-01-15 15:04:28 +01001097 return nc_server_config_realloc(lyd_get_value(node), (void **)&server_opts.endpts, sizeof *server_opts.endpts,
1098 &server_opts.endpt_count);
romanc1d2b092023-02-02 08:58:27 +01001099}
1100
roman5cbb6532023-06-22 12:53:17 +02001101static int
1102nc_server_config_ch_create_endpoint(const struct lyd_node *node, struct nc_ch_client *ch_client)
1103{
1104 node = lyd_child(node);
1105 assert(!strcmp(LYD_NAME(node), "name"));
1106
Michal Vaskocf898172024-01-15 15:04:28 +01001107 return nc_server_config_realloc(lyd_get_value(node), (void **)&ch_client->ch_endpts, sizeof *ch_client->ch_endpts,
1108 &ch_client->ch_endpt_count);
roman5cbb6532023-06-22 12:53:17 +02001109}
1110
romanc1d2b092023-02-02 08:58:27 +01001111/* list */
1112static int
romane028ef92023-02-24 16:33:08 +01001113nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001114{
1115 int ret = 0;
1116 struct nc_endpt *endpt;
1117 struct nc_bind *bind;
roman6430c152023-10-12 11:28:47 +02001118 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001119 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001120
1121 assert(!strcmp(LYD_NAME(node), "endpoint"));
1122
roman5cbb6532023-06-22 12:53:17 +02001123 if (is_listen(node)) {
1124 /* listen */
1125 if (op == NC_OP_CREATE) {
1126 ret = nc_server_config_create_endpoint(node);
1127 if (ret) {
1128 goto cleanup;
1129 }
1130 } else if (op == NC_OP_DELETE) {
1131 /* free all children */
1132 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1133 ret = 1;
1134 goto cleanup;
1135 }
1136
1137 switch (endpt->ti) {
1138#ifdef NC_ENABLED_SSH_TLS
roman506354a2024-04-11 09:37:22 +02001139 case NC_TI_SSH:
roman5cbb6532023-06-22 12:53:17 +02001140 nc_server_config_del_endpt_ssh(endpt, bind);
1141 break;
roman506354a2024-04-11 09:37:22 +02001142 case NC_TI_TLS:
roman5cbb6532023-06-22 12:53:17 +02001143 nc_server_config_del_endpt_tls(endpt, bind);
1144 break;
1145#endif /* NC_ENABLED_SSH_TLS */
romana2ff4ef2024-01-19 14:41:46 +01001146 case NC_TI_UNIX:
1147 break;
roman5cbb6532023-06-22 12:53:17 +02001148 case NC_TI_NONE:
1149 case NC_TI_FD:
1150 ERRINT;
1151 ret = 1;
1152 goto cleanup;
1153 }
romanc1d2b092023-02-02 08:58:27 +01001154 }
roman5cbb6532023-06-22 12:53:17 +02001155 } else if (is_ch(node)) {
romanba93eac2023-07-18 14:36:48 +02001156 /* LOCK */
1157 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001158 /* to avoid unlock on fail */
1159 return 1;
romanc1d2b092023-02-02 08:58:27 +01001160 }
roman3f9b65c2023-06-05 14:26:58 +02001161
roman5cbb6532023-06-22 12:53:17 +02001162 if (op == NC_OP_CREATE) {
1163 ret = nc_server_config_ch_create_endpoint(node, ch_client);
1164 if (ret) {
1165 goto cleanup;
1166 }
1167
1168 /* init ch sock */
1169 ch_client->ch_endpts[ch_client->ch_endpt_count - 1].sock_pending = -1;
roman6430c152023-10-12 11:28:47 +02001170 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01001171 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman6430c152023-10-12 11:28:47 +02001172 ret = 1;
1173 goto cleanup;
1174 }
1175
1176 nc_server_config_ch_del_endpt(ch_client, ch_endpt);
roman3f9b65c2023-06-05 14:26:58 +02001177 }
romanc1d2b092023-02-02 08:58:27 +01001178 }
1179
1180cleanup:
romanba93eac2023-07-18 14:36:48 +02001181 if (is_ch(node)) {
1182 /* UNLOCK */
1183 nc_ch_client_unlock(ch_client);
1184 }
romanc1d2b092023-02-02 08:58:27 +01001185 return ret;
1186}
1187
roman2eab4742023-06-06 10:00:26 +02001188#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02001189
romanc1d2b092023-02-02 08:58:27 +01001190static int
roman874fed12023-05-25 10:20:01 +02001191nc_server_config_create_ssh(struct nc_endpt *endpt)
romanc1d2b092023-02-02 08:58:27 +01001192{
roman506354a2024-04-11 09:37:22 +02001193 endpt->ti = NC_TI_SSH;
romanc1d2b092023-02-02 08:58:27 +01001194 endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
roman3a95bb22023-10-26 11:07:17 +02001195 NC_CHECK_ERRMEM_RET(!endpt->opts.ssh, 1);
romanc1d2b092023-02-02 08:58:27 +01001196
1197 return 0;
1198}
1199
roman5cbb6532023-06-22 12:53:17 +02001200static int
1201nc_server_config_ch_create_ssh(struct nc_ch_endpt *ch_endpt)
1202{
roman506354a2024-04-11 09:37:22 +02001203 ch_endpt->ti = NC_TI_SSH;
roman5cbb6532023-06-22 12:53:17 +02001204 ch_endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts));
roman3a95bb22023-10-26 11:07:17 +02001205 NC_CHECK_ERRMEM_RET(!ch_endpt->opts.ssh, 1);
roman5cbb6532023-06-22 12:53:17 +02001206
1207 return 0;
1208}
1209
romanc1d2b092023-02-02 08:58:27 +01001210/* NP container */
1211static int
romane028ef92023-02-24 16:33:08 +01001212nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001213{
1214 struct nc_endpt *endpt;
1215 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001216 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001217 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001218 int ret = 0;
1219
1220 assert(!strcmp(LYD_NAME(node), "ssh"));
1221
roman5cbb6532023-06-22 12:53:17 +02001222 if (is_listen(node)) {
1223 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1224 ret = 1;
romanc1d2b092023-02-02 08:58:27 +01001225 goto cleanup;
1226 }
roman5cbb6532023-06-22 12:53:17 +02001227
1228 if (op == NC_OP_CREATE) {
1229 ret = nc_server_config_create_ssh(endpt);
1230 if (ret) {
1231 goto cleanup;
1232 }
1233 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02001234 nc_server_config_del_ssh_opts(bind, endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +02001235 }
1236 } else {
romanba93eac2023-07-18 14:36:48 +02001237 /* LOCK */
1238 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001239 /* to avoid unlock on fail */
1240 return 1;
romanba93eac2023-07-18 14:36:48 +02001241 }
1242
roman8341e8b2023-11-23 16:12:42 +01001243 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001244 ret = 1;
1245 goto cleanup;
1246 }
1247
1248 if (op == NC_OP_CREATE) {
1249 ret = nc_server_config_ch_create_ssh(ch_endpt);
1250 if (ret) {
1251 goto cleanup;
1252 }
romanb6f44032023-06-30 15:07:56 +02001253 } else if (op == NC_OP_DELETE) {
roman5ae78282023-11-02 13:34:34 +01001254 nc_server_config_del_ssh_opts(NULL, ch_endpt->opts.ssh);
roman5cbb6532023-06-22 12:53:17 +02001255 }
romanc1d2b092023-02-02 08:58:27 +01001256 }
1257
1258cleanup:
romanba93eac2023-07-18 14:36:48 +02001259 if (is_ch(node)) {
1260 /* UNLOCK */
1261 nc_ch_client_unlock(ch_client);
1262 }
romanc1d2b092023-02-02 08:58:27 +01001263 return ret;
1264}
1265
roman3f9b65c2023-06-05 14:26:58 +02001266static int
1267nc_server_config_create_tls(struct nc_endpt *endpt)
1268{
roman506354a2024-04-11 09:37:22 +02001269 endpt->ti = NC_TI_TLS;
roman3f9b65c2023-06-05 14:26:58 +02001270 endpt->opts.tls = calloc(1, sizeof *endpt->opts.tls);
roman3a95bb22023-10-26 11:07:17 +02001271 NC_CHECK_ERRMEM_RET(!endpt->opts.tls, 1);
roman3f9b65c2023-06-05 14:26:58 +02001272
1273 return 0;
1274}
1275
1276static int
romanb6f44032023-06-30 15:07:56 +02001277nc_server_config_ch_create_tls(struct nc_ch_endpt *ch_endpt)
1278{
roman506354a2024-04-11 09:37:22 +02001279 ch_endpt->ti = NC_TI_TLS;
romanb6f44032023-06-30 15:07:56 +02001280 ch_endpt->opts.tls = calloc(1, sizeof(struct nc_server_tls_opts));
roman3a95bb22023-10-26 11:07:17 +02001281 NC_CHECK_ERRMEM_RET(!ch_endpt->opts.tls, 1);
romanb6f44032023-06-30 15:07:56 +02001282
1283 return 0;
1284}
1285
1286static int
roman3f9b65c2023-06-05 14:26:58 +02001287nc_server_config_tls(const struct lyd_node *node, NC_OPERATION op)
1288{
1289 struct nc_endpt *endpt;
1290 struct nc_bind *bind;
romanb6f44032023-06-30 15:07:56 +02001291 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001292 struct nc_ch_client *ch_client = NULL;
roman3f9b65c2023-06-05 14:26:58 +02001293 int ret = 0;
1294
1295 assert(!strcmp(LYD_NAME(node), "tls"));
1296
romanb6f44032023-06-30 15:07:56 +02001297 if (is_listen(node)) {
1298 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
1299 ret = 1;
roman3f9b65c2023-06-05 14:26:58 +02001300 goto cleanup;
1301 }
romanb6f44032023-06-30 15:07:56 +02001302
1303 if (op == NC_OP_CREATE) {
1304 ret = nc_server_config_create_tls(endpt);
1305 if (ret) {
1306 goto cleanup;
1307 }
1308 } else if (op == NC_OP_DELETE) {
roman6430c152023-10-12 11:28:47 +02001309 nc_server_config_del_tls_opts(bind, endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +02001310 }
1311 } else {
romanba93eac2023-07-18 14:36:48 +02001312 /* LOCK */
1313 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001314 /* to avoid unlock on fail */
1315 return 1;
romanba93eac2023-07-18 14:36:48 +02001316 }
1317
roman8341e8b2023-11-23 16:12:42 +01001318 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
romanb6f44032023-06-30 15:07:56 +02001319 ret = 1;
1320 goto cleanup;
1321 }
1322
1323 if (op == NC_OP_CREATE) {
1324 ret = nc_server_config_ch_create_tls(ch_endpt);
1325 if (ret) {
1326 goto cleanup;
1327 }
roman6430c152023-10-12 11:28:47 +02001328 } else if (op == NC_OP_DELETE) {
roman5ae78282023-11-02 13:34:34 +01001329 nc_server_config_del_tls_opts(NULL, ch_endpt->opts.tls);
romanb6f44032023-06-30 15:07:56 +02001330 }
roman3f9b65c2023-06-05 14:26:58 +02001331 }
1332
1333cleanup:
romanba93eac2023-07-18 14:36:48 +02001334 if (is_ch(node)) {
1335 /* UNLOCK */
1336 nc_ch_client_unlock(ch_client);
1337 }
roman3f9b65c2023-06-05 14:26:58 +02001338 return ret;
1339}
1340
romanc1d2b092023-02-02 08:58:27 +01001341/* mandatory leaf */
1342static int
romane028ef92023-02-24 16:33:08 +01001343nc_server_config_local_address(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001344{
1345 struct nc_endpt *endpt;
1346 struct nc_bind *bind;
1347 int ret = 0;
1348
1349 (void) op;
1350
1351 assert(!strcmp(LYD_NAME(node), "local-address"));
1352
Michal Vaskocf898172024-01-15 15:04:28 +01001353 if (equal_parent_name(node, 5, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001354 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001355 ret = 1;
1356 goto cleanup;
1357 }
1358
roman6430c152023-10-12 11:28:47 +02001359 free(bind->address);
romanc1d2b092023-02-02 08:58:27 +01001360 bind->address = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001361 NC_CHECK_ERRMEM_GOTO(!bind->address, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01001362
romanfb3f7cf2023-11-30 16:10:09 +01001363 ret = nc_server_set_address_port(endpt, bind, lyd_get_value(node), 0);
romanc1d2b092023-02-02 08:58:27 +01001364 if (ret) {
1365 goto cleanup;
1366 }
1367 }
1368
1369cleanup:
1370 return ret;
1371}
1372
1373/* leaf with default value */
1374static int
romane028ef92023-02-24 16:33:08 +01001375nc_server_config_local_port(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001376{
1377 struct nc_endpt *endpt;
1378 struct nc_bind *bind;
1379 int ret = 0;
1380
1381 assert(!strcmp(LYD_NAME(node), "local-port"));
1382
Michal Vaskocf898172024-01-15 15:04:28 +01001383 if (equal_parent_name(node, 5, "listen")) {
romanf02273a2023-05-25 09:44:11 +02001384 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001385 ret = 1;
1386 goto cleanup;
1387 }
1388
1389 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001390 bind->port = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001391 } else {
1392 /* delete -> set to default */
1393 bind->port = 0;
1394 }
1395
romanfb3f7cf2023-11-30 16:10:09 +01001396 ret = nc_server_set_address_port(endpt, bind, NULL, bind->port);
romanc1d2b092023-02-02 08:58:27 +01001397 if (ret) {
1398 goto cleanup;
1399 }
1400 }
1401
1402cleanup:
1403 return ret;
1404}
1405
Michal Vaskocf898172024-01-15 15:04:28 +01001406/* NP container */
romanc1d2b092023-02-02 08:58:27 +01001407static int
romane028ef92023-02-24 16:33:08 +01001408nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001409{
roman5cbb6532023-06-22 12:53:17 +02001410 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001411 struct nc_endpt *endpt;
1412 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001413 struct nc_ch_endpt *ch_endpt;
roman6cb86ea2023-11-08 15:12:05 +01001414 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001415
1416 assert(!strcmp(LYD_NAME(node), "keepalives"));
1417
roman5cbb6532023-06-22 12:53:17 +02001418 if (is_listen(node) && equal_parent_name(node, 1, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001419 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001420 ret = 1;
1421 goto cleanup;
1422 }
1423
1424 if (op == NC_OP_CREATE) {
1425 endpt->ka.enabled = 1;
1426 } else {
1427 endpt->ka.enabled = 0;
1428 }
roman5cbb6532023-06-22 12:53:17 +02001429 } else if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001430 /* LOCK */
1431 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001432 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001433 return 1;
1434 }
1435
roman8341e8b2023-11-23 16:12:42 +01001436 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001437 ret = 1;
1438 goto cleanup;
1439 }
1440
1441 if (op == NC_OP_CREATE) {
1442 ch_endpt->ka.enabled = 1;
1443 } else {
1444 ch_endpt->ka.enabled = 0;
1445 }
romanc1d2b092023-02-02 08:58:27 +01001446 }
1447
1448cleanup:
romanba93eac2023-07-18 14:36:48 +02001449 if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) {
1450 /* UNLOCK */
1451 nc_ch_client_unlock(ch_client);
1452 }
romanc1d2b092023-02-02 08:58:27 +01001453 return ret;
1454}
1455
Michal Vaskocf898172024-01-15 15:04:28 +01001456/* leaf with default value */
romanc1d2b092023-02-02 08:58:27 +01001457static int
romane028ef92023-02-24 16:33:08 +01001458nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001459{
roman5cbb6532023-06-22 12:53:17 +02001460 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001461 struct nc_endpt *endpt;
1462 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001463 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001464 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001465
1466 assert(!strcmp(LYD_NAME(node), "idle-time"));
1467
roman5cbb6532023-06-22 12:53:17 +02001468 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001469 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001470 ret = 1;
1471 goto cleanup;
1472 }
1473
1474 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001475 endpt->ka.idle_time = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001476 } else {
Michal Vaskocf898172024-01-15 15:04:28 +01001477 /* delete -> set to default */
1478 endpt->ka.idle_time = 7200;
romanc1d2b092023-02-02 08:58:27 +01001479 }
roman5cbb6532023-06-22 12:53:17 +02001480 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001481 /* LOCK */
1482 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001483 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001484 return 1;
1485 }
1486
roman8341e8b2023-11-23 16:12:42 +01001487 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001488 ret = 1;
1489 goto cleanup;
1490 }
1491
1492 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001493 ch_endpt->ka.idle_time = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001494 } else {
Michal Vaskocf898172024-01-15 15:04:28 +01001495 /* delete -> set to default */
1496 ch_endpt->ka.idle_time = 7200;
roman5cbb6532023-06-22 12:53:17 +02001497 }
romanc1d2b092023-02-02 08:58:27 +01001498 }
1499
1500cleanup:
roman6430c152023-10-12 11:28:47 +02001501 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001502 /* UNLOCK */
1503 nc_ch_client_unlock(ch_client);
1504 }
romanc1d2b092023-02-02 08:58:27 +01001505 return ret;
1506}
1507
Michal Vaskocf898172024-01-15 15:04:28 +01001508/* leaf with default value */
romanc1d2b092023-02-02 08:58:27 +01001509static int
romane028ef92023-02-24 16:33:08 +01001510nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001511{
roman5cbb6532023-06-22 12:53:17 +02001512 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001513 struct nc_endpt *endpt;
1514 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001515 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001516 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001517
1518 assert(!strcmp(LYD_NAME(node), "max-probes"));
1519
roman5cbb6532023-06-22 12:53:17 +02001520 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001521 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001522 ret = 1;
1523 goto cleanup;
1524 }
1525
1526 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001527 endpt->ka.max_probes = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001528 } else {
Michal Vaskocf898172024-01-15 15:04:28 +01001529 /* delete -> set to default */
1530 endpt->ka.max_probes = 9;
romanc1d2b092023-02-02 08:58:27 +01001531 }
roman5cbb6532023-06-22 12:53:17 +02001532 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001533 /* LOCK */
1534 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001535 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001536 return 1;
1537 }
1538
roman8341e8b2023-11-23 16:12:42 +01001539 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001540 ret = 1;
1541 goto cleanup;
1542 }
1543
1544 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001545 ch_endpt->ka.max_probes = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001546 } else {
Michal Vaskocf898172024-01-15 15:04:28 +01001547 /* delete -> set to default */
1548 ch_endpt->ka.max_probes = 9;
roman5cbb6532023-06-22 12:53:17 +02001549 }
romanc1d2b092023-02-02 08:58:27 +01001550 }
1551
1552cleanup:
roman6430c152023-10-12 11:28:47 +02001553 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001554 /* UNLOCK */
1555 nc_ch_client_unlock(ch_client);
1556 }
romanc1d2b092023-02-02 08:58:27 +01001557 return ret;
1558}
1559
Michal Vaskocf898172024-01-15 15:04:28 +01001560/* leaf with default value */
romanc1d2b092023-02-02 08:58:27 +01001561static int
romane028ef92023-02-24 16:33:08 +01001562nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001563{
roman5cbb6532023-06-22 12:53:17 +02001564 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001565 struct nc_endpt *endpt;
1566 struct nc_bind *bind;
roman5cbb6532023-06-22 12:53:17 +02001567 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01001568 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001569
1570 assert(!strcmp(LYD_NAME(node), "probe-interval"));
1571
roman5cbb6532023-06-22 12:53:17 +02001572 if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) {
romanf02273a2023-05-25 09:44:11 +02001573 if (nc_server_config_get_endpt(node, &endpt, &bind)) {
romanc1d2b092023-02-02 08:58:27 +01001574 ret = 1;
1575 goto cleanup;
1576 }
1577
1578 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001579 endpt->ka.probe_interval = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01001580 } else {
Michal Vaskocf898172024-01-15 15:04:28 +01001581 /* delete -> set to default */
1582 endpt->ka.probe_interval = 75;
romanc1d2b092023-02-02 08:58:27 +01001583 }
roman5cbb6532023-06-22 12:53:17 +02001584 } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001585 /* LOCK */
1586 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001587 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001588 return 1;
1589 }
1590
roman8341e8b2023-11-23 16:12:42 +01001591 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02001592 ret = 1;
1593 goto cleanup;
1594 }
1595
1596 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02001597 ch_endpt->ka.probe_interval = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02001598 } else {
Michal Vaskocf898172024-01-15 15:04:28 +01001599 /* delete -> set to default */
1600 ch_endpt->ka.probe_interval = 75;
roman5cbb6532023-06-22 12:53:17 +02001601 }
romanc1d2b092023-02-02 08:58:27 +01001602 }
1603
1604cleanup:
roman6430c152023-10-12 11:28:47 +02001605 if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) {
romanba93eac2023-07-18 14:36:48 +02001606 /* UNLOCK */
1607 nc_ch_client_unlock(ch_client);
1608 }
romanc1d2b092023-02-02 08:58:27 +01001609 return ret;
1610}
1611
1612static int
roman874fed12023-05-25 10:20:01 +02001613nc_server_config_create_host_key(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01001614{
romanf02273a2023-05-25 09:44:11 +02001615 node = lyd_child(node);
1616 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01001617
romanf02273a2023-05-25 09:44:11 +02001618 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->hostkeys, sizeof *opts->hostkeys, &opts->hostkey_count);
romanc1d2b092023-02-02 08:58:27 +01001619}
1620
1621/* list */
1622static int
romane028ef92023-02-24 16:33:08 +01001623nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001624{
roman5cbb6532023-06-22 12:53:17 +02001625 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001626 struct nc_hostkey *hostkey;
roman4cb8bb12023-06-29 09:16:46 +02001627 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01001628 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001629
1630 assert(!strcmp(LYD_NAME(node), "host-key"));
1631
roman4cb8bb12023-06-29 09:16:46 +02001632 if (equal_parent_name(node, 1, "server-identity")) {
romanba93eac2023-07-18 14:36:48 +02001633 /* LOCK */
1634 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001635 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001636 return 1;
1637 }
1638
roman8341e8b2023-11-23 16:12:42 +01001639 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman6cb86ea2023-11-08 15:12:05 +01001640 ret = 1;
1641 goto cleanup;
1642 }
1643
romanc1d2b092023-02-02 08:58:27 +01001644 if (op == NC_OP_CREATE) {
roman4cb8bb12023-06-29 09:16:46 +02001645 ret = nc_server_config_create_host_key(node, opts);
romanc1d2b092023-02-02 08:58:27 +01001646 if (ret) {
1647 goto cleanup;
1648 }
1649 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01001650 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001651 ret = 1;
1652 goto cleanup;
1653 }
roman4cb8bb12023-06-29 09:16:46 +02001654 nc_server_config_del_hostkey(opts, hostkey);
roman5cbb6532023-06-22 12:53:17 +02001655 }
romanc1d2b092023-02-02 08:58:27 +01001656 }
1657
1658cleanup:
romanba93eac2023-07-18 14:36:48 +02001659 if (is_ch(node) && equal_parent_name(node, 1, "server-identity")) {
1660 /* UNLOCK */
1661 nc_ch_client_unlock(ch_client);
1662 }
romanc1d2b092023-02-02 08:58:27 +01001663 return ret;
1664}
1665
1666/* mandatory leaf */
romane028ef92023-02-24 16:33:08 +01001667static int
1668nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001669{
roman3f9b65c2023-06-05 14:26:58 +02001670 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02001671 const char *format;
roman3f9b65c2023-06-05 14:26:58 +02001672 NC_PUBKEY_FORMAT pubkey_type;
roman8edee342023-03-31 13:25:48 +02001673 struct nc_public_key *pubkey;
romanc1d2b092023-02-02 08:58:27 +01001674 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02001675 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01001676 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001677
1678 assert(!strcmp(LYD_NAME(node), "public-key-format"));
1679
roman6cb86ea2023-11-08 15:12:05 +01001680 /* LOCK */
1681 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
1682 /* to avoid unlock on fail */
1683 return 1;
1684 }
1685
romanc1d2b092023-02-02 08:58:27 +01001686 format = ((struct lyd_node_term *)node)->value.ident->name;
roman3f9b65c2023-06-05 14:26:58 +02001687 if (!strcmp(format, "ssh-public-key-format")) {
roman13145912023-08-17 15:36:54 +02001688 pubkey_type = NC_PUBKEY_FORMAT_SSH;
roman3f9b65c2023-06-05 14:26:58 +02001689 } else if (!strcmp(format, "subject-public-key-info-format")) {
1690 pubkey_type = NC_PUBKEY_FORMAT_X509;
1691 } else {
1692 ERR(NULL, "Public key format (%s) not supported.", format);
1693 ret = 1;
1694 goto cleanup;
1695 }
romanc1d2b092023-02-02 08:58:27 +01001696
roman4cb8bb12023-06-29 09:16:46 +02001697 if (is_ssh(node) && equal_parent_name(node, 4, "server-identity")) {
roman5cbb6532023-06-22 12:53:17 +02001698 /* SSH hostkey public key fmt */
roman8341e8b2023-11-23 16:12:42 +01001699 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02001700 ret = 1;
1701 goto cleanup;
1702 }
1703
1704 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1705 hostkey->key.pubkey_type = pubkey_type;
1706 }
roman4cb8bb12023-06-29 09:16:46 +02001707 } else if (is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) {
roman5cbb6532023-06-22 12:53:17 +02001708 /* SSH client auth public key fmt */
roman8341e8b2023-11-23 16:12:42 +01001709 if (nc_server_config_get_pubkey(node, ch_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001710 ret = 1;
1711 goto cleanup;
1712 }
1713
1714 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman3f9b65c2023-06-05 14:26:58 +02001715 pubkey->type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001716 }
romanb6f44032023-06-30 15:07:56 +02001717 } else if (is_tls(node) && equal_parent_name(node, 3, "server-identity")) {
1718 /* TLS server-identity */
roman8341e8b2023-11-23 16:12:42 +01001719 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02001720 ret = 1;
1721 goto cleanup;
1722 }
1723
roman5cbb6532023-06-22 12:53:17 +02001724 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02001725 opts->pubkey_type = pubkey_type;
romanc1d2b092023-02-02 08:58:27 +01001726 }
romanc1d2b092023-02-02 08:58:27 +01001727 }
1728
1729cleanup:
romanba93eac2023-07-18 14:36:48 +02001730 if (is_ch(node)) {
1731 /* UNLOCK */
1732 nc_ch_client_unlock(ch_client);
1733 }
romanc1d2b092023-02-02 08:58:27 +01001734 return ret;
1735}
1736
1737static int
roman58f79d02023-10-06 10:20:31 +02001738nc_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 +01001739{
romanc1d2b092023-02-02 08:58:27 +01001740 assert(!strcmp(LYD_NAME(node), "public-key"));
1741
romanc1d2b092023-02-02 08:58:27 +01001742 node = lyd_child(node);
1743 assert(!strcmp(LYD_NAME(node), "name"));
1744
Michal Vaskocf898172024-01-15 15:04:28 +01001745 return nc_server_config_realloc(lyd_get_value(node), (void **)&auth_client->pubkeys, sizeof *auth_client->pubkeys,
1746 &auth_client->pubkey_count);
romanc1d2b092023-02-02 08:58:27 +01001747}
1748
1749static int
roman874fed12023-05-25 10:20:01 +02001750nc_server_config_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct nc_public_key *pubkey)
romanc1d2b092023-02-02 08:58:27 +01001751{
roman6430c152023-10-12 11:28:47 +02001752 free(pubkey->data);
roman3f9b65c2023-06-05 14:26:58 +02001753 pubkey->data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001754 NC_CHECK_ERRMEM_RET(!pubkey->data, 1);
romanc1d2b092023-02-02 08:58:27 +01001755
1756 return 0;
1757}
1758
1759static int
roman874fed12023-05-25 10:20:01 +02001760nc_server_config_replace_host_key_public_key(const struct lyd_node *node, struct nc_hostkey *hostkey)
romanc1d2b092023-02-02 08:58:27 +01001761{
roman6430c152023-10-12 11:28:47 +02001762 free(hostkey->key.pubkey_data);
roman3f9b65c2023-06-05 14:26:58 +02001763 hostkey->key.pubkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001764 NC_CHECK_ERRMEM_RET(!hostkey->key.pubkey_data, 1);
romanc1d2b092023-02-02 08:58:27 +01001765
1766 return 0;
1767}
1768
roman3f9b65c2023-06-05 14:26:58 +02001769static int
1770nc_server_config_tls_replace_server_public_key(const struct lyd_node *node, struct nc_server_tls_opts *opts)
1771{
roman6430c152023-10-12 11:28:47 +02001772 free(opts->pubkey_data);
roman3f9b65c2023-06-05 14:26:58 +02001773 opts->pubkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001774 NC_CHECK_ERRMEM_RET(!opts->pubkey_data, 1);
roman3f9b65c2023-06-05 14:26:58 +02001775
1776 return 0;
1777}
1778
romanc1d2b092023-02-02 08:58:27 +01001779static int
romane028ef92023-02-24 16:33:08 +01001780nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01001781{
roman3f9b65c2023-06-05 14:26:58 +02001782 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01001783 struct nc_hostkey *hostkey;
roman58f79d02023-10-06 10:20:31 +02001784 struct nc_auth_client *auth_client;
roman8edee342023-03-31 13:25:48 +02001785 struct nc_public_key *pubkey;
romanb6f44032023-06-30 15:07:56 +02001786 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01001787 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01001788
1789 assert(!strcmp(LYD_NAME(node), "public-key"));
1790
romanba93eac2023-07-18 14:36:48 +02001791 /* LOCK */
1792 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02001793 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001794 return 1;
1795 }
1796
roman4cb8bb12023-06-29 09:16:46 +02001797 if (is_ssh(node) && equal_parent_name(node, 3, "host-key")) {
roman3f9b65c2023-06-05 14:26:58 +02001798 /* server's public-key, mandatory leaf */
roman8341e8b2023-11-23 16:12:42 +01001799 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
romanc1d2b092023-02-02 08:58:27 +01001800 ret = 1;
1801 goto cleanup;
1802 }
1803
roman13145912023-08-17 15:36:54 +02001804 /* the public key must not be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
roman51a1e192023-09-14 10:13:45 +02001805 if (nc_is_pk_subject_public_key_info(lyd_get_value(node))) {
roman13145912023-08-17 15:36:54 +02001806 ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH hostkey is forbidden!");
1807 ret = 1;
1808 goto cleanup;
1809 }
1810
romanc1d2b092023-02-02 08:58:27 +01001811 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02001812 /* set to local */
roman874fed12023-05-25 10:20:01 +02001813 hostkey->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02001814
roman874fed12023-05-25 10:20:01 +02001815 ret = nc_server_config_replace_host_key_public_key(node, hostkey);
romanc1d2b092023-02-02 08:58:27 +01001816 if (ret) {
1817 goto cleanup;
1818 }
1819 }
roman4cb8bb12023-06-29 09:16:46 +02001820 } else if (is_ssh(node) && equal_parent_name(node, 5, "client-authentication")) {
romanc1d2b092023-02-02 08:58:27 +01001821 /* client auth pubkeys, list */
roman8341e8b2023-11-23 16:12:42 +01001822 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01001823 ret = 1;
1824 goto cleanup;
1825 }
1826
1827 if (op == NC_OP_CREATE) {
romanf02273a2023-05-25 09:44:11 +02001828 /* set to local */
roman874fed12023-05-25 10:20:01 +02001829 auth_client->store = NC_STORE_LOCAL;
romanf02273a2023-05-25 09:44:11 +02001830
roman874fed12023-05-25 10:20:01 +02001831 ret = nc_server_config_create_auth_key_public_key_list(node, auth_client);
romanc1d2b092023-02-02 08:58:27 +01001832 if (ret) {
1833 goto cleanup;
1834 }
1835 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01001836 if (nc_server_config_get_pubkey(node, ch_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001837 ret = 1;
1838 goto cleanup;
1839 }
1840
roman874fed12023-05-25 10:20:01 +02001841 nc_server_config_del_auth_client_pubkey(auth_client, pubkey);
romanc1d2b092023-02-02 08:58:27 +01001842 }
roman4cb8bb12023-06-29 09:16:46 +02001843 } else if (is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) {
romanc1d2b092023-02-02 08:58:27 +01001844 /* client auth pubkey, leaf */
roman8341e8b2023-11-23 16:12:42 +01001845 if (nc_server_config_get_pubkey(node, ch_client, &pubkey)) {
romanc1d2b092023-02-02 08:58:27 +01001846 ret = 1;
1847 goto cleanup;
1848 }
1849
roman13145912023-08-17 15:36:54 +02001850 /* the public key must not be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
roman51a1e192023-09-14 10:13:45 +02001851 if (nc_is_pk_subject_public_key_info(lyd_get_value(node))) {
roman13145912023-08-17 15:36:54 +02001852 ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH user's key is forbidden!");
1853 ret = 1;
1854 goto cleanup;
1855 }
1856
romanc1d2b092023-02-02 08:58:27 +01001857 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman874fed12023-05-25 10:20:01 +02001858 ret = nc_server_config_replace_auth_key_public_key_leaf(node, pubkey);
romanc1d2b092023-02-02 08:58:27 +01001859 if (ret) {
1860 goto cleanup;
1861 }
roman6430c152023-10-12 11:28:47 +02001862 } else if (op == NC_OP_DELETE) {
1863 free(pubkey->data);
1864 pubkey->data = NULL;
romanc1d2b092023-02-02 08:58:27 +01001865 }
romanb6f44032023-06-30 15:07:56 +02001866 } else if (is_tls(node) && equal_parent_name(node, 3, "server-identity")) {
1867 /* TLS server-identity */
roman8341e8b2023-11-23 16:12:42 +01001868 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02001869 ret = 1;
1870 goto cleanup;
1871 }
1872
roman13145912023-08-17 15:36:54 +02001873 /* the public key must be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
roman51a1e192023-09-14 10:13:45 +02001874 if (!nc_is_pk_subject_public_key_info(lyd_get_value(node))) {
roman13145912023-08-17 15:36:54 +02001875 ERR(NULL, "TLS server certificate's Public Key must be in the SubjectPublicKeyInfo format!");
1876 ret = 1;
1877 goto cleanup;
1878 }
1879
roman3f9b65c2023-06-05 14:26:58 +02001880 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
1881 /* set to local */
romanb6f44032023-06-30 15:07:56 +02001882 opts->store = NC_STORE_LOCAL;
roman3f9b65c2023-06-05 14:26:58 +02001883
romanb6f44032023-06-30 15:07:56 +02001884 ret = nc_server_config_tls_replace_server_public_key(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02001885 if (ret) {
1886 goto cleanup;
1887 }
1888 }
roman5cbb6532023-06-22 12:53:17 +02001889 }
1890
1891cleanup:
romanba93eac2023-07-18 14:36:48 +02001892 if (is_ch(node)) {
1893 /* UNLOCK */
1894 nc_ch_client_unlock(ch_client);
1895 }
roman5cbb6532023-06-22 12:53:17 +02001896 return ret;
1897}
1898
1899/* leaf */
1900static int
1901nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op)
1902{
1903 int ret = 0;
1904 const char *format;
1905 NC_PRIVKEY_FORMAT privkey_type;
roman5cbb6532023-06-22 12:53:17 +02001906 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02001907 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01001908 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02001909
1910 (void) op;
1911
1912 assert(!strcmp(LYD_NAME(node), "private-key-format"));
1913
roman6cb86ea2023-11-08 15:12:05 +01001914 /* LOCK */
1915 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
1916 /* to avoid unlock on fail */
1917 return 1;
1918 }
1919
roman5cbb6532023-06-22 12:53:17 +02001920 format = ((struct lyd_node_term *)node)->value.ident->name;
1921 if (!format) {
1922 ret = 1;
1923 goto cleanup;
1924 }
1925
1926 privkey_type = nc_server_config_get_private_key_type(format);
1927 if (privkey_type == NC_PRIVKEY_FORMAT_UNKNOWN) {
1928 ERR(NULL, "Unknown private key format.");
1929 ret = 1;
1930 goto cleanup;
1931 }
1932
roman4cb8bb12023-06-29 09:16:46 +02001933 if (is_ssh(node)) {
1934 /* ssh */
roman8341e8b2023-11-23 16:12:42 +01001935 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02001936 ret = 1;
1937 goto cleanup;
1938 }
1939
1940 hostkey->key.privkey_type = privkey_type;
romanb6f44032023-06-30 15:07:56 +02001941 } else if (is_tls(node)) {
1942 /* tls */
roman8341e8b2023-11-23 16:12:42 +01001943 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman5cbb6532023-06-22 12:53:17 +02001944 ret = 1;
1945 goto cleanup;
1946 }
1947
romanb6f44032023-06-30 15:07:56 +02001948 opts->privkey_type = privkey_type;
roman5cbb6532023-06-22 12:53:17 +02001949 }
1950
1951cleanup:
romanba93eac2023-07-18 14:36:48 +02001952 if (is_ch(node)) {
1953 /* UNLOCK */
1954 nc_ch_client_unlock(ch_client);
1955 }
roman5cbb6532023-06-22 12:53:17 +02001956 return ret;
1957}
1958
1959static int
roman5cbb6532023-06-22 12:53:17 +02001960nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op)
1961{
1962 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02001963 struct nc_hostkey *hostkey;
romanb6f44032023-06-30 15:07:56 +02001964 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01001965 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02001966
1967 assert(!strcmp(LYD_NAME(node), "cleartext-private-key"));
1968
romanba93eac2023-07-18 14:36:48 +02001969 /* LOCK */
1970 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02001971 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02001972 return 1;
1973 }
1974
roman4cb8bb12023-06-29 09:16:46 +02001975 if (is_ssh(node)) {
1976 /* ssh */
roman8341e8b2023-11-23 16:12:42 +01001977 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02001978 ret = 1;
1979 goto cleanup;
1980 }
1981
1982 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02001983 free(hostkey->key.privkey_data);
1984 hostkey->key.privkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02001985 NC_CHECK_ERRMEM_GOTO(!hostkey->key.privkey_data, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02001986 } else {
roman6430c152023-10-12 11:28:47 +02001987 free(hostkey->key.privkey_data);
1988 hostkey->key.privkey_data = NULL;
roman5cbb6532023-06-22 12:53:17 +02001989 }
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)) {
roman4cb8bb12023-06-29 09:16:46 +02001993 ret = 1;
1994 goto cleanup;
1995 }
1996
roman5cbb6532023-06-22 12:53:17 +02001997 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02001998 free(opts->privkey_data);
1999 opts->privkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002000 NC_CHECK_ERRMEM_GOTO(!opts->privkey_data, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02002001 } else {
roman6430c152023-10-12 11:28:47 +02002002 free(opts->privkey_data);
2003 opts->privkey_data = NULL;
roman5cbb6532023-06-22 12:53:17 +02002004 }
roman5cbb6532023-06-22 12:53:17 +02002005 }
2006
2007cleanup:
romanba93eac2023-07-18 14:36:48 +02002008 if (is_ch(node)) {
2009 /* UNLOCK */
2010 nc_ch_client_unlock(ch_client);
2011 }
roman5cbb6532023-06-22 12:53:17 +02002012 return ret;
2013}
2014
roman5cbb6532023-06-22 12:53:17 +02002015/* leaf */
2016static int
2017nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op)
2018{
2019 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02002020 struct nc_hostkey *hostkey;
roman8341e8b2023-11-23 16:12:42 +01002021 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02002022
Michal Vaskocf898172024-01-15 15:04:28 +01002023 assert(!strcmp(LYD_NAME(node), "central-keystore-reference"));
roman5cbb6532023-06-22 12:53:17 +02002024
romanba93eac2023-07-18 14:36:48 +02002025 /* LOCK */
2026 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002027 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002028 return 1;
2029 }
2030
roman4cb8bb12023-06-29 09:16:46 +02002031 if (is_ssh(node) && equal_parent_name(node, 3, "server-identity")) {
roman8341e8b2023-11-23 16:12:42 +01002032 if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) {
roman5cbb6532023-06-22 12:53:17 +02002033 ret = 1;
2034 goto cleanup;
2035 }
2036
2037 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2038 /* set to keystore */
2039 hostkey->store = NC_STORE_KEYSTORE;
2040
roman6430c152023-10-12 11:28:47 +02002041 free(hostkey->ks_ref);
romandd019a92023-09-14 10:17:07 +02002042 hostkey->ks_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002043 NC_CHECK_ERRMEM_GOTO(!hostkey->ks_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002044 } else if (op == NC_OP_DELETE) {
2045 free(hostkey->ks_ref);
roman5cbb6532023-06-22 12:53:17 +02002046 hostkey->ks_ref = NULL;
2047 }
roman3f9b65c2023-06-05 14:26:58 +02002048 }
romanc1d2b092023-02-02 08:58:27 +01002049
2050cleanup:
romanba93eac2023-07-18 14:36:48 +02002051 if (is_ch(node)) {
2052 /* UNLOCK */
2053 nc_ch_client_unlock(ch_client);
2054 }
romanc1d2b092023-02-02 08:58:27 +01002055 return ret;
2056}
2057
2058static int
roman6430c152023-10-12 11:28:47 +02002059nc_server_config_create_auth_client(const struct lyd_node *node, struct nc_server_ssh_opts *opts)
romanc1d2b092023-02-02 08:58:27 +01002060{
romanf02273a2023-05-25 09:44:11 +02002061 node = lyd_child(node);
2062 assert(!strcmp(LYD_NAME(node), "name"));
romanc1d2b092023-02-02 08:58:27 +01002063
romanf02273a2023-05-25 09:44:11 +02002064 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 +01002065}
2066
2067/* list */
2068static int
romane028ef92023-02-24 16:33:08 +01002069nc_server_config_user(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002070{
roman5cbb6532023-06-22 12:53:17 +02002071 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002072 struct nc_auth_client *auth_client;
roman4cb8bb12023-06-29 09:16:46 +02002073 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002074 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002075
2076 assert(!strcmp(LYD_NAME(node), "user"));
2077
romanba93eac2023-07-18 14:36:48 +02002078 /* LOCK */
2079 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002080 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002081 return 1;
2082 }
2083
roman8341e8b2023-11-23 16:12:42 +01002084 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002085 ret = 1;
2086 goto cleanup;
2087 }
2088
2089 if (op == NC_OP_CREATE) {
roman6430c152023-10-12 11:28:47 +02002090 ret = nc_server_config_create_auth_client(node, opts);
roman4cb8bb12023-06-29 09:16:46 +02002091 if (ret) {
2092 goto cleanup;
2093 }
2094 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01002095 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002096 ret = 1;
2097 goto cleanup;
2098 }
2099
roman4cb8bb12023-06-29 09:16:46 +02002100 nc_server_config_del_auth_client(opts, auth_client);
romanc1d2b092023-02-02 08:58:27 +01002101 }
2102
2103cleanup:
romanba93eac2023-07-18 14:36:48 +02002104 if (is_ch(node)) {
2105 /* UNLOCK */
2106 nc_ch_client_unlock(ch_client);
2107 }
romanc1d2b092023-02-02 08:58:27 +01002108 return ret;
2109}
2110
2111static int
romane028ef92023-02-24 16:33:08 +01002112nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002113{
romanc1d2b092023-02-02 08:58:27 +01002114 int ret = 0;
roman4cb8bb12023-06-29 09:16:46 +02002115 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002116 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002117
2118 assert(!strcmp(LYD_NAME(node), "auth-timeout"));
2119
romanba93eac2023-07-18 14:36:48 +02002120 /* LOCK */
2121 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002122 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002123 return 1;
2124 }
2125
roman8341e8b2023-11-23 16:12:42 +01002126 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002127 ret = 1;
2128 goto cleanup;
2129 }
romanc1d2b092023-02-02 08:58:27 +01002130
roman4cb8bb12023-06-29 09:16:46 +02002131 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02002132 opts->auth_timeout = ((struct lyd_node_term *)node)->value.uint16;
romanc1d2b092023-02-02 08:58:27 +01002133 }
2134
2135cleanup:
romanba93eac2023-07-18 14:36:48 +02002136 if (is_ch(node)) {
2137 /* UNLOCK */
2138 nc_ch_client_unlock(ch_client);
2139 }
romanc1d2b092023-02-02 08:58:27 +01002140 return ret;
2141}
2142
romanc1d2b092023-02-02 08:58:27 +01002143/* leaf */
2144static int
romane028ef92023-02-24 16:33:08 +01002145nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002146{
romanc1d2b092023-02-02 08:58:27 +01002147 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002148 struct nc_auth_client *auth_client;
roman8341e8b2023-11-23 16:12:42 +01002149 struct nc_ch_client *ch_client = NULL;
roman6430c152023-10-12 11:28:47 +02002150 struct nc_server_tls_opts *opts;
2151 struct nc_cert_grouping *certs_grp;
romanc1d2b092023-02-02 08:58:27 +01002152
Michal Vaskocf898172024-01-15 15:04:28 +01002153 assert(!strcmp(LYD_NAME(node), "central-truststore-reference"));
romanc1d2b092023-02-02 08:58:27 +01002154
romanba93eac2023-07-18 14:36:48 +02002155 /* LOCK */
2156 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002157 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002158 return 1;
2159 }
2160
roman4cb8bb12023-06-29 09:16:46 +02002161 if (is_ssh(node) && equal_parent_name(node, 1, "public-keys")) {
roman8341e8b2023-11-23 16:12:42 +01002162 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
romanc1d2b092023-02-02 08:58:27 +01002163 ret = 1;
2164 goto cleanup;
2165 }
2166
2167 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanf02273a2023-05-25 09:44:11 +02002168 /* set to truststore */
roman874fed12023-05-25 10:20:01 +02002169 auth_client->store = NC_STORE_TRUSTSTORE;
romanf02273a2023-05-25 09:44:11 +02002170
roman6430c152023-10-12 11:28:47 +02002171 free(auth_client->ts_ref);
2172 auth_client->ts_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002173 NC_CHECK_ERRMEM_GOTO(!auth_client->ts_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002174 } else if (op == NC_OP_DELETE) {
2175 free(auth_client->ts_ref);
romand57b3722023-04-05 11:26:25 +02002176 auth_client->ts_ref = NULL;
romanc1d2b092023-02-02 08:58:27 +01002177 }
roman6430c152023-10-12 11:28:47 +02002178 } else if (is_tls(node) && (equal_parent_name(node, 1, "ca-certs") || equal_parent_name(node, 1, "ee-certs"))) {
2179 /* ee-certs or ca-certs */
roman8341e8b2023-11-23 16:12:42 +01002180 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002181 ret = 1;
2182 goto cleanup;
2183 }
2184
roman6430c152023-10-12 11:28:47 +02002185 if (equal_parent_name(node, 1, "ca-certs")) {
2186 certs_grp = &opts->ca_certs;
roman3f9b65c2023-06-05 14:26:58 +02002187 } else {
roman6430c152023-10-12 11:28:47 +02002188 certs_grp = &opts->ee_certs;
roman4cb8bb12023-06-29 09:16:46 +02002189 }
2190
roman3f9b65c2023-06-05 14:26:58 +02002191 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2192 /* set to truststore */
roman6430c152023-10-12 11:28:47 +02002193 certs_grp->store = NC_STORE_TRUSTSTORE;
roman3f9b65c2023-06-05 14:26:58 +02002194
roman6430c152023-10-12 11:28:47 +02002195 free(certs_grp->ts_ref);
2196 certs_grp->ts_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002197 NC_CHECK_ERRMEM_GOTO(!certs_grp->ts_ref, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02002198 } else if (op == NC_OP_DELETE) {
2199 free(certs_grp->ts_ref);
2200 certs_grp->ts_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002201 }
2202 }
romanc1d2b092023-02-02 08:58:27 +01002203
2204cleanup:
romanba93eac2023-07-18 14:36:48 +02002205 if (is_ch(node)) {
2206 /* UNLOCK */
2207 nc_ch_client_unlock(ch_client);
2208 }
romanc1d2b092023-02-02 08:58:27 +01002209 return ret;
2210}
2211
romana9ec3362023-12-21 10:59:57 +01002212static int
2213nc_server_config_use_system_keys(const struct lyd_node *node, NC_OPERATION op)
2214{
2215 int ret = 0;
2216 struct nc_auth_client *auth_client;
2217 struct nc_ch_client *ch_client = NULL;
2218
2219 assert(!strcmp(LYD_NAME(node), "use-system-keys"));
2220
2221 /* LOCK */
2222 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
2223 /* to avoid unlock on fail */
2224 return 1;
2225 }
2226
2227 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
2228 ret = 1;
2229 goto cleanup;
2230 }
2231
2232 if (op == NC_OP_CREATE) {
2233 auth_client->store = NC_STORE_SYSTEM;
2234 }
2235
2236cleanup:
2237 if (is_ch(node)) {
2238 /* UNLOCK */
2239 nc_ch_client_unlock(ch_client);
2240 }
2241 return ret;
2242}
2243
romanc1d2b092023-02-02 08:58:27 +01002244/* leaf */
2245static int
romane028ef92023-02-24 16:33:08 +01002246nc_server_config_password(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002247{
roman5cbb6532023-06-22 12:53:17 +02002248 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002249 struct nc_auth_client *auth_client;
roman8341e8b2023-11-23 16:12:42 +01002250 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002251
2252 assert(!strcmp(LYD_NAME(node), "password"));
2253
romanba93eac2023-07-18 14:36:48 +02002254 /* LOCK */
2255 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002256 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002257 return 1;
2258 }
2259
roman8341e8b2023-11-23 16:12:42 +01002260 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
roman4cb8bb12023-06-29 09:16:46 +02002261 ret = 1;
2262 goto cleanup;
2263 }
2264
2265 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002266 free(auth_client->password);
2267 auth_client->password = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002268 NC_CHECK_ERRMEM_GOTO(!auth_client->password, ret = 1, cleanup);
roman4cb8bb12023-06-29 09:16:46 +02002269 } else {
roman6430c152023-10-12 11:28:47 +02002270 free(auth_client->password);
2271 auth_client->password = NULL;
romanc1d2b092023-02-02 08:58:27 +01002272 }
2273
2274cleanup:
romanba93eac2023-07-18 14:36:48 +02002275 if (is_ch(node)) {
2276 /* UNLOCK */
2277 nc_ch_client_unlock(ch_client);
2278 }
romanc1d2b092023-02-02 08:58:27 +01002279 return ret;
2280}
2281
2282static int
romanc6518422023-11-30 16:39:00 +01002283nc_server_config_use_system_auth(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002284{
roman5cbb6532023-06-22 12:53:17 +02002285 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002286 struct nc_auth_client *auth_client;
roman808f3f62023-11-23 16:01:04 +01002287 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002288
romanc6518422023-11-30 16:39:00 +01002289 assert(!strcmp(LYD_NAME(node), "use-system-auth"));
romanc1d2b092023-02-02 08:58:27 +01002290
romanba93eac2023-07-18 14:36:48 +02002291 /* LOCK */
2292 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002293 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002294 return 1;
2295 }
2296
roman8341e8b2023-11-23 16:12:42 +01002297 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
roman4cb8bb12023-06-29 09:16:46 +02002298 ret = 1;
2299 goto cleanup;
2300 }
2301
roman808f3f62023-11-23 16:01:04 +01002302 if (op == NC_OP_CREATE) {
2303 auth_client->kb_int_enabled = 1;
roman4cb8bb12023-06-29 09:16:46 +02002304 } else {
roman808f3f62023-11-23 16:01:04 +01002305 auth_client->kb_int_enabled = 0;
romanc1d2b092023-02-02 08:58:27 +01002306 }
2307
2308cleanup:
romanba93eac2023-07-18 14:36:48 +02002309 if (is_ch(node)) {
2310 /* UNLOCK */
2311 nc_ch_client_unlock(ch_client);
2312 }
romanc1d2b092023-02-02 08:58:27 +01002313 return ret;
2314}
2315
2316/* leaf */
2317static int
romane028ef92023-02-24 16:33:08 +01002318nc_server_config_none(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002319{
roman5cbb6532023-06-22 12:53:17 +02002320 int ret = 0;
roman58f79d02023-10-06 10:20:31 +02002321 struct nc_auth_client *auth_client;
roman8341e8b2023-11-23 16:12:42 +01002322 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002323
2324 assert(!strcmp(LYD_NAME(node), "none"));
2325
romanba93eac2023-07-18 14:36:48 +02002326 /* LOCK */
2327 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman58f79d02023-10-06 10:20:31 +02002328 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002329 return 1;
2330 }
2331
roman8341e8b2023-11-23 16:12:42 +01002332 if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) {
roman4cb8bb12023-06-29 09:16:46 +02002333 ret = 1;
2334 goto cleanup;
2335 }
romanc1d2b092023-02-02 08:58:27 +01002336
roman4cb8bb12023-06-29 09:16:46 +02002337 if (op == NC_OP_CREATE) {
roman808f3f62023-11-23 16:01:04 +01002338 auth_client->none_enabled = 1;
roman4cb8bb12023-06-29 09:16:46 +02002339 } else {
roman808f3f62023-11-23 16:01:04 +01002340 auth_client->none_enabled = 0;
romanc1d2b092023-02-02 08:58:27 +01002341 }
2342
2343cleanup:
romanba93eac2023-07-18 14:36:48 +02002344 if (is_ch(node)) {
2345 /* UNLOCK */
2346 nc_ch_client_unlock(ch_client);
2347 }
romanc1d2b092023-02-02 08:58:27 +01002348 return ret;
2349}
2350
2351static int
romanc135c6d2023-10-25 13:32:30 +02002352nc_server_config_delete_substring(const char *haystack, const char *needle, const char delim)
2353{
2354 size_t needle_len = strlen(needle);
2355 char *substr;
2356 int substr_found = 0, ret = 0;
2357
2358 while ((substr = strstr(haystack, needle))) {
2359 /* iterate over all the substrings */
2360 if (((substr == haystack) && (*(substr + needle_len) == delim)) ||
2361 ((substr != haystack) && (*(substr - 1) == delim) && (*(substr + needle_len) == delim))) {
2362 /* either the first element of the string or somewhere in the middle */
2363 memmove(substr, substr + needle_len + 1, strlen(substr + needle_len + 1));
2364 substr_found = 1;
2365 break;
2366 } else if ((*(substr - 1) == delim) && (*(substr + needle_len) == '\0')) {
2367 /* the last element of the string */
2368 *(substr - 1) = '\0';
2369 substr_found = 1;
2370 break;
2371 }
2372 haystack = substr + 1;
2373 }
2374 if (!substr_found) {
2375 ret = 1;
2376 }
2377
2378 return ret;
2379}
2380
2381static int
romana6bf6ab2023-05-26 13:26:02 +02002382nc_server_config_transport_params(const char *algorithm, char **alg_store, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002383{
romanc135c6d2023-10-25 13:32:30 +02002384 int ret = 0;
2385 char *alg = NULL;
romana6bf6ab2023-05-26 13:26:02 +02002386
2387 if (!strncmp(algorithm, "openssh-", 8)) {
2388 /* if the name starts with openssh, convert it to it's original libssh accepted form */
roman3a95bb22023-10-26 11:07:17 +02002389 ret = asprintf(&alg, "%s@openssh.com", algorithm + 8);
2390 NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; alg = NULL, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002391 } else if (!strncmp(algorithm, "libssh-", 7)) {
2392 /* if the name starts with libssh, convert it to it's original libssh accepted form */
roman3a95bb22023-10-26 11:07:17 +02002393 ret = asprintf(&alg, "%s@libssh.org", algorithm + 7);
2394 NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; alg = NULL, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002395 } else {
2396 alg = strdup(algorithm);
roman3a95bb22023-10-26 11:07:17 +02002397 NC_CHECK_ERRMEM_GOTO(!alg, ret = 1, cleanup);
romana6bf6ab2023-05-26 13:26:02 +02002398 }
2399
romanc1d2b092023-02-02 08:58:27 +01002400 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2401 if (!*alg_store) {
2402 /* first call */
2403 *alg_store = strdup(alg);
roman3a95bb22023-10-26 11:07:17 +02002404 NC_CHECK_ERRMEM_GOTO(!*alg_store, ret = 1, cleanup);
romanc1d2b092023-02-02 08:58:27 +01002405 } else {
2406 /* +1 because of ',' between algorithms */
roman3a95bb22023-10-26 11:07:17 +02002407 *alg_store = nc_realloc(*alg_store, strlen(*alg_store) + strlen(alg) + 1 + 1);
2408 NC_CHECK_ERRMEM_GOTO(!*alg_store, ret = 1, cleanup);
roman08f67f42023-06-08 13:51:54 +02002409 strcat(*alg_store, ",");
2410 strcat(*alg_store, alg);
romanc1d2b092023-02-02 08:58:27 +01002411 }
2412 } else {
2413 /* delete */
romanc135c6d2023-10-25 13:32:30 +02002414 ret = nc_server_config_delete_substring(*alg_store, alg, ',');
2415 if (ret) {
romanc1d2b092023-02-02 08:58:27 +01002416 ERR(NULL, "Unable to delete an algorithm (%s), which was not previously added.", alg);
romanc135c6d2023-10-25 13:32:30 +02002417 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002418 }
2419 }
2420
2421cleanup:
romana6bf6ab2023-05-26 13:26:02 +02002422 free(alg);
romanc1d2b092023-02-02 08:58:27 +01002423 return ret;
2424}
2425
2426/* leaf-list */
2427static int
romane028ef92023-02-24 16:33:08 +01002428nc_server_config_host_key_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002429{
roman5cbb6532023-06-22 12:53:17 +02002430 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002431 const char *alg;
roman5cbb6532023-06-22 12:53:17 +02002432 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002433 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002434
roman5cbb6532023-06-22 12:53:17 +02002435 assert(!strcmp(LYD_NAME(node), "host-key-alg"));
romanc1d2b092023-02-02 08:58:27 +01002436
romanba93eac2023-07-18 14:36:48 +02002437 /* LOCK */
2438 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002439 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002440 return 1;
2441 }
2442
roman8341e8b2023-11-23 16:12:42 +01002443 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002444 ret = 1;
2445 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002446 }
2447
romand05b2ad2024-01-23 12:02:40 +01002448 /* get the algorithm name and append it to supported algs */
roman5cbb6532023-06-22 12:53:17 +02002449 alg = ((struct lyd_node_term *)node)->value.ident->name;
romand05b2ad2024-01-23 12:02:40 +01002450 if (nc_server_config_transport_params(alg, &opts->hostkey_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002451 ret = 1;
romand05b2ad2024-01-23 12:02:40 +01002452 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002453 }
2454
2455cleanup:
romanba93eac2023-07-18 14:36:48 +02002456 if (is_ch(node)) {
2457 /* UNLOCK */
2458 nc_ch_client_unlock(ch_client);
2459 }
romanc1d2b092023-02-02 08:58:27 +01002460 return ret;
2461}
2462
2463/* leaf-list */
2464static int
romane028ef92023-02-24 16:33:08 +01002465nc_server_config_kex_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002466{
roman5cbb6532023-06-22 12:53:17 +02002467 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002468 const char *alg;
roman5cbb6532023-06-22 12:53:17 +02002469 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002470 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002471
roman5cbb6532023-06-22 12:53:17 +02002472 assert(!strcmp(LYD_NAME(node), "key-exchange-alg"));
romanc1d2b092023-02-02 08:58:27 +01002473
romanba93eac2023-07-18 14:36:48 +02002474 /* LOCK */
2475 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002476 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002477 return 1;
2478 }
2479
roman8341e8b2023-11-23 16:12:42 +01002480 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002481 ret = 1;
2482 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002483 }
2484
romand05b2ad2024-01-23 12:02:40 +01002485 /* get the algorithm name and append it to supported algs */
roman5cbb6532023-06-22 12:53:17 +02002486 alg = ((struct lyd_node_term *)node)->value.ident->name;
romand05b2ad2024-01-23 12:02:40 +01002487 if (nc_server_config_transport_params(alg, &opts->kex_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002488 ret = 1;
romand05b2ad2024-01-23 12:02:40 +01002489 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002490 }
2491
2492cleanup:
romanba93eac2023-07-18 14:36:48 +02002493 if (is_ch(node)) {
2494 /* UNLOCK */
2495 nc_ch_client_unlock(ch_client);
2496 }
romanc1d2b092023-02-02 08:58:27 +01002497 return ret;
2498}
2499
2500/* leaf-list */
2501static int
romane028ef92023-02-24 16:33:08 +01002502nc_server_config_encryption_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002503{
roman5cbb6532023-06-22 12:53:17 +02002504 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002505 const char *alg;
roman5cbb6532023-06-22 12:53:17 +02002506 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002507 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002508
roman5cbb6532023-06-22 12:53:17 +02002509 assert(!strcmp(LYD_NAME(node), "encryption-alg"));
romanc1d2b092023-02-02 08:58:27 +01002510
romanba93eac2023-07-18 14:36:48 +02002511 /* LOCK */
2512 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002513 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002514 return 1;
2515 }
2516
roman8341e8b2023-11-23 16:12:42 +01002517 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002518 ret = 1;
2519 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002520 }
2521
romand05b2ad2024-01-23 12:02:40 +01002522 /* get the algorithm name and append it to supported algs */
roman5cbb6532023-06-22 12:53:17 +02002523 alg = ((struct lyd_node_term *)node)->value.ident->name;
romand05b2ad2024-01-23 12:02:40 +01002524 if (nc_server_config_transport_params(alg, &opts->encryption_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002525 ret = 1;
romand05b2ad2024-01-23 12:02:40 +01002526 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002527 }
2528
2529cleanup:
romanba93eac2023-07-18 14:36:48 +02002530 if (is_ch(node)) {
2531 /* UNLOCK */
2532 nc_ch_client_unlock(ch_client);
2533 }
romanc1d2b092023-02-02 08:58:27 +01002534 return ret;
2535}
2536
2537/* leaf-list */
2538static int
romane028ef92023-02-24 16:33:08 +01002539nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01002540{
roman5cbb6532023-06-22 12:53:17 +02002541 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01002542 const char *alg;
roman5cbb6532023-06-22 12:53:17 +02002543 struct nc_server_ssh_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002544 struct nc_ch_client *ch_client = NULL;
romanc1d2b092023-02-02 08:58:27 +01002545
roman5cbb6532023-06-22 12:53:17 +02002546 assert(!strcmp(LYD_NAME(node), "mac-alg"));
romanc1d2b092023-02-02 08:58:27 +01002547
romanba93eac2023-07-18 14:36:48 +02002548 /* LOCK */
2549 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002550 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002551 return 1;
2552 }
2553
roman8341e8b2023-11-23 16:12:42 +01002554 if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) {
roman4cb8bb12023-06-29 09:16:46 +02002555 ret = 1;
2556 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002557 }
2558
romand05b2ad2024-01-23 12:02:40 +01002559 /* get the algorithm name and append it to supported algs */
roman5cbb6532023-06-22 12:53:17 +02002560 alg = ((struct lyd_node_term *)node)->value.ident->name;
romand05b2ad2024-01-23 12:02:40 +01002561 if (nc_server_config_transport_params(alg, &opts->mac_algs, op)) {
romanc1d2b092023-02-02 08:58:27 +01002562 ret = 1;
romand05b2ad2024-01-23 12:02:40 +01002563 goto cleanup;
romanc1d2b092023-02-02 08:58:27 +01002564 }
2565
2566cleanup:
romanba93eac2023-07-18 14:36:48 +02002567 if (is_ch(node)) {
2568 /* UNLOCK */
2569 nc_ch_client_unlock(ch_client);
2570 }
romanc1d2b092023-02-02 08:58:27 +01002571 return ret;
2572}
2573
roman78df0fa2023-11-02 10:33:57 +01002574static int
2575nc_server_config_check_endpt_reference_cycle(struct nc_endpt *original, struct nc_endpt *next)
2576{
2577 if (!next->referenced_endpt_name) {
2578 /* no further reference -> no cycle */
2579 return 0;
2580 }
2581
2582 if (!strcmp(original->name, next->referenced_endpt_name)) {
2583 /* found cycle */
2584 return 1;
2585 } else {
2586 if (nc_server_get_referenced_endpt(next->referenced_endpt_name, &next)) {
2587 /* referenced endpoint does not exist */
2588 return 1;
2589 }
2590
2591 /* continue further */
2592 return nc_server_config_check_endpt_reference_cycle(original, next);
2593 }
2594}
2595
roman0bbc19c2023-05-26 09:59:09 +02002596/**
roman78df0fa2023-11-02 10:33:57 +01002597 * @brief Set all endpoint references.
roman0bbc19c2023-05-26 09:59:09 +02002598 *
2599 * @return 0 on success, 1 on error.
2600 */
2601static int
roman78df0fa2023-11-02 10:33:57 +01002602nc_server_config_check_endpt_references(void)
roman0bbc19c2023-05-26 09:59:09 +02002603{
2604 uint16_t i, j;
roman78df0fa2023-11-02 10:33:57 +01002605 struct nc_endpt *referenced_endpt = NULL;
roman0bbc19c2023-05-26 09:59:09 +02002606
roman78df0fa2023-11-02 10:33:57 +01002607 /* first do listen endpoints */
roman0bbc19c2023-05-26 09:59:09 +02002608 for (i = 0; i < server_opts.endpt_count; i++) {
roman6430c152023-10-12 11:28:47 +02002609 /* go through all the endpoints */
roman0bbc19c2023-05-26 09:59:09 +02002610 if (server_opts.endpts[i].referenced_endpt_name) {
roman78df0fa2023-11-02 10:33:57 +01002611 /* get referenced endpt */
2612 if (nc_server_get_referenced_endpt(server_opts.endpts[i].referenced_endpt_name, &referenced_endpt)) {
2613 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" does not exist.",
roman0bbc19c2023-05-26 09:59:09 +02002614 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2615 return 1;
2616 }
roman78df0fa2023-11-02 10:33:57 +01002617
2618 /* check if the endpoint references itself */
2619 if (&server_opts.endpts[i] == referenced_endpt) {
2620 ERR(NULL, "Endpoint \"%s\" references itself.", server_opts.endpts[i].name);
2621 return 1;
2622 }
2623
2624 /* check transport */
2625 if ((server_opts.endpts[i].ti != referenced_endpt->ti)) {
2626 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" has different transport type.",
2627 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2628 return 1;
roman506354a2024-04-11 09:37:22 +02002629 } else if ((referenced_endpt->ti != NC_TI_SSH) && (referenced_endpt->ti != NC_TI_TLS)) {
roman78df0fa2023-11-02 10:33:57 +01002630 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" has unsupported transport type.",
2631 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2632 return 1;
2633 }
2634
2635 /* check cyclic reference */
2636 if (nc_server_config_check_endpt_reference_cycle(&server_opts.endpts[i], referenced_endpt)) {
2637 ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" creates a cycle.",
2638 server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
2639 return 1;
2640 }
2641
2642 /* all went well, assign the name to the opts, so we can access it for auth */
roman506354a2024-04-11 09:37:22 +02002643 if (server_opts.endpts[i].ti == NC_TI_SSH) {
roman78df0fa2023-11-02 10:33:57 +01002644 server_opts.endpts[i].opts.ssh->referenced_endpt_name = referenced_endpt->name;
2645 } else {
2646 server_opts.endpts[i].opts.tls->referenced_endpt_name = referenced_endpt->name;
2647 }
roman0bbc19c2023-05-26 09:59:09 +02002648 }
2649 }
2650
roman78df0fa2023-11-02 10:33:57 +01002651 /* now check all the call home endpoints */
2652 /* LOCK */
2653 pthread_rwlock_rdlock(&server_opts.ch_client_lock);
2654 for (i = 0; i < server_opts.ch_client_count; i++) {
2655 /* LOCK */
2656 pthread_mutex_lock(&server_opts.ch_clients[i].lock);
2657 for (j = 0; j < server_opts.ch_clients[i].ch_endpt_count; j++) {
2658 if (server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name) {
2659 /* get referenced endpt */
2660 if (nc_server_get_referenced_endpt(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, &referenced_endpt)) {
2661 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" does not exist.",
2662 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
2663 goto ch_fail;
2664 }
2665
2666 /* check transport */
2667 if (server_opts.ch_clients[i].ch_endpts[j].ti != referenced_endpt->ti) {
2668 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" has different transport type.",
2669 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
2670 goto ch_fail;
roman506354a2024-04-11 09:37:22 +02002671 } else if ((referenced_endpt->ti != NC_TI_SSH) && (referenced_endpt->ti != NC_TI_TLS)) {
roman78df0fa2023-11-02 10:33:57 +01002672 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" has unsupported transport type.",
2673 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
2674 goto ch_fail;
2675 }
2676
2677 /* check cyclic reference */
2678 if (nc_server_config_check_endpt_reference_cycle(referenced_endpt, referenced_endpt)) {
2679 ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" creates a cycle.",
2680 server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
2681 goto ch_fail;
2682 }
2683
2684 /* all went well, assign the name to the opts, so we can access it for auth */
roman506354a2024-04-11 09:37:22 +02002685 if (server_opts.ch_clients[i].ch_endpts[j].ti == NC_TI_SSH) {
roman78df0fa2023-11-02 10:33:57 +01002686 server_opts.ch_clients[i].ch_endpts[j].opts.ssh->referenced_endpt_name = referenced_endpt->name;
2687 } else {
2688 server_opts.ch_clients[i].ch_endpts[j].opts.tls->referenced_endpt_name = referenced_endpt->name;
2689 }
2690 }
2691 }
2692 /* UNLOCK */
2693 pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
2694 }
2695
2696 /* UNLOCK */
2697 pthread_rwlock_unlock(&server_opts.ch_client_lock);
roman0bbc19c2023-05-26 09:59:09 +02002698 return 0;
roman78df0fa2023-11-02 10:33:57 +01002699
2700ch_fail:
2701 /* UNLOCK */
2702 pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
2703 /* UNLOCK */
2704 pthread_rwlock_unlock(&server_opts.ch_client_lock);
roman96c27f92023-11-02 11:09:46 +01002705 return 1;
roman0bbc19c2023-05-26 09:59:09 +02002706}
2707
2708static int
roman78df0fa2023-11-02 10:33:57 +01002709nc_server_config_endpoint_reference(const struct lyd_node *node, NC_OPERATION op)
roman0bbc19c2023-05-26 09:59:09 +02002710{
2711 int ret = 0;
roman78df0fa2023-11-02 10:33:57 +01002712 struct nc_endpt *endpt = NULL;
roman8341e8b2023-11-23 16:12:42 +01002713 struct nc_ch_client *ch_client = NULL;
roman78df0fa2023-11-02 10:33:57 +01002714 struct nc_ch_endpt *ch_endpt = NULL;
2715 struct nc_server_ssh_opts *ssh = NULL;
2716 struct nc_server_tls_opts *tls = NULL;
roman0bbc19c2023-05-26 09:59:09 +02002717
roman78df0fa2023-11-02 10:33:57 +01002718 assert(!strcmp(LYD_NAME(node), "endpoint-reference"));
roman0bbc19c2023-05-26 09:59:09 +02002719
roman78df0fa2023-11-02 10:33:57 +01002720 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
2721 /* to avoid unlock on fail */
2722 return 1;
2723 }
2724
2725 /* get endpt */
2726 if (is_listen(node)) {
2727 ret = nc_server_config_get_endpt(node, &endpt, NULL);
2728 } else {
roman8341e8b2023-11-23 16:12:42 +01002729 ret = nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt);
roman78df0fa2023-11-02 10:33:57 +01002730 }
roman0bbc19c2023-05-26 09:59:09 +02002731 if (ret) {
2732 goto cleanup;
2733 }
2734
2735 if (op == NC_OP_DELETE) {
roman78df0fa2023-11-02 10:33:57 +01002736 if (endpt) {
romanb7bfa652023-11-09 12:36:35 +01002737 /* listen */
roman78df0fa2023-11-02 10:33:57 +01002738 free(endpt->referenced_endpt_name);
2739 endpt->referenced_endpt_name = NULL;
roman2e797ef2023-06-19 10:47:49 +02002740 } else {
romanb7bfa652023-11-09 12:36:35 +01002741 /* call home */
roman78df0fa2023-11-02 10:33:57 +01002742 free(ch_endpt->referenced_endpt_name);
2743 ch_endpt->referenced_endpt_name = NULL;
roman2e797ef2023-06-19 10:47:49 +02002744 }
roman78df0fa2023-11-02 10:33:57 +01002745 if (is_ssh(node)) {
roman8341e8b2023-11-23 16:12:42 +01002746 if (nc_server_config_get_ssh_opts(node, ch_client, &ssh)) {
roman78df0fa2023-11-02 10:33:57 +01002747 ret = 1;
2748 goto cleanup;
2749 }
roman96c27f92023-11-02 11:09:46 +01002750
roman78df0fa2023-11-02 10:33:57 +01002751 ssh->referenced_endpt_name = NULL;
2752 } else {
roman8341e8b2023-11-23 16:12:42 +01002753 if (nc_server_config_get_tls_opts(node, ch_client, &tls)) {
roman78df0fa2023-11-02 10:33:57 +01002754 ret = 1;
2755 goto cleanup;
2756 }
roman0bbc19c2023-05-26 09:59:09 +02002757
roman78df0fa2023-11-02 10:33:57 +01002758 tls->referenced_endpt_name = NULL;
roman0bbc19c2023-05-26 09:59:09 +02002759 }
roman0bbc19c2023-05-26 09:59:09 +02002760
roman0bbc19c2023-05-26 09:59:09 +02002761 goto cleanup;
roman2e797ef2023-06-19 10:47:49 +02002762 } else {
roman78df0fa2023-11-02 10:33:57 +01002763 /* just set the name, check it once configuring of all nodes is done */
2764 if (endpt) {
2765 free(endpt->referenced_endpt_name);
2766 endpt->referenced_endpt_name = strdup(lyd_get_value(node));
2767 NC_CHECK_ERRMEM_GOTO(!endpt->referenced_endpt_name, ret = 1, cleanup);
2768 } else {
2769 free(ch_endpt->referenced_endpt_name);
2770 ch_endpt->referenced_endpt_name = strdup(lyd_get_value(node));
2771 NC_CHECK_ERRMEM_GOTO(!ch_endpt->referenced_endpt_name, ret = 1, cleanup);
2772 }
2773
2774 goto cleanup;
roman2e797ef2023-06-19 10:47:49 +02002775 }
roman0bbc19c2023-05-26 09:59:09 +02002776
2777cleanup:
roman78df0fa2023-11-02 10:33:57 +01002778 if (is_ch(node)) {
2779 /* UNLOCK */
2780 nc_ch_client_unlock(ch_client);
2781 }
2782
roman0bbc19c2023-05-26 09:59:09 +02002783 return ret;
2784}
2785
roman3f9b65c2023-06-05 14:26:58 +02002786static int
roman3f9b65c2023-06-05 14:26:58 +02002787nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op)
2788{
2789 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02002790 struct nc_certificate *cert;
romanb6f44032023-06-30 15:07:56 +02002791 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002792 struct nc_ch_client *ch_client = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002793
2794 assert(!strcmp(LYD_NAME(node), "cert-data"));
2795
romanba93eac2023-07-18 14:36:48 +02002796 /* LOCK */
2797 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002798 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002799 return 1;
2800 }
2801
romanb6f44032023-06-30 15:07:56 +02002802 if (equal_parent_name(node, 3, "server-identity")) {
roman8341e8b2023-11-23 16:12:42 +01002803 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
romanb6f44032023-06-30 15:07:56 +02002804 ret = 1;
2805 goto cleanup;
2806 }
roman3f9b65c2023-06-05 14:26:58 +02002807
roman3f9b65c2023-06-05 14:26:58 +02002808 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002809 free(opts->cert_data);
2810 opts->cert_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002811 NC_CHECK_ERRMEM_GOTO(!opts->cert_data, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02002812 }
roman6430c152023-10-12 11:28:47 +02002813 } else if (equal_parent_name(node, 3, "ca-certs") || equal_parent_name(node, 3, "ee-certs")) {
roman8341e8b2023-11-23 16:12:42 +01002814 if (nc_server_config_get_cert(node, ch_client, &cert)) {
roman3f9b65c2023-06-05 14:26:58 +02002815 ret = 1;
2816 goto cleanup;
2817 }
2818
2819 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02002820 free(cert->data);
2821 cert->data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002822 NC_CHECK_ERRMEM_GOTO(!cert->data, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02002823 } else {
roman6430c152023-10-12 11:28:47 +02002824 free(cert->data);
2825 cert->data = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002826 }
2827 }
2828
2829cleanup:
romanba93eac2023-07-18 14:36:48 +02002830 if (is_ch(node)) {
2831 /* UNLOCK */
2832 nc_ch_client_unlock(ch_client);
2833 }
roman3f9b65c2023-06-05 14:26:58 +02002834 return ret;
2835}
2836
2837static int
roman3f9b65c2023-06-05 14:26:58 +02002838nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op)
2839{
2840 int ret = 0;
roman78df0fa2023-11-02 10:33:57 +01002841 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002842 struct nc_ch_client *ch_client = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002843
2844 assert(!strcmp(LYD_NAME(node), "asymmetric-key"));
2845
romanba93eac2023-07-18 14:36:48 +02002846 /* LOCK */
2847 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002848 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002849 return 1;
2850 }
2851
roman8341e8b2023-11-23 16:12:42 +01002852 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02002853 ret = 1;
2854 goto cleanup;
2855 }
2856
2857 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2858 /* set to keystore */
roman78df0fa2023-11-02 10:33:57 +01002859 opts->store = NC_STORE_KEYSTORE;
roman3f9b65c2023-06-05 14:26:58 +02002860
roman78df0fa2023-11-02 10:33:57 +01002861 free(opts->key_ref);
2862 opts->key_ref = strdup(lyd_get_value(node));
2863 NC_CHECK_ERRMEM_GOTO(!opts->key_ref, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02002864 } else {
roman78df0fa2023-11-02 10:33:57 +01002865 free(opts->key_ref);
2866 opts->key_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002867 }
2868
2869cleanup:
romanba93eac2023-07-18 14:36:48 +02002870 if (is_ch(node)) {
2871 /* UNLOCK */
2872 nc_ch_client_unlock(ch_client);
2873 }
roman3f9b65c2023-06-05 14:26:58 +02002874 return ret;
2875}
2876
2877static int
roman3f9b65c2023-06-05 14:26:58 +02002878nc_server_config_create_ca_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
2879{
2880 assert(!strcmp(LYD_NAME(node), "certificate"));
2881
2882 node = lyd_child(node);
2883 assert(!strcmp(LYD_NAME(node), "name"));
2884
Michal Vaskocf898172024-01-15 15:04:28 +01002885 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ca_certs.certs, sizeof *opts->ca_certs.certs,
2886 &opts->ca_certs.cert_count);
roman3f9b65c2023-06-05 14:26:58 +02002887}
2888
2889static int
2890nc_server_config_create_ee_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts)
2891{
2892 assert(!strcmp(LYD_NAME(node), "certificate"));
2893
2894 node = lyd_child(node);
2895 assert(!strcmp(LYD_NAME(node), "name"));
2896
Michal Vaskocf898172024-01-15 15:04:28 +01002897 return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ee_certs.certs, sizeof *opts->ee_certs.certs,
2898 &opts->ee_certs.cert_count);
roman3f9b65c2023-06-05 14:26:58 +02002899}
2900
2901static int
2902nc_server_config_certificate(const struct lyd_node *node, NC_OPERATION op)
2903{
2904 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02002905 struct nc_server_tls_opts *opts;
roman8341e8b2023-11-23 16:12:42 +01002906 struct nc_ch_client *ch_client = NULL;
roman6430c152023-10-12 11:28:47 +02002907 struct nc_certificate *cert;
roman3f9b65c2023-06-05 14:26:58 +02002908
2909 assert(!strcmp(LYD_NAME(node), "certificate"));
2910
romanba93eac2023-07-18 14:36:48 +02002911 /* LOCK */
2912 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02002913 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02002914 return 1;
2915 }
2916
roman8341e8b2023-11-23 16:12:42 +01002917 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02002918 ret = 1;
2919 goto cleanup;
2920 }
2921
Michal Vaskocf898172024-01-15 15:04:28 +01002922 if (equal_parent_name(node, 1, "central-keystore-reference")) {
romanb6f44032023-06-30 15:07:56 +02002923 /* TLS server-identity */
roman3f9b65c2023-06-05 14:26:58 +02002924 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
2925 /* set to keystore */
romanb6f44032023-06-30 15:07:56 +02002926 opts->store = NC_STORE_KEYSTORE;
roman3f9b65c2023-06-05 14:26:58 +02002927
roman6430c152023-10-12 11:28:47 +02002928 free(opts->cert_ref);
2929 opts->cert_ref = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02002930 NC_CHECK_ERRMEM_GOTO(!opts->cert_ref, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02002931 } else {
roman6430c152023-10-12 11:28:47 +02002932 free(opts->cert_ref);
romanb6f44032023-06-30 15:07:56 +02002933 opts->cert_ref = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002934 }
romanb6f44032023-06-30 15:07:56 +02002935 } else if (equal_parent_name(node, 2, "ca-certs")) {
2936 /* TLS client auth certificate authority */
roman3f9b65c2023-06-05 14:26:58 +02002937 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02002938 ret = nc_server_config_create_ca_certs_certificate(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02002939 if (ret) {
2940 goto cleanup;
2941 }
2942 } else {
roman8341e8b2023-11-23 16:12:42 +01002943 if (nc_server_config_get_cert(node, ch_client, &cert)) {
roman6430c152023-10-12 11:28:47 +02002944 ret = 1;
2945 goto cleanup;
2946 }
2947 nc_server_config_del_cert(&opts->ca_certs, cert);
roman3f9b65c2023-06-05 14:26:58 +02002948 }
romanb6f44032023-06-30 15:07:56 +02002949 } else if (equal_parent_name(node, 2, "ee-certs")) {
2950 /* TLS client auth end entity */
roman3f9b65c2023-06-05 14:26:58 +02002951 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02002952 ret = nc_server_config_create_ee_certs_certificate(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02002953 if (ret) {
2954 goto cleanup;
2955 }
2956 } else {
roman8341e8b2023-11-23 16:12:42 +01002957 if (nc_server_config_get_cert(node, ch_client, &cert)) {
roman6430c152023-10-12 11:28:47 +02002958 ret = 1;
2959 goto cleanup;
2960 }
2961 nc_server_config_del_cert(&opts->ee_certs, cert);
roman3f9b65c2023-06-05 14:26:58 +02002962 }
2963 }
2964
2965cleanup:
romanba93eac2023-07-18 14:36:48 +02002966 if (is_ch(node)) {
2967 /* UNLOCK */
2968 nc_ch_client_unlock(ch_client);
2969 }
roman3f9b65c2023-06-05 14:26:58 +02002970 return ret;
2971}
2972
2973static int
2974nc_server_config_create_cert_to_name(const struct lyd_node *node, struct nc_server_tls_opts *opts)
2975{
2976 int ret = 0;
2977 struct lyd_node *n;
2978 struct nc_ctn *new, *iter;
Michal Vasko3392b4a2024-02-02 08:57:53 +01002979 const char *map_type, *name = NULL;
roman3f9b65c2023-06-05 14:26:58 +02002980 uint32_t id;
2981 NC_TLS_CTN_MAPTYPE m_type;
2982
2983 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
2984
roman3f9b65c2023-06-05 14:26:58 +02002985 /* find the list's key */
2986 lyd_find_path(node, "id", 0, &n);
2987 assert(n);
roman9cdb7b52023-10-25 13:59:55 +02002988 id = ((struct lyd_node_term *)n)->value.uint32;
roman3f9b65c2023-06-05 14:26:58 +02002989
Michal Vasko3392b4a2024-02-02 08:57:53 +01002990 /* get CTN map-type */
2991 if (lyd_find_path(node, "map-type", 0, &n)) {
2992 ERR(NULL, "Missing CTN map-type.");
2993 ret = 1;
2994 goto cleanup;
2995 }
roman3f9b65c2023-06-05 14:26:58 +02002996 map_type = ((struct lyd_node_term *)n)->value.ident->name;
2997 if (!strcmp(map_type, "specified")) {
2998 m_type = NC_TLS_CTN_SPECIFIED;
Michal Vasko3392b4a2024-02-02 08:57:53 +01002999
3000 /* get CTN name */
3001 if (lyd_find_path(node, "name", 0, &n)) {
3002 ERR(NULL, "Missing CTN \"specified\" user name.");
3003 ret = 1;
3004 goto cleanup;
3005 }
3006 name = lyd_get_value(n);
roman3f9b65c2023-06-05 14:26:58 +02003007 } else if (!strcmp(map_type, "san-rfc822-name")) {
3008 m_type = NC_TLS_CTN_SAN_RFC822_NAME;
3009 } else if (!strcmp(map_type, "san-dns-name")) {
3010 m_type = NC_TLS_CTN_SAN_DNS_NAME;
3011 } else if (!strcmp(map_type, "san-ip-address")) {
3012 m_type = NC_TLS_CTN_SAN_IP_ADDRESS;
3013 } else if (!strcmp(map_type, "san-any")) {
3014 m_type = NC_TLS_CTN_SAN_ANY;
3015 } else if (!strcmp(map_type, "common-name")) {
3016 m_type = NC_TLS_CTN_COMMON_NAME;
3017 } else {
Michal Vasko3392b4a2024-02-02 08:57:53 +01003018 ERR(NULL, "CTN map-type \"%s\" not supported.", map_type);
roman3f9b65c2023-06-05 14:26:58 +02003019 ret = 1;
3020 goto cleanup;
3021 }
3022
roman6430c152023-10-12 11:28:47 +02003023 /* create new ctn */
3024 new = calloc(1, sizeof *new);
roman3a95bb22023-10-26 11:07:17 +02003025 NC_CHECK_ERRMEM_GOTO(!new, ret = 1, cleanup);
roman6430c152023-10-12 11:28:47 +02003026
roman3f9b65c2023-06-05 14:26:58 +02003027 /* find the right place for insertion */
3028 if (!opts->ctn) {
3029 /* inserting the first one */
3030 opts->ctn = new;
Roytak421eb0c2023-08-01 22:18:27 +02003031 } else if (opts->ctn->id > id) {
roman3f9b65c2023-06-05 14:26:58 +02003032 /* insert at the beginning */
3033 new->next = opts->ctn;
3034 opts->ctn = new;
3035 } else {
3036 /* have to find the right place */
Roytak421eb0c2023-08-01 22:18:27 +02003037 for (iter = opts->ctn; iter->next && iter->next->id <= id; iter = iter->next) {}
3038 if (iter->id == id) {
Michal Vasko3392b4a2024-02-02 08:57:53 +01003039 /* collision, replace */
romanb7bfa652023-11-09 12:36:35 +01003040 free(new);
roman3f9b65c2023-06-05 14:26:58 +02003041 new = iter;
Michal Vasko3392b4a2024-02-02 08:57:53 +01003042 free(new->name);
3043 new->name = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003044 } else {
3045 new->next = iter->next;
3046 iter->next = new;
3047 }
3048 }
3049
3050 /* insert the right data */
3051 new->id = id;
Michal Vasko3392b4a2024-02-02 08:57:53 +01003052 if (name) {
3053 new->name = strdup(name);
3054 NC_CHECK_ERRMEM_GOTO(!new->name, ret = 1, cleanup);
3055 }
roman3f9b65c2023-06-05 14:26:58 +02003056 new->map_type = m_type;
3057
3058cleanup:
3059 return ret;
3060}
3061
3062static int
3063nc_server_config_cert_to_name(const struct lyd_node *node, NC_OPERATION op)
3064{
3065 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003066 struct nc_server_tls_opts *opts;
roman3f9b65c2023-06-05 14:26:58 +02003067 struct nc_ctn *ctn;
roman8341e8b2023-11-23 16:12:42 +01003068 struct nc_ch_client *ch_client = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003069
3070 assert(!strcmp(LYD_NAME(node), "cert-to-name"));
3071
romanba93eac2023-07-18 14:36:48 +02003072 /* LOCK */
3073 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003074 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003075 return 1;
3076 }
3077
roman8341e8b2023-11-23 16:12:42 +01003078 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman3f9b65c2023-06-05 14:26:58 +02003079 ret = 1;
3080 goto cleanup;
3081 }
3082
3083 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romanb6f44032023-06-30 15:07:56 +02003084 ret = nc_server_config_create_cert_to_name(node, opts);
roman3f9b65c2023-06-05 14:26:58 +02003085 if (ret) {
3086 goto cleanup;
3087 }
3088 } else {
3089 /* find the given ctn entry */
roman8341e8b2023-11-23 16:12:42 +01003090 if (nc_server_config_get_ctn(node, ch_client, &ctn)) {
roman3f9b65c2023-06-05 14:26:58 +02003091 ret = 1;
3092 goto cleanup;
3093 }
romanb6f44032023-06-30 15:07:56 +02003094 nc_server_config_del_ctn(opts, ctn);
roman3f9b65c2023-06-05 14:26:58 +02003095 }
3096
3097cleanup:
romanba93eac2023-07-18 14:36:48 +02003098 if (is_ch(node)) {
3099 /* UNLOCK */
3100 nc_ch_client_unlock(ch_client);
3101 }
roman3f9b65c2023-06-05 14:26:58 +02003102 return ret;
3103}
3104
3105static int
roman3f9b65c2023-06-05 14:26:58 +02003106nc_server_config_fingerprint(const struct lyd_node *node, NC_OPERATION op)
3107{
3108 int ret = 0;
roman3f9b65c2023-06-05 14:26:58 +02003109 struct nc_ctn *ctn;
roman8341e8b2023-11-23 16:12:42 +01003110 struct nc_ch_client *ch_client = NULL;
romanba93eac2023-07-18 14:36:48 +02003111
3112 assert(!strcmp(LYD_NAME(node), "fingerprint"));
3113
3114 /* LOCK */
3115 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003116 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003117 return 1;
3118 }
roman3f9b65c2023-06-05 14:26:58 +02003119
roman8341e8b2023-11-23 16:12:42 +01003120 if (nc_server_config_get_ctn(node, ch_client, &ctn)) {
roman3f9b65c2023-06-05 14:26:58 +02003121 ret = 1;
3122 goto cleanup;
3123 }
3124
3125 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003126 free(ctn->fingerprint);
3127 ctn->fingerprint = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003128 NC_CHECK_ERRMEM_GOTO(!ctn->fingerprint, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +02003129 } else {
roman6430c152023-10-12 11:28:47 +02003130 free(ctn->fingerprint);
3131 ctn->fingerprint = NULL;
roman3f9b65c2023-06-05 14:26:58 +02003132 }
3133
3134cleanup:
romanba93eac2023-07-18 14:36:48 +02003135 if (is_ch(node)) {
3136 /* UNLOCK */
3137 nc_ch_client_unlock(ch_client);
3138 }
roman3f9b65c2023-06-05 14:26:58 +02003139 return ret;
3140}
3141
roman12644fe2023-06-08 11:06:42 +02003142static int
3143nc_server_config_tls_version(const struct lyd_node *node, NC_OPERATION op)
3144{
3145 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003146 struct nc_server_tls_opts *opts;
roman12644fe2023-06-08 11:06:42 +02003147 const char *version = NULL;
roman8341e8b2023-11-23 16:12:42 +01003148 struct nc_ch_client *ch_client = NULL;
roman6430c152023-10-12 11:28:47 +02003149 NC_TLS_VERSION tls_version;
roman12644fe2023-06-08 11:06:42 +02003150
3151 assert(!strcmp(LYD_NAME(node), "tls-version"));
3152
romanba93eac2023-07-18 14:36:48 +02003153 /* LOCK */
3154 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003155 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003156 return 1;
3157 }
3158
roman8341e8b2023-11-23 16:12:42 +01003159 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman12644fe2023-06-08 11:06:42 +02003160 ret = 1;
3161 goto cleanup;
3162 }
3163
roman6430c152023-10-12 11:28:47 +02003164 /* str to tls_version */
roman12644fe2023-06-08 11:06:42 +02003165 version = ((struct lyd_node_term *)node)->value.ident->name;
3166 if (!strcmp(version, "tls10")) {
roman6430c152023-10-12 11:28:47 +02003167 tls_version = NC_TLS_VERSION_10;
roman12644fe2023-06-08 11:06:42 +02003168 } else if (!strcmp(version, "tls11")) {
roman6430c152023-10-12 11:28:47 +02003169 tls_version = NC_TLS_VERSION_11;
roman12644fe2023-06-08 11:06:42 +02003170 } else if (!strcmp(version, "tls12")) {
roman6430c152023-10-12 11:28:47 +02003171 tls_version = NC_TLS_VERSION_12;
roman12644fe2023-06-08 11:06:42 +02003172 } else if (!strcmp(version, "tls13")) {
roman6430c152023-10-12 11:28:47 +02003173 tls_version = NC_TLS_VERSION_13;
roman12644fe2023-06-08 11:06:42 +02003174 } else {
3175 ERR(NULL, "TLS version \"%s\" not supported.", version);
3176 ret = 1;
3177 goto cleanup;
3178 }
3179
roman6430c152023-10-12 11:28:47 +02003180 if (op == NC_OP_CREATE) {
3181 /* add the version if it isn't there already */
3182 opts->tls_versions |= tls_version;
3183 } else if ((op == NC_OP_DELETE) && (opts->tls_versions & tls_version)) {
3184 /* delete the version if it is there */
roman84fe3252023-10-25 11:28:32 +02003185 opts->tls_versions &= ~tls_version;
roman6430c152023-10-12 11:28:47 +02003186 }
3187
roman12644fe2023-06-08 11:06:42 +02003188cleanup:
romanba93eac2023-07-18 14:36:48 +02003189 if (is_ch(node)) {
3190 /* UNLOCK */
3191 nc_ch_client_unlock(ch_client);
3192 }
roman12644fe2023-06-08 11:06:42 +02003193 return ret;
3194}
3195
3196static int
3197nc_server_config_create_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher)
3198{
3199 int ret = 0;
roman506354a2024-04-11 09:37:22 +02003200 char *processed_cipher = NULL;
roman12644fe2023-06-08 11:06:42 +02003201
roman506354a2024-04-11 09:37:22 +02003202 ret = nc_tls_process_cipher_suite_wrap(cipher, &processed_cipher);
3203 if (ret) {
3204 ERR(NULL, "Failed to process the cipher suite \"%s\".", cipher);
3205 goto cleanup;
roman12644fe2023-06-08 11:06:42 +02003206 }
roman12644fe2023-06-08 11:06:42 +02003207
roman506354a2024-04-11 09:37:22 +02003208 ret = nc_tls_append_cipher_suite_wrap(opts, processed_cipher);
3209 if (ret) {
3210 ERR(NULL, "Failed to append the cipher suite \"%s\".", cipher);
3211 goto cleanup;
roman12644fe2023-06-08 11:06:42 +02003212 }
3213
3214cleanup:
roman506354a2024-04-11 09:37:22 +02003215 free(processed_cipher);
roman12644fe2023-06-08 11:06:42 +02003216 return ret;
3217}
3218
3219static int
romanb6f44032023-06-30 15:07:56 +02003220nc_server_config_del_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher)
roman12644fe2023-06-08 11:06:42 +02003221{
romanc135c6d2023-10-25 13:32:30 +02003222 int ret = 0;
roman12644fe2023-06-08 11:06:42 +02003223
romanc135c6d2023-10-25 13:32:30 +02003224 ret = nc_server_config_delete_substring(opts->ciphers, cipher, ':');
3225 if (ret) {
roman12644fe2023-06-08 11:06:42 +02003226 ERR(NULL, "Unable to delete a cipher (%s), which was not previously added.", cipher);
3227 return 1;
3228 }
3229
3230 return 0;
3231}
3232
3233static int
3234nc_server_config_cipher_suite(const struct lyd_node *node, NC_OPERATION op)
3235{
3236 int ret = 0;
romanb6f44032023-06-30 15:07:56 +02003237 struct nc_server_tls_opts *opts;
roman12644fe2023-06-08 11:06:42 +02003238 const char *cipher = NULL;
roman8341e8b2023-11-23 16:12:42 +01003239 struct nc_ch_client *ch_client = NULL;
roman12644fe2023-06-08 11:06:42 +02003240
romanfaecc582023-06-15 16:13:31 +02003241 assert(!strcmp(LYD_NAME(node), "cipher-suite"));
3242
romanba93eac2023-07-18 14:36:48 +02003243 /* LOCK */
3244 if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003245 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003246 return 1;
3247 }
3248
roman8341e8b2023-11-23 16:12:42 +01003249 if (nc_server_config_get_tls_opts(node, ch_client, &opts)) {
roman12644fe2023-06-08 11:06:42 +02003250 ret = 1;
3251 goto cleanup;
3252 }
3253
3254 cipher = ((struct lyd_node_term *)node)->value.ident->name;
3255 if (op == NC_OP_CREATE) {
romanb6f44032023-06-30 15:07:56 +02003256 ret = nc_server_config_create_cipher_suite(opts, cipher);
roman12644fe2023-06-08 11:06:42 +02003257 if (ret) {
3258 goto cleanup;
3259 }
3260 } else if (op == NC_OP_DELETE) {
romanb6f44032023-06-30 15:07:56 +02003261 ret = nc_server_config_del_cipher_suite(opts, cipher);
roman12644fe2023-06-08 11:06:42 +02003262 if (ret) {
3263 goto cleanup;
3264 }
3265 }
3266
3267cleanup:
romanba93eac2023-07-18 14:36:48 +02003268 if (is_ch(node)) {
3269 /* UNLOCK */
3270 nc_ch_client_unlock(ch_client);
3271 }
roman12644fe2023-06-08 11:06:42 +02003272 return ret;
3273}
3274
roman2eab4742023-06-06 10:00:26 +02003275#endif /* NC_ENABLED_SSH_TLS */
roman3f9b65c2023-06-05 14:26:58 +02003276
roman83683fb2023-02-24 09:15:23 +01003277static int
roman5cbb6532023-06-22 12:53:17 +02003278nc_server_config_create_netconf_client(const struct lyd_node *node)
3279{
3280 int ret = 0;
3281
3282 node = lyd_child(node);
3283 assert(!strcmp(LYD_NAME(node), "name"));
3284
3285 /* LOCK */
3286 pthread_rwlock_wrlock(&server_opts.ch_client_lock);
3287
3288 ret = nc_server_config_realloc(lyd_get_value(node), (void **)&server_opts.ch_clients, sizeof *server_opts.ch_clients, &server_opts.ch_client_count);
3289 if (ret) {
3290 goto cleanup;
3291 }
3292
3293 server_opts.ch_clients[server_opts.ch_client_count - 1].id = ATOMIC_INC_RELAXED(server_opts.new_client_id);
3294 server_opts.ch_clients[server_opts.ch_client_count - 1].start_with = NC_CH_FIRST_LISTED;
roman6430c152023-10-12 11:28:47 +02003295 server_opts.ch_clients[server_opts.ch_client_count - 1].max_attempts = 3;
roman5cbb6532023-06-22 12:53:17 +02003296
3297 pthread_mutex_init(&server_opts.ch_clients[server_opts.ch_client_count - 1].lock, NULL);
3298
3299cleanup:
3300 /* UNLOCK */
3301 pthread_rwlock_unlock(&server_opts.ch_client_lock);
3302 return ret;
3303}
3304
3305static int
3306nc_server_config_netconf_client(const struct lyd_node *node, NC_OPERATION op)
3307{
3308 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02003309
3310 assert(!strcmp(LYD_NAME(node), "netconf-client"));
3311
3312 if (op == NC_OP_CREATE) {
3313 ret = nc_server_config_create_netconf_client(node);
3314 if (ret) {
3315 goto cleanup;
3316 }
roman450c00b2023-11-02 10:31:45 +01003317
roman96c27f92023-11-02 11:09:46 +01003318#ifdef NC_ENABLED_SSH_TLS
roman450c00b2023-11-02 10:31:45 +01003319 if (server_opts.ch_dispatch_data.acquire_ctx_cb && server_opts.ch_dispatch_data.release_ctx_cb &&
roman96c27f92023-11-02 11:09:46 +01003320 server_opts.ch_dispatch_data.new_session_cb) {
roman450c00b2023-11-02 10:31:45 +01003321 /* we have all we need for dispatching a new call home thread */
3322 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 +01003323 server_opts.ch_dispatch_data.release_ctx_cb, server_opts.ch_dispatch_data.ctx_cb_data,
3324 server_opts.ch_dispatch_data.new_session_cb, server_opts.ch_dispatch_data.new_session_cb_data);
roman450c00b2023-11-02 10:31:45 +01003325 if (ret) {
3326 ERR(NULL, "Dispatching a new Call Home thread failed for Call Home client \"%s\".", lyd_get_value(lyd_child(node)));
3327 goto cleanup;
3328 }
3329 }
roman96c27f92023-11-02 11:09:46 +01003330#endif /* NC_ENABLED_SSH_TLS */
roman5cbb6532023-06-22 12:53:17 +02003331 } else if (op == NC_OP_DELETE) {
roman8341e8b2023-11-23 16:12:42 +01003332 nc_server_config_ch_del_client(node);
roman5cbb6532023-06-22 12:53:17 +02003333 }
3334
3335cleanup:
3336 return ret;
3337}
3338
3339#ifdef NC_ENABLED_SSH_TLS
3340
3341static int
3342nc_server_config_remote_address(const struct lyd_node *node, NC_OPERATION op)
3343{
3344 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02003345 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01003346 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02003347
romanb6f44032023-06-30 15:07:56 +02003348 assert(!strcmp(LYD_NAME(node), "remote-address"));
3349
romanba93eac2023-07-18 14:36:48 +02003350 /* LOCK */
3351 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003352 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003353 return 1;
3354 }
3355
roman8341e8b2023-11-23 16:12:42 +01003356 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02003357 ret = 1;
3358 goto cleanup;
3359 }
3360
3361 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman6430c152023-10-12 11:28:47 +02003362 free(ch_endpt->address);
roman5cbb6532023-06-22 12:53:17 +02003363 ch_endpt->address = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +02003364 NC_CHECK_ERRMEM_GOTO(!ch_endpt->address, ret = 1, cleanup);
roman5cbb6532023-06-22 12:53:17 +02003365 } else {
roman6430c152023-10-12 11:28:47 +02003366 free(ch_endpt->address);
3367 ch_endpt->address = NULL;
roman5cbb6532023-06-22 12:53:17 +02003368 }
3369
3370cleanup:
romanba93eac2023-07-18 14:36:48 +02003371 /* UNLOCK */
3372 nc_ch_client_unlock(ch_client);
roman5cbb6532023-06-22 12:53:17 +02003373 return ret;
3374}
3375
3376static int
3377nc_server_config_remote_port(const struct lyd_node *node, NC_OPERATION op)
3378{
3379 int ret = 0;
roman5cbb6532023-06-22 12:53:17 +02003380 struct nc_ch_endpt *ch_endpt;
roman8341e8b2023-11-23 16:12:42 +01003381 struct nc_ch_client *ch_client = NULL;
roman5cbb6532023-06-22 12:53:17 +02003382
romanb6f44032023-06-30 15:07:56 +02003383 assert(!strcmp(LYD_NAME(node), "remote-port"));
3384
romanba93eac2023-07-18 14:36:48 +02003385 /* LOCK */
3386 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003387 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003388 return 1;
3389 }
3390
roman8341e8b2023-11-23 16:12:42 +01003391 if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) {
roman5cbb6532023-06-22 12:53:17 +02003392 ret = 1;
3393 goto cleanup;
3394 }
3395
3396 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02003397 ch_endpt->port = ((struct lyd_node_term *)node)->value.uint16;
roman5cbb6532023-06-22 12:53:17 +02003398 } else {
3399 ch_endpt->port = 0;
3400 }
3401
3402cleanup:
romanba93eac2023-07-18 14:36:48 +02003403 /* UNLOCK */
3404 nc_ch_client_unlock(ch_client);
roman5cbb6532023-06-22 12:53:17 +02003405 return ret;
3406}
3407
3408#endif /* NC_ENABLED_SSH_TLS */
3409
3410static int
romanb6f44032023-06-30 15:07:56 +02003411nc_server_config_persistent(const struct lyd_node *node, NC_OPERATION op)
3412{
3413 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003414 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003415
3416 assert(!strcmp(LYD_NAME(node), "persistent"));
3417
3418 (void) op;
3419
romanba93eac2023-07-18 14:36:48 +02003420 /* LOCK */
3421 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003422 /* to avoid unlock on fail */
3423 return 1;
romanb6f44032023-06-30 15:07:56 +02003424 }
3425
3426 ch_client->conn_type = NC_CH_PERSIST;
3427
romanba93eac2023-07-18 14:36:48 +02003428 /* UNLOCK */
3429 nc_ch_client_unlock(ch_client);
3430
romanb6f44032023-06-30 15:07:56 +02003431 return ret;
3432}
3433
3434static int
3435nc_server_config_periodic(const struct lyd_node *node, NC_OPERATION op)
3436{
3437 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003438 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003439
3440 assert(!strcmp(LYD_NAME(node), "periodic"));
3441
3442 (void) op;
3443
romanba93eac2023-07-18 14:36:48 +02003444 /* LOCK */
3445 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003446 /* to avoid unlock on fail */
3447 return 1;
romanb6f44032023-06-30 15:07:56 +02003448 }
3449
3450 ch_client->conn_type = NC_CH_PERIOD;
3451 /* set default values */
3452 ch_client->period = 60;
3453 ch_client->anchor_time = 0;
3454 ch_client->idle_timeout = 180;
3455
romanba93eac2023-07-18 14:36:48 +02003456 /* UNLOCK */
3457 nc_ch_client_unlock(ch_client);
3458
romanb6f44032023-06-30 15:07:56 +02003459 return ret;
3460}
3461
3462static int
3463nc_server_config_period(const struct lyd_node *node, NC_OPERATION op)
3464{
3465 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003466 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003467
3468 assert(!strcmp(LYD_NAME(node), "period"));
3469
romanba93eac2023-07-18 14:36:48 +02003470 /* LOCK */
3471 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003472 /* to avoid unlock on fail */
3473 return 1;
romanb6f44032023-06-30 15:07:56 +02003474 }
3475
3476 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02003477 ch_client->period = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02003478 } else if (op == NC_OP_DELETE) {
3479 ch_client->period = 60;
3480 }
3481
romanba93eac2023-07-18 14:36:48 +02003482 /* UNLOCK */
3483 nc_ch_client_unlock(ch_client);
3484
romanb6f44032023-06-30 15:07:56 +02003485 return ret;
3486}
3487
3488static int
3489nc_server_config_anchor_time(const struct lyd_node *node, NC_OPERATION op)
3490{
3491 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003492 struct nc_ch_client *ch_client = NULL;
romana3c95c72023-10-26 11:15:53 +02003493 struct lyd_value_date_and_time *anchor_time;
romanb6f44032023-06-30 15:07:56 +02003494
3495 assert(!strcmp(LYD_NAME(node), "anchor-time"));
3496
romanba93eac2023-07-18 14:36:48 +02003497 /* LOCK */
3498 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003499 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003500 return 1;
romanb6f44032023-06-30 15:07:56 +02003501 }
3502
romana3c95c72023-10-26 11:15:53 +02003503 /* get the value of time from the node directly */
3504 LYD_VALUE_GET(&((struct lyd_node_term *)node)->value, anchor_time);
romanb6f44032023-06-30 15:07:56 +02003505
3506 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
romana3c95c72023-10-26 11:15:53 +02003507 ch_client->anchor_time = anchor_time->time;
romanb6f44032023-06-30 15:07:56 +02003508 } else if (op == NC_OP_DELETE) {
3509 ch_client->anchor_time = 0;
3510 }
3511
romanba93eac2023-07-18 14:36:48 +02003512 /* UNLOCK */
3513 nc_ch_client_unlock(ch_client);
romanb6f44032023-06-30 15:07:56 +02003514 return ret;
3515}
3516
3517static int
3518nc_server_config_reconnect_strategy(const struct lyd_node *node, NC_OPERATION op)
3519{
3520 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003521 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003522
3523 assert(!strcmp(LYD_NAME(node), "reconnect-strategy"));
3524
3525 (void) op;
3526
romanba93eac2023-07-18 14:36:48 +02003527 /* LOCK */
3528 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003529 /* to avoid unlock on fail */
3530 return 1;
romanb6f44032023-06-30 15:07:56 +02003531 }
3532
3533 /* set to default values */
3534 ch_client->start_with = NC_CH_FIRST_LISTED;
3535 ch_client->max_wait = 5;
3536 ch_client->max_attempts = 3;
3537
romanba93eac2023-07-18 14:36:48 +02003538 /* UNLOCK */
3539 nc_ch_client_unlock(ch_client);
3540
romanb6f44032023-06-30 15:07:56 +02003541 return ret;
3542}
3543
3544static int
3545nc_server_config_start_with(const struct lyd_node *node, NC_OPERATION op)
3546{
3547 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003548 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003549 const char *value;
3550
3551 assert(!strcmp(LYD_NAME(node), "start-with"));
3552
romanba93eac2023-07-18 14:36:48 +02003553 /* LOCK */
3554 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003555 /* to avoid unlock on fail */
romanba93eac2023-07-18 14:36:48 +02003556 return 1;
romanb6f44032023-06-30 15:07:56 +02003557 }
3558
3559 if (op == NC_OP_DELETE) {
3560 ch_client->start_with = NC_CH_FIRST_LISTED;
3561 goto cleanup;
3562 }
3563
3564 value = lyd_get_value(node);
3565 if (!strcmp(value, "first-listed")) {
3566 ch_client->start_with = NC_CH_FIRST_LISTED;
3567 } else if (!strcmp(value, "last-connected")) {
3568 ch_client->start_with = NC_CH_LAST_CONNECTED;
3569 } else if (!strcmp(value, "random-selection")) {
3570 ch_client->start_with = NC_CH_RANDOM;
3571 } else {
3572 ERR(NULL, "Unexpected start-with value \"%s\".", value);
3573 ret = 1;
3574 goto cleanup;
3575 }
3576
3577cleanup:
romanba93eac2023-07-18 14:36:48 +02003578 /* UNLOCK */
3579 nc_ch_client_unlock(ch_client);
romanb6f44032023-06-30 15:07:56 +02003580 return ret;
3581}
3582
3583static int
3584nc_server_config_max_wait(const struct lyd_node *node, NC_OPERATION op)
3585{
3586 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003587 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003588
3589 assert(!strcmp(LYD_NAME(node), "max-wait"));
3590
romanba93eac2023-07-18 14:36:48 +02003591 /* LOCK */
3592 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003593 /* to avoid unlock on fail */
3594 return 1;
romanb6f44032023-06-30 15:07:56 +02003595 }
3596
3597 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02003598 ch_client->max_wait = ((struct lyd_node_term *)node)->value.uint16;
romanb6f44032023-06-30 15:07:56 +02003599 } else {
3600 ch_client->max_wait = 5;
3601 }
3602
romanba93eac2023-07-18 14:36:48 +02003603 /* UNLOCK */
3604 nc_ch_client_unlock(ch_client);
3605
romanb6f44032023-06-30 15:07:56 +02003606 return ret;
3607}
3608
3609static int
3610nc_server_config_max_attempts(const struct lyd_node *node, NC_OPERATION op)
3611{
3612 int ret = 0;
roman8341e8b2023-11-23 16:12:42 +01003613 struct nc_ch_client *ch_client = NULL;
romanb6f44032023-06-30 15:07:56 +02003614
3615 assert(!strcmp(LYD_NAME(node), "max-attempts"));
3616
romanba93eac2023-07-18 14:36:48 +02003617 /* LOCK */
3618 if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
roman6430c152023-10-12 11:28:47 +02003619 /* to avoid unlock on fail */
3620 return 1;
romanb6f44032023-06-30 15:07:56 +02003621 }
3622
3623 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman91ffeb42023-10-25 13:32:03 +02003624 ch_client->max_attempts = ((struct lyd_node_term *)node)->value.uint8;
romanb6f44032023-06-30 15:07:56 +02003625 } else {
3626 ch_client->max_attempts = 3;
3627 }
3628
romanba93eac2023-07-18 14:36:48 +02003629 /* UNLOCK */
3630 nc_ch_client_unlock(ch_client);
3631
romanb6f44032023-06-30 15:07:56 +02003632 return ret;
3633}
3634
3635static int
romanf02273a2023-05-25 09:44:11 +02003636nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01003637{
3638 const char *name = LYD_NAME(node);
roman6430c152023-10-12 11:28:47 +02003639 int ret = 0;
romanc1d2b092023-02-02 08:58:27 +01003640
3641 if (!strcmp(name, "listen")) {
roman6430c152023-10-12 11:28:47 +02003642 ret = nc_server_config_listen(node, op);
3643 } else if (!strcmp(name, "call-home")) {
3644 ret = nc_server_config_ch(node, op);
romanc1d2b092023-02-02 08:58:27 +01003645 } else if (!strcmp(name, "endpoint")) {
roman6430c152023-10-12 11:28:47 +02003646 ret = nc_server_config_endpoint(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003647 }
roman2eab4742023-06-06 10:00:26 +02003648#ifdef NC_ENABLED_SSH_TLS
roman3f9b65c2023-06-05 14:26:58 +02003649 else if (!strcmp(name, "ssh")) {
roman6430c152023-10-12 11:28:47 +02003650 ret = nc_server_config_ssh(node, op);
roman2eab4742023-06-06 10:00:26 +02003651 } else if (!strcmp(name, "local-address")) {
roman6430c152023-10-12 11:28:47 +02003652 ret = nc_server_config_local_address(node, op);
romanc1d2b092023-02-02 08:58:27 +01003653 } else if (!strcmp(name, "local-port")) {
roman6430c152023-10-12 11:28:47 +02003654 ret = nc_server_config_local_port(node, op);
romanc1d2b092023-02-02 08:58:27 +01003655 } else if (!strcmp(name, "keepalives")) {
roman6430c152023-10-12 11:28:47 +02003656 ret = nc_server_config_keepalives(node, op);
romanc1d2b092023-02-02 08:58:27 +01003657 } else if (!strcmp(name, "idle-time")) {
roman6430c152023-10-12 11:28:47 +02003658 ret = nc_server_config_idle_time(node, op);
romanc1d2b092023-02-02 08:58:27 +01003659 } else if (!strcmp(name, "max-probes")) {
roman6430c152023-10-12 11:28:47 +02003660 ret = nc_server_config_max_probes(node, op);
romanc1d2b092023-02-02 08:58:27 +01003661 } else if (!strcmp(name, "probe-interval")) {
roman6430c152023-10-12 11:28:47 +02003662 ret = nc_server_config_probe_interval(node, op);
roman2eab4742023-06-06 10:00:26 +02003663 } else if (!strcmp(name, "host-key")) {
roman6430c152023-10-12 11:28:47 +02003664 ret = nc_server_config_host_key(node, op);
roman2eab4742023-06-06 10:00:26 +02003665 } else if (!strcmp(name, "public-key-format")) {
roman6430c152023-10-12 11:28:47 +02003666 ret = nc_server_config_public_key_format(node, op);
romanc1d2b092023-02-02 08:58:27 +01003667 } else if (!strcmp(name, "public-key")) {
roman6430c152023-10-12 11:28:47 +02003668 ret = nc_server_config_public_key(node, op);
romanc1d2b092023-02-02 08:58:27 +01003669 } else if (!strcmp(name, "private-key-format")) {
roman6430c152023-10-12 11:28:47 +02003670 ret = nc_server_config_private_key_format(node, op);
romanc1d2b092023-02-02 08:58:27 +01003671 } else if (!strcmp(name, "cleartext-private-key")) {
roman6430c152023-10-12 11:28:47 +02003672 ret = nc_server_config_cleartext_private_key(node, op);
Michal Vaskocf898172024-01-15 15:04:28 +01003673 } else if (!strcmp(name, "central-keystore-reference")) {
roman6430c152023-10-12 11:28:47 +02003674 ret = nc_server_config_keystore_reference(node, op);
romanc1d2b092023-02-02 08:58:27 +01003675 } else if (!strcmp(name, "user")) {
roman6430c152023-10-12 11:28:47 +02003676 ret = nc_server_config_user(node, op);
romanc1d2b092023-02-02 08:58:27 +01003677 } else if (!strcmp(name, "auth-timeout")) {
roman6430c152023-10-12 11:28:47 +02003678 ret = nc_server_config_auth_timeout(node, op);
Michal Vaskocf898172024-01-15 15:04:28 +01003679 } else if (!strcmp(name, "central-truststore-reference")) {
roman6430c152023-10-12 11:28:47 +02003680 ret = nc_server_config_truststore_reference(node, op);
romana9ec3362023-12-21 10:59:57 +01003681 } else if (!strcmp(name, "use-system-keys")) {
3682 ret = nc_server_config_use_system_keys(node, op);
roman2eab4742023-06-06 10:00:26 +02003683 } else if (!strcmp(name, "password")) {
roman6430c152023-10-12 11:28:47 +02003684 ret = nc_server_config_password(node, op);
romanc6518422023-11-30 16:39:00 +01003685 } else if (!strcmp(name, "use-system-auth")) {
3686 ret = nc_server_config_use_system_auth(node, op);
romanc1d2b092023-02-02 08:58:27 +01003687 } else if (!strcmp(name, "none")) {
roman6430c152023-10-12 11:28:47 +02003688 ret = nc_server_config_none(node, op);
romanc1d2b092023-02-02 08:58:27 +01003689 } else if (!strcmp(name, "host-key-alg")) {
roman6430c152023-10-12 11:28:47 +02003690 ret = nc_server_config_host_key_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01003691 } else if (!strcmp(name, "key-exchange-alg")) {
roman6430c152023-10-12 11:28:47 +02003692 ret = nc_server_config_kex_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01003693 } else if (!strcmp(name, "encryption-alg")) {
roman6430c152023-10-12 11:28:47 +02003694 ret = nc_server_config_encryption_alg(node, op);
romanc1d2b092023-02-02 08:58:27 +01003695 } else if (!strcmp(name, "mac-alg")) {
roman6430c152023-10-12 11:28:47 +02003696 ret = nc_server_config_mac_alg(node, op);
roman78df0fa2023-11-02 10:33:57 +01003697 } else if (!strcmp(name, "endpoint-reference")) {
3698 ret = nc_server_config_endpoint_reference(node, op);
roman2eab4742023-06-06 10:00:26 +02003699 } else if (!strcmp(name, "tls")) {
roman6430c152023-10-12 11:28:47 +02003700 ret = nc_server_config_tls(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003701 } else if (!strcmp(name, "cert-data")) {
roman6430c152023-10-12 11:28:47 +02003702 ret = nc_server_config_cert_data(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003703 } else if (!strcmp(name, "asymmetric-key")) {
roman6430c152023-10-12 11:28:47 +02003704 ret = nc_server_config_asymmetric_key(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003705 } else if (!strcmp(name, "certificate")) {
roman6430c152023-10-12 11:28:47 +02003706 ret = nc_server_config_certificate(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003707 } else if (!strcmp(name, "cert-to-name")) {
roman6430c152023-10-12 11:28:47 +02003708 ret = nc_server_config_cert_to_name(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003709 } else if (!strcmp(name, "fingerprint")) {
roman6430c152023-10-12 11:28:47 +02003710 ret = nc_server_config_fingerprint(node, op);
roman12644fe2023-06-08 11:06:42 +02003711 } else if (!strcmp(name, "tls-version")) {
roman6430c152023-10-12 11:28:47 +02003712 ret = nc_server_config_tls_version(node, op);
roman12644fe2023-06-08 11:06:42 +02003713 } else if (!strcmp(name, "cipher-suite")) {
roman6430c152023-10-12 11:28:47 +02003714 ret = nc_server_config_cipher_suite(node, op);
roman3f9b65c2023-06-05 14:26:58 +02003715 }
roman2eab4742023-06-06 10:00:26 +02003716#endif /* NC_ENABLED_SSH_TLS */
roman5cbb6532023-06-22 12:53:17 +02003717 else if (!strcmp(name, "netconf-client")) {
roman6430c152023-10-12 11:28:47 +02003718 ret = nc_server_config_netconf_client(node, op);
roman5cbb6532023-06-22 12:53:17 +02003719 }
3720#ifdef NC_ENABLED_SSH_TLS
3721 else if (!strcmp(name, "remote-address")) {
roman6430c152023-10-12 11:28:47 +02003722 ret = nc_server_config_remote_address(node, op);
roman5cbb6532023-06-22 12:53:17 +02003723 } else if (!strcmp(name, "remote-port")) {
roman6430c152023-10-12 11:28:47 +02003724 ret = nc_server_config_remote_port(node, op);
roman5cbb6532023-06-22 12:53:17 +02003725 }
3726#endif /* NC_ENABLED_SSH_TLS */
romanb6f44032023-06-30 15:07:56 +02003727 else if (!strcmp(name, "persistent")) {
roman6430c152023-10-12 11:28:47 +02003728 ret = nc_server_config_persistent(node, op);
romanb6f44032023-06-30 15:07:56 +02003729 } else if (!strcmp(name, "periodic")) {
roman6430c152023-10-12 11:28:47 +02003730 ret = nc_server_config_periodic(node, op);
romanb6f44032023-06-30 15:07:56 +02003731 } else if (!strcmp(name, "period")) {
roman6430c152023-10-12 11:28:47 +02003732 ret = nc_server_config_period(node, op);
romanb6f44032023-06-30 15:07:56 +02003733 } else if (!strcmp(name, "anchor-time")) {
roman6430c152023-10-12 11:28:47 +02003734 ret = nc_server_config_anchor_time(node, op);
romaneaf84c72023-10-19 14:38:05 +02003735 } else if (!strcmp(name, "idle-timeout")) {
3736 ret = nc_server_config_idle_timeout(node, op);
romanb6f44032023-06-30 15:07:56 +02003737 } else if (!strcmp(name, "reconnect-strategy")) {
roman6430c152023-10-12 11:28:47 +02003738 ret = nc_server_config_reconnect_strategy(node, op);
romanb6f44032023-06-30 15:07:56 +02003739 } else if (!strcmp(name, "start-with")) {
roman6430c152023-10-12 11:28:47 +02003740 ret = nc_server_config_start_with(node, op);
romanb6f44032023-06-30 15:07:56 +02003741 } else if (!strcmp(name, "max-wait")) {
roman6430c152023-10-12 11:28:47 +02003742 ret = nc_server_config_max_wait(node, op);
romanb6f44032023-06-30 15:07:56 +02003743 } else if (!strcmp(name, "max-attempts")) {
roman6430c152023-10-12 11:28:47 +02003744 ret = nc_server_config_max_attempts(node, op);
3745 }
3746
3747 if (ret) {
3748 ERR(NULL, "Configuring node \"%s\" failed.", LYD_NAME(node));
3749 return 1;
romanb6f44032023-06-30 15:07:56 +02003750 }
romanc1d2b092023-02-02 08:58:27 +01003751
3752 return 0;
romanc1d2b092023-02-02 08:58:27 +01003753}
3754
3755int
roman0bbc19c2023-05-26 09:59:09 +02003756nc_server_config_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, NC_MODULE module)
romanc1d2b092023-02-02 08:58:27 +01003757{
3758 struct lyd_node *child;
3759 struct lyd_meta *m;
romanf9906b42023-05-22 14:04:29 +02003760 NC_OPERATION current_op = NC_OP_UNKNOWN;
romanf02273a2023-05-25 09:44:11 +02003761 int ret;
romanc1d2b092023-02-02 08:58:27 +01003762
3763 assert(node);
3764
romanf9906b42023-05-22 14:04:29 +02003765 /* get current op if there is any */
3766 if ((m = lyd_find_meta(node->meta, NULL, "yang:operation"))) {
3767 if (!strcmp(lyd_get_meta_value(m), "create")) {
3768 current_op = NC_OP_CREATE;
3769 } else if (!strcmp(lyd_get_meta_value(m), "delete")) {
3770 current_op = NC_OP_DELETE;
3771 } else if (!strcmp(lyd_get_meta_value(m), "replace")) {
3772 current_op = NC_OP_REPLACE;
3773 } else if (!strcmp(lyd_get_meta_value(m), "none")) {
3774 current_op = NC_OP_NONE;
romanc1d2b092023-02-02 08:58:27 +01003775 }
3776 }
3777
3778 /* node has no op, inherit from the parent */
romanf9906b42023-05-22 14:04:29 +02003779 if (!current_op) {
3780 if (!parent_op) {
3781 ERR(NULL, "Unknown operation for node \"%s\".", LYD_NAME(node));
3782 return 1;
3783 }
3784
romanc1d2b092023-02-02 08:58:27 +01003785 current_op = parent_op;
3786 }
3787
3788 switch (current_op) {
3789 case NC_OP_NONE:
3790 break;
3791 case NC_OP_CREATE:
3792 case NC_OP_DELETE:
3793 case NC_OP_REPLACE:
roman2eab4742023-06-06 10:00:26 +02003794#ifdef NC_ENABLED_SSH_TLS
3795 if (module == NC_MODULE_KEYSTORE) {
romanf02273a2023-05-25 09:44:11 +02003796 ret = nc_server_config_parse_keystore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02003797 } else if (module == NC_MODULE_TRUSTSTORE) {
romanf02273a2023-05-25 09:44:11 +02003798 ret = nc_server_config_parse_truststore(node, current_op);
roman2eab4742023-06-06 10:00:26 +02003799 } else
3800#endif /* NC_ENABLED_SSH_TLS */
3801 {
3802 ret = nc_server_config_parse_netconf_server(node, current_op);
romanf02273a2023-05-25 09:44:11 +02003803 }
3804 if (ret) {
3805 return ret;
romanc1d2b092023-02-02 08:58:27 +01003806 }
3807 break;
3808 default:
3809 break;
3810 }
3811
3812 if (current_op != NC_OP_DELETE) {
3813 LY_LIST_FOR(lyd_child(node), child) {
roman0bbc19c2023-05-26 09:59:09 +02003814 if (nc_server_config_parse_tree(child, current_op, module)) {
romanc1d2b092023-02-02 08:58:27 +01003815 return 1;
3816 }
3817 }
3818 }
3819 return 0;
3820}
3821
romanc1d2b092023-02-02 08:58:27 +01003822API int
3823nc_server_config_load_modules(struct ly_ctx **ctx)
3824{
3825 int i, new_ctx = 0;
3826
3827 if (!*ctx) {
3828 if (ly_ctx_new(NC_SERVER_SEARCH_DIR, 0, ctx)) {
3829 ERR(NULL, "Couldn't create new libyang context.\n");
3830 goto error;
3831 }
3832 new_ctx = 1;
3833 }
3834
3835 /* all features */
3836 const char *ietf_nectonf_server[] = {"ssh-listen", "tls-listen", "ssh-call-home", "tls-call-home", "central-netconf-server-supported", NULL};
3837 /* all features */
3838 const char *ietf_x509_cert_to_name[] = {NULL};
roman7fdc84d2023-06-06 13:14:53 +02003839 /* no private-key-encryption, csr-generation, p10-csr-format, certificate-expiration-notification,
roman3c6c7e62023-09-14 10:19:19 +02003840 * encrypted-passwords, hidden-symmetric-keys, encrypted-symmetric-keys, hidden-private-keys, encrypted-private-keys,
3841 * one-symmetric-key-format, one-asymmetric-key-format, symmetrically-encrypted-value-format,
3842 * asymmetrically-encrypted-value-format, cms-enveloped-data-format, cms-encrypted-data-format,
Roytakb2794852023-10-18 14:30:22 +02003843 * cleartext-symmetric-keys */
roman3c6c7e62023-09-14 10:19:19 +02003844 const char *ietf_crypto_types[] = {"cleartext-passwords", "cleartext-private-keys", NULL};
romanc1d2b092023-02-02 08:58:27 +01003845 /* all features */
3846 const char *ietf_tcp_common[] = {"keepalives-supported", NULL};
roman7fdc84d2023-06-06 13:14:53 +02003847 /* all features */
3848 const char *ietf_tcp_server[] = {"tcp-server-keepalives", NULL};
Roytakb2794852023-10-18 14:30:22 +02003849 /* no proxy-connect, socks5-gss-api, socks5-username-password, local-binding-supported ? */
3850 const char *ietf_tcp_client[] = {"tcp-client-keepalives", NULL};
roman3c6c7e62023-09-14 10:19:19 +02003851 /* no ssh-x509-certs, public-key-generation */
3852 const char *ietf_ssh_common[] = {"transport-params", NULL};
roman7fdc84d2023-06-06 13:14:53 +02003853 /* no ssh-server-keepalives and local-user-auth-hostbased */
3854 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 +01003855 /* all features */
3856 const char *iana_ssh_encryption_algs[] = {NULL};
3857 /* all features */
3858 const char *iana_ssh_key_exchange_algs[] = {NULL};
3859 /* all features */
3860 const char *iana_ssh_mac_algs[] = {NULL};
3861 /* all features */
3862 const char *iana_ssh_public_key_algs[] = {NULL};
romanc1d2b092023-02-02 08:58:27 +01003863 /* all features */
roman7fdc84d2023-06-06 13:14:53 +02003864 const char *iana_crypt_hash[] = {"crypt-hash-md5", "crypt-hash-sha-256", "crypt-hash-sha-512", NULL};
3865 /* no symmetric-keys */
3866 const char *ietf_keystore[] = {"central-keystore-supported", "inline-definitions-supported", "asymmetric-keys", NULL};
3867 /* all features */
3868 const char *ietf_truststore[] = {"central-truststore-supported", "inline-definitions-supported", "certificates", "public-keys", NULL};
roman3c6c7e62023-09-14 10:19:19 +02003869 /* no public-key-generation */
3870 const char *ietf_tls_common[] = {"tls10", "tls11", "tls12", "tls13", "hello-params", NULL};
3871 /* no tls-server-keepalives, server-ident-raw-public-key, server-ident-tls12-psk, server-ident-tls13-epsk,
3872 * client-auth-raw-public-key, client-auth-tls12-psk, client-auth-tls13-epsk */
3873 const char *ietf_tls_server[] = {"server-ident-x509-cert", "client-auth-supported", "client-auth-x509-cert", NULL};
roman7fdc84d2023-06-06 13:14:53 +02003874 /* all features */
roman12644fe2023-06-08 11:06:42 +02003875 const char *iana_tls_cipher_suite_algs[] = {NULL};
romanc1d2b092023-02-02 08:58:27 +01003876 /* all features */
3877 const char *libnetconf2_netconf_server[] = {NULL};
3878
3879 const char *module_names[] = {
roman7fdc84d2023-06-06 13:14:53 +02003880 "ietf-netconf-server", "ietf-x509-cert-to-name", "ietf-crypto-types", "ietf-tcp-common", "ietf-tcp-server",
3881 "ietf-tcp-client", "ietf-ssh-common", "ietf-ssh-server", "iana-ssh-encryption-algs",
3882 "iana-ssh-key-exchange-algs", "iana-ssh-mac-algs", "iana-ssh-public-key-algs", "iana-crypt-hash",
roman12644fe2023-06-08 11:06:42 +02003883 "ietf-keystore", "ietf-truststore", "ietf-tls-common", "ietf-tls-server", "iana-tls-cipher-suite-algs",
3884 "libnetconf2-netconf-server", NULL
romanc1d2b092023-02-02 08:58:27 +01003885 };
3886
3887 const char **module_features[] = {
roman7fdc84d2023-06-06 13:14:53 +02003888 ietf_nectonf_server, ietf_x509_cert_to_name, ietf_crypto_types, ietf_tcp_common,
3889 ietf_tcp_server, ietf_tcp_client, ietf_ssh_common, ietf_ssh_server, iana_ssh_encryption_algs,
3890 iana_ssh_key_exchange_algs, iana_ssh_mac_algs, iana_ssh_public_key_algs, iana_crypt_hash,
roman12644fe2023-06-08 11:06:42 +02003891 ietf_keystore, ietf_truststore, ietf_tls_common, ietf_tls_server, iana_tls_cipher_suite_algs,
3892 libnetconf2_netconf_server, NULL
romanc1d2b092023-02-02 08:58:27 +01003893 };
3894
3895 for (i = 0; module_names[i] != NULL; i++) {
3896 if (!ly_ctx_load_module(*ctx, module_names[i], NULL, module_features[i])) {
3897 ERR(NULL, "Loading module \"%s\" failed.\n", module_names[i]);
3898 goto error;
3899 }
3900 }
3901
3902 return 0;
3903
3904error:
3905 if (new_ctx) {
3906 ly_ctx_destroy(*ctx);
3907 *ctx = NULL;
3908 }
3909 return 1;
3910}
3911
romanf9906b42023-05-22 14:04:29 +02003912static int
Michal Vaskocf898172024-01-15 15:04:28 +01003913nc_server_config_fill_netconf_server(const struct lyd_node *data, NC_OPERATION op)
romanc1d2b092023-02-02 08:58:27 +01003914{
3915 int ret = 0;
roman84fe3252023-10-25 11:28:32 +02003916 uint32_t log_options = 0;
romanc1d2b092023-02-02 08:58:27 +01003917 struct lyd_node *tree;
romand57b3722023-04-05 11:26:25 +02003918
romanc9b62d62023-09-14 10:19:50 +02003919 /* silently search for ietf-netconf-server, it may not be present */
roman84fe3252023-10-25 11:28:32 +02003920 ly_temp_log_options(&log_options);
romanc9b62d62023-09-14 10:19:50 +02003921
romanc1d2b092023-02-02 08:58:27 +01003922 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &tree);
romanc9b62d62023-09-14 10:19:50 +02003923 if (ret || (tree->flags & LYD_DEFAULT)) {
3924 /* not found */
3925 ret = 0;
romanc1d2b092023-02-02 08:58:27 +01003926 goto cleanup;
3927 }
3928
roman0bbc19c2023-05-26 09:59:09 +02003929 if (nc_server_config_parse_tree(tree, op, NC_MODULE_NETCONF_SERVER)) {
3930 ret = 1;
3931 goto cleanup;
3932 }
3933
roman2eab4742023-06-06 10:00:26 +02003934#ifdef NC_ENABLED_SSH_TLS
roman78df0fa2023-11-02 10:33:57 +01003935 /* check and set all endpoint references */
3936 if (nc_server_config_check_endpt_references()) {
romanf9906b42023-05-22 14:04:29 +02003937 ret = 1;
3938 goto cleanup;
3939 }
roman2eab4742023-06-06 10:00:26 +02003940#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02003941
3942cleanup:
romanc9b62d62023-09-14 10:19:50 +02003943 /* reset the logging options back to what they were */
roman84fe3252023-10-25 11:28:32 +02003944 ly_temp_log_options(NULL);
romanf9906b42023-05-22 14:04:29 +02003945 return ret;
3946}
3947
3948API int
romanf6f37a52023-05-25 14:27:51 +02003949nc_server_config_setup_diff(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02003950{
3951 int ret = 0;
3952
romanc9b62d62023-09-14 10:19:50 +02003953 NC_CHECK_ARG_RET(NULL, data, 1);
3954
romanf9906b42023-05-22 14:04:29 +02003955 /* LOCK */
3956 pthread_rwlock_wrlock(&server_opts.config_lock);
3957
roman2eab4742023-06-06 10:00:26 +02003958#ifdef NC_ENABLED_SSH_TLS
romanf9906b42023-05-22 14:04:29 +02003959 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02003960 ret = nc_server_config_fill_keystore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02003961 if (ret) {
3962 ERR(NULL, "Filling keystore failed.");
3963 goto cleanup;
3964 }
3965
3966 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02003967 ret = nc_server_config_fill_truststore(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02003968 if (ret) {
3969 ERR(NULL, "Filling truststore failed.");
3970 goto cleanup;
3971 }
roman2eab4742023-06-06 10:00:26 +02003972#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02003973
3974 /* configure netconf-server */
Michal Vaskocf898172024-01-15 15:04:28 +01003975 ret = nc_server_config_fill_netconf_server(data, NC_OP_UNKNOWN);
romanf9906b42023-05-22 14:04:29 +02003976 if (ret) {
3977 ERR(NULL, "Filling netconf-server failed.");
3978 goto cleanup;
3979 }
3980
3981cleanup:
3982 /* UNLOCK */
3983 pthread_rwlock_unlock(&server_opts.config_lock);
3984 return ret;
3985}
3986
3987API int
romanf6f37a52023-05-25 14:27:51 +02003988nc_server_config_setup_data(const struct lyd_node *data)
romanf9906b42023-05-22 14:04:29 +02003989{
3990 int ret = 0;
3991 struct lyd_node *tree, *iter, *root;
3992
romanc9b62d62023-09-14 10:19:50 +02003993 NC_CHECK_ARG_RET(NULL, data, 1);
3994
romanf9906b42023-05-22 14:04:29 +02003995 /* LOCK */
3996 pthread_rwlock_wrlock(&server_opts.config_lock);
3997
3998 /* find the netconf-server node */
3999 ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &root);
4000 if (ret) {
4001 ERR(NULL, "Unable to find the netconf-server container in the YANG data.");
4002 goto cleanup;
4003 }
4004
4005 /* iterate through all the nodes and make sure there is no operation attribute */
4006 LY_LIST_FOR(root, tree) {
4007 LYD_TREE_DFS_BEGIN(tree, iter) {
4008 if (lyd_find_meta(iter->meta, NULL, "yang:operation")) {
4009 ERR(NULL, "Unexpected operation attribute in the YANG data.");
romanc1d2b092023-02-02 08:58:27 +01004010 ret = 1;
4011 goto cleanup;
4012 }
romanf9906b42023-05-22 14:04:29 +02004013 LYD_TREE_DFS_END(tree, iter);
romanc1d2b092023-02-02 08:58:27 +01004014 }
4015 }
4016
romanf9906b42023-05-22 14:04:29 +02004017 /* delete the current configuration */
romanf02273a2023-05-25 09:44:11 +02004018 nc_server_config_listen(NULL, NC_OP_DELETE);
roman4cb8bb12023-06-29 09:16:46 +02004019 nc_server_config_ch(NULL, NC_OP_DELETE);
roman2eab4742023-06-06 10:00:26 +02004020#ifdef NC_ENABLED_SSH_TLS
romanf02273a2023-05-25 09:44:11 +02004021 nc_server_config_ks_keystore(NULL, NC_OP_DELETE);
4022 nc_server_config_ts_truststore(NULL, NC_OP_DELETE);
romanf9906b42023-05-22 14:04:29 +02004023
4024 /* configure keystore */
romanf02273a2023-05-25 09:44:11 +02004025 ret = nc_server_config_fill_keystore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02004026 if (ret) {
4027 ERR(NULL, "Filling keystore failed.");
4028 goto cleanup;
4029 }
4030
4031 /* configure truststore */
romanf02273a2023-05-25 09:44:11 +02004032 ret = nc_server_config_fill_truststore(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02004033 if (ret) {
4034 ERR(NULL, "Filling truststore failed.");
4035 goto cleanup;
4036 }
roman2eab4742023-06-06 10:00:26 +02004037#endif /* NC_ENABLED_SSH_TLS */
romanf9906b42023-05-22 14:04:29 +02004038
4039 /* configure netconf-server */
Michal Vaskocf898172024-01-15 15:04:28 +01004040 ret = nc_server_config_fill_netconf_server(data, NC_OP_CREATE);
romanf9906b42023-05-22 14:04:29 +02004041 if (ret) {
4042 ERR(NULL, "Filling netconf-server failed.");
romanc1d2b092023-02-02 08:58:27 +01004043 goto cleanup;
4044 }
4045
4046cleanup:
4047 /* UNLOCK */
4048 pthread_rwlock_unlock(&server_opts.config_lock);
4049 return ret;
4050}
roman3f9b65c2023-06-05 14:26:58 +02004051
4052API int
4053nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path)
4054{
4055 struct lyd_node *tree = NULL;
4056 int ret = 0;
4057
4058 NC_CHECK_ARG_RET(NULL, path, 1);
4059
4060 ret = lyd_parse_data_path(ctx, path, LYD_UNKNOWN, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree);
4061 if (ret) {
4062 goto cleanup;
4063 }
4064
4065 ret = nc_server_config_setup_data(tree);
4066 if (ret) {
4067 goto cleanup;
4068 }
4069
4070cleanup:
4071 lyd_free_all(tree);
4072 return ret;
4073}
romand05b2ad2024-01-23 12:02:40 +01004074
4075#ifdef NC_ENABLED_SSH_TLS
4076
4077static int
4078nc_server_config_oper_get_algs(const struct ly_ctx *ctx, const char *mod_name, const char *ln2_algs[],
4079 const char *mod_algs[], struct lyd_node **algs)
4080{
4081 int ret, r, i;
4082 struct lyd_node *parent = NULL;
4083 char *path = NULL;
4084
4085 NC_CHECK_ARG_RET(NULL, ctx, mod_name, ln2_algs, mod_algs, algs, 1);
4086
4087 *algs = NULL;
4088
4089 r = asprintf(&path, "/%s:supported-algorithms", mod_name);
4090 NC_CHECK_ERRMEM_RET(r == -1, 1);
4091
4092 /* create supported algorithms container */
4093 ret = lyd_new_path(NULL, ctx, path, NULL, 0, &parent);
4094 free(path);
4095 if (ret) {
4096 ERR(NULL, "Creating supported algorithms container failed.");
4097 goto cleanup;
4098 }
4099
4100 /* append algs from libnetconf2-netconf-server */
4101 for (i = 0; ln2_algs[i]; i++) {
4102 r = asprintf(&path, "libnetconf2-netconf-server:%s", ln2_algs[i]);
4103 NC_CHECK_ERRMEM_GOTO(r == -1, ret = 1, cleanup);
4104 ret = lyd_new_term(parent, NULL, "supported-algorithm", path, 0, NULL);
4105 free(path);
4106 if (ret) {
4107 ERR(NULL, "Creating new supported algorithm failed.");
4108 goto cleanup;
4109 }
4110 }
4111
4112 /* append algs from mod_name module */
4113 for (i = 0; mod_algs[i]; i++) {
4114 r = asprintf(&path, "%s:%s", mod_name, mod_algs[i]);
4115 NC_CHECK_ERRMEM_GOTO(r == -1, ret = 1, cleanup);
4116 ret = lyd_new_term(parent, NULL, "supported-algorithm", path, 0, NULL);
4117 free(path);
4118 if (ret) {
4119 ERR(NULL, "Creating new supported algorithm failed.");
4120 goto cleanup;
4121 }
4122 }
4123
4124cleanup:
4125 if (ret) {
4126 lyd_free_tree(parent);
4127 } else {
4128 *algs = parent;
4129 }
4130 return ret;
4131}
4132
4133API int
4134nc_server_config_oper_get_hostkey_algs(const struct ly_ctx *ctx, struct lyd_node **hostkey_algs)
4135{
4136 /* identities of hostkey algs supported by libssh (v0.10.5) defined in libnetconf2-netconf-server yang module */
4137 const char *libnetconf2_hostkey_algs[] = {
4138 "openssh-ssh-ed25519-cert-v01", "openssh-ecdsa-sha2-nistp521-cert-v01",
4139 "openssh-ecdsa-sha2-nistp384-cert-v01", "openssh-ecdsa-sha2-nistp256-cert-v01",
4140 "openssh-rsa-sha2-512-cert-v01", "openssh-rsa-sha2-256-cert-v01",
4141 "openssh-ssh-rsa-cert-v01", "openssh-ssh-dss-cert-v01", NULL
4142 };
4143
4144 /* identities of hostkey algs supported by libssh (v0.10.5) defined in iana-ssh-public-key-algs yang module */
4145 const char *iana_hostkey_algs[] = {
4146 "ssh-ed25519", "ecdsa-sha2-nistp521", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp256",
4147 "rsa-sha2-512", "rsa-sha2-256", "ssh-rsa", "ssh-dss", NULL
4148 };
4149
4150 NC_CHECK_ARG_RET(NULL, ctx, hostkey_algs, 1);
4151
4152 return nc_server_config_oper_get_algs(ctx, "iana-ssh-public-key-algs", libnetconf2_hostkey_algs,
4153 iana_hostkey_algs, hostkey_algs);
4154}
4155
4156API int
4157nc_server_config_oper_get_kex_algs(const struct ly_ctx *ctx, struct lyd_node **kex_algs)
4158{
4159 /* identities of kex algs supported by libssh (v0.10.5) defined in libnetconf2-netconf-server yang module */
4160 const char *libnetconf2_kex_algs[] = {
4161 "libssh-curve25519-sha256", NULL
4162 };
4163
4164 /* identities of kex algs supported by libssh (v0.10.5) defined in iana-ssh-key-exchange-algs yang module */
4165 const char *iana_kex_algs[] = {
4166 "diffie-hellman-group-exchange-sha1", "curve25519-sha256", "ecdh-sha2-nistp256", "ecdh-sha2-nistp384",
4167 "ecdh-sha2-nistp521", "diffie-hellman-group18-sha512", "diffie-hellman-group16-sha512",
4168 "diffie-hellman-group-exchange-sha256", "diffie-hellman-group14-sha256", NULL
4169 };
4170
4171 NC_CHECK_ARG_RET(NULL, ctx, kex_algs, 1);
4172
4173 return nc_server_config_oper_get_algs(ctx, "iana-ssh-key-exchange-algs", libnetconf2_kex_algs,
4174 iana_kex_algs, kex_algs);
4175}
4176
4177API int
4178nc_server_config_oper_get_encryption_algs(const struct ly_ctx *ctx, struct lyd_node **encryption_algs)
4179{
4180 /* identities of encryption algs supported by libssh (v0.10.5) defined in libnetconf2-netconf-server yang module */
4181 const char *libnetconf2_encryption_algs[] = {
4182 "openssh-chacha20-poly1305", "openssh-aes256-gcm", "openssh-aes128-gcm", NULL
4183 };
4184
4185 /* identities of encryption algs supported by libssh (v0.10.5) defined in iana-ssh-encryption-algs yang module */
4186 const char *iana_encryption_algs[] = {
4187 "aes256-ctr", "aes192-ctr", "aes128-ctr", "aes256-cbc", "aes192-cbc", "aes128-cbc",
4188 "blowfish-cbc", "triple-des-cbc", "none", NULL
4189 };
4190
4191 NC_CHECK_ARG_RET(NULL, ctx, encryption_algs, 1);
4192
4193 return nc_server_config_oper_get_algs(ctx, "iana-ssh-encryption-algs", libnetconf2_encryption_algs,
4194 iana_encryption_algs, encryption_algs);
4195}
4196
4197API int
4198nc_server_config_oper_get_mac_algs(const struct ly_ctx *ctx, struct lyd_node **mac_algs)
4199{
4200 /* identities of mac algs supported by libssh (v0.10.5) defined in libnetconf2-netconf-server yang module */
4201 const char *libnetconf2_mac_algs[] = {
4202 "openssh-hmac-sha2-256-etm", "openssh-hmac-sha2-512-etm", "openssh-hmac-sha1-etm", NULL
4203 };
4204
4205 /* identities of mac algs supported by libssh (v0.10.5) defined in iana-ssh-mac-algs yang module */
4206 const char *iana_mac_algs[] = {
4207 "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1", NULL
4208 };
4209
4210 NC_CHECK_ARG_RET(NULL, ctx, mac_algs, 1);
4211
4212 return nc_server_config_oper_get_algs(ctx, "iana-ssh-mac-algs", libnetconf2_mac_algs,
4213 iana_mac_algs, mac_algs);
4214}
4215
4216#endif /* NC_ENABLED_SSH_TLS */