1 /*
2  *
3   ***** BEGIN LICENSE BLOCK *****
4 
5   Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
6   Copyright (C) 2017-2019 Olof Hagsand
7   Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC(Netgate)
8 
9   This file is part of CLIXON.
10 
11   Licensed under the Apache License, Version 2.0 (the "License");
12   you may not use this file except in compliance with the License.
13   You may obtain a copy of the License at
14 
15     http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22 
23   Alternatively, the contents of this file may be used under the terms of
24   the GNU General Public License Version 3 or later (the "GPL"),
25   in which case the provisions of the GPL are applicable instead
26   of those above. If you wish to allow use of your version of this file only
27   under the terms of the GPL, and not to allow others to
28   use your version of this file under the terms of Apache License version 2,
29   indicate your decision by deleting the provisions above and replace them with
30   the  notice and other provisions required by the GPL. If you do not delete
31   the provisions above, a recipient may use your version of this file under
32   the terms of any one of the Apache License version 2 or the GPL.
33 
34   ***** END LICENSE BLOCK *****
35 
36  * Netconf library functions. See RFC6241
37  * Functions to generate a netconf error message come in two forms: xml-tree and
38  * cbuf. XML tree is preferred.
39  */
40 
41 #ifdef HAVE_CONFIG_H
42 #include "clixon_config.h" /* generated by config & autoconf */
43 #endif
44 
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <unistd.h>
48 #include <errno.h>
49 #include <string.h>
50 #include <limits.h>
51 #include <stdint.h>
52 #include <syslog.h>
53 
54 /* cligen */
55 #include <cligen/cligen.h>
56 
57 /* clixon */
58 #include "clixon_queue.h"
59 #include "clixon_hash.h"
60 #include "clixon_string.h"
61 #include "clixon_err.h"
62 #include "clixon_handle.h"
63 #include "clixon_yang.h"
64 #include "clixon_log.h"
65 #include "clixon_xml.h"
66 #include "clixon_options.h"
67 #include "clixon_data.h"
68 #include "clixon_xml_map.h"
69 #include "clixon_xml_io.h"
70 #include "clixon_xpath_ctx.h"
71 #include "clixon_xpath.h"
72 #include "clixon_yang_module.h"
73 #include "clixon_yang_parse_lib.h"
74 #include "clixon_netconf_lib.h"
75 
76 /*! Create Netconf in-use error XML tree according to RFC 6241 Appendix A
77  *
78  * The request requires a resource that already is in use.
79  * @param[out] cb       CLIgen buf. Error XML is written in this buffer
80  * @param[in]  type     Error type: "application" or "protocol"
81  * @param[in]  message  Error message (will be XML encoded)
82  */
83 int
netconf_in_use(cbuf * cb,char * type,char * message)84 netconf_in_use(cbuf *cb,
85 	       char *type,
86 	       char *message)
87 {
88     int   retval = -1;
89     char *encstr = NULL;
90 
91     if (cprintf(cb, "<rpc-reply xmlns=\"%s\"><rpc-error>"
92 		"<error-type>%s</error-type>"
93 		"<error-tag>in-use</error-tag>"
94 		"<error-severity>error</error-severity>",
95 		NETCONF_BASE_NAMESPACE,
96 		type) <0)
97 	goto err;
98     if (message){
99 	if (xml_chardata_encode(&encstr, "%s", message) < 0)
100 	    goto done;
101 	if (cprintf(cb, "<error-message>%s</error-message>", encstr) < 0)
102 	    goto err;
103     }
104     if (cprintf(cb, "</rpc-error></rpc-reply>") <0)
105 	goto err;
106     retval = 0;
107  done:
108     if (encstr)
109 	free(encstr);
110     return retval;
111  err:
112     clicon_err(OE_XML, errno, "cprintf");
113     goto done;
114 }
115 
116 /*! Create Netconf invalid-value error XML tree according to RFC 6241 Appendix A
117  *
118  * The request specifies an unacceptable value for one or more parameters.
119  * @param[out] xret    Error XML tree. Free with xml_free after use
120  * @param[in]  type    Error type: "application" or "protocol"
121  * @param[in]  message Error message (will be XML encoded)
122  */
123 int
netconf_invalid_value_xml(cxobj ** xret,char * type,char * message)124 netconf_invalid_value_xml(cxobj **xret,
125 			  char   *type,
126 			  char   *message)
127 {
128     int    retval =-1;
129     cxobj *xerr = NULL;
130     char  *encstr = NULL;
131     cxobj *xa;
132 
133     if (*xret == NULL){
134 	if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
135 	    goto done;
136     }
137     else if (xml_name_set(*xret, "rpc-reply") < 0)
138 	goto done;
139     if ((xa = xml_new("xmlns", *xret, CX_ATTR)) == NULL)
140 	goto done;
141     if (xml_value_set(xa, NETCONF_BASE_NAMESPACE) < 0)
142 	goto done;
143     if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
144 	goto done;
145     if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL,
146 			    "<error-type>%s</error-type>"
147 			    "<error-tag>invalid-value</error-tag>"
148 			    "<error-severity>error</error-severity>", type) < 0)
149 	goto done;
150     if (message){
151 	if (xml_chardata_encode(&encstr, "%s", message) < 0)
152 	    goto done;
153 	if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL,
154 				"<error-message>%s</error-message>", encstr) < 0)
155 	    goto done;
156     }
157     retval = 0;
158  done:
159     if (encstr)
160 	free(encstr);
161     return retval;
162 }
163 
164 /*! Create Netconf invalid-value error XML tree according to RFC 6241 Appendix A
165  *
166  * The request specifies an unacceptable value for one or more parameters.
167  * @param[out] cb      CLIgen buf. Error XML is written in this buffer
168  * @param[in]  type    Error type: "application" or "protocol"
169  * @param[in]  message Error message (will be XML encoded)
170  */
171 int
netconf_invalid_value(cbuf * cb,char * type,char * message)172 netconf_invalid_value(cbuf *cb,
173 		      char *type,
174 		      char *message)
175 {
176     int    retval = -1;
177     cxobj *xret = NULL;
178 
179     if (netconf_invalid_value_xml(&xret, type, message) < 0)
180 	goto done;
181     if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
182 	goto done;
183     retval = 0;
184  done:
185     if (xret)
186 	xml_free(xret);
187     return retval;
188 }
189 
190 /*! Create Netconf too-big error XML tree according to RFC 6241 Appendix A
191  *
192  * The request or response (that would be generated) is
193  * too large for the implementation to handle.
194  * @param[out] cb      CLIgen buf. Error XML is written in this buffer
195  * @param[in]  type    Error type: "transport", "rpc", "application", "protocol"
196  * @param[in]  message Error message (will be XML encoded)
197  */
198 int
netconf_too_big(cbuf * cb,char * type,char * message)199 netconf_too_big(cbuf *cb,
200 		char *type,
201 		char *message)
202 {
203     int     retval = -1;
204     char *encstr = NULL;
205 
206     if (cprintf(cb, "<rpc-reply xmlns=\"%s\"><rpc-error>"
207 		"<error-type>%s</error-type>"
208 		"<error-tag>too-big</error-tag>"
209 		"<error-severity>error</error-severity>",
210 		NETCONF_BASE_NAMESPACE,
211 		type) <0)
212 	goto err;
213     if (message){
214 	if (xml_chardata_encode(&encstr, "%s", message) < 0)
215 	    goto done;
216 	if (cprintf(cb, "<error-message>%s</error-message>", encstr) < 0)
217 	    goto err;
218     }
219     if (cprintf(cb, "</rpc-error></rpc-reply>") <0)
220 	goto err;
221     retval = 0;
222  done:
223     if (encstr)
224 	free(encstr);
225     return retval;
226  err:
227     clicon_err(OE_XML, errno, "cprintf");
228     goto done;
229 }
230 
231 /*! Create Netconf missing-attribute error XML tree according to RFC 6241 App A
232  *
233  * An expected attribute is missing.
234  * @param[out] cb      CLIgen buf. Error XML is written in this buffer
235  * @param[in]  type    Error type: "rpc", "application" or "protocol"
236  * @param[in]  info    bad-attribute or bad-element xml
237  * @param[in]  message Error message (will be XML encoded)
238  */
239 int
netconf_missing_attribute(cbuf * cb,char * type,char * info,char * message)240 netconf_missing_attribute(cbuf *cb,
241 			  char *type,
242 			  char *info,
243 			  char *message)
244 {
245     int   retval = -1;
246     char *encstr = NULL;
247 
248     if (cprintf(cb, "<rpc-reply xmlns=\"%s\"><rpc-error>"
249 		"<error-type>%s</error-type>"
250 		"<error-tag>missing-attribute</error-tag>"
251 		"<error-info>%s</error-info>"
252 		"<error-severity>error</error-severity>",
253 		NETCONF_BASE_NAMESPACE,	type, info) <0)
254 	goto err;
255     if (message){
256 	if (xml_chardata_encode(&encstr, "%s", message) < 0)
257 	    goto done;
258 	if (cprintf(cb, "<error-message>%s</error-message>", encstr) < 0)
259 	    goto err;
260     }
261     if (cprintf(cb, "</rpc-error></rpc-reply>") <0)
262 	goto err;
263     retval = 0;
264  done:
265     return retval;
266  err:
267     clicon_err(OE_XML, errno, "cprintf");
268     goto done;
269 }
270 
271 /*! Create Netconf bad-attribute error XML tree according to RFC 6241 App A
272  *
273  * An attribute value is not correct; e.g., wrong type,
274  * out of range, pattern mismatch.
275  * @param[out] cb      CLIgen buf. Error XML is written in this buffer
276  * @param[in]  type    Error type: "rpc", "application" or "protocol"
277  * @param[in]  info    bad-attribute or bad-element xml
278  * @param[in]  message Error message (will be XML encoded)
279  */
280 int
netconf_bad_attribute(cbuf * cb,char * type,char * info,char * message)281 netconf_bad_attribute(cbuf *cb,
282 		      char *type,
283 		      char *info,
284 		      char *message)
285 {
286     int    retval = -1;
287     cxobj *xret = NULL;
288 
289     if (netconf_bad_attribute_xml(&xret, type, info, message) < 0)
290 	goto done;
291     if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
292 	goto done;
293     retval = 0;
294  done:
295     if (xret)
296 	xml_free(xret);
297     return retval;
298 }
299 
300 /*! Create Netconf bad-attribute error XML tree according to RFC 6241 App A
301  *
302  * An attribute value is not correct; e.g., wrong type,
303  * out of range, pattern mismatch.
304  * @param[out] xret    Error XML tree. Free with xml_free after use
305  * @param[in]  type    Error type: "rpc", "application" or "protocol"
306  * @param[in]  info    bad-attribute or bad-element xml
307  * @param[in]  message Error message (will be XML encoded)
308  */
309 int
netconf_bad_attribute_xml(cxobj ** xret,char * type,char * info,char * message)310 netconf_bad_attribute_xml(cxobj **xret,
311 			  char   *type,
312 			  char   *info,
313 			  char   *message)
314 {
315     int   retval = -1;
316     cxobj *xerr = NULL;
317     char  *encstr = NULL;
318     cxobj *xa;
319 
320     if (*xret == NULL){
321 	if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
322 	    goto done;
323     }
324     else if (xml_name_set(*xret, "rpc-reply") < 0)
325 	goto done;
326     if ((xa = xml_new("xmlns", *xret, CX_ATTR)) == NULL)
327 	goto done;
328     if (xml_value_set(xa, NETCONF_BASE_NAMESPACE) < 0)
329 	goto done;
330     if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
331 	goto done;
332     if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-type>%s</error-type>"
333 			    "<error-tag>bad-attribute</error-tag>"
334 			    "<error-info>%s</error-info>"
335 			    "<error-severity>error</error-severity>", type, info) < 0)
336 	goto done;
337     if (message){
338 	if (xml_chardata_encode(&encstr, "%s", message) < 0)
339 	    goto done;
340 	if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-message>%s</error-message>",
341 				encstr) < 0)
342 	    goto done;
343     }
344     retval = 0;
345  done:
346     if (encstr)
347 	free(encstr);
348     return retval;
349 }
350 
351 
352 /*! Create Netconf unknown-attribute error XML tree according to RFC 6241 App A
353  *
354  * An unexpected attribute is present.
355  * @param[out] cb      CLIgen buf. Error XML is written in this buffer
356  * @param[in]  type    Error type: "rpc", "application" or "protocol"
357  * @param[in]  info    bad-attribute or bad-element xml
358  * @param[in]  message Error message
359  */
360 int
netconf_unknown_attribute(cbuf * cb,char * type,char * info,char * message)361 netconf_unknown_attribute(cbuf *cb,
362 			  char *type,
363 			  char *info,
364 			  char *message)
365 {
366     int   retval = -1;
367     char *encstr = NULL;
368 
369     if (cprintf(cb, "<rpc-reply xmlns=\"%s\"><rpc-error>"
370 		"<error-type>%s</error-type>"
371 		"<error-tag>unknown-attribute</error-tag>"
372 		"<error-info>%s</error-info>"
373 		"<error-severity>error</error-severity>",
374 		NETCONF_BASE_NAMESPACE, type, info) <0)
375 	goto err;
376     if (message){
377 	if (xml_chardata_encode(&encstr, "%s", message) < 0)
378 	    goto done;
379 	if (cprintf(cb, "<error-message>%s</error-message>", encstr) < 0)
380 	    goto err;
381     }
382     if (cprintf(cb, "</rpc-error></rpc-reply>") <0)
383 	goto err;
384     retval = 0;
385  done:
386     if (encstr)
387 	free(encstr);
388     return retval;
389  err:
390     clicon_err(OE_XML, errno, "cprintf");
391     goto done;
392 }
393 
394 /*! Common Netconf element XML tree according to RFC 6241 App A
395  * @param[out] xret    Error XML tree. Free with xml_free after use
396  * @param[in]  type    Error type: "application" or "protocol"
397  * @param[in]  tag     Error tag
398  * @param[in]  element bad-element xml
399  * @param[in]  message Error message (will be XML encoded)
400  */
401 static int
netconf_common_xml(cxobj ** xret,char * type,char * tag,char * infotag,char * element,char * message)402 netconf_common_xml(cxobj **xret,
403 		   char   *type,
404 		   char   *tag,
405 		   char   *infotag,
406 		   char   *element,
407 		   char   *message)
408 {
409     int    retval =-1;
410     cxobj *xerr;
411     char  *encstr = NULL;
412     cxobj *xa;
413 
414     if (*xret == NULL){
415 	if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
416 	    goto done;
417 	if ((xa = xml_new("xmlns", *xret, CX_ATTR)) == NULL)
418 	    goto done;
419 	if (xml_value_set(xa, NETCONF_BASE_NAMESPACE) < 0)
420 	    goto done;
421     }
422     else if (xml_name_set(*xret, "rpc-reply") < 0)
423 	goto done;
424 
425     if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
426 	goto done;
427     if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-type>%s</error-type>"
428 			    "<error-tag>%s</error-tag>"
429 			    "<error-info><%s>%s</%s></error-info>"
430 			    "<error-severity>error</error-severity>",
431 			    type, tag, infotag, element, infotag) < 0)
432 	goto done;
433     if (message){
434 	if (xml_chardata_encode(&encstr, "%s", message) < 0)
435 	    goto done;
436 	if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-message>%s</error-message>",
437 				encstr) < 0)
438 	    goto done;
439     }
440     retval = 0;
441  done:
442     if (encstr)
443 	free(encstr);
444     return retval;
445 }
446 
447 /*! Create Netconf missing-element error XML tree according to RFC 6241 App A
448  *
449  * An expected element is missing.
450  * @param[out] cb      CLIgen buf. Error XML is written in this buffer
451  * @param[in]  type    Error type: "application" or "protocol"
452  * @param[in]  info    bad-element xml
453  * @param[in]  message Error message
454  */
455 int
netconf_missing_element(cbuf * cb,char * type,char * element,char * message)456 netconf_missing_element(cbuf      *cb,
457 			char      *type,
458 			char      *element,
459 			char      *message)
460 {
461     int    retval = -1;
462     cxobj *xret = NULL;
463 
464     if (netconf_common_xml(&xret, type, "missing-element",
465 			   "bad-element", element, message) < 0)
466 	goto done;
467     if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
468 	goto done;
469     retval = 0;
470  done:
471     if (xret)
472 	xml_free(xret);
473     return retval;
474 }
475 
476 /*! Create Netconf missing-element error XML tree according to RFC 6241 App A
477  * @param[out] xret    Error XML tree. Free with xml_free after use
478  * @param[in]  type    Error type: "application" or "protocol"
479  * @param[in]  element bad-element xml
480  * @param[in]  message Error message
481  */
482 int
netconf_missing_element_xml(cxobj ** xret,char * type,char * element,char * message)483 netconf_missing_element_xml(cxobj **xret,
484 			    char   *type,
485 			    char   *element,
486 			    char   *message)
487 {
488     return netconf_common_xml(xret, type, "missing-element",
489 			      "bad-element", element, message);
490 }
491 
492 /*! Create Netconf bad-element error XML tree according to RFC 6241 App A
493  *
494  * An element value is not correct; e.g., wrong type, out of range,
495  * pattern mismatch.
496  * @param[out] cb      CLIgen buf. Error XML is written in this buffer
497  * @param[in]  type    Error type: "application" or "protocol"
498  * @param[in]  elemnt  Bad element name
499  * @param[in]  message Error message
500  */
501 int
netconf_bad_element(cbuf * cb,char * type,char * element,char * message)502 netconf_bad_element(cbuf *cb,
503 		    char *type,
504 		    char *element,
505 		    char *message)
506 {
507     int    retval = -1;
508     cxobj *xret = NULL;
509 
510     if (netconf_common_xml(&xret, type, "bad-element",
511 			   "bad-element",element, message) < 0)
512 	goto done;
513     if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
514 	goto done;
515     retval = 0;
516  done:
517     if (xret)
518 	xml_free(xret);
519     return retval;
520 }
521 
522 int
netconf_bad_element_xml(cxobj ** xret,char * type,char * element,char * message)523 netconf_bad_element_xml(cxobj **xret,
524 			char   *type,
525 			char   *element,
526 			char   *message)
527 {
528     return netconf_common_xml(xret, type, "bad-element", "bad-element", element, message);
529 }
530 
531 /*! Create Netconf unknown-element error XML tree according to RFC 6241 App A
532  *
533  * An unexpected element is present.
534  * @param[out] cb      CLIgen buf. Error XML is written in this buffer
535  * @param[in]  type    Error type: "application" or "protocol"
536  * @param[in]  element Bad element name
537  * @param[in]  message Error message
538  */
539 int
netconf_unknown_element(cbuf * cb,char * type,char * element,char * message)540 netconf_unknown_element(cbuf *cb,
541 			char *type,
542 			char *element,
543 			char *message)
544 {
545     int    retval = -1;
546     cxobj *xret = NULL;
547 
548     if (netconf_common_xml(&xret, type, "unknown-element",
549 			   "bad-element", element, message) < 0)
550 	goto done;
551     if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
552 	goto done;
553     retval = 0;
554  done:
555     if (xret)
556 	xml_free(xret);
557     return retval;
558 }
559 
560 /*! Create Netconf unknown-element error XML tree according to RFC 6241 App A
561  *
562  * An unexpected element is present.
563  * @param[out] xret    XML buffer
564  * @param[in]  type    Error type: "application" or "protocol"
565  * @param[in]  element Bad element name
566  * @param[in]  message Error message
567  */
568 int
netconf_unknown_element_xml(cxobj ** xret,char * type,char * element,char * message)569 netconf_unknown_element_xml(cxobj **xret,
570 			    char   *type,
571 			    char   *element,
572 			    char   *message)
573 {
574     return netconf_common_xml(xret, type, "unknown-element",
575 			      "bad-element", element, message);
576 }
577 
578 /*! Create Netconf unknown-namespace error XML tree according to RFC 6241 App A
579  *
580  * An unexpected namespace is present.
581  * @param[out] cb      CLIgen buf. Error XML is written in this buffer
582  * @param[in]  type    Error type: "application" or "protocol"
583  * @param[in]  info    bad-element or bad-namespace xml
584  * @param[in]  message Error message
585  */
586 int
netconf_unknown_namespace(cbuf * cb,char * type,char * ns,char * message)587 netconf_unknown_namespace(cbuf *cb,
588 			  char *type,
589 			  char *ns,
590 			  char *message)
591 {
592     int    retval = -1;
593     cxobj *xret = NULL;
594 
595     if (netconf_common_xml(&xret, type, "unknown-namespace",
596 			   "bad-namespace", ns, message) < 0)
597 	goto done;
598     if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
599 	goto done;
600     retval = 0;
601  done:
602     if (xret)
603 	xml_free(xret);
604     return retval;
605 }
606 
607 int
netconf_unknown_namespace_xml(cxobj ** xret,char * type,char * ns,char * message)608 netconf_unknown_namespace_xml(cxobj **xret,
609 			      char   *type,
610 			      char   *ns,
611 			      char   *message)
612 {
613     return netconf_common_xml(xret, type, "unknown-namespace",
614 			      "bad-namespace", ns, message);
615 }
616 
617 /*! Create Netconf access-denied error cbuf according to RFC 6241 App A
618  *
619  * Access to the requested protocol operation or data model is denied because
620  * authorization failed.
621  * @param[out] cb      CLIgen buf. Error XML is written in this buffer
622  * @param[in]  type    Error type: "application" or "protocol"
623  * @param[in]  message Error message
624  * @see netconf_access_denied_xml  Same but returns XML tree
625  */
626 int
netconf_access_denied(cbuf * cb,char * type,char * message)627 netconf_access_denied(cbuf *cb,
628 		      char *type,
629 		      char *message)
630 {
631     int    retval = -1;
632     cxobj *xret = NULL;
633 
634     if (netconf_access_denied_xml(&xret, type, message) < 0)
635 	goto done;
636     if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
637 	goto done;
638     retval = 0;
639  done:
640     if (xret)
641 	xml_free(xret);
642     return retval;
643 }
644 
645 /*! Create Netconf access-denied error XML tree according to RFC 6241 App A
646  *
647  * Access to the requested protocol operation or data model is denied because
648  * authorization failed.
649  * @param[out] xret    Error XML tree. Free with xml_free after use
650  * @param[in]  type    Error type: "application" or "protocol"
651  * @param[in]  message Error message  (will be XML encoded)
652  * @code
653  *  cxobj *xret = NULL;
654  *  if (netconf_access_denied_xml(&xret, "protocol", "Unauthorized") < 0)
655  *    err;
656  *  xml_free(xret);
657  * @endcode
658  * @see netconf_access_denied  Same but returns cligen buffer
659  */
660 int
netconf_access_denied_xml(cxobj ** xret,char * type,char * message)661 netconf_access_denied_xml(cxobj **xret,
662 			  char   *type,
663 			  char   *message)
664 {
665     int    retval =-1;
666     cxobj *xerr;
667     char  *encstr = NULL;
668     cxobj *xa;
669 
670     if (*xret == NULL){
671 	if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
672 	    goto done;
673     }
674     else if (xml_name_set(*xret, "rpc-reply") < 0)
675 	goto done;
676     if ((xa = xml_new("xmlns", *xret, CX_ATTR)) == NULL)
677 	goto done;
678     if (xml_value_set(xa, NETCONF_BASE_NAMESPACE) < 0)
679 	goto done;
680     if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
681 	goto done;
682     if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-type>%s</error-type>"
683 			    "<error-tag>access-denied</error-tag>"
684 			    "<error-severity>error</error-severity>", type) < 0)
685 	goto done;
686     if (message){
687 	if (xml_chardata_encode(&encstr, "%s", message) < 0)
688 	    goto done;
689 	if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-message>%s</error-message>",
690 				encstr) < 0)
691 	    goto done;
692     }
693     retval = 0;
694  done:
695     if (encstr)
696 	free(encstr);
697     return retval;
698 }
699 
700 /*! Create Netconf lock-denied error XML tree according to RFC 6241 App A
701  *
702  * Access to the requested lock is denied because the lock is currently held
703  * by another entity.
704  * @param[out] cb      CLIgen buf. Error XML is written in this buffer
705  * @param[in]  info    session-id xml
706  * @param[in]  message Error message
707  */
708 int
netconf_lock_denied(cbuf * cb,char * info,char * message)709 netconf_lock_denied(cbuf *cb,
710 		    char *info,
711 		    char *message)
712 {
713     int   retval = -1;
714     char *encstr = NULL;
715 
716     if (cprintf(cb, "<rpc-reply xmlns=\"%s\"><rpc-error>"
717 		"<error-type>protocol</error-type>"
718 		"<error-tag>lock-denied</error-tag>"
719 		"<error-info>%s</error-info>"
720 		"<error-severity>error</error-severity>",
721 		NETCONF_BASE_NAMESPACE, info) <0)
722 	goto err;
723     if (message){
724 	if (xml_chardata_encode(&encstr, "%s", message) < 0)
725 	    goto done;
726 	if (cprintf(cb, "<error-message>%s</error-message>", encstr) < 0)
727 	    goto err;
728     }
729     if (cprintf(cb, "</rpc-error></rpc-reply>") <0)
730 	goto err;
731     retval = 0;
732  done:
733     if (encstr)
734 	free(encstr);
735     return retval;
736  err:
737     clicon_err(OE_XML, errno, "cprintf");
738     goto done;
739 }
740 
741 /*! Create Netconf resource-denied error XML tree according to RFC 6241 App A
742  *
743  * Request could not be completed because of insufficient resources.
744  * @param[out] cb      CLIgen buf. Error XML is written in this buffer
745  * @param[in]  type    Error type: "transport, "rpc", "application", "protocol"
746  * @param[in]  message Error message
747  */
748 int
netconf_resource_denied(cbuf * cb,char * type,char * message)749 netconf_resource_denied(cbuf *cb,
750 			char *type,
751 			char *message)
752 {
753     int   retval = -1;
754     char *encstr = NULL;
755 
756     if (cprintf(cb, "<rpc-reply xmlns=\"%s\"><rpc-error>"
757 		"<error-type>%s</error-type>"
758 		"<error-tag>resource-denied</error-tag>"
759 		"<error-severity>error</error-severity>",
760 		NETCONF_BASE_NAMESPACE, type) <0)
761 	goto err;
762     if (message){
763 	if (xml_chardata_encode(&encstr, "%s", message) < 0)
764 	    goto done;
765 	if (cprintf(cb, "<error-message>%s</error-message>", encstr) < 0)
766 	    goto err;
767     }
768     if (cprintf(cb, "</rpc-error></rpc-reply>") <0)
769 	goto err;
770     retval = 0;
771  done:
772     if (encstr)
773 	free(encstr);
774     return retval;
775  err:
776     clicon_err(OE_XML, errno, "cprintf");
777     goto done;
778 }
779 
780 /*! Create Netconf rollback-failed error XML tree according to RFC 6241 App A
781  *
782  * Request to roll back some configuration change (via rollback-on-error or
783  * <discard-changes> operations) was not completed for some reason.
784  * @param[out] cb      CLIgen buf. Error XML is written in this buffer
785  * @param[in]  type    Error type: "application" or "protocol"
786  * @param[in]  message Error message
787  */
788 int
netconf_rollback_failed(cbuf * cb,char * type,char * message)789 netconf_rollback_failed(cbuf *cb,
790 			char *type,
791 			char *message)
792 {
793     int   retval = -1;
794     char *encstr = NULL;
795 
796     if (cprintf(cb, "<rpc-reply xmlns=\"%s\"><rpc-error>"
797 		"<error-type>%s</error-type>"
798 		"<error-tag>rollback-failed</error-tag>"
799 		"<error-severity>error</error-severity>",
800 		NETCONF_BASE_NAMESPACE, type) <0)
801 	goto err;
802     if (message){
803 	if (xml_chardata_encode(&encstr, "%s", message) < 0)
804 	    goto done;
805 	if (cprintf(cb, "<error-message>%s</error-message>", encstr) < 0)
806 	    goto err;
807     }
808     if (cprintf(cb, "</rpc-error></rpc-reply>") <0)
809 	goto err;
810     retval = 0;
811  done:
812     if (encstr)
813 	free(encstr);
814     return retval;
815  err:
816     clicon_err(OE_XML, errno, "cprintf");
817     goto done;
818 }
819 
820 /*! Create Netconf data-exists error XML tree according to RFC 6241 Appendix A
821  *
822  * Request could not be completed because the relevant
823  * data model content already exists.  For example,
824  * a "create" operation was attempted on data that already exists.
825  * @param[out] cb      CLIgen buf. Error XML is written in this buffer
826  * @param[in]  message Error message
827  */
828 int
netconf_data_exists(cbuf * cb,char * message)829 netconf_data_exists(cbuf      *cb,
830 		    char      *message)
831 {
832     int   retval = -1;
833     char *encstr = NULL;
834 
835     if (cprintf(cb, "<rpc-reply xmlns=\"%s\"><rpc-error>"
836 		"<error-type>application</error-type>"
837 		"<error-tag>data-exists</error-tag>"
838 		"<error-severity>error</error-severity>",
839 		NETCONF_BASE_NAMESPACE) <0)
840 	goto err;
841     if (message){
842 	if (xml_chardata_encode(&encstr, "%s", message) < 0)
843 	    goto done;
844 	if (cprintf(cb, "<error-message>%s</error-message>", encstr) < 0)
845 	    goto err;
846     }
847     if (cprintf(cb, "</rpc-error></rpc-reply>") <0)
848 	goto err;
849     retval = 0;
850  done:
851     if (encstr)
852 	free(encstr);
853     return retval;
854  err:
855     clicon_err(OE_XML, errno, "cprintf");
856     goto done;
857 }
858 
859 /*! Create Netconf data-missing error XML tree according to RFC 6241 App A
860  *
861  * Request could not be completed because the relevant data model content
862  * does not exist.  For example, a "delete" operation was attempted on
863  * data that does not exist.
864  * @param[out] cb      CLIgen buf. Error XML is written in this buffer
865  * @param[in]  missing_choice  If set, see RFC7950: 15.6 violates mandatory choice
866  * @param[in]  message Error message
867  */
868 int
netconf_data_missing(cbuf * cb,char * missing_choice,char * message)869 netconf_data_missing(cbuf *cb,
870 		     char *missing_choice,
871 		     char *message)
872 {
873     int   retval = -1;
874     cxobj *xret = NULL;
875 
876     if (netconf_data_missing_xml(&xret, missing_choice, message) < 0)
877 	goto done;
878     if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
879 	goto done;
880     retval = 0;
881  done:
882     if (xret)
883 	xml_free(xret);
884     return retval;
885 }
886 
887 /*! Create Netconf data-missing error XML tree according to RFC 6241 App A
888  *
889  * Request could not be completed because the relevant data model content
890  * does not exist.  For example, a "delete" operation was attempted on
891  * data that does not exist.
892  * @param[out] xret    Error XML tree. Free with xml_free after use
893  * @param[in]  missing_choice  If set, see RFC7950: 15.6 violates mandatiry choice
894  * @param[in]  message Error message
895  */
896 int
netconf_data_missing_xml(cxobj ** xret,char * missing_choice,char * message)897 netconf_data_missing_xml(cxobj **xret,
898 			 char   *missing_choice,
899 			 char   *message)
900 {
901     int   retval = -1;
902     char *encstr = NULL;
903     cxobj *xerr;
904     cxobj *xa;
905 
906     if (*xret == NULL){
907 	if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
908 	    goto done;
909     }
910     else if (xml_name_set(*xret, "rpc-reply") < 0)
911 	goto done;
912     if ((xa = xml_new("xmlns", *xret, CX_ATTR)) == NULL)
913 	goto done;
914     if (xml_value_set(xa, NETCONF_BASE_NAMESPACE) < 0)
915 	goto done;
916     if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
917 	goto done;
918     if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL,
919 			    "<error-type>application</error-type>"
920 			    "<error-tag>data-missing</error-tag>") < 0)
921 	goto done;
922     if (missing_choice) /* NYI: RFC7950: 15.6 <error-path> */
923 	if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL,
924 				"<error-app-tag>missing-choice</error-app-tag>"
925 				"<error-info><missing-choice>%s</missing-choice></error-info>",
926 				missing_choice) < 0)
927 	    goto done;
928     if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL,
929 			    "<error-severity>error</error-severity>") < 0)
930 	goto done;
931     if (message){
932 	if (xml_chardata_encode(&encstr, "%s", message) < 0)
933 	    goto done;
934 	if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL,
935 				"<error-message>%s</error-message>", encstr) < 0)
936 	    goto done;
937     }
938     retval = 0;
939  done:
940     if (encstr)
941 	free(encstr);
942     return retval;
943 }
944 
945 /*! Create Netconf operation-not-supported error XML according to RFC 6241 App A
946  *
947  * Request could not be completed because the requested operation is not
948  * supported by this implementation.
949  * @param[out] cb      CLIgen buf. Error XML is written in this buffer
950  * @param[in]  type    Error type: "application" or "protocol"
951  * @param[in]  message Error message
952  */
953 int
netconf_operation_not_supported(cbuf * cb,char * type,char * message)954 netconf_operation_not_supported(cbuf *cb,
955 				char *type,
956 				char *message)
957 {
958     int   retval = -1;
959     char *encstr = NULL;
960 
961     if (cprintf(cb, "<rpc-reply xmlns=\"%s\"><rpc-error>"
962 		"<error-type>%s</error-type>"
963 		"<error-tag>operation-not-supported</error-tag>"
964 		"<error-severity>error</error-severity>",
965 		NETCONF_BASE_NAMESPACE, type) <0)
966 	goto err;
967     if (message){
968 	if (xml_chardata_encode(&encstr, "%s", message) < 0)
969 	    goto done;
970 	if (cprintf(cb, "<error-message>%s</error-message>", encstr) < 0)
971 	    goto err;
972     }
973     if (cprintf(cb, "</rpc-error></rpc-reply>") <0)
974 	goto err;
975     retval = 0;
976  done:
977     if (encstr)
978 	free(encstr);
979     return retval;
980  err:
981     clicon_err(OE_XML, errno, "cprintf");
982     goto done;
983 }
984 
985 /*! Create Netconf operation-failed error XML tree according to RFC 6241 App A
986  *
987  * Request could not be completed because the requested operation failed for
988  * some reason not covered by any other error condition.
989  * @param[out] cb      CLIgen buf. Error XML is written in this buffer
990  * @param[in]  type    Error type: "rpc", "application" or "protocol"
991  * @param[in]  message Error message (will be XML encoded)
992  * @see netconf_operation_failed_xml  Same but returns XML tree
993  */
994 int
netconf_operation_failed(cbuf * cb,char * type,char * message)995 netconf_operation_failed(cbuf  *cb,
996 			 char  *type,
997 			 char  *message)
998 {
999     int    retval = -1;
1000     cxobj *xret = NULL;
1001 
1002     if (netconf_operation_failed_xml(&xret, type, message) < 0)
1003 	goto done;
1004     if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
1005 	goto done;
1006     retval = 0;
1007  done:
1008     if (xret)
1009 	xml_free(xret);
1010     return retval;
1011 }
1012 
1013 /*! Create Netconf operation-failed error XML tree according to RFC 6241 App A
1014  *
1015  * Request could not be completed because the requested operation failed for
1016  * some reason not covered by any other error condition.
1017  * @param[out] xret    Error XML tree
1018  * @param[in]  type    Error type: "rpc", "application" or "protocol"
1019  * @param[in]  message Error message (will be XML encoded)
1020  * @code
1021  *  cxobj *xret = NULL;
1022  *  if (netconf_operation_failed_xml(&xret, "protocol", "Unauthorized") < 0)
1023  *    err;
1024  *  xml_free(xret);
1025  * @endcode
1026  * @see netconf_operation_failed  Same but returns cligen buffer
1027  */
1028 int
netconf_operation_failed_xml(cxobj ** xret,char * type,char * message)1029 netconf_operation_failed_xml(cxobj **xret,
1030 			     char  *type,
1031 			     char  *message)
1032 
1033 {
1034     int   retval =-1;
1035     cxobj *xerr;
1036     char  *encstr = NULL;
1037     cxobj *xa;
1038 
1039     if (*xret == NULL){
1040 	if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
1041 	    goto done;
1042     }
1043     else if (xml_name_set(*xret, "rpc-reply") < 0)
1044 	goto done;
1045     if ((xa = xml_new("xmlns", *xret, CX_ATTR)) == NULL)
1046 	goto done;
1047     if (xml_value_set(xa, NETCONF_BASE_NAMESPACE) < 0)
1048 	goto done;
1049     if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
1050 	goto done;
1051     if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-type>%s</error-type>"
1052 			    "<error-tag>operation-failed</error-tag>"
1053 			    "<error-severity>error</error-severity>",
1054 			    type) < 0)
1055 	goto done;
1056     if (message){
1057 	 if (xml_chardata_encode(&encstr, "%s", message) < 0)
1058 	     goto done;
1059 	 if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-message>%s</error-message>",
1060 				 encstr) < 0)
1061 	goto done;
1062     }
1063     retval = 0;
1064  done:
1065     if (encstr)
1066 	free(encstr);
1067     return retval;
1068 }
1069 
1070 /*! Create Netconf malformed-message error XML tree according to RFC 6241 App A
1071  *
1072  * A message could not be handled because it failed to be parsed correctly.
1073  * For example, the message is not well-formed XML or it uses an
1074  * invalid character set.
1075  * @param[out]  cb      CLIgen buf. Error XML is written in this buffer
1076  * @param[in]   message Error message
1077  * @note New in :base:1.1
1078  * @see netconf_malformed_message_xml  Same but returns XML tree
1079  */
1080 int
netconf_malformed_message(cbuf * cb,char * message)1081 netconf_malformed_message(cbuf  *cb,
1082 			  char  *message)
1083 {
1084     int   retval = -1;
1085     cxobj *xret = NULL;
1086 
1087     if (netconf_malformed_message_xml(&xret, message) < 0)
1088 	goto done;
1089     if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
1090 	goto done;
1091     retval = 0;
1092  done:
1093     if (xret)
1094 	xml_free(xret);
1095     return retval;
1096 }
1097 
1098 /*! Create Netconf malformed-message error XML tree according to RFC 6241 App A
1099  *
1100  * A message could not be handled because it failed to be parsed correctly.
1101  * For example, the message is not well-formed XML or it uses an
1102  * invalid character set.
1103  * @param[out] xret    Error XML tree
1104  * @param[in]  message Error message (will be XML encoded)
1105  * @note New in :base:1.1
1106  * @code
1107  *  cxobj *xret = NULL;
1108  *  if (netconf_malformed_message_xml(&xret, "Unauthorized") < 0)
1109  *    err;
1110  *  xml_free(xret);
1111  * @endcode
1112  * @see netconf_malformed_message  Same but returns cligen buffer
1113  */
1114 int
netconf_malformed_message_xml(cxobj ** xret,char * message)1115 netconf_malformed_message_xml(cxobj **xret,
1116 			      char   *message)
1117 {
1118     int    retval =-1;
1119     cxobj *xerr;
1120     char  *encstr = NULL;
1121     cxobj *xa;
1122 
1123     if (*xret == NULL){
1124 	if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
1125 	    goto done;
1126     }
1127     else if (xml_name_set(*xret, "rpc-reply") < 0)
1128 	goto done;
1129     if ((xa = xml_new("xmlns", *xret, CX_ATTR)) == NULL)
1130 	goto done;
1131     if (xml_value_set(xa, NETCONF_BASE_NAMESPACE) < 0)
1132 	goto done;
1133     if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
1134 	goto done;
1135     if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-type>rpc</error-type>"
1136 			    "<error-tag>malformed-message</error-tag>"
1137 			    "<error-severity>error</error-severity>") < 0)
1138 	goto done;
1139      if (message){
1140 	 if (xml_chardata_encode(&encstr, "%s", message) < 0)
1141 	     goto done;
1142 	 if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-message>%s</error-message>",
1143 				 encstr) < 0)
1144 	     goto done;
1145      }
1146     retval = 0;
1147  done:
1148     if (encstr)
1149 	free(encstr);
1150     return retval;
1151 }
1152 
1153 /*! Create Netconf data-not-unique error message according to RFC 7950 15.1
1154  *
1155  * A NETCONF operation would result in configuration data where a
1156  *   "unique" constraint is invalidated.
1157  * @param[out]  xret   Error XML tree. Free with xml_free after use
1158  * @param[in]   x      List element containing duplicate
1159  * @param[in]   cvk    List of comonents in x that are non-unique
1160  * @see RFC7950 Sec 15.1
1161  */
1162 int
netconf_data_not_unique_xml(cxobj ** xret,cxobj * x,cvec * cvk)1163 netconf_data_not_unique_xml(cxobj **xret,
1164 			    cxobj  *x,
1165 			    cvec   *cvk)
1166 {
1167     int     retval = -1;
1168     cg_var *cvi = NULL;
1169     cxobj  *xi;
1170     cxobj  *xerr;
1171     cxobj  *xinfo;
1172     cbuf   *cb = NULL;
1173     cxobj *xa;
1174 
1175     if (*xret == NULL){
1176 	if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
1177 	    goto done;
1178     }
1179     else if (xml_name_set(*xret, "rpc-reply") < 0)
1180 	goto done;
1181     if ((xa = xml_new("xmlns", *xret, CX_ATTR)) == NULL)
1182 	goto done;
1183     if (xml_value_set(xa, NETCONF_BASE_NAMESPACE) < 0)
1184 	goto done;
1185     if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
1186 	goto done;
1187     if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL,
1188 			    "<error-type>protocol</error-type>"
1189 			    "<error-tag>operation-failed</error-tag>"
1190 			    "<error-app-tag>data-not-unique</error-app-tag>"
1191 			    "<error-severity>error</error-severity>") < 0)
1192 	goto done;
1193     if (cvec_len(cvk)){
1194 	if ((xinfo = xml_new("error-info", xerr, CX_ELMNT)) == NULL)
1195 	    goto done;
1196 	if ((cb = cbuf_new()) == NULL){
1197 	    clicon_err(OE_UNIX, errno, "cbuf_new");
1198 	    goto done;
1199 	}
1200 	while ((cvi = cvec_each(cvk, cvi)) != NULL){
1201 	    if ((xi = xml_find(x, cv_string_get(cvi))) == NULL)
1202 		continue; /* ignore, shouldnt happen */
1203 	    clicon_xml2cbuf(cb, xi, 0, 0, -1);
1204 	    if (clixon_xml_parse_va(YB_NONE, NULL, &xinfo, NULL,
1205 				    "<non-unique>%s</non-unique>", cbuf_get(cb)) < 0)
1206 		goto done;
1207 	    cbuf_reset(cb);
1208 	}
1209     }
1210     retval = 0;
1211  done:
1212     if (cb)
1213 	cbuf_free(cb);
1214     return retval;
1215 }
1216 
1217 /*! Create Netconf too-many/few-elements err msg according to RFC 7950 15.2/15.3
1218  *
1219  * A NETCONF operation would result in configuration data where a
1220  * list or a leaf-list would have too many entries, the following error
1221  * @param[out]  xret     Error XML tree. Free with xml_free after use
1222  * @param[in]   xp       XML parent node (for error)
1223  * @param[in]   name     Name of list (for error)
1224  * @param[in]   max      If set, return too-many, otherwise too-few
1225  * @see RFC7950 Sec 15.1
1226  */
1227 int
netconf_minmax_elements_xml(cxobj ** xret,cxobj * xp,char * name,int max)1228 netconf_minmax_elements_xml(cxobj **xret,
1229 			    cxobj  *xp,
1230 			    char   *name,
1231 	                    int     max)
1232 {
1233     int    retval = -1;
1234     cxobj *xerr;
1235     char  *path = NULL;
1236     cbuf  *cb = NULL;
1237     cxobj *xa;
1238 
1239     if (*xret == NULL){
1240 	if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
1241 	    goto done;
1242     }
1243     else if (xml_name_set(*xret, "rpc-reply") < 0)
1244 	goto done;
1245     if ((xa = xml_new("xmlns", *xret, CX_ATTR)) == NULL)
1246 	goto done;
1247     if (xml_value_set(xa, NETCONF_BASE_NAMESPACE) < 0)
1248 	goto done;
1249     if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
1250 	goto done;
1251     if ((cb = cbuf_new()) == NULL){
1252 	clicon_err(OE_UNIX, errno, "cbuf_new");
1253 	goto done;
1254     }
1255     if (xml_parent(xp)){ /* Dont include root, eg <config> */
1256 	if (xml2xpath(xp, &path) < 0)
1257 	    goto done;
1258 	if (path)
1259 	    cprintf(cb, "%s", path);
1260     }
1261     cprintf(cb, "/%s", name);
1262     if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-type>protocol</error-type>"
1263 			    "<error-tag>operation-failed</error-tag>"
1264 			    "<error-app-tag>too-%s-elements</error-app-tag>"
1265 			    "<error-severity>error</error-severity>"
1266 			    "<error-path>%s</error-path>",
1267 			    max?"many":"few",
1268 			    cbuf_get(cb)) < 0)
1269 	goto done;
1270     retval = 0;
1271  done:
1272     if (path)
1273 	free(path);
1274     if (cb)
1275 	cbuf_free(cb);
1276     return retval;
1277 }
1278 
1279 /*! Help function: merge - check yang - if error make netconf errmsg
1280  * @param[in]     x       XML tree
1281  * @param[in]     yspec   Yang spec
1282  * @param[in,out] xret    Existing XML tree, merge x into this
1283  * @retval       -1       Error (fatal)
1284  * @retval        0       Statedata callback failed
1285  * @retval        1       OK
1286  */
1287 int
netconf_trymerge(cxobj * x,yang_stmt * yspec,cxobj ** xret)1288 netconf_trymerge(cxobj       *x,
1289 		 yang_stmt   *yspec,
1290     		 cxobj      **xret)
1291 {
1292     int    retval = -1;
1293     char  *reason = NULL;
1294     cxobj *xc;
1295 
1296     if (*xret == NULL){
1297 	if ((*xret = xml_dup(x)) == NULL)
1298 	    goto done;
1299 	goto ok;
1300     }
1301     if (xml_merge(*xret, x, yspec, &reason) < 0)
1302 	goto done;
1303     if (reason){
1304 	while ((xc = xml_child_i(*xret, 0)) != NULL)
1305 	    xml_purge(xc);
1306 	if (netconf_operation_failed_xml(xret, "rpc", reason)< 0)
1307 	    goto done;
1308 	goto fail;
1309     }
1310  ok:
1311     retval = 1;
1312  done:
1313     if (reason)
1314 	free(reason);
1315     return retval;
1316  fail:
1317     retval = 0;
1318     goto done;
1319 }
1320 
1321 /*! Load ietf netconf yang module and set enabled features
1322  *
1323  * This function should be called after options loaded but before yang modules.
1324  * (a yang module may import ietf-netconf and then features must be set)
1325  * @param[in] h  Clixon handle
1326  * @retval    0  OK
1327  * @retval   -1  Error
1328  * The features added are (in order) (numbers are section# in RFC6241):
1329  *   candidate (8.3)
1330  *   validate (8.6)
1331  *   startup (8.7)
1332  *   xpath (8.9)
1333  * @see netconf_module_load  that is called later
1334  */
1335 int
netconf_module_features(clicon_handle h)1336 netconf_module_features(clicon_handle h)
1337 {
1338     int        retval = -1;
1339     cxobj     *xc;
1340 
1341     if ((xc = clicon_conf_xml(h)) == NULL){
1342 	clicon_err(OE_CFG, ENOENT, "Clicon configuration not loaded");
1343 	goto done;
1344     }
1345     /* Enable features (hardcoded here) */
1346     if (clixon_xml_parse_string("<CLICON_FEATURE>ietf-netconf:candidate</CLICON_FEATURE>",
1347 				YB_PARENT, NULL, &xc, NULL) < 0)
1348 	goto done;
1349     if (clixon_xml_parse_string("<CLICON_FEATURE>ietf-netconf:validate</CLICON_FEATURE>",
1350 				YB_PARENT,  NULL, &xc, NULL) < 0)
1351 	goto done;
1352     if (clixon_xml_parse_string("<CLICON_FEATURE>ietf-netconf:xpath</CLICON_FEATURE>",
1353 				YB_PARENT, NULL, &xc, NULL) < 0)
1354 	goto done;
1355     retval = 0;
1356  done:
1357     return retval;
1358 }
1359 
1360 /*! Load ietf netconf yang module and set enabled features
1361  * @param[in] h  Clixon handle
1362  * @retval    0  OK
1363  * @retval   -1  Error
1364  * @see netconf_module_feature  should be called before any yang modules
1365  */
1366 int
netconf_module_load(clicon_handle h)1367 netconf_module_load(clicon_handle h)
1368 {
1369     int        retval = -1;
1370     yang_stmt *yspec;
1371 
1372     yspec = clicon_dbspec_yang(h);
1373     /* Load yang spec */
1374     if (yang_spec_parse_module(h, "ietf-netconf", NULL, yspec)< 0)
1375 	goto done;
1376     if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277"))
1377 	if (yang_spec_parse_module(h, "clixon-rfc5277", NULL, yspec)< 0)
1378 	    goto done;
1379     /* YANG module revision change management */
1380     if (clicon_option_bool(h, "CLICON_XML_CHANGELOG"))
1381 	if (yang_spec_parse_module(h, "clixon-xml-changelog", NULL, yspec)< 0)
1382 	    goto done;
1383     retval = 0;
1384  done:
1385     return retval;
1386 }
1387 
1388 /*! Find some sub-child in netconf/xm request.
1389  * Actually, find a child with a certain name and return its body
1390  * @param[in]  xn
1391  * @param[in]  name
1392  * @retval     db    Name of database
1393  * @retval     NULL  Not found
1394  * The following code returns "source"
1395  * @code
1396  *   cxobj *xt = NULL;
1397  *   char  *db;
1398  *   clixon_xml_parse_string("<x><target>source</target></x>", YB_NONE, NULL, &xt, NULL);
1399  *   db = netconf_db_find(xt, "target");
1400  * @endcode
1401  */
1402 char*
netconf_db_find(cxobj * xn,char * name)1403 netconf_db_find(cxobj *xn,
1404 		char  *name)
1405 {
1406     cxobj *xs; /* source */
1407     cxobj *xi;
1408     char  *db = NULL;
1409 
1410     if ((xs = xml_find(xn, name)) == NULL)
1411 	goto done;
1412     if ((xi = xml_child_i(xs, 0)) == NULL)
1413 	goto done;
1414     db = xml_name(xi);
1415  done:
1416     return db;
1417 }
1418 
1419 /*! Generate netconf error msg to cbuf to use in string printout or logs
1420  * @param[in]     xerr    Netconf error message on the level: <rpc-error>
1421  * @param[in,out] cberr   Translation from netconf err to cbuf.
1422  * @retval     0       OK, with cberr set
1423  * @retval    -1       Error
1424  * @code
1425  *     cbuf *cb = NULL;
1426  *     if ((cb = cbuf_new()) ==NULL){
1427  * 	  err;
1428  *     if (netconf_err2cb(xerr, cb) < 0)
1429  *        err;
1430  *     printf("%s", cbuf_get(cb));
1431  *     cbuf_free(cb);
1432  * @endcode
1433  * @see clixon_netconf_error
1434  */
1435 int
netconf_err2cb(cxobj * xerr,cbuf * cberr)1436 netconf_err2cb(cxobj *xerr,
1437 	       cbuf  *cberr)
1438 {
1439     int    retval = -1;
1440     cxobj *x;
1441 
1442     if ((x=xpath_first(xerr, NULL, "//error-type"))!=NULL)
1443 	cprintf(cberr, "%s ", xml_body(x));
1444     if ((x=xpath_first(xerr, NULL, "//error-tag"))!=NULL)
1445 	cprintf(cberr, "%s ", xml_body(x));
1446     if ((x=xpath_first(xerr, NULL, "//error-message"))!=NULL)
1447 	cprintf(cberr, "%s ", xml_body(x));
1448     if ((x=xpath_first(xerr, NULL, "//error-info")) != NULL &&
1449 	xml_child_nr(x) > 0){
1450 	clicon_xml2cbuf(cberr, xml_child_i(x, 0), 0, 0, -1);
1451     }
1452     if ((x=xpath_first(xerr, NULL, "//error-app-tag"))!=NULL)
1453 	cprintf(cberr, ": %s ", xml_body(x));
1454     if ((x=xpath_first(xerr, NULL, "//error-path"))!=NULL)
1455 	cprintf(cberr, ": %s ", xml_body(x));
1456     retval = 0;
1457     return retval;
1458 }
1459 
1460 /* See RFC 8040 4.8.1
1461  * @see netconf_content_str2int
1462  */
1463 static const map_str2int netconf_content_map[] = {
1464     {"config",     CONTENT_CONFIG},
1465     {"nonconfig",  CONTENT_NONCONFIG},
1466     {"all",        CONTENT_ALL},
1467     {NULL,        -1}
1468 };
1469 
1470 const netconf_content
netconf_content_str2int(char * str)1471 netconf_content_str2int(char *str)
1472 {
1473     return clicon_str2int(netconf_content_map, str);
1474 }
1475 
1476 const char *
netconf_content_int2str(netconf_content nr)1477 netconf_content_int2str(netconf_content nr)
1478 {
1479     return clicon_int2str(netconf_content_map, nr);
1480 }
1481 
1482 /*! Create Netconf server hello. Single cap and defer individual to querying modules
1483 
1484  * @param[in]  h           Clicon handle
1485  * @param[in]  cb          Msg buffer
1486  * @param[in]  session_id  Id of client session
1487  * Lots of dependencies here. regarding the hello protocol.
1488  * RFC6241 NETCONF Protocol says: (8.1)
1489  *    MUST send a <hello> element containing a list of that peer's capabilities
1490  *    MUST send at least the base NETCONF capability, urn:ietf:params:netconf:base:1.1
1491  *    MAY include capabilities for previous NETCONF versions
1492  *    A server MUST include a <session-id>
1493  *    A client MUST NOT include a <session-id>
1494  *    A server receiving <session-id> MUST terminate the NETCONF session.
1495  *    A client not receiving <session-id> MUST terminate w/o sending<close-session>
1496  * the example shows urn:ietf:params:netconf:capability:startup:1.0
1497 
1498  * RFC5277 NETCONF Event Notifications
1499  *  urn:ietf:params:netconf:capability:notification:1.0 is advertised during the capability exchange
1500  *
1501  * RFC6022 YANG Module for NETCONF Monitoring
1502  *     MUST advertise the capability URI "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring"
1503  * RFC7895 Yang module library defines how to announce module features (not hello capabilities)
1504  * RFC7950 YANG 1.1 says (5.6.4);
1505  *    MUST announce the modules it implements by implementing the YANG module
1506  *    "ietf-yang-library" (RFC7895) and listing all implemented modules in the
1507  *    "/modules-state/module" list.
1508  *    MUST advertise urn:ietf:params:netconf:capability:yang-library:1.0?
1509  *    revision=<date>&module-set-id=<id> in the <hello> message.
1510  *
1511  * Question: should the NETCONF in RFC6241 sections 8.2-8.9 be announced both
1512  * as features and as capabilities in the <hello> message according to RFC6241?
1513  *   urn:ietf:params:netconf:capability:candidate:1.0 (8.3)
1514  *   urn:ietf:params:netconf:capability:validate:1.1 (8.6)
1515  *   urn:ietf:params:netconf:capability:startup:1.0 (8.7)
1516  *   urn:ietf:params:netconf:capability:xpath:1.0 (8.9)
1517  *   urn:ietf:params:netconf:capability:notification:1.0 (RFC5277)
1518  *
1519  * @note the hello message is created bythe netconf application, not the
1520  *  backend, and backend may implement more modules - please consider if using
1521  *  library routines for detecting capabilities here. In contrast, yang module
1522  * list (RFC7895) is processed by the backend.
1523  * @note encode bodies, see xml_chardata_encode()
1524  * @see yang_modules_state_get
1525  * @see netconf_module_load
1526  */
1527 int
netconf_hello_server(clicon_handle h,cbuf * cb,uint32_t session_id)1528 netconf_hello_server(clicon_handle h,
1529 		     cbuf         *cb,
1530 		     uint32_t      session_id)
1531 {
1532     int   retval = -1;
1533     char *module_set_id;
1534     char *ietf_yang_library_revision;
1535     char *encstr = NULL;
1536 
1537     module_set_id = clicon_option_str(h, "CLICON_MODULE_SET_ID");
1538 
1539     cprintf(cb, "<hello xmlns=\"%s\">", NETCONF_BASE_NAMESPACE);
1540     cprintf(cb, "<capabilities>");
1541     cprintf(cb, "<capability>urn:ietf:params:netconf:base:1.0</capability>");
1542     /* Check if RFC7895 loaded and revision found */
1543     if ((ietf_yang_library_revision = yang_modules_revision(h)) != NULL){
1544 	if (xml_chardata_encode(&encstr, "urn:ietf:params:netconf:capability:yang-library:1.0?revision=%s&module-set-id=%s",
1545 				ietf_yang_library_revision,
1546 				module_set_id) < 0)
1547 	    goto done;
1548 	cprintf(cb, "<capability>%s</capability>", encstr);
1549     }
1550     cprintf(cb, "<capability>urn:ietf:params:netconf:capability:candidate:1.0</capability>");
1551     cprintf(cb, "<capability>urn:ietf:params:netconf:capability:validate:1.1</capability>");
1552     cprintf(cb, "<capability>urn:ietf:params:netconf:capability:startup:1.0</capability>");
1553     cprintf(cb, "<capability>urn:ietf:params:netconf:capability:xpath:1.0</capability>");
1554     cprintf(cb, "<capability>urn:ietf:params:netconf:capability:notification:1.0</capability>");
1555     cprintf(cb, "</capabilities>");
1556     if (session_id)
1557 	cprintf(cb, "<session-id>%lu</session-id>", (long unsigned int)session_id);
1558     cprintf(cb, "</hello>");
1559     cprintf(cb, "]]>]]>");
1560     retval = 0;
1561  done:
1562     if (encstr)
1563 	free(encstr);
1564     return retval;
1565 }
1566 
1567 int
netconf_hello_req(clicon_handle h,cbuf * cb)1568 netconf_hello_req(clicon_handle h,
1569 		  cbuf         *cb)
1570 {
1571     int   retval = -1;
1572 
1573     cprintf(cb, "<hello xmlns=\"%s\">", NETCONF_BASE_NAMESPACE);
1574     cprintf(cb, "<capabilities>");
1575         cprintf(cb, "<capability>urn:ietf:params:netconf:base:1.0</capability>");
1576     cprintf(cb, "</capabilities>");
1577     cprintf(cb, "</hello>");
1578     cprintf(cb, "]]>]]>");
1579     retval = 0;
1580     return retval;
1581 }
1582 
1583 /*! Generate textual error log from Netconf error message
1584  *
1585  * Get a text error message from netconf error message and generate error on the form:
1586  *   <msg>: "<arg>": <netconf-error>   or   <msg>: <netconf-error>
1587  * @param[in]  fn      Inline function name (when called from clicon_err() macro)
1588  * @param[in]  line    Inline file line number (when called from clicon_err() macro)
1589  * @param[in]  xerr    Netconf error xml tree on the form: <rpc-error>
1590  * @param[in]  format  Format string
1591  * @param[in]  arg     String argument to format (optional)
1592  */
1593 int
clixon_netconf_error_fn(const char * fn,const int line,cxobj * xerr,const char * msg,const char * arg)1594 clixon_netconf_error_fn(const char *fn,
1595 			const int   line,
1596 			cxobj       *xerr,
1597 			const char  *msg,
1598 			const char  *arg)
1599 {
1600     int    retval = -1;
1601     cbuf  *cb = NULL;
1602 
1603     if ((cb = cbuf_new()) ==NULL){
1604 	clicon_err(OE_XML, errno, "cbuf_new");
1605 	goto done;
1606     }
1607     if (msg){
1608 	cprintf(cb, "%s", msg);
1609 	if (arg)
1610 	    cprintf(cb, " \"%s\" ", arg);
1611 
1612 	cprintf(cb, ": ");
1613     }
1614     if (netconf_err2cb(xerr, cb) < 0)
1615 	goto done;
1616 #if 0 /* More verbose output for debugging */
1617     clicon_log(LOG_ERR, "%s: %d: %s", fn, line, cbuf_get(cb));
1618 #else
1619     clicon_log(LOG_ERR, "%s", cbuf_get(cb));
1620 #endif
1621     retval = 0;
1622  done:
1623     if (cb)
1624 	cbuf_free(cb);
1625     return retval;
1626 }
1627 
1628 /*! Add internal error info to existing netconf error message by rewriting
1629  *
1630  * If a eg sanity check detects errors in internal messages passing, such as from a plugin or
1631  * in backend communication, an error is generated. However, it does not make sense to send this
1632  * error message as-is to the requestor. Instead this function transforms the error to a more
1633  * generic "operation-failed" error and adds info in its error message to say it is an internal error.
1634  * If a requestor receives such an error, it will be clear that the error is internal.
1635  * @param[in]  xerr    Netconf error xml tree on the form: <rpc-error>
1636  * @param[in]  msg     Error message
1637  * @param[in]  arg     Extra error message (consider stdarg?)
1638  * @retval     0       OK
1639  * @retval     -1      Error
1640  */
1641 int
clixon_netconf_internal_error(cxobj * xerr,char * msg,char * arg)1642 clixon_netconf_internal_error(cxobj *xerr,
1643 			      char  *msg,
1644 			      char  *arg)
1645 {
1646     int    retval = -1;
1647     cxobj *xr;
1648     cxobj *xb;
1649 
1650     if ((xr = xpath_first(xerr, NULL, "//error-tag")) != NULL &&
1651 	(xb = xml_body_get(xr))){
1652 	if (xml_value_set(xb, "operation-failed") < 0)
1653 	    goto done;
1654     }
1655     if ((xr = xpath_first(xerr, NULL, "//error-message")) != NULL &&
1656 	(xb = xml_body_get(xr))){
1657 	if (xml_value_append(xb, msg) < 0)
1658 	    goto done;
1659 	if (arg &&xml_value_append(xb, arg) < 0)
1660 	    goto done;
1661     }
1662     retval = 0;
1663  done:
1664     return retval;
1665 }
1666