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