1 /*************************************************************************
3 * Copyright 2020 highstreet technologies GmbH and others
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 ***************************************************************************/
20 #include "nc_client.h"
21 #include "utils/log_utils.h"
22 #include "utils/sys_utils.h"
27 #include "core/session.h"
28 #include "core/nc_config.h"
30 #include <libnetconf2/session.h>
31 #include <libnetconf2/session_client.h>
32 #include <libnetconf2/messages_client.h>
34 static char *nc_client_pass_cb(const char *username, const char *hostname, void *priv) {
35 nc_client_t *client = (nc_client_t *)priv;
36 return strdup(client->password);
39 static int nc_client_auth_hostkey_check(const char *hostname, ssh_session session, void *priv) {
40 return 0; //auto-authorize
43 nc_client_t *nc_client_ssh_connect(const char *host, uint16_t port, const char *username, const char *password) {
49 nc_client_t *client = (nc_client_t *)malloc(sizeof(nc_client_t));
54 client->edit_batch_root = 0;
56 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, 3);
57 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, -1);
58 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1);
60 nc_client_ssh_set_username(username);
61 client->password = strdup(password);
62 if(client->password == 0) {
63 log_error("strdup failed\n");
68 nc_client_ssh_set_auth_password_clb(nc_client_pass_cb, client);
69 nc_client_ssh_set_auth_hostkey_check_clb(nc_client_auth_hostkey_check, 0);
71 client->session = nc_connect_ssh(host, port, 0);
72 if(client->session == 0) {
73 log_error("nc_connect_ssh failed\n");
74 free(client->password);
82 nc_client_t *nc_client_tls_connect(const char *host, uint16_t port) {
86 nc_client_t *client = (nc_client_t *)malloc(sizeof(nc_client_t));
91 client->edit_batch_root = 0;
93 int rc = nc_client_tls_set_cert_key_paths(CLIENT_CERT_PATH, CLIENT_KEY_PATH);
95 log_error("nc_client_tls_set_cert_key_paths failed\n");
99 rc = nc_client_tls_set_trusted_ca_paths(CLIENT_CA_FILE, 0);
101 log_error("nc_client_tls_set_trusted_ca_paths failed\n");
105 client->session = nc_connect_tls(host, port, 0);
106 if(client->session == 0) {
107 log_error("nc_connect_tls failed\n");
115 int nc_client_disconnect(nc_client_t *client) {
118 nc_session_free(client->session, 0);
119 free(client->password);
125 struct lyd_node *nc_client_send_rpc(nc_client_t *client, struct lyd_node *data, int timeout) {
130 struct nc_reply *reply;
131 NC_MSG_TYPE send_ret;
132 NC_MSG_TYPE reply_ret;
136 if(lyd_print_mem(&xmldata, data, LYD_XML, 0) != 0) {
137 log_error("lyd_print_mem failed\n");
141 rpc = nc_rpc_act_generic_xml(xmldata, NC_PARAMTYPE_CONST);
143 log_error("could not create rpc\n");
149 send_ret = nc_send_rpc(client->session, rpc, timeout, &msg_id);
150 if(send_ret != NC_MSG_RPC) {
151 log_error("could not send rpc\n");
157 repeat_nc_recv_reply:
158 reply_ret = nc_recv_reply(client->session, rpc, msg_id, timeout, LYD_OPT_DESTRUCT | LYD_OPT_NOSIBLINGS, &reply);
159 if(reply_ret != NC_MSG_REPLY) {
160 if(reply_ret == NC_MSG_NOTIF) {
161 goto repeat_nc_recv_reply;
164 log_error("could not get rpc reply\n");
170 if(reply->type != NC_RPL_DATA) {
171 log_error("reply has no data\n");
174 nc_reply_free(reply);
178 char *ret_data_xml = strdup(""); //libyang does not support having the parent RPC in XML
179 struct lyd_node *chd = 0;
180 LY_TREE_FOR(((struct nc_reply_data *)reply)->data->child, chd) {
182 if(lyd_print_mem(&temp_xml, chd, LYD_XML, 0) != 0) {
183 log_error("lyd_print_mem failed\n");
187 nc_reply_free(reply);
191 ret_data_xml = (char *)realloc(ret_data_xml, sizeof(char) * (strlen(ret_data_xml) + strlen(temp_xml) + 1));
192 strcat(ret_data_xml, temp_xml);
197 nc_reply_free(reply);
200 struct lyd_node *ret_data = lyd_parse_mem(session_context, ret_data_xml, LYD_XML, LYD_OPT_RPCREPLY | LYD_OPT_NOEXTDEPS, data, 0);
205 struct lyd_node *nc_client_get_batch(nc_client_t *client, const char *xpath, int timeout) {
210 struct nc_reply *reply;
211 NC_MSG_TYPE send_ret;
212 NC_MSG_TYPE reply_ret;
215 rpc = nc_rpc_get(xpath, NC_WD_UNKNOWN, NC_PARAMTYPE_CONST);
217 log_error("could not create rpc\n");
222 send_ret = nc_send_rpc(client->session, rpc, timeout, &msg_id);
223 if(send_ret != NC_MSG_RPC) {
224 log_error("could not send rpc\n");
229 repeat_nc_recv_reply:
231 reply_ret = nc_recv_reply(client->session, rpc, msg_id, timeout, LYD_OPT_DESTRUCT | LYD_OPT_NOSIBLINGS, &reply);
232 if(reply_ret != NC_MSG_REPLY) {
233 if(reply_ret == NC_MSG_NOTIF) {
234 goto repeat_nc_recv_reply;
237 log_error("could not get rpc reply\n");
242 if(reply->type != NC_RPL_DATA) {
243 log_error("reply has no data\n");
245 nc_reply_free(reply);
249 char *ret_data_xml = 0;
250 if(lyd_print_mem(&ret_data_xml, ((struct nc_reply_data *)reply)->data, LYD_XML, 0) != 0) {
251 log_error("lyd_print_mem failed\n");
252 nc_reply_free(reply);
257 nc_reply_free(reply);
260 struct lyd_node *ret_data = lyd_parse_mem(session_context, ret_data_xml, LYD_XML, LYD_OPT_DATA | LYD_OPT_NOSIBLINGS);
265 int nc_client_edit_batch(nc_client_t *client, struct lyd_node *data, int timeout) {
270 struct nc_reply *reply;
271 NC_MSG_TYPE send_ret;
272 NC_MSG_TYPE reply_ret;
276 int rc = lyd_print_mem(&content, data, LYD_XML, 0);
278 log_error("lyd_print_mem failed\n");
279 return NTS_ERR_FAILED;
282 rpc = nc_rpc_edit(NC_DATASTORE_RUNNING, NC_RPC_EDIT_DFLTOP_MERGE, NC_RPC_EDIT_TESTOPT_SET, NC_RPC_EDIT_ERROPT_STOP, content, NC_PARAMTYPE_CONST);
284 log_error("could not create rpc\n");
286 return NTS_ERR_FAILED;
290 send_ret = nc_send_rpc(client->session, rpc, timeout, &msg_id);
291 if(send_ret != NC_MSG_RPC) {
292 log_error("could not send rpc\n");
295 return NTS_ERR_FAILED;
298 reply_ret = nc_recv_reply(client->session, rpc, msg_id, timeout, LYD_OPT_DESTRUCT | LYD_OPT_NOSIBLINGS, &reply);
299 if((reply_ret != NC_MSG_REPLY) || (reply->type != NC_RPL_OK)) {
300 log_error("could not get rpc reply\n");
304 return NTS_ERR_FAILED;
308 nc_reply_free(reply);
314 int nc_client_set_item_str(nc_client_t *client, const char *xpath, const char *value) {
319 if(client->edit_batch_root) {
320 struct lyd_node *n = lyd_new_path(client->edit_batch_root, 0, xpath, (void*)value, LYD_ANYDATA_CONSTSTRING, 0);
322 log_error("lyd_new_path error\n");
323 return NTS_ERR_FAILED;
327 client->edit_batch_root = lyd_new_path(0, session_context, xpath, (void*)value, LYD_ANYDATA_CONSTSTRING, 0);
328 if(client->edit_batch_root == 0) {
329 log_error("lyd_new_path error\n");
330 return NTS_ERR_FAILED;
337 int nc_client_edit_apply_changes(nc_client_t *client, int timeout) {
339 assert(client->edit_batch_root);
341 int rc = nc_client_edit_batch(client, client->edit_batch_root, timeout);
342 lyd_free_withsiblings(client->edit_batch_root);
343 client->edit_batch_root = 0;
347 int lyd_utils_dup(sr_session_ctx_t *session, const char *xpath_s, const char *xpath_d, struct lyd_node **tree) {
354 *tree = lyd_new_path(0, session_context, xpath_d, 0, LYD_ANYDATA_CONSTSTRING, 0);
356 return NTS_ERR_FAILED;
360 struct lyd_node *data_s = 0;
361 int rc = sr_get_data(session, xpath_s, 0, 0, 0, &data_s);
362 if(rc != SR_ERR_OK) {
363 log_error("could not get value for xPath=%s from the datastore\n", xpath_s);
365 return NTS_ERR_FAILED;
368 struct lyd_node *next = 0;
369 struct lyd_node *snode = 0;
370 LY_TREE_DFS_BEGIN(data_s, next, snode) {
371 char *xpath_c = lyd_path(snode);
372 if((snode->schema->nodetype == LYS_LEAF) || (snode->schema->nodetype == LYS_LEAFLIST)) {
373 const char *value = ((struct lyd_node_leaf_list*)snode)->value_str;
374 char *new_xpath = str_replace(xpath_c, xpath_s, xpath_d);
376 // ly_log_options(0);
377 ly_verb(LY_LLERR); //checkAL
378 lyd_new_path(*tree, 0, new_xpath, (void*)value, LYD_ANYDATA_CONSTSTRING, 0);
382 LY_TREE_DFS_END(data_s, next, snode);