blob: f94cd7403b7a1ffd293125757aa29c9d4213c0d4 [file] [log] [blame]
roman3f9b65c2023-06-05 14:26:58 +02001/**
Roytakb2794852023-10-18 14:30:22 +02002 * @file server_config_util.c
roman3f9b65c2023-06-05 14:26:58 +02003 * @author Roman Janota <janota@cesnet.cz>
Roytakb2794852023-10-18 14:30:22 +02004 * @brief libnetconf2 server configuration utilities
roman3f9b65c2023-06-05 14:26:58 +02005 *
6 * @copyright
7 * Copyright (c) 2023 CESNET, z.s.p.o.
8 *
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 */
15
16#define _GNU_SOURCE
17
Roytakb2794852023-10-18 14:30:22 +020018#include "server_config_util.h"
19
roman2eab4742023-06-06 10:00:26 +020020#include <libyang/libyang.h>
roman5d9fc732023-10-26 11:26:57 +020021
22#include <inttypes.h>
romand30af552023-06-16 15:18:27 +020023#include <stdarg.h>
roman3f9b65c2023-06-05 14:26:58 +020024#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
roman3f9b65c2023-06-05 14:26:58 +020028#include "compat.h"
roman3f9b65c2023-06-05 14:26:58 +020029#include "log_p.h"
30#include "session.h"
31#include "session_p.h"
roman44af5052024-04-05 12:31:24 +020032#include "session_wrapper.h"
roman3f9b65c2023-06-05 14:26:58 +020033
roman8ba6efa2023-07-12 15:27:52 +020034int
Roytakb2794852023-10-18 14:30:22 +020035nc_server_config_create(const struct ly_ctx *ctx, struct lyd_node **tree, const char *value, const char *path_fmt, ...)
roman8ba6efa2023-07-12 15:27:52 +020036{
37 int ret = 0;
38 va_list ap;
39 char *path = NULL;
40
Roytak7b9bf292023-10-04 14:06:38 +020041 NC_CHECK_ARG_RET(NULL, ctx, tree, path_fmt, 1);
42
roman8ba6efa2023-07-12 15:27:52 +020043 va_start(ap, path_fmt);
44
45 /* create the path from the format */
46 ret = vasprintf(&path, path_fmt, ap);
roman3a95bb22023-10-26 11:07:17 +020047 NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; path = NULL, cleanup);
roman8ba6efa2023-07-12 15:27:52 +020048
49 /* create the nodes in the path */
roman5ef2a572023-08-18 15:45:44 +020050 if (!*tree) {
51 ret = lyd_new_path(*tree, ctx, path, value, LYD_NEW_PATH_UPDATE, tree);
52 } else {
53 /* this could output NULL if no new nodes, lyd_find_path would fail then */
54 ret = lyd_new_path(*tree, ctx, path, value, LYD_NEW_PATH_UPDATE, NULL);
55 }
roman8ba6efa2023-07-12 15:27:52 +020056 if (ret) {
57 goto cleanup;
58 }
59
60 /* set the node to the top level node */
61 ret = lyd_find_path(*tree, "/ietf-netconf-server:netconf-server", 0, tree);
62 if (ret) {
63 goto cleanup;
64 }
65
66 /* add all default nodes */
67 ret = lyd_new_implicit_tree(*tree, LYD_IMPLICIT_NO_STATE, NULL);
68 if (ret) {
69 goto cleanup;
70 }
71
72cleanup:
73 free(path);
74 va_end(ap);
75 return ret;
76}
77
78int
Roytakb2794852023-10-18 14:30:22 +020079nc_server_config_append(const struct ly_ctx *ctx, const char *parent_path, const char *child_name,
roman8ba6efa2023-07-12 15:27:52 +020080 const char *value, struct lyd_node **tree)
81{
82 int ret = 0;
83 char *path = NULL;
84
Roytak7b9bf292023-10-04 14:06:38 +020085 NC_CHECK_ARG_RET(NULL, ctx, parent_path, child_name, tree, 1);
86
roman8ba6efa2023-07-12 15:27:52 +020087 /* create the path by appending child to the parent path */
88 ret = asprintf(&path, "%s/%s", parent_path, child_name);
roman3a95bb22023-10-26 11:07:17 +020089 NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; path = NULL, cleanup);
roman8ba6efa2023-07-12 15:27:52 +020090
91 /* create the nodes in the path */
roman5ef2a572023-08-18 15:45:44 +020092 if (!*tree) {
93 ret = lyd_new_path(*tree, ctx, path, value, LYD_NEW_PATH_UPDATE, tree);
94 } else {
95 /* this could output NULL if no new nodes, lyd_find_path would fail then */
96 ret = lyd_new_path(*tree, ctx, path, value, LYD_NEW_PATH_UPDATE, NULL);
97 }
roman8ba6efa2023-07-12 15:27:52 +020098 if (ret) {
99 goto cleanup;
100 }
101
102 /* set the node to the top level node */
103 ret = lyd_find_path(*tree, "/ietf-netconf-server:netconf-server", 0, tree);
104 if (ret) {
105 goto cleanup;
106 }
107
108 /* add all default nodes */
109 ret = lyd_new_implicit_tree(*tree, LYD_IMPLICIT_NO_STATE, NULL);
110 if (ret) {
111 goto cleanup;
112 }
113
114cleanup:
115 free(path);
116 return ret;
117}
118
119int
Roytakb2794852023-10-18 14:30:22 +0200120nc_server_config_delete(struct lyd_node **tree, const char *path_fmt, ...)
Roytak7b9bf292023-10-04 14:06:38 +0200121{
122 int ret = 0;
123 va_list ap;
124 char *path = NULL;
125 struct lyd_node *sub = NULL;
126
127 NC_CHECK_ARG_RET(NULL, tree, path_fmt, 1);
128
129 va_start(ap, path_fmt);
130
131 /* create the path from the format */
132 ret = vasprintf(&path, path_fmt, ap);
roman3a95bb22023-10-26 11:07:17 +0200133 NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; path = NULL, cleanup);
Roytak7b9bf292023-10-04 14:06:38 +0200134
135 /* find the node we want to delete */
136 ret = lyd_find_path(*tree, path, 0, &sub);
137 if (ret) {
138 goto cleanup;
139 }
140
141 lyd_free_tree(sub);
142
143 /* set the node to top level container */
144 ret = lyd_find_path(*tree, "/ietf-netconf-server:netconf-server", 0, tree);
145 if (ret) {
146 goto cleanup;
147 }
148
149 /* add all default nodes */
150 ret = lyd_new_implicit_tree(*tree, LYD_IMPLICIT_NO_STATE, NULL);
151 if (ret) {
152 goto cleanup;
153 }
154
155cleanup:
156 free(path);
157 va_end(ap);
158 return ret;
159}
160
161int
Roytakb2794852023-10-18 14:30:22 +0200162nc_server_config_check_delete(struct lyd_node **tree, const char *path_fmt, ...)
roman8ba6efa2023-07-12 15:27:52 +0200163{
164 int ret = 0;
165 va_list ap;
166 char *path = NULL;
167 struct lyd_node *sub = NULL;
168
Roytak7b9bf292023-10-04 14:06:38 +0200169 NC_CHECK_ARG_RET(NULL, tree, path_fmt, 1);
170
roman8ba6efa2023-07-12 15:27:52 +0200171 va_start(ap, path_fmt);
172
173 /* create the path from the format */
174 ret = vasprintf(&path, path_fmt, ap);
roman3a95bb22023-10-26 11:07:17 +0200175 NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; path = NULL, cleanup);
roman8ba6efa2023-07-12 15:27:52 +0200176
177 /* find the node we want to delete */
178 ret = lyd_find_path(*tree, path, 0, &sub);
179 if ((ret == LY_EINCOMPLETE) || (ret == LY_ENOTFOUND)) {
180 ret = 0;
181 goto cleanup;
182 } else if (ret) {
183 ERR(NULL, "Unable to delete node in the path \"%s\".", path);
184 goto cleanup;
185 }
186
187 lyd_free_tree(sub);
188
189 /* set the node to top level container */
190 ret = lyd_find_path(*tree, "/ietf-netconf-server:netconf-server", 0, tree);
191 if (ret) {
192 goto cleanup;
193 }
194
195cleanup:
196 free(path);
197 va_end(ap);
198 return ret;
199}
200
roman2eab4742023-06-06 10:00:26 +0200201#ifdef NC_ENABLED_SSH_TLS
202
roman3f9b65c2023-06-05 14:26:58 +0200203const char *
Roytakb2794852023-10-18 14:30:22 +0200204nc_server_config_util_privkey_format_to_identityref(NC_PRIVKEY_FORMAT format)
roman3f9b65c2023-06-05 14:26:58 +0200205{
206 switch (format) {
207 case NC_PRIVKEY_FORMAT_RSA:
208 return "ietf-crypto-types:rsa-private-key-format";
209 case NC_PRIVKEY_FORMAT_EC:
210 return "ietf-crypto-types:ec-private-key-format";
211 case NC_PRIVKEY_FORMAT_X509:
roman13145912023-08-17 15:36:54 +0200212 return "libnetconf2-netconf-server:private-key-info-format";
roman3f9b65c2023-06-05 14:26:58 +0200213 case NC_PRIVKEY_FORMAT_OPENSSH:
214 return "libnetconf2-netconf-server:openssh-private-key-format";
215 default:
216 ERR(NULL, "Private key type not supported.");
217 return NULL;
218 }
219}
220
roman13145912023-08-17 15:36:54 +0200221static int
romana1583522024-04-23 15:13:17 +0200222nc_server_config_util_rsa_pubkey_param_to_bin(void *bn, unsigned char **bin, int *bin_len)
roman13145912023-08-17 15:36:54 +0200223{
224 int ret = 0;
225 unsigned char *bin_tmp = NULL;
226
227 NC_CHECK_ARG_RET(NULL, bn, bin, bin_len, 1);
228
229 *bin = NULL;
230
roman13145912023-08-17 15:36:54 +0200231 /* convert to binary */
romana1583522024-04-23 15:13:17 +0200232 if (nc_tls_mpi2bin_wrap(bn, &bin_tmp, bin_len)) {
233 ret = 1;
234 goto cleanup;
235 }
roman13145912023-08-17 15:36:54 +0200236
237 /* if the highest bit in the MSB is set a byte with the value 0 has to be prepended */
238 if (bin_tmp[0] & 0x80) {
239 *bin = malloc(*bin_len + 1);
roman3a95bb22023-10-26 11:07:17 +0200240 NC_CHECK_ERRMEM_GOTO(!*bin, ret = 1, cleanup);
roman13145912023-08-17 15:36:54 +0200241 (*bin)[0] = 0;
242 memcpy(*bin + 1, bin_tmp, *bin_len);
243 (*bin_len)++;
244 } else {
245 *bin = malloc(*bin_len);
roman3a95bb22023-10-26 11:07:17 +0200246 NC_CHECK_ERRMEM_GOTO(!*bin, ret = 1, cleanup);
roman13145912023-08-17 15:36:54 +0200247 memcpy(*bin, bin_tmp, *bin_len);
248 }
249
250cleanup:
251 free(bin_tmp);
252 return ret;
253}
254
255/* ssh pubkey defined in RFC 4253 section 6.6 */
256static int
roman72908d42024-04-26 16:13:17 +0200257nc_server_config_util_pkey_to_ssh_pubkey(void *pkey, char **pubkey)
roman13145912023-08-17 15:36:54 +0200258{
259 int ret = 0, e_len, n_len, p_len, bin_len;
romana1583522024-04-23 15:13:17 +0200260 void *e = NULL, *n = NULL, *p = NULL, *p_grp = NULL;
roman13145912023-08-17 15:36:54 +0200261 unsigned char *e_bin = NULL, *n_bin = NULL, *p_bin = NULL, *bin = NULL, *bin_tmp;
262 const char *algorithm_name, *curve_name;
263 char *ec_group = NULL;
264 uint32_t alg_name_len, curve_name_len, alg_name_len_be, curve_name_len_be, p_len_be, e_len_be, n_len_be;
roman13145912023-08-17 15:36:54 +0200265
Roytak7b9bf292023-10-04 14:06:38 +0200266 NC_CHECK_ARG_RET(NULL, pkey, pubkey, 1);
267
roman44af5052024-04-05 12:31:24 +0200268 if (nc_tls_privkey_is_rsa_wrap(pkey)) {
roman13145912023-08-17 15:36:54 +0200269 /* RSA key */
270 algorithm_name = "ssh-rsa";
271
272 /* get the public key params */
roman44af5052024-04-05 12:31:24 +0200273 if (nc_tls_get_rsa_pubkey_params_wrap(pkey, &e, &n)) {
roman13145912023-08-17 15:36:54 +0200274 ret = 1;
275 goto cleanup;
276 }
277
278 /* BIGNUM to bin */
romana1583522024-04-23 15:13:17 +0200279 if (nc_server_config_util_rsa_pubkey_param_to_bin(e, &e_bin, &e_len) ||
280 nc_server_config_util_rsa_pubkey_param_to_bin(n, &n_bin, &n_len)) {
roman13145912023-08-17 15:36:54 +0200281 ret = 1;
282 goto cleanup;
283 }
284
285 alg_name_len = strlen(algorithm_name);
286 /* buffer for public key in binary, which looks like this:
287 * alg_name len (4 bytes), alg_name, PK exponent len (4 bytes), PK exponent, modulus len (4 bytes), modulus
288 */
289 bin_len = 4 + alg_name_len + 4 + e_len + 4 + n_len;
290 bin = malloc(bin_len);
roman3a95bb22023-10-26 11:07:17 +0200291 NC_CHECK_ERRMEM_GOTO(!bin, ret = 1, cleanup);
roman13145912023-08-17 15:36:54 +0200292
293 /* to network byte order (big endian) */
294 alg_name_len_be = htonl(alg_name_len);
295 e_len_be = htonl(e_len);
296 n_len_be = htonl(n_len);
297
298 /* create the public key in binary */
299 bin_tmp = bin;
300 memcpy(bin_tmp, &alg_name_len_be, 4);
301 bin_tmp += 4;
302 memcpy(bin_tmp, algorithm_name, alg_name_len);
303 bin_tmp += alg_name_len;
304 memcpy(bin_tmp, &e_len_be, 4);
305 bin_tmp += 4;
306 memcpy(bin_tmp, e_bin, e_len);
307 bin_tmp += e_len;
308 memcpy(bin_tmp, &n_len_be, 4);
309 bin_tmp += 4;
310 memcpy(bin_tmp, n_bin, n_len);
roman44af5052024-04-05 12:31:24 +0200311 } else if (nc_tls_privkey_is_ec_wrap(pkey)) {
roman13145912023-08-17 15:36:54 +0200312 /* EC Private key, get it's group first */
roman44af5052024-04-05 12:31:24 +0200313 ec_group = nc_tls_get_ec_group_wrap(pkey);
314 if (!ec_group) {
roman13145912023-08-17 15:36:54 +0200315 ret = 1;
316 goto cleanup;
317 }
318
319 /* get alg and curve names */
320 if (!strcmp(ec_group, "P-256") || !strcmp(ec_group, "secp256r1") || !strcmp(ec_group, "prime256v1")) {
321 algorithm_name = "ecdsa-sha2-nistp256";
322 curve_name = "nistp256";
323 } else if (!strcmp(ec_group, "P-384") || !strcmp(ec_group, "secp384r1")) {
324 algorithm_name = "ecdsa-sha2-nistp384";
325 curve_name = "nistp384";
326 } else if (!strcmp(ec_group, "P-521") || !strcmp(ec_group, "secp521r1")) {
327 algorithm_name = "ecdsa-sha2-nistp521";
328 curve_name = "nistp521";
329 } else {
330 ERR(NULL, "EC group \"%s\" not supported.", ec_group);
331 ret = 1;
332 goto cleanup;
333 }
334
335 /* get the public key - p, which is a point on the elliptic curve */
romana1583522024-04-23 15:13:17 +0200336 ret = nc_tls_get_ec_pubkey_params_wrap(pkey, &p, &p_grp);
roman44af5052024-04-05 12:31:24 +0200337 if (ret) {
338 ERR(NULL, "Getting public key point from the EC private key failed.");
roman13145912023-08-17 15:36:54 +0200339 ret = 1;
340 goto cleanup;
341 }
342
romana1583522024-04-23 15:13:17 +0200343 /* EC point to bin */
344 ret = nc_tls_ec_point_to_bin_wrap(p, p_grp, &p_bin, &p_len);
345 if (ret) {
346 ERR(NULL, "Converting EC public key point to binary failed.");
347 ret = 1;
348 goto cleanup;
349 }
350
roman13145912023-08-17 15:36:54 +0200351 alg_name_len = strlen(algorithm_name);
352 curve_name_len = strlen(curve_name);
353 /* buffer for public key in binary, which looks like so:
354 * alg_name len (4 bytes), alg_name, curve_name len (4 bytes), curve_name, PK point p len (4 bytes), PK point p
355 */
356 bin_len = 4 + alg_name_len + 4 + curve_name_len + 4 + p_len;
357 bin = malloc(bin_len);
roman3a95bb22023-10-26 11:07:17 +0200358 NC_CHECK_ERRMEM_GOTO(!bin, ret = 1, cleanup);
roman13145912023-08-17 15:36:54 +0200359
360 /* to network byte order (big endian) */
361 alg_name_len_be = htonl(alg_name_len);
362 curve_name_len_be = htonl(curve_name_len);
363 p_len_be = htonl(p_len);
364
365 /* create the public key in binary */
366 bin_tmp = bin;
367 memcpy(bin_tmp, &alg_name_len_be, 4);
368 bin_tmp += 4;
369 memcpy(bin_tmp, algorithm_name, alg_name_len);
370 bin_tmp += alg_name_len;
371 memcpy(bin_tmp, &curve_name_len_be, 4);
372 bin_tmp += 4;
373 memcpy(bin_tmp, curve_name, curve_name_len);
374 bin_tmp += curve_name_len;
375 memcpy(bin_tmp, &p_len_be, 4);
376 bin_tmp += 4;
377 memcpy(bin_tmp, p_bin, p_len);
roman13145912023-08-17 15:36:54 +0200378 } else {
379 ERR(NULL, "Unable to generate public key from private key (Private key type not supported).");
380 ret = 1;
381 goto cleanup;
382 }
383
Roytak7b9bf292023-10-04 14:06:38 +0200384 /* convert created bin to b64 */
roman44af5052024-04-05 12:31:24 +0200385 ret = nc_base64_encode_wrap(bin, bin_len, pubkey);
roman13145912023-08-17 15:36:54 +0200386 if (ret) {
387 ERR(NULL, "Converting public key from binary to base64 failed.");
388 goto cleanup;
389 }
390
391cleanup:
romana1583522024-04-23 15:13:17 +0200392 nc_tls_destroy_mpi_wrap(e);
393 nc_tls_destroy_mpi_wrap(n);
394 nc_tls_ec_point_destroy_wrap(p);
395 nc_tls_ec_group_destroy_wrap(p_grp);
roman13145912023-08-17 15:36:54 +0200396 free(bin);
397 free(e_bin);
398 free(n_bin);
399 free(ec_group);
400 free(p_bin);
roman13145912023-08-17 15:36:54 +0200401 return ret;
402}
403
404/* spki = subject public key info */
405static int
roman72908d42024-04-26 16:13:17 +0200406nc_server_config_util_pkey_to_spki_pubkey(void *pkey, char **pubkey)
roman13145912023-08-17 15:36:54 +0200407{
roman44af5052024-04-05 12:31:24 +0200408 int ret = 0;
409 char *pub_pem = NULL;
roman13145912023-08-17 15:36:54 +0200410
Roytak7b9bf292023-10-04 14:06:38 +0200411 NC_CHECK_ARG_RET(NULL, pkey, pubkey, 1);
412
romana1583522024-04-23 15:13:17 +0200413 pub_pem = nc_tls_export_pubkey_pem_wrap(pkey);
roman44af5052024-04-05 12:31:24 +0200414 if (!pub_pem) {
roman13145912023-08-17 15:36:54 +0200415 ret = 1;
416 goto cleanup;
417 }
418
419 /* copy the public key without the header and footer */
roman44af5052024-04-05 12:31:24 +0200420 *pubkey = strndup(pub_pem + strlen(NC_SUBJECT_PUBKEY_INFO_HEADER),
421 strlen(pub_pem) - strlen(NC_SUBJECT_PUBKEY_INFO_HEADER) - strlen(NC_SUBJECT_PUBKEY_INFO_FOOTER));
roman3a95bb22023-10-26 11:07:17 +0200422 NC_CHECK_ERRMEM_GOTO(!*pubkey, ret = 1, cleanup);
roman13145912023-08-17 15:36:54 +0200423
424cleanup:
roman44af5052024-04-05 12:31:24 +0200425 free(pub_pem);
roman13145912023-08-17 15:36:54 +0200426 return ret;
427}
428
roman3f9b65c2023-06-05 14:26:58 +0200429int
Roytakb2794852023-10-18 14:30:22 +0200430nc_server_config_util_read_certificate(const char *cert_path, char **cert)
roman3f9b65c2023-06-05 14:26:58 +0200431{
roman44af5052024-04-05 12:31:24 +0200432 int ret = 0;
433 void *crt = NULL;
434 char *pem = NULL;
roman3f9b65c2023-06-05 14:26:58 +0200435
Roytak7b9bf292023-10-04 14:06:38 +0200436 NC_CHECK_ARG_RET(NULL, cert_path, cert, 1);
roman3f9b65c2023-06-05 14:26:58 +0200437
roman44af5052024-04-05 12:31:24 +0200438 crt = nc_tls_import_cert_file_wrap(cert_path);
439 if (!crt) {
440 return 1;
441 }
442
romana1583522024-04-23 15:13:17 +0200443 pem = nc_tls_export_cert_pem_wrap(crt);
roman44af5052024-04-05 12:31:24 +0200444 if (!pem) {
roman3f9b65c2023-06-05 14:26:58 +0200445 ret = 1;
446 goto cleanup;
447 }
448
roman44af5052024-04-05 12:31:24 +0200449 /* copy the cert without its header and footer */
450 *cert = strndup(pem + strlen(NC_PEM_CERTIFICATE_HEADER),
451 strlen(pem) - strlen(NC_PEM_CERTIFICATE_HEADER) - strlen(NC_PEM_CERTIFICATE_FOOTER));
roman3a95bb22023-10-26 11:07:17 +0200452 NC_CHECK_ERRMEM_GOTO(!*cert, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +0200453
roman3f9b65c2023-06-05 14:26:58 +0200454cleanup:
roman44af5052024-04-05 12:31:24 +0200455 free(pem);
456 nc_tls_cert_destroy_wrap(crt);
roman3f9b65c2023-06-05 14:26:58 +0200457 return ret;
458}
459
460static int
roman72908d42024-04-26 16:13:17 +0200461nc_server_config_util_read_ssh2_pubkey(const char *pubkey_path, char **pubkey)
roman3f9b65c2023-06-05 14:26:58 +0200462{
463 char *buffer = NULL;
464 size_t size = 0, pubkey_len = 0;
465 void *tmp;
466 ssize_t read;
467 int ret = 0;
roman44af5052024-04-05 12:31:24 +0200468 FILE *f = NULL;
roman3f9b65c2023-06-05 14:26:58 +0200469
roman44af5052024-04-05 12:31:24 +0200470 NC_CHECK_ARG_RET(NULL, pubkey_path, pubkey, 1);
471
472 f = fopen(pubkey_path, "r");
473 if (!f) {
474 ERR(NULL, "Failed to open file \"%s\".", pubkey_path);
475 ret = 1;
476 goto cleanup;
477 }
Roytak7b9bf292023-10-04 14:06:38 +0200478
479 /* read lines from the file and create the public key without NL from it */
roman3f9b65c2023-06-05 14:26:58 +0200480 while ((read = getline(&buffer, &size, f)) > 0) {
481 if (!strncmp(buffer, "----", 4)) {
Roytak7b9bf292023-10-04 14:06:38 +0200482 /* skip header and footer */
roman3f9b65c2023-06-05 14:26:58 +0200483 continue;
484 }
485
486 if (!strncmp(buffer, "Comment:", 8)) {
Roytak7b9bf292023-10-04 14:06:38 +0200487 /* skip a comment */
roman3f9b65c2023-06-05 14:26:58 +0200488 continue;
489 }
490
491 if (buffer[read - 1] == '\n') {
Roytak7b9bf292023-10-04 14:06:38 +0200492 /* avoid NL */
roman3f9b65c2023-06-05 14:26:58 +0200493 read--;
494 }
495
496 tmp = realloc(*pubkey, pubkey_len + read + 1);
roman3a95bb22023-10-26 11:07:17 +0200497 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +0200498
499 *pubkey = tmp;
500 memcpy(*pubkey + pubkey_len, buffer, read);
501 pubkey_len += read;
502 }
503
504 if (!pubkey_len) {
505 ERR(NULL, "Unexpected public key format.");
506 ret = 1;
507 goto cleanup;
508 }
509
510 (*pubkey)[pubkey_len] = '\0';
511
512cleanup:
roman44af5052024-04-05 12:31:24 +0200513 if (f) {
514 fclose(f);
515 }
roman3f9b65c2023-06-05 14:26:58 +0200516 free(buffer);
517 return ret;
518}
519
520static int
roman72908d42024-04-26 16:13:17 +0200521nc_server_config_util_read_spki_pubkey(const char *pubkey_path, char **pubkey)
roman3f9b65c2023-06-05 14:26:58 +0200522{
523 int ret = 0;
roman44af5052024-04-05 12:31:24 +0200524 void *pub_pkey = NULL;
roman13145912023-08-17 15:36:54 +0200525
roman44af5052024-04-05 12:31:24 +0200526 NC_CHECK_ARG_RET(NULL, pubkey_path, pubkey, 1);
roman3f9b65c2023-06-05 14:26:58 +0200527
528 /* read the pubkey from file */
roman44af5052024-04-05 12:31:24 +0200529 pub_pkey = nc_tls_import_pubkey_file_wrap(pubkey_path);
roman13145912023-08-17 15:36:54 +0200530 if (!pub_pkey) {
roman13145912023-08-17 15:36:54 +0200531 return 1;
roman3f9b65c2023-06-05 14:26:58 +0200532 }
533
roman72908d42024-04-26 16:13:17 +0200534 ret = nc_server_config_util_pkey_to_ssh_pubkey(pub_pkey, pubkey);
roman44af5052024-04-05 12:31:24 +0200535 nc_tls_privkey_destroy_wrap(pub_pkey);
roman3f9b65c2023-06-05 14:26:58 +0200536 return ret;
537}
538
roman3f9b65c2023-06-05 14:26:58 +0200539static int
roman72908d42024-04-26 16:13:17 +0200540nc_server_config_util_read_openssh_pubkey(const char *pubkey_path, char **pubkey)
roman3f9b65c2023-06-05 14:26:58 +0200541{
542 int ret = 0;
543 ssh_key pub_sshkey = NULL;
544
roman13145912023-08-17 15:36:54 +0200545 NC_CHECK_ARG_RET(NULL, pubkey_path, pubkey, 1);
546
roman3f9b65c2023-06-05 14:26:58 +0200547 ret = ssh_pki_import_pubkey_file(pubkey_path, &pub_sshkey);
548 if (ret) {
549 ERR(NULL, "Importing public key from file \"%s\" failed.", pubkey_path);
550 return ret;
551 }
552
553 ret = ssh_pki_export_pubkey_base64(pub_sshkey, pubkey);
554 if (ret) {
roman13145912023-08-17 15:36:54 +0200555 ERR(NULL, "Importing pubkey failed.");
556 goto cleanup;
roman3f9b65c2023-06-05 14:26:58 +0200557 }
558
roman13145912023-08-17 15:36:54 +0200559cleanup:
roman3f9b65c2023-06-05 14:26:58 +0200560 ssh_key_free(pub_sshkey);
roman13145912023-08-17 15:36:54 +0200561 return 0;
roman3f9b65c2023-06-05 14:26:58 +0200562}
563
roman3f9b65c2023-06-05 14:26:58 +0200564int
Roytakb2794852023-10-18 14:30:22 +0200565nc_server_config_util_get_ssh_pubkey_file(const char *pubkey_path, char **pubkey)
roman3f9b65c2023-06-05 14:26:58 +0200566{
567 int ret = 0;
568 FILE *f = NULL;
569 char *header = NULL;
570 size_t len = 0;
571
roman13145912023-08-17 15:36:54 +0200572 NC_CHECK_ARG_RET(NULL, pubkey_path, pubkey, 1);
roman3f9b65c2023-06-05 14:26:58 +0200573
574 *pubkey = NULL;
575
576 f = fopen(pubkey_path, "r");
577 if (!f) {
578 ERR(NULL, "Unable to open file \"%s\".", pubkey_path);
579 ret = 1;
580 goto cleanup;
581 }
582
roman13145912023-08-17 15:36:54 +0200583 /* read the header */
roman44af5052024-04-05 12:31:24 +0200584 ret = getline(&header, &len, f);
585 fclose(f);
586 if (ret < 0) {
roman3f9b65c2023-06-05 14:26:58 +0200587 ERR(NULL, "Error reading header from file \"%s\".", pubkey_path);
588 ret = 1;
589 goto cleanup;
590 }
roman3f9b65c2023-06-05 14:26:58 +0200591
592 if (!strncmp(header, NC_SUBJECT_PUBKEY_INFO_HEADER, strlen(NC_SUBJECT_PUBKEY_INFO_HEADER))) {
593 /* it's subject public key info public key */
roman72908d42024-04-26 16:13:17 +0200594 ret = nc_server_config_util_read_spki_pubkey(pubkey_path, pubkey);
roman3f9b65c2023-06-05 14:26:58 +0200595 } else if (!strncmp(header, NC_SSH2_PUBKEY_HEADER, strlen(NC_SSH2_PUBKEY_HEADER))) {
596 /* it's ssh2 public key */
roman72908d42024-04-26 16:13:17 +0200597 ret = nc_server_config_util_read_ssh2_pubkey(pubkey_path, pubkey);
roman7fdc84d2023-06-06 13:14:53 +0200598 } else {
roman3f9b65c2023-06-05 14:26:58 +0200599 /* it's probably OpenSSH public key */
roman72908d42024-04-26 16:13:17 +0200600 ret = nc_server_config_util_read_openssh_pubkey(pubkey_path, pubkey);
roman3f9b65c2023-06-05 14:26:58 +0200601 }
roman3f9b65c2023-06-05 14:26:58 +0200602 if (ret) {
603 ERR(NULL, "Error getting public key from file \"%s\".", pubkey_path);
604 goto cleanup;
605 }
606
607cleanup:
roman3f9b65c2023-06-05 14:26:58 +0200608 free(header);
roman3f9b65c2023-06-05 14:26:58 +0200609 return ret;
610}
611
roman3f9b65c2023-06-05 14:26:58 +0200612int
Roytakb2794852023-10-18 14:30:22 +0200613nc_server_config_util_get_spki_pubkey_file(const char *pubkey_path, char **pubkey)
roman3f9b65c2023-06-05 14:26:58 +0200614{
615 int ret = 0;
roman44af5052024-04-05 12:31:24 +0200616 void *pkey = NULL;
roman3f9b65c2023-06-05 14:26:58 +0200617
roman13145912023-08-17 15:36:54 +0200618 NC_CHECK_ARG_RET(NULL, pubkey_path, pubkey, 1);
roman3f9b65c2023-06-05 14:26:58 +0200619
roman3f9b65c2023-06-05 14:26:58 +0200620 *pubkey = NULL;
621
roman44af5052024-04-05 12:31:24 +0200622 pkey = nc_tls_import_pubkey_file_wrap(pubkey_path);
623 if (!pkey) {
roman13145912023-08-17 15:36:54 +0200624 return 1;
625 }
626
roman72908d42024-04-26 16:13:17 +0200627 ret = nc_server_config_util_pkey_to_spki_pubkey(pkey, pubkey);
roman13145912023-08-17 15:36:54 +0200628 if (ret) {
629 goto cleanup;
630 }
631
632cleanup:
roman44af5052024-04-05 12:31:24 +0200633 nc_tls_privkey_destroy_wrap(pkey);
roman13145912023-08-17 15:36:54 +0200634 return ret;
635}
636
637static int
roman72908d42024-04-26 16:13:17 +0200638nc_server_config_util_get_privkey_format(const char *privkey, NC_PRIVKEY_FORMAT *privkey_format)
roman13145912023-08-17 15:36:54 +0200639{
roman72908d42024-04-26 16:13:17 +0200640 NC_CHECK_ARG_RET(NULL, privkey, privkey_format, 1);
roman13145912023-08-17 15:36:54 +0200641
roman72908d42024-04-26 16:13:17 +0200642 if (!strncmp(privkey, NC_PKCS8_PRIVKEY_HEADER, strlen(NC_PKCS8_PRIVKEY_HEADER))) {
roman13145912023-08-17 15:36:54 +0200643 /* it's PKCS8 (X.509) private key */
644 *privkey_format = NC_PRIVKEY_FORMAT_X509;
roman72908d42024-04-26 16:13:17 +0200645 } else if (!strncmp(privkey, NC_OPENSSH_PRIVKEY_HEADER, strlen(NC_OPENSSH_PRIVKEY_HEADER))) {
roman13145912023-08-17 15:36:54 +0200646 /* it's OpenSSH private key */
647 *privkey_format = NC_PRIVKEY_FORMAT_OPENSSH;
roman72908d42024-04-26 16:13:17 +0200648 } else if (!strncmp(privkey, NC_PKCS1_RSA_PRIVKEY_HEADER, strlen(NC_PKCS1_RSA_PRIVKEY_HEADER))) {
roman13145912023-08-17 15:36:54 +0200649 /* it's RSA privkey in PKCS1 format */
650 *privkey_format = NC_PRIVKEY_FORMAT_RSA;
roman72908d42024-04-26 16:13:17 +0200651 } else if (!strncmp(privkey, NC_SEC1_EC_PRIVKEY_HEADER, strlen(NC_SEC1_EC_PRIVKEY_HEADER))) {
roman13145912023-08-17 15:36:54 +0200652 /* it's EC privkey in SEC1 format */
653 *privkey_format = NC_PRIVKEY_FORMAT_EC;
654 } else {
roman72908d42024-04-26 16:13:17 +0200655 /* not supported */
roman13145912023-08-17 15:36:54 +0200656 return 1;
657 }
658
roman13145912023-08-17 15:36:54 +0200659 return 0;
660}
661
662static int
roman72908d42024-04-26 16:13:17 +0200663nc_server_config_util_get_privkey_libtls(const char *privkey_path, char **privkey, void **pkey)
roman13145912023-08-17 15:36:54 +0200664{
roman44af5052024-04-05 12:31:24 +0200665 void *pkey_tmp;
666 char *privkey_tmp;
roman13145912023-08-17 15:36:54 +0200667
romana1583522024-04-23 15:13:17 +0200668 NC_CHECK_ARG_RET(NULL, privkey_path, privkey, pkey, 1);
Roytak7b9bf292023-10-04 14:06:38 +0200669
roman44af5052024-04-05 12:31:24 +0200670 *privkey = *pkey = NULL;
671
romana1583522024-04-23 15:13:17 +0200672 pkey_tmp = nc_tls_import_privkey_file_wrap(privkey_path);
roman44af5052024-04-05 12:31:24 +0200673 if (!pkey_tmp) {
674 return 1;
roman13145912023-08-17 15:36:54 +0200675 }
676
romana1583522024-04-23 15:13:17 +0200677 privkey_tmp = nc_tls_export_privkey_pem_wrap(pkey_tmp);
roman44af5052024-04-05 12:31:24 +0200678 if (!privkey_tmp) {
679 nc_tls_privkey_destroy_wrap(pkey_tmp);
680 return 1;
roman13145912023-08-17 15:36:54 +0200681 }
682
roman44af5052024-04-05 12:31:24 +0200683 *privkey = privkey_tmp;
684 *pkey = pkey_tmp;
685 return 0;
roman13145912023-08-17 15:36:54 +0200686}
687
688static int
roman44af5052024-04-05 12:31:24 +0200689nc_server_config_util_get_privkey_libssh(const char *privkey_path, char **privkey, void **pkey)
roman13145912023-08-17 15:36:54 +0200690{
691 int ret = 0;
roman13145912023-08-17 15:36:54 +0200692 ssh_key key = NULL;
roman44af5052024-04-05 12:31:24 +0200693 void *pkey_tmp = NULL;
694 char *privkey_tmp = NULL;
roman13145912023-08-17 15:36:54 +0200695
Roytak7b9bf292023-10-04 14:06:38 +0200696 NC_CHECK_ARG_RET(NULL, privkey_path, privkey, pkey, 1);
697
roman13145912023-08-17 15:36:54 +0200698 ret = ssh_pki_import_privkey_file(privkey_path, NULL, NULL, NULL, &key);
699 if (ret) {
700 ERR(NULL, "Importing privkey from file \"%s\" failed.", privkey_path);
roman44af5052024-04-05 12:31:24 +0200701 ret = 1;
roman13145912023-08-17 15:36:54 +0200702 goto cleanup;
703 }
704
roman44af5052024-04-05 12:31:24 +0200705 /* export the key in PEM */
706 ret = ssh_pki_export_privkey_base64(key, NULL, NULL, NULL, &privkey_tmp);
roman13145912023-08-17 15:36:54 +0200707 if (ret) {
708 ERR(NULL, "Exporting privkey to base64 failed.");
709 goto cleanup;
710 }
711
roman44af5052024-04-05 12:31:24 +0200712 pkey_tmp = nc_tls_pem_to_privkey_wrap(privkey_tmp);
713 if (!pkey_tmp) {
714 free(privkey_tmp);
roman13145912023-08-17 15:36:54 +0200715 ret = 1;
716 goto cleanup;
717 }
718
roman44af5052024-04-05 12:31:24 +0200719 *privkey = privkey_tmp;
720 *pkey = pkey_tmp;
roman13145912023-08-17 15:36:54 +0200721
722cleanup:
roman13145912023-08-17 15:36:54 +0200723 ssh_key_free(key);
724 return ret;
725}
726
727static int
roman44af5052024-04-05 12:31:24 +0200728nc_server_config_util_pem_strip_header_footer(const char *pem, char **privkey)
729{
730 const char *header, *footer;
731
732 if (!strncmp(pem, NC_PKCS8_PRIVKEY_HEADER, strlen(NC_PKCS8_PRIVKEY_HEADER))) {
733 /* it's PKCS8 (X.509) private key */
734 header = NC_PKCS8_PRIVKEY_HEADER;
735 footer = NC_PKCS8_PRIVKEY_FOOTER;
736 } else if (!strncmp(pem, NC_OPENSSH_PRIVKEY_HEADER, strlen(NC_OPENSSH_PRIVKEY_HEADER))) {
737 /* it's OpenSSH private key */
738 header = NC_OPENSSH_PRIVKEY_HEADER;
739 footer = NC_OPENSSH_PRIVKEY_FOOTER;
740 } else if (!strncmp(pem, NC_PKCS1_RSA_PRIVKEY_HEADER, strlen(NC_PKCS1_RSA_PRIVKEY_HEADER))) {
741 /* it's RSA privkey in PKCS1 format */
742 header = NC_PKCS1_RSA_PRIVKEY_HEADER;
743 footer = NC_PKCS1_RSA_PRIVKEY_FOOTER;
744 } else if (!strncmp(pem, NC_SEC1_EC_PRIVKEY_HEADER, strlen(NC_SEC1_EC_PRIVKEY_HEADER))) {
745 /* it's EC privkey in SEC1 format */
746 header = NC_SEC1_EC_PRIVKEY_HEADER;
747 footer = NC_SEC1_EC_PRIVKEY_FOOTER;
748 } else {
749 return 1;
750 }
751
752 /* make a copy without the header and footer */
753 *privkey = strndup(pem + strlen(header), strlen(pem) - strlen(header) - strlen(footer));
754 NC_CHECK_ERRMEM_RET(!*privkey, 1);
755
756 return 0;
757}
758
759static int
760nc_server_config_util_get_privkey(const char *privkey_path, NC_PRIVKEY_FORMAT *privkey_format, char **privkey, void **pkey)
roman13145912023-08-17 15:36:54 +0200761{
762 int ret = 0;
763 FILE *f_privkey = NULL;
764 char *priv = NULL;
roman72908d42024-04-26 16:13:17 +0200765 char *privkey_header = NULL;
766 size_t header_len = 0;
roman13145912023-08-17 15:36:54 +0200767
Roytak7b9bf292023-10-04 14:06:38 +0200768 NC_CHECK_ARG_RET(NULL, privkey_path, privkey_format, privkey, pkey, 1);
769
roman3f9b65c2023-06-05 14:26:58 +0200770 f_privkey = fopen(privkey_path, "r");
771 if (!f_privkey) {
772 ERR(NULL, "Unable to open file \"%s\".", privkey_path);
773 ret = 1;
774 goto cleanup;
775 }
776
roman72908d42024-04-26 16:13:17 +0200777 /* read privkey header */
778 if (getline(&privkey_header, &header_len, f_privkey) < 0) {
779 ERR(NULL, "Error reading header from file \"%s\".", privkey_path);
780 ret = 1;
roman3f9b65c2023-06-05 14:26:58 +0200781 goto cleanup;
782 }
roman3f9b65c2023-06-05 14:26:58 +0200783
roman72908d42024-04-26 16:13:17 +0200784 /* get privkey format */
785 ret = nc_server_config_util_get_privkey_format(privkey_header, privkey_format);
786 if (ret) {
787 ERR(NULL, "Private key format \"%s\" not supported.", privkey_header);
788 goto cleanup;
789 }
790
791 /* decide how to parse it based on the format */
roman13145912023-08-17 15:36:54 +0200792 switch (*privkey_format) {
793 /* fall-through */
794 case NC_PRIVKEY_FORMAT_RSA:
795 case NC_PRIVKEY_FORMAT_EC:
796 case NC_PRIVKEY_FORMAT_X509:
roman72908d42024-04-26 16:13:17 +0200797 /* the TLS lib can do this */
798 ret = nc_server_config_util_get_privkey_libtls(privkey_path, &priv, pkey);
roman13145912023-08-17 15:36:54 +0200799 break;
800 case NC_PRIVKEY_FORMAT_OPENSSH:
801 /* need the help of libssh */
Roytakb2794852023-10-18 14:30:22 +0200802 ret = nc_server_config_util_get_privkey_libssh(privkey_path, &priv, pkey);
roman13145912023-08-17 15:36:54 +0200803 /* if the function returned successfully, the key is no longer OpenSSH, it was converted to x509 */
804 *privkey_format = NC_PRIVKEY_FORMAT_X509;
805 break;
806 default:
807 ERR(NULL, "Private key format not recognized.");
roman3f9b65c2023-06-05 14:26:58 +0200808 ret = 1;
roman13145912023-08-17 15:36:54 +0200809 break;
roman3f9b65c2023-06-05 14:26:58 +0200810 }
roman3f9b65c2023-06-05 14:26:58 +0200811 if (ret) {
812 goto cleanup;
813 }
814
roman72908d42024-04-26 16:13:17 +0200815 /* parsing may have changed its type, get it again */
816 ret = nc_server_config_util_get_privkey_format(priv, privkey_format);
817 if (ret) {
818 ERR(NULL, "Getting private key format from file \"%s\" failed.", privkey_path);
819 goto cleanup;
820 }
821
romand30af552023-06-16 15:18:27 +0200822 /* strip private key's header and footer */
roman44af5052024-04-05 12:31:24 +0200823 ret = nc_server_config_util_pem_strip_header_footer(priv, privkey);
824 if (ret) {
roman72908d42024-04-26 16:13:17 +0200825 ERR(NULL, "Stripping header and footer from private key \"%s\" failed.", privkey_path);
roman44af5052024-04-05 12:31:24 +0200826 goto cleanup;
827 }
romand30af552023-06-16 15:18:27 +0200828
roman3f9b65c2023-06-05 14:26:58 +0200829cleanup:
830 if (f_privkey) {
831 fclose(f_privkey);
832 }
833
roman72908d42024-04-26 16:13:17 +0200834 free(privkey_header);
romand30af552023-06-16 15:18:27 +0200835 free(priv);
roman13145912023-08-17 15:36:54 +0200836 return ret;
837}
roman3f9b65c2023-06-05 14:26:58 +0200838
roman13145912023-08-17 15:36:54 +0200839int
Roytakb2794852023-10-18 14:30:22 +0200840nc_server_config_util_get_asym_key_pair(const char *privkey_path, const char *pubkey_path, NC_PUBKEY_FORMAT wanted_pubkey_format,
roman13145912023-08-17 15:36:54 +0200841 char **privkey, NC_PRIVKEY_FORMAT *privkey_type, char **pubkey)
842{
843 int ret = 0;
roman44af5052024-04-05 12:31:24 +0200844 void *pkey = NULL;
roman13145912023-08-17 15:36:54 +0200845
846 NC_CHECK_ARG_RET(NULL, privkey_path, privkey, privkey_type, pubkey, 1);
847
848 *privkey = NULL;
849 *pubkey = NULL;
850
851 /* get private key base64 and EVP_PKEY */
roman44af5052024-04-05 12:31:24 +0200852 ret = nc_server_config_util_get_privkey(privkey_path, privkey_type, privkey, &pkey);
roman13145912023-08-17 15:36:54 +0200853 if (ret) {
854 ERR(NULL, "Getting private key from file \"%s\" failed.", privkey_path);
855 goto cleanup;
856 }
857
858 /* get public key, either from file or generate it from the EVP_PKEY */
859 if (!pubkey_path) {
860 if (wanted_pubkey_format == NC_PUBKEY_FORMAT_SSH) {
roman72908d42024-04-26 16:13:17 +0200861 ret = nc_server_config_util_pkey_to_ssh_pubkey(pkey, pubkey);
roman13145912023-08-17 15:36:54 +0200862 } else {
roman72908d42024-04-26 16:13:17 +0200863 ret = nc_server_config_util_pkey_to_spki_pubkey(pkey, pubkey);
roman13145912023-08-17 15:36:54 +0200864 }
865 } else {
866 if (wanted_pubkey_format == NC_PUBKEY_FORMAT_SSH) {
Roytakb2794852023-10-18 14:30:22 +0200867 ret = nc_server_config_util_get_ssh_pubkey_file(pubkey_path, pubkey);
roman13145912023-08-17 15:36:54 +0200868 } else {
Roytakb2794852023-10-18 14:30:22 +0200869 ret = nc_server_config_util_get_spki_pubkey_file(pubkey_path, pubkey);
roman13145912023-08-17 15:36:54 +0200870 }
871 }
872 if (ret) {
873 if (pubkey_path) {
874 ERR(NULL, "Getting public key from file \"%s\" failed.", pubkey_path);
875 } else {
876 ERR(NULL, "Generating public key from private key failed.");
877 }
878 goto cleanup;
879 }
880
881cleanup:
roman44af5052024-04-05 12:31:24 +0200882 nc_tls_privkey_destroy_wrap(pkey);
roman3f9b65c2023-06-05 14:26:58 +0200883 return ret;
884}
885
886API int
Roytakb2794852023-10-18 14:30:22 +0200887nc_server_config_add_address_port(const struct ly_ctx *ctx, const char *endpt_name, NC_TRANSPORT_IMPL transport,
roman142718b2023-06-29 09:15:29 +0200888 const char *address, uint16_t port, struct lyd_node **config)
roman3f9b65c2023-06-05 14:26:58 +0200889{
890 int ret = 0;
romand30af552023-06-16 15:18:27 +0200891 const char *address_fmt, *port_fmt;
roman142718b2023-06-29 09:15:29 +0200892 char port_buf[6] = {0};
roman3f9b65c2023-06-05 14:26:58 +0200893
Roytak7b9bf292023-10-04 14:06:38 +0200894 NC_CHECK_ARG_RET(NULL, ctx, endpt_name, address, config, 1);
roman3f9b65c2023-06-05 14:26:58 +0200895
roman506354a2024-04-11 09:37:22 +0200896 if (transport == NC_TI_SSH) {
romand30af552023-06-16 15:18:27 +0200897 /* SSH path */
Michal Vaskocf898172024-01-15 15:04:28 +0100898 address_fmt = "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/tcp-server-parameters/local-address";
899 port_fmt = "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/tcp-server-parameters/local-port";
roman506354a2024-04-11 09:37:22 +0200900 } else if (transport == NC_TI_TLS) {
romand30af552023-06-16 15:18:27 +0200901 /* TLS path */
Michal Vaskocf898172024-01-15 15:04:28 +0100902 address_fmt = "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/tcp-server-parameters/local-address";
903 port_fmt = "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/tcp-server-parameters/local-port";
roman2eab4742023-06-06 10:00:26 +0200904 } else {
Roytak7b9bf292023-10-04 14:06:38 +0200905 ERR(NULL, "Can not set address and port of a non SSH/TLS endpoint.");
roman2eab4742023-06-06 10:00:26 +0200906 ret = 1;
907 goto cleanup;
roman3f9b65c2023-06-05 14:26:58 +0200908 }
roman3f9b65c2023-06-05 14:26:58 +0200909
Roytakb2794852023-10-18 14:30:22 +0200910 ret = nc_server_config_create(ctx, config, address, address_fmt, endpt_name);
roman3f9b65c2023-06-05 14:26:58 +0200911 if (ret) {
912 goto cleanup;
913 }
914
roman142718b2023-06-29 09:15:29 +0200915 sprintf(port_buf, "%d", port);
Roytakb2794852023-10-18 14:30:22 +0200916 ret = nc_server_config_create(ctx, config, port_buf, port_fmt, endpt_name);
roman3f9b65c2023-06-05 14:26:58 +0200917 if (ret) {
918 goto cleanup;
919 }
romand30af552023-06-16 15:18:27 +0200920
roman3f9b65c2023-06-05 14:26:58 +0200921cleanup:
romand30af552023-06-16 15:18:27 +0200922 return ret;
923}
924
roman5cbb6532023-06-22 12:53:17 +0200925API int
Roytakb2794852023-10-18 14:30:22 +0200926nc_server_config_add_ch_address_port(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name,
roman5cbb6532023-06-22 12:53:17 +0200927 NC_TRANSPORT_IMPL transport, const char *address, const char *port, struct lyd_node **config)
928{
929 int ret = 0;
930 const char *address_fmt, *port_fmt;
931
Roytak7b9bf292023-10-04 14:06:38 +0200932 NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, address, port, config, 1);
roman5cbb6532023-06-22 12:53:17 +0200933
roman506354a2024-04-11 09:37:22 +0200934 if (transport == NC_TI_SSH) {
roman5cbb6532023-06-22 12:53:17 +0200935 /* SSH path */
936 address_fmt = "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/tcp-client-parameters/remote-address";
937 port_fmt = "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/tcp-client-parameters/remote-port";
roman506354a2024-04-11 09:37:22 +0200938 } else if (transport == NC_TI_TLS) {
roman5cbb6532023-06-22 12:53:17 +0200939 /* TLS path */
940 address_fmt = "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tcp-client-parameters/remote-address";
941 port_fmt = "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tcp-client-parameters/remote-port";
942 } else {
943 ERR(NULL, "Transport not supported.");
944 ret = 1;
945 goto cleanup;
946 }
947
Roytakb2794852023-10-18 14:30:22 +0200948 ret = nc_server_config_create(ctx, config, address, address_fmt, client_name, endpt_name);
roman5cbb6532023-06-22 12:53:17 +0200949 if (ret) {
950 goto cleanup;
951 }
952
Roytakb2794852023-10-18 14:30:22 +0200953 ret = nc_server_config_create(ctx, config, port, port_fmt, client_name, endpt_name);
roman5cbb6532023-06-22 12:53:17 +0200954 if (ret) {
955 goto cleanup;
956 }
957
958cleanup:
959 return ret;
960}
961
962API int
Roytakb2794852023-10-18 14:30:22 +0200963nc_server_config_del_endpt(const char *endpt_name, struct lyd_node **config)
roman5cbb6532023-06-22 12:53:17 +0200964{
roman8ba6efa2023-07-12 15:27:52 +0200965 NC_CHECK_ARG_RET(NULL, config, 1);
roman5cbb6532023-06-22 12:53:17 +0200966
roman8ba6efa2023-07-12 15:27:52 +0200967 if (endpt_name) {
Michal Vaskocf898172024-01-15 15:04:28 +0100968 return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']", endpt_name);
roman8ba6efa2023-07-12 15:27:52 +0200969 } else {
Michal Vaskocf898172024-01-15 15:04:28 +0100970 return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint");
roman8ba6efa2023-07-12 15:27:52 +0200971 }
972}
973
974API int
Roytakb2794852023-10-18 14:30:22 +0200975nc_server_config_del_ch_client(const char *ch_client_name, struct lyd_node **config)
roman8ba6efa2023-07-12 15:27:52 +0200976{
977 NC_CHECK_ARG_RET(NULL, config, 1);
978
979 if (ch_client_name) {
Roytakb2794852023-10-18 14:30:22 +0200980 return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']", ch_client_name);
roman8ba6efa2023-07-12 15:27:52 +0200981 } else {
Roytakb2794852023-10-18 14:30:22 +0200982 return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client");
roman8ba6efa2023-07-12 15:27:52 +0200983 }
984}
985
986API int
Roytakb2794852023-10-18 14:30:22 +0200987nc_server_config_del_ch_endpt(const char *client_name, const char *endpt_name, struct lyd_node **config)
roman8ba6efa2023-07-12 15:27:52 +0200988{
989 NC_CHECK_ARG_RET(NULL, client_name, config, 1);
990
991 if (endpt_name) {
Roytakb2794852023-10-18 14:30:22 +0200992 return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/"
roman8ba6efa2023-07-12 15:27:52 +0200993 "endpoints/endpoint[name='%s']", client_name, endpt_name);
994 } else {
Roytakb2794852023-10-18 14:30:22 +0200995 return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/"
roman8ba6efa2023-07-12 15:27:52 +0200996 "endpoints/endpoint", client_name);
997 }
roman5cbb6532023-06-22 12:53:17 +0200998}
999
roman142718b2023-06-29 09:15:29 +02001000API int
Roytakb2794852023-10-18 14:30:22 +02001001nc_server_config_add_keystore_asym_key(const struct ly_ctx *ctx, NC_TRANSPORT_IMPL ti, const char *asym_key_name,
roman13145912023-08-17 15:36:54 +02001002 const char *privkey_path, const char *pubkey_path, struct lyd_node **config)
roman142718b2023-06-29 09:15:29 +02001003{
1004 int ret = 0;
1005 char *privkey = NULL, *pubkey = NULL;
1006 NC_PRIVKEY_FORMAT privkey_type;
roman142718b2023-06-29 09:15:29 +02001007 const char *privkey_format, *pubkey_format;
1008
roman12c3d522023-07-26 13:39:30 +02001009 NC_CHECK_ARG_RET(NULL, ctx, asym_key_name, privkey_path, config, 1);
roman142718b2023-06-29 09:15:29 +02001010
1011 /* get the keys as a string from the given files */
roman506354a2024-04-11 09:37:22 +02001012 if (ti == NC_TI_SSH) {
Michal Vasko7ac7c562024-03-05 09:51:21 +01001013 ret = nc_server_config_util_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_SSH, &privkey,
1014 &privkey_type, &pubkey);
roman506354a2024-04-11 09:37:22 +02001015 } else if (ti == NC_TI_TLS) {
Michal Vasko7ac7c562024-03-05 09:51:21 +01001016 ret = nc_server_config_util_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_X509, &privkey,
1017 &privkey_type, &pubkey);
roman13145912023-08-17 15:36:54 +02001018 } else {
1019 ERR(NULL, "Only SSH and TLS transports can be used to create an asymmetric key pair in the keystore.");
1020 ret = 1;
1021 goto cleanup;
1022 }
roman142718b2023-06-29 09:15:29 +02001023 if (ret) {
roman142718b2023-06-29 09:15:29 +02001024 goto cleanup;
1025 }
1026
1027 /* get pubkey format str */
roman506354a2024-04-11 09:37:22 +02001028 if (ti == NC_TI_SSH) {
roman142718b2023-06-29 09:15:29 +02001029 pubkey_format = "ietf-crypto-types:ssh-public-key-format";
roman13145912023-08-17 15:36:54 +02001030 } else {
1031 pubkey_format = "ietf-crypto-types:subject-public-key-info-format";
roman142718b2023-06-29 09:15:29 +02001032 }
1033
1034 /* get privkey identityref value */
Roytakb2794852023-10-18 14:30:22 +02001035 privkey_format = nc_server_config_util_privkey_format_to_identityref(privkey_type);
roman142718b2023-06-29 09:15:29 +02001036 if (!privkey_format) {
1037 ret = 1;
1038 goto cleanup;
1039 }
1040
Roytakb2794852023-10-18 14:30:22 +02001041 ret = nc_server_config_create(ctx, config, pubkey_format, "/ietf-keystore:keystore/asymmetric-keys/"
roman12c3d522023-07-26 13:39:30 +02001042 "asymmetric-key[name='%s']/public-key-format", asym_key_name);
roman142718b2023-06-29 09:15:29 +02001043 if (ret) {
1044 goto cleanup;
1045 }
1046
Roytakb2794852023-10-18 14:30:22 +02001047 ret = nc_server_config_create(ctx, config, pubkey, "/ietf-keystore:keystore/asymmetric-keys/"
roman12c3d522023-07-26 13:39:30 +02001048 "asymmetric-key[name='%s']/public-key", asym_key_name);
roman142718b2023-06-29 09:15:29 +02001049 if (ret) {
1050 goto cleanup;
1051 }
1052
Roytakb2794852023-10-18 14:30:22 +02001053 ret = nc_server_config_create(ctx, config, privkey_format, "/ietf-keystore:keystore/asymmetric-keys/"
roman12c3d522023-07-26 13:39:30 +02001054 "asymmetric-key[name='%s']/private-key-format", asym_key_name);
roman142718b2023-06-29 09:15:29 +02001055 if (ret) {
1056 goto cleanup;
1057 }
1058
Roytakb2794852023-10-18 14:30:22 +02001059 ret = nc_server_config_create(ctx, config, privkey, "/ietf-keystore:keystore/asymmetric-keys/"
roman12c3d522023-07-26 13:39:30 +02001060 "asymmetric-key[name='%s']/cleartext-private-key", asym_key_name);
roman142718b2023-06-29 09:15:29 +02001061 if (ret) {
1062 goto cleanup;
1063 }
1064
1065cleanup:
1066 free(privkey);
1067 free(pubkey);
1068 return ret;
1069}
1070
1071API int
Roytakb2794852023-10-18 14:30:22 +02001072nc_server_config_del_keystore_asym_key(const char *asym_key_name, struct lyd_node **config)
roman8ba6efa2023-07-12 15:27:52 +02001073{
1074 NC_CHECK_ARG_RET(NULL, config, 1);
1075
roman12c3d522023-07-26 13:39:30 +02001076 if (asym_key_name) {
Roytakb2794852023-10-18 14:30:22 +02001077 return nc_server_config_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='%s']", asym_key_name);
roman8ba6efa2023-07-12 15:27:52 +02001078 } else {
Roytakb2794852023-10-18 14:30:22 +02001079 return nc_server_config_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key");
roman8ba6efa2023-07-12 15:27:52 +02001080 }
1081}
1082
1083API int
Roytakb2794852023-10-18 14:30:22 +02001084nc_server_config_add_keystore_cert(const struct ly_ctx *ctx, const char *asym_key_name, const char *cert_name,
roman12c3d522023-07-26 13:39:30 +02001085 const char *cert_path, struct lyd_node **config)
1086{
1087 int ret = 0;
1088 char *cert = NULL;
1089
1090 NC_CHECK_ARG_RET(NULL, ctx, asym_key_name, cert_name, cert_path, config, 1);
1091
1092 /* get cert data */
Roytakb2794852023-10-18 14:30:22 +02001093 ret = nc_server_config_util_read_certificate(cert_path, &cert);
roman12c3d522023-07-26 13:39:30 +02001094 if (ret) {
1095 goto cleanup;
1096 }
1097
Roytakb2794852023-10-18 14:30:22 +02001098 ret = nc_server_config_create(ctx, config, cert, "/ietf-keystore:keystore/asymmetric-keys/"
roman12c3d522023-07-26 13:39:30 +02001099 "asymmetric-key[name='%s']/certificates/certificate[name='%s']/cert-data", asym_key_name, cert_name);
1100
1101cleanup:
1102 free(cert);
1103 return ret;
1104}
1105
1106API int
Roytakb2794852023-10-18 14:30:22 +02001107nc_server_config_del_keystore_cert(const char *asym_key_name, const char *cert_name, struct lyd_node **config)
roman12c3d522023-07-26 13:39:30 +02001108{
1109 NC_CHECK_ARG_RET(NULL, asym_key_name, config, 1);
1110
1111 if (cert_name) {
Roytakb2794852023-10-18 14:30:22 +02001112 return nc_server_config_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='%s']/"
roman12c3d522023-07-26 13:39:30 +02001113 "certificates/certificate[name='%s']", asym_key_name, cert_name);
1114 } else {
Roytakb2794852023-10-18 14:30:22 +02001115 return nc_server_config_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='%s']/"
roman12c3d522023-07-26 13:39:30 +02001116 "certificates/certificate", asym_key_name);
1117 }
1118}
1119
1120API int
romand348b942023-10-13 14:32:19 +02001121nc_server_config_add_truststore_pubkey(const struct ly_ctx *ctx, const char *pub_bag_name, const char *pubkey_name,
1122 const char *pubkey_path, struct lyd_node **config)
roman142718b2023-06-29 09:15:29 +02001123{
1124 int ret = 0;
1125 char *pubkey = NULL;
roman13145912023-08-17 15:36:54 +02001126 const char *pubkey_format = "ietf-crypto-types:ssh-public-key-format";
roman142718b2023-06-29 09:15:29 +02001127
roman12c3d522023-07-26 13:39:30 +02001128 NC_CHECK_ARG_RET(NULL, ctx, pub_bag_name, pubkey_name, pubkey_path, config, 1);
roman142718b2023-06-29 09:15:29 +02001129
romand348b942023-10-13 14:32:19 +02001130 ret = nc_server_config_util_get_ssh_pubkey_file(pubkey_path, &pubkey);
roman142718b2023-06-29 09:15:29 +02001131 if (ret) {
1132 goto cleanup;
1133 }
1134
Roytakb2794852023-10-18 14:30:22 +02001135 ret = nc_server_config_create(ctx, config, pubkey_format, "/ietf-truststore:truststore/public-key-bags/"
roman12c3d522023-07-26 13:39:30 +02001136 "public-key-bag[name='%s']/public-key[name='%s']/public-key-format", pub_bag_name, pubkey_name);
roman142718b2023-06-29 09:15:29 +02001137 if (ret) {
1138 goto cleanup;
1139 }
1140
Roytakb2794852023-10-18 14:30:22 +02001141 ret = nc_server_config_create(ctx, config, pubkey, "/ietf-truststore:truststore/public-key-bags/"
roman12c3d522023-07-26 13:39:30 +02001142 "public-key-bag[name='%s']/public-key[name='%s']/public-key", pub_bag_name, pubkey_name);
roman142718b2023-06-29 09:15:29 +02001143 if (ret) {
1144 goto cleanup;
1145 }
1146
1147cleanup:
1148 free(pubkey);
1149 return ret;
1150}
1151
roman8ba6efa2023-07-12 15:27:52 +02001152API int
Roytakb2794852023-10-18 14:30:22 +02001153nc_server_config_del_truststore_pubkey(const char *pub_bag_name,
roman8ba6efa2023-07-12 15:27:52 +02001154 const char *pubkey_name, struct lyd_node **config)
1155{
roman12c3d522023-07-26 13:39:30 +02001156 NC_CHECK_ARG_RET(NULL, pub_bag_name, config, 1);
roman8ba6efa2023-07-12 15:27:52 +02001157
1158 if (pubkey_name) {
Roytakb2794852023-10-18 14:30:22 +02001159 return nc_server_config_delete(config, "/ietf-truststore:truststore/public-key-bags/"
roman12c3d522023-07-26 13:39:30 +02001160 "public-key-bag[name='%s']/public-key[name='%s']", pub_bag_name, pubkey_name);
roman8ba6efa2023-07-12 15:27:52 +02001161 } else {
Roytakb2794852023-10-18 14:30:22 +02001162 return nc_server_config_delete(config, "/ietf-truststore:truststore/public-key-bags/"
roman12c3d522023-07-26 13:39:30 +02001163 "public-key-bag[name='%s']/public-key", pub_bag_name);
1164 }
1165}
1166
1167API int
Roytakb2794852023-10-18 14:30:22 +02001168nc_server_config_add_truststore_cert(const struct ly_ctx *ctx, const char *cert_bag_name, const char *cert_name,
roman12c3d522023-07-26 13:39:30 +02001169 const char *cert_path, struct lyd_node **config)
1170{
1171 int ret = 0;
1172 char *cert = NULL;
1173
1174 NC_CHECK_ARG_RET(NULL, ctx, cert_bag_name, cert_name, cert_path, config, 1);
1175
Roytakb2794852023-10-18 14:30:22 +02001176 ret = nc_server_config_util_read_certificate(cert_path, &cert);
roman12c3d522023-07-26 13:39:30 +02001177 if (ret) {
1178 goto cleanup;
1179 }
1180
Roytakb2794852023-10-18 14:30:22 +02001181 ret = nc_server_config_create(ctx, config, cert, "/ietf-truststore:truststore/certificate-bags/"
roman12c3d522023-07-26 13:39:30 +02001182 "certificate-bag[name='%s']/certificate[name='%s']/cert-data", cert_bag_name, cert_name);
1183 if (ret) {
1184 goto cleanup;
1185 }
1186
1187cleanup:
1188 free(cert);
1189 return ret;
1190}
1191
1192API int
Roytakb2794852023-10-18 14:30:22 +02001193nc_server_config_del_truststore_cert(const char *cert_bag_name,
roman12c3d522023-07-26 13:39:30 +02001194 const char *cert_name, struct lyd_node **config)
1195{
1196 NC_CHECK_ARG_RET(NULL, cert_bag_name, config, 1);
1197
1198 if (cert_name) {
Roytakb2794852023-10-18 14:30:22 +02001199 return nc_server_config_delete(config, "/ietf-truststore:truststore/certificate-bags/"
roman12c3d522023-07-26 13:39:30 +02001200 "certificate-bag[name='%s']/certificate[name='%s']", cert_bag_name, cert_name);
1201 } else {
Roytakb2794852023-10-18 14:30:22 +02001202 return nc_server_config_delete(config, "/ietf-truststore:truststore/certificate-bags/"
roman12c3d522023-07-26 13:39:30 +02001203 "certificate-bag[name='%s']/certificate", cert_bag_name);
roman8ba6efa2023-07-12 15:27:52 +02001204 }
1205}
1206
roman2eab4742023-06-06 10:00:26 +02001207#endif /* NC_ENABLED_SSH_TLS */
romanb6f44032023-06-30 15:07:56 +02001208
romanb6f44032023-06-30 15:07:56 +02001209API int
Roytakb2794852023-10-18 14:30:22 +02001210nc_server_config_add_ch_persistent(const struct ly_ctx *ctx, const char *ch_client_name, struct lyd_node **config)
romanb6f44032023-06-30 15:07:56 +02001211{
1212 NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, config, 1);
1213
1214 /* delete periodic tree if exists */
Roytakb2794852023-10-18 14:30:22 +02001215 if (nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
romanb6f44032023-06-30 15:07:56 +02001216 "netconf-client[name='%s']/connection-type/periodic", ch_client_name)) {
1217 return 1;
1218 }
1219
Roytakb2794852023-10-18 14:30:22 +02001220 return nc_server_config_create(ctx, config, NULL, "/ietf-netconf-server:netconf-server/call-home/"
romanb6f44032023-06-30 15:07:56 +02001221 "netconf-client[name='%s']/connection-type/persistent", ch_client_name);
1222}
1223
1224API int
Roytakb2794852023-10-18 14:30:22 +02001225nc_server_config_add_ch_period(const struct ly_ctx *ctx, const char *ch_client_name, uint16_t period,
romanb6f44032023-06-30 15:07:56 +02001226 struct lyd_node **config)
1227{
1228 char buf[6] = {0};
1229
Roytak7b9bf292023-10-04 14:06:38 +02001230 NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, config, 1);
romanb6f44032023-06-30 15:07:56 +02001231
1232 /* delete persistent tree if exists */
Roytakb2794852023-10-18 14:30:22 +02001233 if (nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
romanb6f44032023-06-30 15:07:56 +02001234 "netconf-client[name='%s']/connection-type/persistent", ch_client_name)) {
1235 return 1;
1236 }
1237
roman5d9fc732023-10-26 11:26:57 +02001238 sprintf(buf, "%" PRIu16, period);
Roytakb2794852023-10-18 14:30:22 +02001239 return nc_server_config_create(ctx, config, buf, "/ietf-netconf-server:netconf-server/call-home/"
romanb6f44032023-06-30 15:07:56 +02001240 "netconf-client[name='%s']/connection-type/periodic/period", ch_client_name);
1241}
1242
1243API int
Roytakb2794852023-10-18 14:30:22 +02001244nc_server_config_del_ch_period(const char *ch_client_name, struct lyd_node **config)
roman8ba6efa2023-07-12 15:27:52 +02001245{
1246 NC_CHECK_ARG_RET(NULL, ch_client_name, config, 1);
1247
Roytakb2794852023-10-18 14:30:22 +02001248 return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
roman8ba6efa2023-07-12 15:27:52 +02001249 "netconf-client[name='%s']/connection-type/periodic/period", ch_client_name);
1250}
1251
1252API int
Roytakb2794852023-10-18 14:30:22 +02001253nc_server_config_add_ch_anchor_time(const struct ly_ctx *ctx, const char *ch_client_name,
romanb6f44032023-06-30 15:07:56 +02001254 const char *anchor_time, struct lyd_node **config)
1255{
Roytak7b9bf292023-10-04 14:06:38 +02001256 NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, anchor_time, config, 1);
romanb6f44032023-06-30 15:07:56 +02001257
1258 /* delete persistent tree if exists */
Roytakb2794852023-10-18 14:30:22 +02001259 if (nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
romanb6f44032023-06-30 15:07:56 +02001260 "netconf-client[name='%s']/connection-type/persistent", ch_client_name)) {
1261 return 1;
1262 }
1263
Roytakb2794852023-10-18 14:30:22 +02001264 return nc_server_config_create(ctx, config, anchor_time, "/ietf-netconf-server:netconf-server/call-home/"
romanb6f44032023-06-30 15:07:56 +02001265 "netconf-client[name='%s']/connection-type/periodic/anchor-time", ch_client_name);
1266}
1267
1268API int
Roytakb2794852023-10-18 14:30:22 +02001269nc_server_config_del_ch_anchor_time(const char *ch_client_name, struct lyd_node **config)
roman8ba6efa2023-07-12 15:27:52 +02001270{
1271 NC_CHECK_ARG_RET(NULL, ch_client_name, config, 1);
1272
Roytakb2794852023-10-18 14:30:22 +02001273 return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
roman8ba6efa2023-07-12 15:27:52 +02001274 "netconf-client[name='%s']/connection-type/periodic/anchor-time", ch_client_name);
1275}
1276
1277API int
Roytakb2794852023-10-18 14:30:22 +02001278nc_server_config_add_ch_idle_timeout(const struct ly_ctx *ctx, const char *ch_client_name,
romanb6f44032023-06-30 15:07:56 +02001279 uint16_t idle_timeout, struct lyd_node **config)
1280{
1281 char buf[6] = {0};
1282
Roytak7b9bf292023-10-04 14:06:38 +02001283 NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, config, 1);
romanb6f44032023-06-30 15:07:56 +02001284
1285 /* delete persistent tree if exists */
Roytakb2794852023-10-18 14:30:22 +02001286 if (nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
romanb6f44032023-06-30 15:07:56 +02001287 "netconf-client[name='%s']/connection-type/persistent", ch_client_name)) {
1288 return 1;
1289 }
1290
roman5d9fc732023-10-26 11:26:57 +02001291 sprintf(buf, "%" PRIu16, idle_timeout);
Roytakb2794852023-10-18 14:30:22 +02001292 return nc_server_config_create(ctx, config, buf, "/ietf-netconf-server:netconf-server/call-home/"
romanb6f44032023-06-30 15:07:56 +02001293 "netconf-client[name='%s']/connection-type/periodic/idle-timeout", ch_client_name);
1294}
1295
1296API int
Roytakb2794852023-10-18 14:30:22 +02001297nc_server_config_del_ch_idle_timeout(const char *ch_client_name, struct lyd_node **config)
roman8ba6efa2023-07-12 15:27:52 +02001298{
1299 NC_CHECK_ARG_RET(NULL, ch_client_name, config, 1);
1300
Roytakb2794852023-10-18 14:30:22 +02001301 return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
roman8ba6efa2023-07-12 15:27:52 +02001302 "netconf-client[name='%s']/connection-type/periodic/idle-timeout", ch_client_name);
1303}
1304
1305API int
Roytakb2794852023-10-18 14:30:22 +02001306nc_server_config_add_ch_reconnect_strategy(const struct ly_ctx *ctx, const char *ch_client_name,
roman8ba6efa2023-07-12 15:27:52 +02001307 NC_CH_START_WITH start_with, uint16_t max_wait, uint8_t max_attempts, struct lyd_node **config)
romanb6f44032023-06-30 15:07:56 +02001308{
1309 int ret = 0;
1310 char *path = NULL;
1311 char buf[6] = {0};
1312 const char *start_with_val;
1313
1314 NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, config, 1);
1315
1316 /* prepared the path */
roman3a95bb22023-10-26 11:07:17 +02001317 ret = asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/reconnect-strategy", ch_client_name);
1318 NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup);
romanb6f44032023-06-30 15:07:56 +02001319
romanded52582023-11-08 15:21:30 +01001320 /* get string value from enum */
1321 if (start_with == NC_CH_FIRST_LISTED) {
1322 start_with_val = "first-listed";
1323 } else if (start_with == NC_CH_LAST_CONNECTED) {
1324 start_with_val = "last-connected";
1325 } else if (start_with == NC_CH_RANDOM) {
1326 start_with_val = "random-selection";
1327 } else {
1328 ERR(NULL, "Unknown reconnect strategy.");
1329 goto cleanup;
1330 }
romanb6f44032023-06-30 15:07:56 +02001331
romanded52582023-11-08 15:21:30 +01001332 ret = nc_server_config_append(ctx, path, "start-with", start_with_val, config);
1333 if (ret) {
1334 goto cleanup;
romanb6f44032023-06-30 15:07:56 +02001335 }
1336
1337 if (max_attempts) {
roman5d9fc732023-10-26 11:26:57 +02001338 sprintf(buf, "%" PRIu8, max_attempts);
Roytakb2794852023-10-18 14:30:22 +02001339 ret = nc_server_config_append(ctx, path, "max-attempts", buf, config);
romanb6f44032023-06-30 15:07:56 +02001340 if (ret) {
1341 goto cleanup;
1342 }
1343 memset(buf, 0, 6);
1344 }
1345
1346 if (max_wait) {
roman5d9fc732023-10-26 11:26:57 +02001347 sprintf(buf, "%" PRIu16, max_wait);
Roytakb2794852023-10-18 14:30:22 +02001348 ret = nc_server_config_append(ctx, path, "max-wait", buf, config);
romanb6f44032023-06-30 15:07:56 +02001349 if (ret) {
1350 goto cleanup;
1351 }
1352 }
1353
1354cleanup:
1355 free(path);
1356 return ret;
1357}
roman8ba6efa2023-07-12 15:27:52 +02001358
1359API int
Roytakb2794852023-10-18 14:30:22 +02001360nc_server_config_del_ch_reconnect_strategy(const char *ch_client_name, struct lyd_node **config)
roman8ba6efa2023-07-12 15:27:52 +02001361{
1362 NC_CHECK_ARG_RET(NULL, ch_client_name, config, 1);
1363
Roytakb2794852023-10-18 14:30:22 +02001364 return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
roman8ba6efa2023-07-12 15:27:52 +02001365 "netconf-client[name='%s']/reconnect-strategy", ch_client_name);
1366}