blob: d7c627c45985366a7667558a5163b0a6983c3749 [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
roman44af5052024-04-05 12:31:24 +0200222nc_server_config_util_bn_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
231 /* prepare buffer for converting BN to binary */
roman44af5052024-04-05 12:31:24 +0200232 *bin_len = nc_tls_get_bn_num_bytes_wrap(bn);
233 bin_tmp = calloc(*bin_len, sizeof *bin_tmp);
roman3a95bb22023-10-26 11:07:17 +0200234 NC_CHECK_ERRMEM_RET(!bin_tmp, 1);
roman13145912023-08-17 15:36:54 +0200235
236 /* convert to binary */
roman44af5052024-04-05 12:31:24 +0200237 nc_tls_bn_bn2bin_wrap(bn, bin_tmp);
roman13145912023-08-17 15:36:54 +0200238
239 /* if the highest bit in the MSB is set a byte with the value 0 has to be prepended */
240 if (bin_tmp[0] & 0x80) {
241 *bin = malloc(*bin_len + 1);
roman3a95bb22023-10-26 11:07:17 +0200242 NC_CHECK_ERRMEM_GOTO(!*bin, ret = 1, cleanup);
roman13145912023-08-17 15:36:54 +0200243 (*bin)[0] = 0;
244 memcpy(*bin + 1, bin_tmp, *bin_len);
245 (*bin_len)++;
246 } else {
247 *bin = malloc(*bin_len);
roman3a95bb22023-10-26 11:07:17 +0200248 NC_CHECK_ERRMEM_GOTO(!*bin, ret = 1, cleanup);
roman13145912023-08-17 15:36:54 +0200249 memcpy(*bin, bin_tmp, *bin_len);
250 }
251
252cleanup:
253 free(bin_tmp);
254 return ret;
255}
256
257/* ssh pubkey defined in RFC 4253 section 6.6 */
258static int
roman44af5052024-04-05 12:31:24 +0200259nc_server_config_util_evp_pkey_to_ssh_pubkey(void *pkey, char **pubkey)
roman13145912023-08-17 15:36:54 +0200260{
261 int ret = 0, e_len, n_len, p_len, bin_len;
roman44af5052024-04-05 12:31:24 +0200262 void *e = NULL, *n = NULL;
roman13145912023-08-17 15:36:54 +0200263 unsigned char *e_bin = NULL, *n_bin = NULL, *p_bin = NULL, *bin = NULL, *bin_tmp;
264 const char *algorithm_name, *curve_name;
265 char *ec_group = NULL;
266 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 +0200267
Roytak7b9bf292023-10-04 14:06:38 +0200268 NC_CHECK_ARG_RET(NULL, pkey, pubkey, 1);
269
roman44af5052024-04-05 12:31:24 +0200270 if (nc_tls_privkey_is_rsa_wrap(pkey)) {
roman13145912023-08-17 15:36:54 +0200271 /* RSA key */
272 algorithm_name = "ssh-rsa";
273
274 /* get the public key params */
roman44af5052024-04-05 12:31:24 +0200275 if (nc_tls_get_rsa_pubkey_params_wrap(pkey, &e, &n)) {
roman13145912023-08-17 15:36:54 +0200276 ret = 1;
277 goto cleanup;
278 }
279
280 /* BIGNUM to bin */
Roytakb2794852023-10-18 14:30:22 +0200281 if (nc_server_config_util_bn_to_bin(e, &e_bin, &e_len) || nc_server_config_util_bn_to_bin(n, &n_bin, &n_len)) {
roman13145912023-08-17 15:36:54 +0200282 ret = 1;
283 goto cleanup;
284 }
285
286 alg_name_len = strlen(algorithm_name);
287 /* buffer for public key in binary, which looks like this:
288 * alg_name len (4 bytes), alg_name, PK exponent len (4 bytes), PK exponent, modulus len (4 bytes), modulus
289 */
290 bin_len = 4 + alg_name_len + 4 + e_len + 4 + n_len;
291 bin = malloc(bin_len);
roman3a95bb22023-10-26 11:07:17 +0200292 NC_CHECK_ERRMEM_GOTO(!bin, ret = 1, cleanup);
roman13145912023-08-17 15:36:54 +0200293
294 /* to network byte order (big endian) */
295 alg_name_len_be = htonl(alg_name_len);
296 e_len_be = htonl(e_len);
297 n_len_be = htonl(n_len);
298
299 /* create the public key in binary */
300 bin_tmp = bin;
301 memcpy(bin_tmp, &alg_name_len_be, 4);
302 bin_tmp += 4;
303 memcpy(bin_tmp, algorithm_name, alg_name_len);
304 bin_tmp += alg_name_len;
305 memcpy(bin_tmp, &e_len_be, 4);
306 bin_tmp += 4;
307 memcpy(bin_tmp, e_bin, e_len);
308 bin_tmp += e_len;
309 memcpy(bin_tmp, &n_len_be, 4);
310 bin_tmp += 4;
311 memcpy(bin_tmp, n_bin, n_len);
roman44af5052024-04-05 12:31:24 +0200312 } else if (nc_tls_privkey_is_ec_wrap(pkey)) {
roman13145912023-08-17 15:36:54 +0200313 /* EC Private key, get it's group first */
roman44af5052024-04-05 12:31:24 +0200314 ec_group = nc_tls_get_ec_group_wrap(pkey);
315 if (!ec_group) {
roman13145912023-08-17 15:36:54 +0200316 ret = 1;
317 goto cleanup;
318 }
319
320 /* get alg and curve names */
321 if (!strcmp(ec_group, "P-256") || !strcmp(ec_group, "secp256r1") || !strcmp(ec_group, "prime256v1")) {
322 algorithm_name = "ecdsa-sha2-nistp256";
323 curve_name = "nistp256";
324 } else if (!strcmp(ec_group, "P-384") || !strcmp(ec_group, "secp384r1")) {
325 algorithm_name = "ecdsa-sha2-nistp384";
326 curve_name = "nistp384";
327 } else if (!strcmp(ec_group, "P-521") || !strcmp(ec_group, "secp521r1")) {
328 algorithm_name = "ecdsa-sha2-nistp521";
329 curve_name = "nistp521";
330 } else {
331 ERR(NULL, "EC group \"%s\" not supported.", ec_group);
332 ret = 1;
333 goto cleanup;
334 }
335
336 /* get the public key - p, which is a point on the elliptic curve */
roman44af5052024-04-05 12:31:24 +0200337 ret = nc_tls_get_ec_pubkey_param_wrap(pkey, &p_bin, &p_len);
338 if (ret) {
339 ERR(NULL, "Getting public key point from the EC private key failed.");
roman13145912023-08-17 15:36:54 +0200340 ret = 1;
341 goto cleanup;
342 }
343
roman13145912023-08-17 15:36:54 +0200344 alg_name_len = strlen(algorithm_name);
345 curve_name_len = strlen(curve_name);
346 /* buffer for public key in binary, which looks like so:
347 * alg_name len (4 bytes), alg_name, curve_name len (4 bytes), curve_name, PK point p len (4 bytes), PK point p
348 */
349 bin_len = 4 + alg_name_len + 4 + curve_name_len + 4 + p_len;
350 bin = malloc(bin_len);
roman3a95bb22023-10-26 11:07:17 +0200351 NC_CHECK_ERRMEM_GOTO(!bin, ret = 1, cleanup);
roman13145912023-08-17 15:36:54 +0200352
353 /* to network byte order (big endian) */
354 alg_name_len_be = htonl(alg_name_len);
355 curve_name_len_be = htonl(curve_name_len);
356 p_len_be = htonl(p_len);
357
358 /* create the public key in binary */
359 bin_tmp = bin;
360 memcpy(bin_tmp, &alg_name_len_be, 4);
361 bin_tmp += 4;
362 memcpy(bin_tmp, algorithm_name, alg_name_len);
363 bin_tmp += alg_name_len;
364 memcpy(bin_tmp, &curve_name_len_be, 4);
365 bin_tmp += 4;
366 memcpy(bin_tmp, curve_name, curve_name_len);
367 bin_tmp += curve_name_len;
368 memcpy(bin_tmp, &p_len_be, 4);
369 bin_tmp += 4;
370 memcpy(bin_tmp, p_bin, p_len);
roman13145912023-08-17 15:36:54 +0200371 } else {
372 ERR(NULL, "Unable to generate public key from private key (Private key type not supported).");
373 ret = 1;
374 goto cleanup;
375 }
376
Roytak7b9bf292023-10-04 14:06:38 +0200377 /* convert created bin to b64 */
roman44af5052024-04-05 12:31:24 +0200378 ret = nc_base64_encode_wrap(bin, bin_len, pubkey);
roman13145912023-08-17 15:36:54 +0200379 if (ret) {
380 ERR(NULL, "Converting public key from binary to base64 failed.");
381 goto cleanup;
382 }
383
384cleanup:
385 free(bin);
386 free(e_bin);
387 free(n_bin);
388 free(ec_group);
389 free(p_bin);
roman13145912023-08-17 15:36:54 +0200390 return ret;
391}
392
393/* spki = subject public key info */
394static int
roman44af5052024-04-05 12:31:24 +0200395nc_server_config_util_evp_pkey_to_spki_pubkey(void *pkey, char **pubkey)
roman13145912023-08-17 15:36:54 +0200396{
roman44af5052024-04-05 12:31:24 +0200397 int ret = 0;
398 char *pub_pem = NULL;
roman13145912023-08-17 15:36:54 +0200399
Roytak7b9bf292023-10-04 14:06:38 +0200400 NC_CHECK_ARG_RET(NULL, pkey, pubkey, 1);
401
roman44af5052024-04-05 12:31:24 +0200402 pub_pem = nc_tls_export_pubkey_wrap(pkey);
403 if (!pub_pem) {
roman13145912023-08-17 15:36:54 +0200404 ret = 1;
405 goto cleanup;
406 }
407
408 /* copy the public key without the header and footer */
roman44af5052024-04-05 12:31:24 +0200409 *pubkey = strndup(pub_pem + strlen(NC_SUBJECT_PUBKEY_INFO_HEADER),
410 strlen(pub_pem) - strlen(NC_SUBJECT_PUBKEY_INFO_HEADER) - strlen(NC_SUBJECT_PUBKEY_INFO_FOOTER));
roman3a95bb22023-10-26 11:07:17 +0200411 NC_CHECK_ERRMEM_GOTO(!*pubkey, ret = 1, cleanup);
roman13145912023-08-17 15:36:54 +0200412
413cleanup:
roman44af5052024-04-05 12:31:24 +0200414 free(pub_pem);
roman13145912023-08-17 15:36:54 +0200415 return ret;
416}
417
roman3f9b65c2023-06-05 14:26:58 +0200418int
Roytakb2794852023-10-18 14:30:22 +0200419nc_server_config_util_read_certificate(const char *cert_path, char **cert)
roman3f9b65c2023-06-05 14:26:58 +0200420{
roman44af5052024-04-05 12:31:24 +0200421 int ret = 0;
422 void *crt = NULL;
423 char *pem = NULL;
roman3f9b65c2023-06-05 14:26:58 +0200424
Roytak7b9bf292023-10-04 14:06:38 +0200425 NC_CHECK_ARG_RET(NULL, cert_path, cert, 1);
roman3f9b65c2023-06-05 14:26:58 +0200426
roman44af5052024-04-05 12:31:24 +0200427 crt = nc_tls_import_cert_file_wrap(cert_path);
428 if (!crt) {
429 return 1;
430 }
431
432 pem = nc_tls_export_cert_wrap(crt);
433 if (!pem) {
roman3f9b65c2023-06-05 14:26:58 +0200434 ret = 1;
435 goto cleanup;
436 }
437
roman44af5052024-04-05 12:31:24 +0200438 /* copy the cert without its header and footer */
439 *cert = strndup(pem + strlen(NC_PEM_CERTIFICATE_HEADER),
440 strlen(pem) - strlen(NC_PEM_CERTIFICATE_HEADER) - strlen(NC_PEM_CERTIFICATE_FOOTER));
roman3a95bb22023-10-26 11:07:17 +0200441 NC_CHECK_ERRMEM_GOTO(!*cert, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +0200442
roman3f9b65c2023-06-05 14:26:58 +0200443cleanup:
roman44af5052024-04-05 12:31:24 +0200444 free(pem);
445 nc_tls_cert_destroy_wrap(crt);
roman3f9b65c2023-06-05 14:26:58 +0200446 return ret;
447}
448
449static int
roman44af5052024-04-05 12:31:24 +0200450nc_server_config_util_read_pubkey_ssh2(const char *pubkey_path, char **pubkey)
roman3f9b65c2023-06-05 14:26:58 +0200451{
452 char *buffer = NULL;
453 size_t size = 0, pubkey_len = 0;
454 void *tmp;
455 ssize_t read;
456 int ret = 0;
roman44af5052024-04-05 12:31:24 +0200457 FILE *f = NULL;
roman3f9b65c2023-06-05 14:26:58 +0200458
roman44af5052024-04-05 12:31:24 +0200459 NC_CHECK_ARG_RET(NULL, pubkey_path, pubkey, 1);
460
461 f = fopen(pubkey_path, "r");
462 if (!f) {
463 ERR(NULL, "Failed to open file \"%s\".", pubkey_path);
464 ret = 1;
465 goto cleanup;
466 }
Roytak7b9bf292023-10-04 14:06:38 +0200467
468 /* read lines from the file and create the public key without NL from it */
roman3f9b65c2023-06-05 14:26:58 +0200469 while ((read = getline(&buffer, &size, f)) > 0) {
470 if (!strncmp(buffer, "----", 4)) {
Roytak7b9bf292023-10-04 14:06:38 +0200471 /* skip header and footer */
roman3f9b65c2023-06-05 14:26:58 +0200472 continue;
473 }
474
475 if (!strncmp(buffer, "Comment:", 8)) {
Roytak7b9bf292023-10-04 14:06:38 +0200476 /* skip a comment */
roman3f9b65c2023-06-05 14:26:58 +0200477 continue;
478 }
479
480 if (buffer[read - 1] == '\n') {
Roytak7b9bf292023-10-04 14:06:38 +0200481 /* avoid NL */
roman3f9b65c2023-06-05 14:26:58 +0200482 read--;
483 }
484
485 tmp = realloc(*pubkey, pubkey_len + read + 1);
roman3a95bb22023-10-26 11:07:17 +0200486 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
roman3f9b65c2023-06-05 14:26:58 +0200487
488 *pubkey = tmp;
489 memcpy(*pubkey + pubkey_len, buffer, read);
490 pubkey_len += read;
491 }
492
493 if (!pubkey_len) {
494 ERR(NULL, "Unexpected public key format.");
495 ret = 1;
496 goto cleanup;
497 }
498
499 (*pubkey)[pubkey_len] = '\0';
500
501cleanup:
roman44af5052024-04-05 12:31:24 +0200502 if (f) {
503 fclose(f);
504 }
roman3f9b65c2023-06-05 14:26:58 +0200505 free(buffer);
506 return ret;
507}
508
509static int
roman44af5052024-04-05 12:31:24 +0200510nc_server_config_util_read_pubkey_openssl(const char *pubkey_path, char **pubkey)
roman3f9b65c2023-06-05 14:26:58 +0200511{
512 int ret = 0;
roman44af5052024-04-05 12:31:24 +0200513 void *pub_pkey = NULL;
roman13145912023-08-17 15:36:54 +0200514
roman44af5052024-04-05 12:31:24 +0200515 NC_CHECK_ARG_RET(NULL, pubkey_path, pubkey, 1);
roman3f9b65c2023-06-05 14:26:58 +0200516
517 /* read the pubkey from file */
roman44af5052024-04-05 12:31:24 +0200518 pub_pkey = nc_tls_import_pubkey_file_wrap(pubkey_path);
roman13145912023-08-17 15:36:54 +0200519 if (!pub_pkey) {
roman13145912023-08-17 15:36:54 +0200520 return 1;
roman3f9b65c2023-06-05 14:26:58 +0200521 }
522
Roytakb2794852023-10-18 14:30:22 +0200523 ret = nc_server_config_util_evp_pkey_to_ssh_pubkey(pub_pkey, pubkey);
roman44af5052024-04-05 12:31:24 +0200524 nc_tls_privkey_destroy_wrap(pub_pkey);
roman3f9b65c2023-06-05 14:26:58 +0200525 return ret;
526}
527
roman3f9b65c2023-06-05 14:26:58 +0200528static int
Roytakb2794852023-10-18 14:30:22 +0200529nc_server_config_util_read_pubkey_libssh(const char *pubkey_path, char **pubkey)
roman3f9b65c2023-06-05 14:26:58 +0200530{
531 int ret = 0;
532 ssh_key pub_sshkey = NULL;
533
roman13145912023-08-17 15:36:54 +0200534 NC_CHECK_ARG_RET(NULL, pubkey_path, pubkey, 1);
535
roman3f9b65c2023-06-05 14:26:58 +0200536 ret = ssh_pki_import_pubkey_file(pubkey_path, &pub_sshkey);
537 if (ret) {
538 ERR(NULL, "Importing public key from file \"%s\" failed.", pubkey_path);
539 return ret;
540 }
541
542 ret = ssh_pki_export_pubkey_base64(pub_sshkey, pubkey);
543 if (ret) {
roman13145912023-08-17 15:36:54 +0200544 ERR(NULL, "Importing pubkey failed.");
545 goto cleanup;
roman3f9b65c2023-06-05 14:26:58 +0200546 }
547
roman13145912023-08-17 15:36:54 +0200548cleanup:
roman3f9b65c2023-06-05 14:26:58 +0200549 ssh_key_free(pub_sshkey);
roman13145912023-08-17 15:36:54 +0200550 return 0;
roman3f9b65c2023-06-05 14:26:58 +0200551}
552
roman3f9b65c2023-06-05 14:26:58 +0200553int
Roytakb2794852023-10-18 14:30:22 +0200554nc_server_config_util_get_ssh_pubkey_file(const char *pubkey_path, char **pubkey)
roman3f9b65c2023-06-05 14:26:58 +0200555{
556 int ret = 0;
557 FILE *f = NULL;
558 char *header = NULL;
559 size_t len = 0;
560
roman13145912023-08-17 15:36:54 +0200561 NC_CHECK_ARG_RET(NULL, pubkey_path, pubkey, 1);
roman3f9b65c2023-06-05 14:26:58 +0200562
563 *pubkey = NULL;
564
565 f = fopen(pubkey_path, "r");
566 if (!f) {
567 ERR(NULL, "Unable to open file \"%s\".", pubkey_path);
568 ret = 1;
569 goto cleanup;
570 }
571
roman13145912023-08-17 15:36:54 +0200572 /* read the header */
roman44af5052024-04-05 12:31:24 +0200573 ret = getline(&header, &len, f);
574 fclose(f);
575 if (ret < 0) {
roman3f9b65c2023-06-05 14:26:58 +0200576 ERR(NULL, "Error reading header from file \"%s\".", pubkey_path);
577 ret = 1;
578 goto cleanup;
579 }
roman3f9b65c2023-06-05 14:26:58 +0200580
581 if (!strncmp(header, NC_SUBJECT_PUBKEY_INFO_HEADER, strlen(NC_SUBJECT_PUBKEY_INFO_HEADER))) {
582 /* it's subject public key info public key */
roman44af5052024-04-05 12:31:24 +0200583 ret = nc_server_config_util_read_pubkey_openssl(pubkey_path, pubkey);
roman3f9b65c2023-06-05 14:26:58 +0200584 } else if (!strncmp(header, NC_SSH2_PUBKEY_HEADER, strlen(NC_SSH2_PUBKEY_HEADER))) {
585 /* it's ssh2 public key */
roman44af5052024-04-05 12:31:24 +0200586 ret = nc_server_config_util_read_pubkey_ssh2(pubkey_path, pubkey);
roman7fdc84d2023-06-06 13:14:53 +0200587 } else {
roman3f9b65c2023-06-05 14:26:58 +0200588 /* it's probably OpenSSH public key */
Roytakb2794852023-10-18 14:30:22 +0200589 ret = nc_server_config_util_read_pubkey_libssh(pubkey_path, pubkey);
roman3f9b65c2023-06-05 14:26:58 +0200590 }
roman3f9b65c2023-06-05 14:26:58 +0200591 if (ret) {
592 ERR(NULL, "Error getting public key from file \"%s\".", pubkey_path);
593 goto cleanup;
594 }
595
596cleanup:
roman3f9b65c2023-06-05 14:26:58 +0200597 free(header);
roman3f9b65c2023-06-05 14:26:58 +0200598 return ret;
599}
600
roman3f9b65c2023-06-05 14:26:58 +0200601int
Roytakb2794852023-10-18 14:30:22 +0200602nc_server_config_util_get_spki_pubkey_file(const char *pubkey_path, char **pubkey)
roman3f9b65c2023-06-05 14:26:58 +0200603{
604 int ret = 0;
roman44af5052024-04-05 12:31:24 +0200605 void *pkey = NULL;
roman3f9b65c2023-06-05 14:26:58 +0200606
roman13145912023-08-17 15:36:54 +0200607 NC_CHECK_ARG_RET(NULL, pubkey_path, pubkey, 1);
roman3f9b65c2023-06-05 14:26:58 +0200608
roman3f9b65c2023-06-05 14:26:58 +0200609 *pubkey = NULL;
610
roman44af5052024-04-05 12:31:24 +0200611 pkey = nc_tls_import_pubkey_file_wrap(pubkey_path);
612 if (!pkey) {
roman13145912023-08-17 15:36:54 +0200613 return 1;
614 }
615
roman44af5052024-04-05 12:31:24 +0200616 ret = nc_server_config_util_evp_pkey_to_spki_pubkey(pkey, pubkey);
roman13145912023-08-17 15:36:54 +0200617 if (ret) {
618 goto cleanup;
619 }
620
621cleanup:
roman44af5052024-04-05 12:31:24 +0200622 nc_tls_privkey_destroy_wrap(pkey);
roman13145912023-08-17 15:36:54 +0200623 return ret;
624}
625
626static int
Roytakb2794852023-10-18 14:30:22 +0200627nc_server_config_util_privkey_header_to_format(FILE *f_privkey, const char *privkey_path, NC_PRIVKEY_FORMAT *privkey_format)
roman13145912023-08-17 15:36:54 +0200628{
629 char *privkey_header = NULL;
630 size_t len = 0;
631
Roytak7b9bf292023-10-04 14:06:38 +0200632 NC_CHECK_ARG_RET(NULL, f_privkey, privkey_path, privkey_format, 1);
633
roman13145912023-08-17 15:36:54 +0200634 /* read header */
635 if (getline(&privkey_header, &len, f_privkey) < 0) {
636 ERR(NULL, "Error reading header from file \"%s\".", privkey_path);
637 return 1;
638 }
639
640 if (!strncmp(privkey_header, NC_PKCS8_PRIVKEY_HEADER, strlen(NC_PKCS8_PRIVKEY_HEADER))) {
641 /* it's PKCS8 (X.509) private key */
642 *privkey_format = NC_PRIVKEY_FORMAT_X509;
643 } else if (!strncmp(privkey_header, NC_OPENSSH_PRIVKEY_HEADER, strlen(NC_OPENSSH_PRIVKEY_HEADER))) {
644 /* it's OpenSSH private key */
645 *privkey_format = NC_PRIVKEY_FORMAT_OPENSSH;
646 } else if (!strncmp(privkey_header, NC_PKCS1_RSA_PRIVKEY_HEADER, strlen(NC_PKCS1_RSA_PRIVKEY_HEADER))) {
647 /* it's RSA privkey in PKCS1 format */
648 *privkey_format = NC_PRIVKEY_FORMAT_RSA;
649 } else if (!strncmp(privkey_header, NC_SEC1_EC_PRIVKEY_HEADER, strlen(NC_SEC1_EC_PRIVKEY_HEADER))) {
650 /* it's EC privkey in SEC1 format */
651 *privkey_format = NC_PRIVKEY_FORMAT_EC;
652 } else {
653 ERR(NULL, "Private key format (%s) not supported.", privkey_header);
654 free(privkey_header);
655 return 1;
656 }
657
658 /* reset the reading head */
659 rewind(f_privkey);
660 free(privkey_header);
661 return 0;
662}
663
664static int
roman44af5052024-04-05 12:31:24 +0200665nc_server_config_util_get_privkey_openssl(const char *privkey_path, FILE *f_privkey, char **privkey, void **pkey)
roman13145912023-08-17 15:36:54 +0200666{
roman44af5052024-04-05 12:31:24 +0200667 void *pkey_tmp;
668 char *privkey_tmp;
roman13145912023-08-17 15:36:54 +0200669
Roytak7b9bf292023-10-04 14:06:38 +0200670 NC_CHECK_ARG_RET(NULL, privkey_path, f_privkey, privkey, pkey, 1);
671
roman44af5052024-04-05 12:31:24 +0200672 *privkey = *pkey = NULL;
673
674 pkey_tmp = nc_tls_import_key_file_wrap(privkey_path, f_privkey);
675 if (!pkey_tmp) {
676 return 1;
roman13145912023-08-17 15:36:54 +0200677 }
678
roman44af5052024-04-05 12:31:24 +0200679 privkey_tmp = nc_tls_export_key_wrap(pkey_tmp);
680 if (!privkey_tmp) {
681 nc_tls_privkey_destroy_wrap(pkey_tmp);
682 return 1;
roman13145912023-08-17 15:36:54 +0200683 }
684
roman44af5052024-04-05 12:31:24 +0200685 *privkey = privkey_tmp;
686 *pkey = pkey_tmp;
687 return 0;
roman13145912023-08-17 15:36:54 +0200688}
689
690static int
roman44af5052024-04-05 12:31:24 +0200691nc_server_config_util_get_privkey_libssh(const char *privkey_path, char **privkey, void **pkey)
roman13145912023-08-17 15:36:54 +0200692{
693 int ret = 0;
roman13145912023-08-17 15:36:54 +0200694 ssh_key key = NULL;
roman44af5052024-04-05 12:31:24 +0200695 void *pkey_tmp = NULL;
696 char *privkey_tmp = NULL;
roman13145912023-08-17 15:36:54 +0200697
Roytak7b9bf292023-10-04 14:06:38 +0200698 NC_CHECK_ARG_RET(NULL, privkey_path, privkey, pkey, 1);
699
roman13145912023-08-17 15:36:54 +0200700 ret = ssh_pki_import_privkey_file(privkey_path, NULL, NULL, NULL, &key);
701 if (ret) {
702 ERR(NULL, "Importing privkey from file \"%s\" failed.", privkey_path);
roman44af5052024-04-05 12:31:24 +0200703 ret = 1;
roman13145912023-08-17 15:36:54 +0200704 goto cleanup;
705 }
706
roman44af5052024-04-05 12:31:24 +0200707 /* export the key in PEM */
708 ret = ssh_pki_export_privkey_base64(key, NULL, NULL, NULL, &privkey_tmp);
roman13145912023-08-17 15:36:54 +0200709 if (ret) {
710 ERR(NULL, "Exporting privkey to base64 failed.");
711 goto cleanup;
712 }
713
roman44af5052024-04-05 12:31:24 +0200714 pkey_tmp = nc_tls_pem_to_privkey_wrap(privkey_tmp);
715 if (!pkey_tmp) {
716 free(privkey_tmp);
roman13145912023-08-17 15:36:54 +0200717 ret = 1;
718 goto cleanup;
719 }
720
roman44af5052024-04-05 12:31:24 +0200721 *privkey = privkey_tmp;
722 *pkey = pkey_tmp;
roman13145912023-08-17 15:36:54 +0200723
724cleanup:
roman13145912023-08-17 15:36:54 +0200725 ssh_key_free(key);
726 return ret;
727}
728
729static int
roman44af5052024-04-05 12:31:24 +0200730nc_server_config_util_pem_strip_header_footer(const char *pem, char **privkey)
731{
732 const char *header, *footer;
733
734 if (!strncmp(pem, NC_PKCS8_PRIVKEY_HEADER, strlen(NC_PKCS8_PRIVKEY_HEADER))) {
735 /* it's PKCS8 (X.509) private key */
736 header = NC_PKCS8_PRIVKEY_HEADER;
737 footer = NC_PKCS8_PRIVKEY_FOOTER;
738 } else if (!strncmp(pem, NC_OPENSSH_PRIVKEY_HEADER, strlen(NC_OPENSSH_PRIVKEY_HEADER))) {
739 /* it's OpenSSH private key */
740 header = NC_OPENSSH_PRIVKEY_HEADER;
741 footer = NC_OPENSSH_PRIVKEY_FOOTER;
742 } else if (!strncmp(pem, NC_PKCS1_RSA_PRIVKEY_HEADER, strlen(NC_PKCS1_RSA_PRIVKEY_HEADER))) {
743 /* it's RSA privkey in PKCS1 format */
744 header = NC_PKCS1_RSA_PRIVKEY_HEADER;
745 footer = NC_PKCS1_RSA_PRIVKEY_FOOTER;
746 } else if (!strncmp(pem, NC_SEC1_EC_PRIVKEY_HEADER, strlen(NC_SEC1_EC_PRIVKEY_HEADER))) {
747 /* it's EC privkey in SEC1 format */
748 header = NC_SEC1_EC_PRIVKEY_HEADER;
749 footer = NC_SEC1_EC_PRIVKEY_FOOTER;
750 } else {
751 return 1;
752 }
753
754 /* make a copy without the header and footer */
755 *privkey = strndup(pem + strlen(header), strlen(pem) - strlen(header) - strlen(footer));
756 NC_CHECK_ERRMEM_RET(!*privkey, 1);
757
758 return 0;
759}
760
761static int
762nc_server_config_util_get_privkey(const char *privkey_path, NC_PRIVKEY_FORMAT *privkey_format, char **privkey, void **pkey)
roman13145912023-08-17 15:36:54 +0200763{
764 int ret = 0;
765 FILE *f_privkey = NULL;
766 char *priv = NULL;
767
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
roman13145912023-08-17 15:36:54 +0200777 /* read the first line from the privkey to determine it's type */
Roytakb2794852023-10-18 14:30:22 +0200778 ret = nc_server_config_util_privkey_header_to_format(f_privkey, privkey_path, privkey_format);
roman13145912023-08-17 15:36:54 +0200779 if (ret) {
780 ERR(NULL, "Getting private key format from file \"%s\" failed.", privkey_path);
roman3f9b65c2023-06-05 14:26:58 +0200781 goto cleanup;
782 }
roman3f9b65c2023-06-05 14:26:58 +0200783
roman13145912023-08-17 15:36:54 +0200784 switch (*privkey_format) {
785 /* fall-through */
786 case NC_PRIVKEY_FORMAT_RSA:
787 case NC_PRIVKEY_FORMAT_EC:
788 case NC_PRIVKEY_FORMAT_X509:
789 /* OpenSSL solely can do this */
Roytakb2794852023-10-18 14:30:22 +0200790 ret = nc_server_config_util_get_privkey_openssl(privkey_path, f_privkey, &priv, pkey);
roman13145912023-08-17 15:36:54 +0200791 break;
792 case NC_PRIVKEY_FORMAT_OPENSSH:
793 /* need the help of libssh */
Roytakb2794852023-10-18 14:30:22 +0200794 ret = nc_server_config_util_get_privkey_libssh(privkey_path, &priv, pkey);
roman13145912023-08-17 15:36:54 +0200795 /* if the function returned successfully, the key is no longer OpenSSH, it was converted to x509 */
796 *privkey_format = NC_PRIVKEY_FORMAT_X509;
797 break;
798 default:
799 ERR(NULL, "Private key format not recognized.");
roman3f9b65c2023-06-05 14:26:58 +0200800 ret = 1;
roman13145912023-08-17 15:36:54 +0200801 break;
roman3f9b65c2023-06-05 14:26:58 +0200802 }
roman3f9b65c2023-06-05 14:26:58 +0200803 if (ret) {
804 goto cleanup;
805 }
806
romand30af552023-06-16 15:18:27 +0200807 /* strip private key's header and footer */
roman44af5052024-04-05 12:31:24 +0200808 ret = nc_server_config_util_pem_strip_header_footer(priv, privkey);
809 if (ret) {
810 ERR(NULL, "Stripping header and footer from private key failed.");
811 goto cleanup;
812 }
romand30af552023-06-16 15:18:27 +0200813
roman3f9b65c2023-06-05 14:26:58 +0200814cleanup:
815 if (f_privkey) {
816 fclose(f_privkey);
817 }
818
romand30af552023-06-16 15:18:27 +0200819 free(priv);
roman13145912023-08-17 15:36:54 +0200820 return ret;
821}
roman3f9b65c2023-06-05 14:26:58 +0200822
roman13145912023-08-17 15:36:54 +0200823int
Roytakb2794852023-10-18 14:30:22 +0200824nc_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 +0200825 char **privkey, NC_PRIVKEY_FORMAT *privkey_type, char **pubkey)
826{
827 int ret = 0;
roman44af5052024-04-05 12:31:24 +0200828 void *pkey = NULL;
roman13145912023-08-17 15:36:54 +0200829
830 NC_CHECK_ARG_RET(NULL, privkey_path, privkey, privkey_type, pubkey, 1);
831
832 *privkey = NULL;
833 *pubkey = NULL;
834
835 /* get private key base64 and EVP_PKEY */
roman44af5052024-04-05 12:31:24 +0200836 ret = nc_server_config_util_get_privkey(privkey_path, privkey_type, privkey, &pkey);
roman13145912023-08-17 15:36:54 +0200837 if (ret) {
838 ERR(NULL, "Getting private key from file \"%s\" failed.", privkey_path);
839 goto cleanup;
840 }
841
842 /* get public key, either from file or generate it from the EVP_PKEY */
843 if (!pubkey_path) {
844 if (wanted_pubkey_format == NC_PUBKEY_FORMAT_SSH) {
roman44af5052024-04-05 12:31:24 +0200845 ret = nc_server_config_util_evp_pkey_to_ssh_pubkey(pkey, pubkey);
roman13145912023-08-17 15:36:54 +0200846 } else {
roman44af5052024-04-05 12:31:24 +0200847 ret = nc_server_config_util_evp_pkey_to_spki_pubkey(pkey, pubkey);
roman13145912023-08-17 15:36:54 +0200848 }
849 } else {
850 if (wanted_pubkey_format == NC_PUBKEY_FORMAT_SSH) {
Roytakb2794852023-10-18 14:30:22 +0200851 ret = nc_server_config_util_get_ssh_pubkey_file(pubkey_path, pubkey);
roman13145912023-08-17 15:36:54 +0200852 } else {
Roytakb2794852023-10-18 14:30:22 +0200853 ret = nc_server_config_util_get_spki_pubkey_file(pubkey_path, pubkey);
roman13145912023-08-17 15:36:54 +0200854 }
855 }
856 if (ret) {
857 if (pubkey_path) {
858 ERR(NULL, "Getting public key from file \"%s\" failed.", pubkey_path);
859 } else {
860 ERR(NULL, "Generating public key from private key failed.");
861 }
862 goto cleanup;
863 }
864
865cleanup:
roman44af5052024-04-05 12:31:24 +0200866 nc_tls_privkey_destroy_wrap(pkey);
roman3f9b65c2023-06-05 14:26:58 +0200867 return ret;
868}
869
870API int
Roytakb2794852023-10-18 14:30:22 +0200871nc_server_config_add_address_port(const struct ly_ctx *ctx, const char *endpt_name, NC_TRANSPORT_IMPL transport,
roman142718b2023-06-29 09:15:29 +0200872 const char *address, uint16_t port, struct lyd_node **config)
roman3f9b65c2023-06-05 14:26:58 +0200873{
874 int ret = 0;
romand30af552023-06-16 15:18:27 +0200875 const char *address_fmt, *port_fmt;
roman142718b2023-06-29 09:15:29 +0200876 char port_buf[6] = {0};
roman3f9b65c2023-06-05 14:26:58 +0200877
Roytak7b9bf292023-10-04 14:06:38 +0200878 NC_CHECK_ARG_RET(NULL, ctx, endpt_name, address, config, 1);
roman3f9b65c2023-06-05 14:26:58 +0200879
roman506354a2024-04-11 09:37:22 +0200880 if (transport == NC_TI_SSH) {
romand30af552023-06-16 15:18:27 +0200881 /* SSH path */
Michal Vaskocf898172024-01-15 15:04:28 +0100882 address_fmt = "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/tcp-server-parameters/local-address";
883 port_fmt = "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/tcp-server-parameters/local-port";
roman506354a2024-04-11 09:37:22 +0200884 } else if (transport == NC_TI_TLS) {
romand30af552023-06-16 15:18:27 +0200885 /* TLS path */
Michal Vaskocf898172024-01-15 15:04:28 +0100886 address_fmt = "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/tcp-server-parameters/local-address";
887 port_fmt = "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/tcp-server-parameters/local-port";
roman2eab4742023-06-06 10:00:26 +0200888 } else {
Roytak7b9bf292023-10-04 14:06:38 +0200889 ERR(NULL, "Can not set address and port of a non SSH/TLS endpoint.");
roman2eab4742023-06-06 10:00:26 +0200890 ret = 1;
891 goto cleanup;
roman3f9b65c2023-06-05 14:26:58 +0200892 }
roman3f9b65c2023-06-05 14:26:58 +0200893
Roytakb2794852023-10-18 14:30:22 +0200894 ret = nc_server_config_create(ctx, config, address, address_fmt, endpt_name);
roman3f9b65c2023-06-05 14:26:58 +0200895 if (ret) {
896 goto cleanup;
897 }
898
roman142718b2023-06-29 09:15:29 +0200899 sprintf(port_buf, "%d", port);
Roytakb2794852023-10-18 14:30:22 +0200900 ret = nc_server_config_create(ctx, config, port_buf, port_fmt, endpt_name);
roman3f9b65c2023-06-05 14:26:58 +0200901 if (ret) {
902 goto cleanup;
903 }
romand30af552023-06-16 15:18:27 +0200904
roman3f9b65c2023-06-05 14:26:58 +0200905cleanup:
romand30af552023-06-16 15:18:27 +0200906 return ret;
907}
908
roman5cbb6532023-06-22 12:53:17 +0200909API int
Roytakb2794852023-10-18 14:30:22 +0200910nc_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 +0200911 NC_TRANSPORT_IMPL transport, const char *address, const char *port, struct lyd_node **config)
912{
913 int ret = 0;
914 const char *address_fmt, *port_fmt;
915
Roytak7b9bf292023-10-04 14:06:38 +0200916 NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, address, port, config, 1);
roman5cbb6532023-06-22 12:53:17 +0200917
roman506354a2024-04-11 09:37:22 +0200918 if (transport == NC_TI_SSH) {
roman5cbb6532023-06-22 12:53:17 +0200919 /* SSH path */
920 address_fmt = "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/tcp-client-parameters/remote-address";
921 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 +0200922 } else if (transport == NC_TI_TLS) {
roman5cbb6532023-06-22 12:53:17 +0200923 /* TLS path */
924 address_fmt = "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tcp-client-parameters/remote-address";
925 port_fmt = "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tcp-client-parameters/remote-port";
926 } else {
927 ERR(NULL, "Transport not supported.");
928 ret = 1;
929 goto cleanup;
930 }
931
Roytakb2794852023-10-18 14:30:22 +0200932 ret = nc_server_config_create(ctx, config, address, address_fmt, client_name, endpt_name);
roman5cbb6532023-06-22 12:53:17 +0200933 if (ret) {
934 goto cleanup;
935 }
936
Roytakb2794852023-10-18 14:30:22 +0200937 ret = nc_server_config_create(ctx, config, port, port_fmt, client_name, endpt_name);
roman5cbb6532023-06-22 12:53:17 +0200938 if (ret) {
939 goto cleanup;
940 }
941
942cleanup:
943 return ret;
944}
945
946API int
Roytakb2794852023-10-18 14:30:22 +0200947nc_server_config_del_endpt(const char *endpt_name, struct lyd_node **config)
roman5cbb6532023-06-22 12:53:17 +0200948{
roman8ba6efa2023-07-12 15:27:52 +0200949 NC_CHECK_ARG_RET(NULL, config, 1);
roman5cbb6532023-06-22 12:53:17 +0200950
roman8ba6efa2023-07-12 15:27:52 +0200951 if (endpt_name) {
Michal Vaskocf898172024-01-15 15:04:28 +0100952 return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']", endpt_name);
roman8ba6efa2023-07-12 15:27:52 +0200953 } else {
Michal Vaskocf898172024-01-15 15:04:28 +0100954 return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint");
roman8ba6efa2023-07-12 15:27:52 +0200955 }
956}
957
958API int
Roytakb2794852023-10-18 14:30:22 +0200959nc_server_config_del_ch_client(const char *ch_client_name, struct lyd_node **config)
roman8ba6efa2023-07-12 15:27:52 +0200960{
961 NC_CHECK_ARG_RET(NULL, config, 1);
962
963 if (ch_client_name) {
Roytakb2794852023-10-18 14:30:22 +0200964 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 +0200965 } else {
Roytakb2794852023-10-18 14:30:22 +0200966 return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client");
roman8ba6efa2023-07-12 15:27:52 +0200967 }
968}
969
970API int
Roytakb2794852023-10-18 14:30:22 +0200971nc_server_config_del_ch_endpt(const char *client_name, const char *endpt_name, struct lyd_node **config)
roman8ba6efa2023-07-12 15:27:52 +0200972{
973 NC_CHECK_ARG_RET(NULL, client_name, config, 1);
974
975 if (endpt_name) {
Roytakb2794852023-10-18 14:30:22 +0200976 return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/"
roman8ba6efa2023-07-12 15:27:52 +0200977 "endpoints/endpoint[name='%s']", client_name, endpt_name);
978 } else {
Roytakb2794852023-10-18 14:30:22 +0200979 return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/"
roman8ba6efa2023-07-12 15:27:52 +0200980 "endpoints/endpoint", client_name);
981 }
roman5cbb6532023-06-22 12:53:17 +0200982}
983
roman142718b2023-06-29 09:15:29 +0200984API int
Roytakb2794852023-10-18 14:30:22 +0200985nc_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 +0200986 const char *privkey_path, const char *pubkey_path, struct lyd_node **config)
roman142718b2023-06-29 09:15:29 +0200987{
988 int ret = 0;
989 char *privkey = NULL, *pubkey = NULL;
990 NC_PRIVKEY_FORMAT privkey_type;
roman142718b2023-06-29 09:15:29 +0200991 const char *privkey_format, *pubkey_format;
992
roman12c3d522023-07-26 13:39:30 +0200993 NC_CHECK_ARG_RET(NULL, ctx, asym_key_name, privkey_path, config, 1);
roman142718b2023-06-29 09:15:29 +0200994
995 /* get the keys as a string from the given files */
roman506354a2024-04-11 09:37:22 +0200996 if (ti == NC_TI_SSH) {
Michal Vasko7ac7c562024-03-05 09:51:21 +0100997 ret = nc_server_config_util_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_SSH, &privkey,
998 &privkey_type, &pubkey);
roman506354a2024-04-11 09:37:22 +0200999 } else if (ti == NC_TI_TLS) {
Michal Vasko7ac7c562024-03-05 09:51:21 +01001000 ret = nc_server_config_util_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_X509, &privkey,
1001 &privkey_type, &pubkey);
roman13145912023-08-17 15:36:54 +02001002 } else {
1003 ERR(NULL, "Only SSH and TLS transports can be used to create an asymmetric key pair in the keystore.");
1004 ret = 1;
1005 goto cleanup;
1006 }
roman142718b2023-06-29 09:15:29 +02001007 if (ret) {
roman142718b2023-06-29 09:15:29 +02001008 goto cleanup;
1009 }
1010
1011 /* get pubkey format str */
roman506354a2024-04-11 09:37:22 +02001012 if (ti == NC_TI_SSH) {
roman142718b2023-06-29 09:15:29 +02001013 pubkey_format = "ietf-crypto-types:ssh-public-key-format";
roman13145912023-08-17 15:36:54 +02001014 } else {
1015 pubkey_format = "ietf-crypto-types:subject-public-key-info-format";
roman142718b2023-06-29 09:15:29 +02001016 }
1017
1018 /* get privkey identityref value */
Roytakb2794852023-10-18 14:30:22 +02001019 privkey_format = nc_server_config_util_privkey_format_to_identityref(privkey_type);
roman142718b2023-06-29 09:15:29 +02001020 if (!privkey_format) {
1021 ret = 1;
1022 goto cleanup;
1023 }
1024
Roytakb2794852023-10-18 14:30:22 +02001025 ret = nc_server_config_create(ctx, config, pubkey_format, "/ietf-keystore:keystore/asymmetric-keys/"
roman12c3d522023-07-26 13:39:30 +02001026 "asymmetric-key[name='%s']/public-key-format", asym_key_name);
roman142718b2023-06-29 09:15:29 +02001027 if (ret) {
1028 goto cleanup;
1029 }
1030
Roytakb2794852023-10-18 14:30:22 +02001031 ret = nc_server_config_create(ctx, config, pubkey, "/ietf-keystore:keystore/asymmetric-keys/"
roman12c3d522023-07-26 13:39:30 +02001032 "asymmetric-key[name='%s']/public-key", asym_key_name);
roman142718b2023-06-29 09:15:29 +02001033 if (ret) {
1034 goto cleanup;
1035 }
1036
Roytakb2794852023-10-18 14:30:22 +02001037 ret = nc_server_config_create(ctx, config, privkey_format, "/ietf-keystore:keystore/asymmetric-keys/"
roman12c3d522023-07-26 13:39:30 +02001038 "asymmetric-key[name='%s']/private-key-format", asym_key_name);
roman142718b2023-06-29 09:15:29 +02001039 if (ret) {
1040 goto cleanup;
1041 }
1042
Roytakb2794852023-10-18 14:30:22 +02001043 ret = nc_server_config_create(ctx, config, privkey, "/ietf-keystore:keystore/asymmetric-keys/"
roman12c3d522023-07-26 13:39:30 +02001044 "asymmetric-key[name='%s']/cleartext-private-key", asym_key_name);
roman142718b2023-06-29 09:15:29 +02001045 if (ret) {
1046 goto cleanup;
1047 }
1048
1049cleanup:
1050 free(privkey);
1051 free(pubkey);
1052 return ret;
1053}
1054
1055API int
Roytakb2794852023-10-18 14:30:22 +02001056nc_server_config_del_keystore_asym_key(const char *asym_key_name, struct lyd_node **config)
roman8ba6efa2023-07-12 15:27:52 +02001057{
1058 NC_CHECK_ARG_RET(NULL, config, 1);
1059
roman12c3d522023-07-26 13:39:30 +02001060 if (asym_key_name) {
Roytakb2794852023-10-18 14:30:22 +02001061 return nc_server_config_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='%s']", asym_key_name);
roman8ba6efa2023-07-12 15:27:52 +02001062 } else {
Roytakb2794852023-10-18 14:30:22 +02001063 return nc_server_config_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key");
roman8ba6efa2023-07-12 15:27:52 +02001064 }
1065}
1066
1067API int
Roytakb2794852023-10-18 14:30:22 +02001068nc_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 +02001069 const char *cert_path, struct lyd_node **config)
1070{
1071 int ret = 0;
1072 char *cert = NULL;
1073
1074 NC_CHECK_ARG_RET(NULL, ctx, asym_key_name, cert_name, cert_path, config, 1);
1075
1076 /* get cert data */
Roytakb2794852023-10-18 14:30:22 +02001077 ret = nc_server_config_util_read_certificate(cert_path, &cert);
roman12c3d522023-07-26 13:39:30 +02001078 if (ret) {
1079 goto cleanup;
1080 }
1081
Roytakb2794852023-10-18 14:30:22 +02001082 ret = nc_server_config_create(ctx, config, cert, "/ietf-keystore:keystore/asymmetric-keys/"
roman12c3d522023-07-26 13:39:30 +02001083 "asymmetric-key[name='%s']/certificates/certificate[name='%s']/cert-data", asym_key_name, cert_name);
1084
1085cleanup:
1086 free(cert);
1087 return ret;
1088}
1089
1090API int
Roytakb2794852023-10-18 14:30:22 +02001091nc_server_config_del_keystore_cert(const char *asym_key_name, const char *cert_name, struct lyd_node **config)
roman12c3d522023-07-26 13:39:30 +02001092{
1093 NC_CHECK_ARG_RET(NULL, asym_key_name, config, 1);
1094
1095 if (cert_name) {
Roytakb2794852023-10-18 14:30:22 +02001096 return nc_server_config_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='%s']/"
roman12c3d522023-07-26 13:39:30 +02001097 "certificates/certificate[name='%s']", asym_key_name, cert_name);
1098 } else {
Roytakb2794852023-10-18 14:30:22 +02001099 return nc_server_config_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='%s']/"
roman12c3d522023-07-26 13:39:30 +02001100 "certificates/certificate", asym_key_name);
1101 }
1102}
1103
1104API int
romand348b942023-10-13 14:32:19 +02001105nc_server_config_add_truststore_pubkey(const struct ly_ctx *ctx, const char *pub_bag_name, const char *pubkey_name,
1106 const char *pubkey_path, struct lyd_node **config)
roman142718b2023-06-29 09:15:29 +02001107{
1108 int ret = 0;
1109 char *pubkey = NULL;
roman13145912023-08-17 15:36:54 +02001110 const char *pubkey_format = "ietf-crypto-types:ssh-public-key-format";
roman142718b2023-06-29 09:15:29 +02001111
roman12c3d522023-07-26 13:39:30 +02001112 NC_CHECK_ARG_RET(NULL, ctx, pub_bag_name, pubkey_name, pubkey_path, config, 1);
roman142718b2023-06-29 09:15:29 +02001113
romand348b942023-10-13 14:32:19 +02001114 ret = nc_server_config_util_get_ssh_pubkey_file(pubkey_path, &pubkey);
roman142718b2023-06-29 09:15:29 +02001115 if (ret) {
1116 goto cleanup;
1117 }
1118
Roytakb2794852023-10-18 14:30:22 +02001119 ret = nc_server_config_create(ctx, config, pubkey_format, "/ietf-truststore:truststore/public-key-bags/"
roman12c3d522023-07-26 13:39:30 +02001120 "public-key-bag[name='%s']/public-key[name='%s']/public-key-format", pub_bag_name, pubkey_name);
roman142718b2023-06-29 09:15:29 +02001121 if (ret) {
1122 goto cleanup;
1123 }
1124
Roytakb2794852023-10-18 14:30:22 +02001125 ret = nc_server_config_create(ctx, config, pubkey, "/ietf-truststore:truststore/public-key-bags/"
roman12c3d522023-07-26 13:39:30 +02001126 "public-key-bag[name='%s']/public-key[name='%s']/public-key", pub_bag_name, pubkey_name);
roman142718b2023-06-29 09:15:29 +02001127 if (ret) {
1128 goto cleanup;
1129 }
1130
1131cleanup:
1132 free(pubkey);
1133 return ret;
1134}
1135
roman8ba6efa2023-07-12 15:27:52 +02001136API int
Roytakb2794852023-10-18 14:30:22 +02001137nc_server_config_del_truststore_pubkey(const char *pub_bag_name,
roman8ba6efa2023-07-12 15:27:52 +02001138 const char *pubkey_name, struct lyd_node **config)
1139{
roman12c3d522023-07-26 13:39:30 +02001140 NC_CHECK_ARG_RET(NULL, pub_bag_name, config, 1);
roman8ba6efa2023-07-12 15:27:52 +02001141
1142 if (pubkey_name) {
Roytakb2794852023-10-18 14:30:22 +02001143 return nc_server_config_delete(config, "/ietf-truststore:truststore/public-key-bags/"
roman12c3d522023-07-26 13:39:30 +02001144 "public-key-bag[name='%s']/public-key[name='%s']", pub_bag_name, pubkey_name);
roman8ba6efa2023-07-12 15:27:52 +02001145 } else {
Roytakb2794852023-10-18 14:30:22 +02001146 return nc_server_config_delete(config, "/ietf-truststore:truststore/public-key-bags/"
roman12c3d522023-07-26 13:39:30 +02001147 "public-key-bag[name='%s']/public-key", pub_bag_name);
1148 }
1149}
1150
1151API int
Roytakb2794852023-10-18 14:30:22 +02001152nc_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 +02001153 const char *cert_path, struct lyd_node **config)
1154{
1155 int ret = 0;
1156 char *cert = NULL;
1157
1158 NC_CHECK_ARG_RET(NULL, ctx, cert_bag_name, cert_name, cert_path, config, 1);
1159
Roytakb2794852023-10-18 14:30:22 +02001160 ret = nc_server_config_util_read_certificate(cert_path, &cert);
roman12c3d522023-07-26 13:39:30 +02001161 if (ret) {
1162 goto cleanup;
1163 }
1164
Roytakb2794852023-10-18 14:30:22 +02001165 ret = nc_server_config_create(ctx, config, cert, "/ietf-truststore:truststore/certificate-bags/"
roman12c3d522023-07-26 13:39:30 +02001166 "certificate-bag[name='%s']/certificate[name='%s']/cert-data", cert_bag_name, cert_name);
1167 if (ret) {
1168 goto cleanup;
1169 }
1170
1171cleanup:
1172 free(cert);
1173 return ret;
1174}
1175
1176API int
Roytakb2794852023-10-18 14:30:22 +02001177nc_server_config_del_truststore_cert(const char *cert_bag_name,
roman12c3d522023-07-26 13:39:30 +02001178 const char *cert_name, struct lyd_node **config)
1179{
1180 NC_CHECK_ARG_RET(NULL, cert_bag_name, config, 1);
1181
1182 if (cert_name) {
Roytakb2794852023-10-18 14:30:22 +02001183 return nc_server_config_delete(config, "/ietf-truststore:truststore/certificate-bags/"
roman12c3d522023-07-26 13:39:30 +02001184 "certificate-bag[name='%s']/certificate[name='%s']", cert_bag_name, cert_name);
1185 } else {
Roytakb2794852023-10-18 14:30:22 +02001186 return nc_server_config_delete(config, "/ietf-truststore:truststore/certificate-bags/"
roman12c3d522023-07-26 13:39:30 +02001187 "certificate-bag[name='%s']/certificate", cert_bag_name);
roman8ba6efa2023-07-12 15:27:52 +02001188 }
1189}
1190
roman2eab4742023-06-06 10:00:26 +02001191#endif /* NC_ENABLED_SSH_TLS */
romanb6f44032023-06-30 15:07:56 +02001192
romanb6f44032023-06-30 15:07:56 +02001193API int
Roytakb2794852023-10-18 14:30:22 +02001194nc_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 +02001195{
1196 NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, config, 1);
1197
1198 /* delete periodic tree if exists */
Roytakb2794852023-10-18 14:30:22 +02001199 if (nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
romanb6f44032023-06-30 15:07:56 +02001200 "netconf-client[name='%s']/connection-type/periodic", ch_client_name)) {
1201 return 1;
1202 }
1203
Roytakb2794852023-10-18 14:30:22 +02001204 return nc_server_config_create(ctx, config, NULL, "/ietf-netconf-server:netconf-server/call-home/"
romanb6f44032023-06-30 15:07:56 +02001205 "netconf-client[name='%s']/connection-type/persistent", ch_client_name);
1206}
1207
1208API int
Roytakb2794852023-10-18 14:30:22 +02001209nc_server_config_add_ch_period(const struct ly_ctx *ctx, const char *ch_client_name, uint16_t period,
romanb6f44032023-06-30 15:07:56 +02001210 struct lyd_node **config)
1211{
1212 char buf[6] = {0};
1213
Roytak7b9bf292023-10-04 14:06:38 +02001214 NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, config, 1);
romanb6f44032023-06-30 15:07:56 +02001215
1216 /* delete persistent tree if exists */
Roytakb2794852023-10-18 14:30:22 +02001217 if (nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
romanb6f44032023-06-30 15:07:56 +02001218 "netconf-client[name='%s']/connection-type/persistent", ch_client_name)) {
1219 return 1;
1220 }
1221
roman5d9fc732023-10-26 11:26:57 +02001222 sprintf(buf, "%" PRIu16, period);
Roytakb2794852023-10-18 14:30:22 +02001223 return nc_server_config_create(ctx, config, buf, "/ietf-netconf-server:netconf-server/call-home/"
romanb6f44032023-06-30 15:07:56 +02001224 "netconf-client[name='%s']/connection-type/periodic/period", ch_client_name);
1225}
1226
1227API int
Roytakb2794852023-10-18 14:30:22 +02001228nc_server_config_del_ch_period(const char *ch_client_name, struct lyd_node **config)
roman8ba6efa2023-07-12 15:27:52 +02001229{
1230 NC_CHECK_ARG_RET(NULL, ch_client_name, config, 1);
1231
Roytakb2794852023-10-18 14:30:22 +02001232 return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
roman8ba6efa2023-07-12 15:27:52 +02001233 "netconf-client[name='%s']/connection-type/periodic/period", ch_client_name);
1234}
1235
1236API int
Roytakb2794852023-10-18 14:30:22 +02001237nc_server_config_add_ch_anchor_time(const struct ly_ctx *ctx, const char *ch_client_name,
romanb6f44032023-06-30 15:07:56 +02001238 const char *anchor_time, struct lyd_node **config)
1239{
Roytak7b9bf292023-10-04 14:06:38 +02001240 NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, anchor_time, config, 1);
romanb6f44032023-06-30 15:07:56 +02001241
1242 /* delete persistent tree if exists */
Roytakb2794852023-10-18 14:30:22 +02001243 if (nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
romanb6f44032023-06-30 15:07:56 +02001244 "netconf-client[name='%s']/connection-type/persistent", ch_client_name)) {
1245 return 1;
1246 }
1247
Roytakb2794852023-10-18 14:30:22 +02001248 return nc_server_config_create(ctx, config, anchor_time, "/ietf-netconf-server:netconf-server/call-home/"
romanb6f44032023-06-30 15:07:56 +02001249 "netconf-client[name='%s']/connection-type/periodic/anchor-time", ch_client_name);
1250}
1251
1252API int
Roytakb2794852023-10-18 14:30:22 +02001253nc_server_config_del_ch_anchor_time(const char *ch_client_name, struct lyd_node **config)
roman8ba6efa2023-07-12 15:27:52 +02001254{
1255 NC_CHECK_ARG_RET(NULL, ch_client_name, config, 1);
1256
Roytakb2794852023-10-18 14:30:22 +02001257 return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
roman8ba6efa2023-07-12 15:27:52 +02001258 "netconf-client[name='%s']/connection-type/periodic/anchor-time", ch_client_name);
1259}
1260
1261API int
Roytakb2794852023-10-18 14:30:22 +02001262nc_server_config_add_ch_idle_timeout(const struct ly_ctx *ctx, const char *ch_client_name,
romanb6f44032023-06-30 15:07:56 +02001263 uint16_t idle_timeout, struct lyd_node **config)
1264{
1265 char buf[6] = {0};
1266
Roytak7b9bf292023-10-04 14:06:38 +02001267 NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, config, 1);
romanb6f44032023-06-30 15:07:56 +02001268
1269 /* delete persistent tree if exists */
Roytakb2794852023-10-18 14:30:22 +02001270 if (nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
romanb6f44032023-06-30 15:07:56 +02001271 "netconf-client[name='%s']/connection-type/persistent", ch_client_name)) {
1272 return 1;
1273 }
1274
roman5d9fc732023-10-26 11:26:57 +02001275 sprintf(buf, "%" PRIu16, idle_timeout);
Roytakb2794852023-10-18 14:30:22 +02001276 return nc_server_config_create(ctx, config, buf, "/ietf-netconf-server:netconf-server/call-home/"
romanb6f44032023-06-30 15:07:56 +02001277 "netconf-client[name='%s']/connection-type/periodic/idle-timeout", ch_client_name);
1278}
1279
1280API int
Roytakb2794852023-10-18 14:30:22 +02001281nc_server_config_del_ch_idle_timeout(const char *ch_client_name, struct lyd_node **config)
roman8ba6efa2023-07-12 15:27:52 +02001282{
1283 NC_CHECK_ARG_RET(NULL, ch_client_name, config, 1);
1284
Roytakb2794852023-10-18 14:30:22 +02001285 return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
roman8ba6efa2023-07-12 15:27:52 +02001286 "netconf-client[name='%s']/connection-type/periodic/idle-timeout", ch_client_name);
1287}
1288
1289API int
Roytakb2794852023-10-18 14:30:22 +02001290nc_server_config_add_ch_reconnect_strategy(const struct ly_ctx *ctx, const char *ch_client_name,
roman8ba6efa2023-07-12 15:27:52 +02001291 NC_CH_START_WITH start_with, uint16_t max_wait, uint8_t max_attempts, struct lyd_node **config)
romanb6f44032023-06-30 15:07:56 +02001292{
1293 int ret = 0;
1294 char *path = NULL;
1295 char buf[6] = {0};
1296 const char *start_with_val;
1297
1298 NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, config, 1);
1299
1300 /* prepared the path */
roman3a95bb22023-10-26 11:07:17 +02001301 ret = asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/reconnect-strategy", ch_client_name);
1302 NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup);
romanb6f44032023-06-30 15:07:56 +02001303
romanded52582023-11-08 15:21:30 +01001304 /* get string value from enum */
1305 if (start_with == NC_CH_FIRST_LISTED) {
1306 start_with_val = "first-listed";
1307 } else if (start_with == NC_CH_LAST_CONNECTED) {
1308 start_with_val = "last-connected";
1309 } else if (start_with == NC_CH_RANDOM) {
1310 start_with_val = "random-selection";
1311 } else {
1312 ERR(NULL, "Unknown reconnect strategy.");
1313 goto cleanup;
1314 }
romanb6f44032023-06-30 15:07:56 +02001315
romanded52582023-11-08 15:21:30 +01001316 ret = nc_server_config_append(ctx, path, "start-with", start_with_val, config);
1317 if (ret) {
1318 goto cleanup;
romanb6f44032023-06-30 15:07:56 +02001319 }
1320
1321 if (max_attempts) {
roman5d9fc732023-10-26 11:26:57 +02001322 sprintf(buf, "%" PRIu8, max_attempts);
Roytakb2794852023-10-18 14:30:22 +02001323 ret = nc_server_config_append(ctx, path, "max-attempts", buf, config);
romanb6f44032023-06-30 15:07:56 +02001324 if (ret) {
1325 goto cleanup;
1326 }
1327 memset(buf, 0, 6);
1328 }
1329
1330 if (max_wait) {
roman5d9fc732023-10-26 11:26:57 +02001331 sprintf(buf, "%" PRIu16, max_wait);
Roytakb2794852023-10-18 14:30:22 +02001332 ret = nc_server_config_append(ctx, path, "max-wait", buf, config);
romanb6f44032023-06-30 15:07:56 +02001333 if (ret) {
1334 goto cleanup;
1335 }
1336 }
1337
1338cleanup:
1339 free(path);
1340 return ret;
1341}
roman8ba6efa2023-07-12 15:27:52 +02001342
1343API int
Roytakb2794852023-10-18 14:30:22 +02001344nc_server_config_del_ch_reconnect_strategy(const char *ch_client_name, struct lyd_node **config)
roman8ba6efa2023-07-12 15:27:52 +02001345{
1346 NC_CHECK_ARG_RET(NULL, ch_client_name, config, 1);
1347
Roytakb2794852023-10-18 14:30:22 +02001348 return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
roman8ba6efa2023-07-12 15:27:52 +02001349 "netconf-client[name='%s']/reconnect-strategy", ch_client_name);
1350}