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  *
37  * XML code
38  *
39  * "api-path" is "URI-encoded path expression" definition in RFC8040 3.5.3
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 <ctype.h>
50 #include <string.h>
51 #include <syslog.h>
52 #include <fcntl.h>
53 #include <assert.h>
54 #include <arpa/inet.h>
55 #include <sys/param.h>
56 #include <netinet/in.h>
57 
58 /* cligen */
59 #include <cligen/cligen.h>
60 
61 /* clicon */
62 
63 #include "clixon_string.h"
64 #include "clixon_queue.h"
65 #include "clixon_hash.h"
66 #include "clixon_handle.h"
67 #include "clixon_string.h"
68 #include "clixon_err.h"
69 #include "clixon_log.h"
70 #include "clixon_yang.h"
71 #include "clixon_xml.h"
72 #include "clixon_netconf_lib.h"
73 #include "clixon_options.h"
74 #include "clixon_xml_nsctx.h"
75 #include "clixon_xpath_ctx.h"
76 #include "clixon_xpath.h"
77 #include "clixon_yang_module.h"
78 #include "clixon_yang_type.h"
79 #include "clixon_xml_map.h"
80 #include "clixon_validate.h"
81 
82 /*! Validate xml node of type leafref, ensure the value is one of that path's reference
83  * @param[in]  xt    XML leaf node of type leafref
84  * @param[in]  ys    Yang spec of leaf
85  * @param[in]  ytype Yang type statement belonging to the XML node
86  * @param[out] xret  Error XML tree. Free with xml_free after use
87  * @retval     1     Validation OK
88  * @retval     0     Validation failed
89  * @retval    -1     Error
90  * From rfc7950 Sec 9.9.2
91  *  The "path" XPath expression is  evaluated in the following context,
92  *  in addition to the definition in Section 6.4.1:
93  *   o  If the "path" statement is defined within a typedef, the context
94  *      node is the leaf or leaf-list node in the data tree that
95  *      references the typedef. (ie ys)
96  *   o  Otherwise, the context node is the node in the data tree for which
97  *      the "path" statement is defined. (ie yc)
98  */
99 static int
validate_leafref(cxobj * xt,yang_stmt * ys,yang_stmt * ytype,cxobj ** xret)100 validate_leafref(cxobj     *xt,
101 		 yang_stmt *ys,
102 		 yang_stmt *ytype,
103 		 cxobj    **xret)
104 {
105     int          retval = -1;
106     yang_stmt   *ypath;
107     yang_stmt   *yp;
108     cxobj      **xvec = NULL;
109     cxobj       *x;
110     int          i;
111     size_t       xlen = 0;
112     char        *leafrefbody;
113     char        *leafbody;
114     cvec        *nsc = NULL;
115     cbuf        *cberr = NULL;
116     char        *path;
117 
118     if ((leafrefbody = xml_body(xt)) == NULL)
119 	goto ok;
120     if ((ypath = yang_find(ytype, Y_PATH, NULL)) == NULL){
121 	if (netconf_missing_element_xml(xret, "application", yang_argument_get(ytype), "Leafref requires path statement") < 0)
122 	    goto done;
123 	goto fail;
124     }
125     /* See comment^: If path is defined in typedef or not */
126     if ((yp = yang_parent_get(ytype)) != NULL &&
127 	yang_keyword_get(yp) == Y_TYPEDEF){
128 	if (xml_nsctx_yang(ys, &nsc) < 0)
129 	    goto done;
130     }
131     else
132 	if (xml_nsctx_yang(ytype, &nsc) < 0)
133 	    goto done;
134     path = yang_argument_get(ypath);
135     if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, path) < 0)
136 	goto done;
137     for (i = 0; i < xlen; i++) {
138 	x = xvec[i];
139 	if ((leafbody = xml_body(x)) == NULL)
140 	    continue;
141 	if (strcmp(leafbody, leafrefbody) == 0)
142 	    break;
143     }
144     if (i==xlen){
145 	if ((cberr = cbuf_new()) == NULL){
146 	    clicon_err(OE_UNIX, errno, "cbuf_new");
147 	    goto done;
148 	}
149 	cprintf(cberr, "Leafref validation failed: No leaf %s matching path %s", leafrefbody, path);
150 	if (netconf_bad_element_xml(xret, "application", leafrefbody, cbuf_get(cberr)) < 0)
151 	    goto done;
152 	goto fail;
153     }
154  ok:
155     retval = 1;
156  done:
157     if (cberr)
158 	cbuf_free(cberr);
159     if (nsc)
160 	xml_nsctx_free(nsc);
161     if (xvec)
162 	free(xvec);
163     return retval;
164  fail:
165     retval = 0;
166     goto done;
167 }
168 
169 /*! Validate xml node of type identityref, ensure value is a defined identity
170  * Check if a given node has value derived from base identity. This is
171  * a run-time check necessary when validating eg netconf.
172  * Valid values for an identityref are any identities derived from all
173  * the identityref's base identities.
174  * Example:
175  * b0 --> b1 --> b2  (b1 & b2 are derived)
176  * identityref b2
177  *   base b0;
178  * This function does: derived_from(b2, b0);
179  * @param[in]  xt    XML leaf node of type identityref
180  * @param[in]  ys    Yang spec of leaf
181  * @param[in]  ytype Yang type field of type identityref
182  * @param[out] xret  Error XML tree. Free with xml_free after use
183  * @retval     1     Validation OK
184  * @retval     0     Validation failed
185  * @retval    -1     Error
186  * @see ys_populate_identity where the derived types are set
187  * @see yang_augment_node
188  * @see RFC7950 Sec 9.10.2:
189  * @see xp_function_derived_from  similar code other context
190  */
191 static int
validate_identityref(cxobj * xt,yang_stmt * ys,yang_stmt * ytype,cxobj ** xret)192 validate_identityref(cxobj     *xt,
193 		     yang_stmt *ys,
194 		     yang_stmt *ytype,
195 		     cxobj    **xret)
196 {
197     int         retval = -1;
198     char       *node = NULL;
199     char       *idref = NULL;
200     yang_stmt  *ybaseref; /* This is the type's base reference */
201     yang_stmt  *ybaseid;
202     char       *prefix = NULL;
203     char       *id = NULL;
204     cbuf       *cberr = NULL;
205     cbuf       *cb = NULL;
206     cvec       *idrefvec; /* Derived identityref list: (module:id)**/
207     yang_stmt  *ymod;
208 
209     if ((cb = cbuf_new()) == NULL){
210 	clicon_err(OE_UNIX, errno, "cbuf_new");
211 	goto done;
212     }
213     if ((cberr = cbuf_new()) == NULL){
214 	clicon_err(OE_UNIX, errno, "cbuf_new");
215 	goto done;
216     }
217     /* Get idref value. Then see if this value is derived from ytype.
218      */
219     if ((node = xml_body(xt)) == NULL){ /* It may not be empty */
220 	if (netconf_bad_element_xml(xret, "application", xml_name(xt), "Identityref should not be empty") < 0)
221 	    goto done;
222 	goto fail;
223     }
224     if (nodeid_split(node, &prefix, &id) < 0)
225 	goto done;
226     /* This is the type's base reference */
227     if ((ybaseref = yang_find(ytype, Y_BASE, NULL)) == NULL){
228 	if (netconf_missing_element_xml(xret, "application", yang_argument_get(ytype), "Identityref validation failed, no base") < 0)
229 	    goto done;
230 	goto fail;
231     }
232     /* This is the actual base identity */
233     if ((ybaseid = yang_find_identity(ybaseref, yang_argument_get(ybaseref))) == NULL){
234 	if (netconf_missing_element_xml(xret, "application", yang_argument_get(ybaseref), "Identityref validation failed, no base identity") < 0)
235 	    goto done;
236 	goto fail;
237     }
238 
239     /* idref from prefix:id to module:id */
240     if (prefix == NULL)
241 	ymod = ys_module(ys);
242     else{ /* from prefix to name */
243 #if 1 /* IDENTITYREF_KLUDGE  */
244 	ymod = yang_find_module_by_prefix_yspec(ys_spec(ys), prefix);
245 #endif
246     }
247     if (ymod == NULL){
248 	cprintf(cberr, "Identityref validation failed, %s not derived from %s",
249 		node, yang_argument_get(ybaseid));
250 	if (xret && netconf_operation_failed_xml(xret, "application", cbuf_get(cberr)) < 0)
251 	    goto done;
252 	goto fail;
253     }
254     cprintf(cb, "%s:%s", yang_argument_get(ymod), id);
255     idref = cbuf_get(cb);
256     /* Here check if node is in the derived node list of the base identity
257      * The derived node list is a cvec computed XXX
258      */
259     idrefvec = yang_cvec_get(ybaseid);
260     if (cvec_find(idrefvec, idref) == NULL){
261 	cprintf(cberr, "Identityref validation failed, %s not derived from %s",
262 		node, yang_argument_get(ybaseid));
263 	if (netconf_operation_failed_xml(xret, "application", cbuf_get(cberr)) < 0)
264 	    goto done;
265 	goto fail;
266     }
267     retval = 1;
268  done:
269     if (cberr)
270 	cbuf_free(cberr);
271     if (cb)
272 	cbuf_free(cb);
273     if (id)
274 	free(id);
275     if (prefix)
276 	free(prefix);
277     return retval;
278  fail:
279     retval = 0;
280     goto done;
281 }
282 
283 /*! Validate an RPC node
284  * @param[in]  h     Clicon handle
285  * @param[in]  xrpc  XML node to be validated
286  * @param[out] xret  Error XML tree. Free with xml_free after use
287  * @retval     1     Validation OK
288  * @retval     0     Validation failed
289  * @retval    -1     Error
290  * rfc7950
291  * 7.14.2
292  * If a leaf in the input tree has a "mandatory" statement with the
293  * value "true", the leaf MUST be present in an RPC invocation.
294  *
295  * If a leaf in the input tree has a default value, the server MUST use
296  * this value in the same cases as those described in Section 7.6.1.  In
297  * these cases, the server MUST operationally behave as if the leaf was
298  * present in the RPC invocation with the default value as its value.
299  *
300  * If a leaf-list in the input tree has one or more default values, the
301  * server MUST use these values in the same cases as those described in
302  * Section 7.7.2.  In these cases, the server MUST operationally behave
303  * as if the leaf-list was present in the RPC invocation with the
304  * default values as its values.
305  *
306  * Since the input tree is not part of any datastore, all "config"
307  * statements for nodes in the input tree are ignored.
308  *
309  * If any node has a "when" statement that would evaluate to "false",
310  * then this node MUST NOT be present in the input tree.
311  *
312  * 7.14.4
313  * Input parameters are encoded as child XML elements to the rpc node's
314  * XML element, in the same order as they are defined within the "input"
315  * statement.
316  *
317  * If the RPC operation invocation succeeded and no output parameters
318  * are returned, the <rpc-reply> contains a single <ok/> element defined
319  * in [RFC6241].  If output parameters are returned, they are encoded as
320  * child elements to the <rpc-reply> element defined in [RFC6241], in
321  * the same order as they are defined within the "output" statement.
322  * @see xml_yang_validate_all
323  * @note Should need a variant accepting cxobj **xret
324  */
325 int
xml_yang_validate_rpc(clicon_handle h,cxobj * xrpc,cxobj ** xret)326 xml_yang_validate_rpc(clicon_handle h,
327 		      cxobj        *xrpc,
328 		      cxobj       **xret)
329 {
330     int        retval = -1;
331     yang_stmt *yn=NULL;  /* rpc name */
332     cxobj     *xn;       /* rpc name */
333 
334     if (strcmp(xml_name(xrpc), "rpc")){
335 	clicon_err(OE_XML, EINVAL, "Expected RPC");
336 	goto done;
337     }
338     xn = NULL;
339     /* xn is name of rpc, ie <rcp><xn/></rpc> */
340     while ((xn = xml_child_each(xrpc, xn, CX_ELMNT)) != NULL) {
341 	if ((yn = xml_spec(xn)) == NULL){
342 	    if (netconf_unknown_element_xml(xret, "application", xml_name(xn), NULL) < 0)
343 		goto done;
344 	    goto fail;
345 	}
346 	if ((retval = xml_yang_validate_all(h, xn, xret)) < 1)
347 	    goto done; /* error or validation fail */
348 	if ((retval = xml_yang_validate_add(h, xn, xret)) < 1)
349 	    goto done; /* error or validation fail */
350 	if (xml_default_recurse(xn, 0) < 0)
351 	    goto done;
352     }
353     // ok: /* pass validation */
354     retval = 1;
355  done:
356     return retval;
357  fail:
358     retval = 0;
359     goto done;
360 }
361 
362 /*! Check if an xml node is a part of a choice and have >1 siblings
363  * @param[in]  xt    XML node to be validated
364  * @param[in]  yt    xt:s yang statement
365  * @param[out] xret    Error XML tree. Free with xml_free after use
366  * @retval     1     Validation OK
367  * @retval     0     Validation failed (cbret set)
368  * @retval    -1     Error
369  * Check if xt is part of valid choice
370  */
371 static int
check_choice(cxobj * xt,yang_stmt * yt,cxobj ** xret)372 check_choice(cxobj     *xt,
373 	     yang_stmt *yt,
374 	     cxobj    **xret)
375 {
376     int        retval = -1;
377     yang_stmt *y;
378     yang_stmt *ytp;      /* yt:s parent */
379     yang_stmt *ytcase = NULL;   /* yt:s parent case if any */
380     yang_stmt *ytchoice = NULL;
381     yang_stmt *yp;
382     cxobj     *x;
383     cxobj     *xp;
384 
385     if ((ytp = yang_parent_get(yt)) == NULL)
386 	goto ok;
387     /* Return OK if xt is not choice */
388     switch (yang_keyword_get(ytp)){
389     case Y_CASE:
390 	ytcase = ytp;
391 	ytchoice = yang_parent_get(ytp);
392 	break;
393     case Y_CHOICE:
394 	ytchoice = ytp;
395 	break;
396     default:
397 	goto ok;  /* Not choice */
398 	break;
399     }
400     if ((xp = xml_parent(xt)) == NULL)
401 	goto ok;
402     x = NULL; /* Find a child with same yang spec */
403     while ((x = xml_child_each(xp, x, CX_ELMNT)) != NULL) {
404 	if (x == xt)
405 	    continue;
406 	y = xml_spec(x);
407 	if (y == yt) /* eg same list */
408 	    continue;
409 	yp = yang_parent_get(y);
410 	switch (yang_keyword_get(yp)){
411 	case Y_CASE:
412 	    if (yang_parent_get(yp) != ytchoice) /* Not same choice (not releveant)  */
413 		continue;
414 	    if (yp == ytcase) /* same choice but different case */
415 		continue;
416 	    break;
417 	case Y_CHOICE:
418 	    if (yp != ytcase) /* Not same choice (not relevant) */
419 		continue;
420 	    break;
421 	default:
422 	    continue; /* not choice */
423 	    break;
424 	}
425 	if (netconf_bad_element_xml(xret, "application", xml_name(x), "Element in choice statement already exists") < 0)
426 	    goto done;
427 	goto fail;
428     } /* while */
429 
430  ok:
431     retval = 1;
432  done:
433     return retval;
434  fail:
435     retval = 0;
436     goto done;
437 }
438 
439 /*! Check that an XML tree of type list has valid keys
440  * @param[in]  xt    XML tree
441  * @param[in]  yt    Yang spec of xt of type LIST which is a config true node.
442  * @param[out] xret  Error XML tree. Free with xml_free after use
443  * @retval     1     Validation OK
444  * @retval     0     Validation failed (xret set)
445  * @retval    -1     Error
446  * This ensures that there are keys in XML corresponding to the Yang
447  * This function is broken out from generic validation since it needs specially checked in incoming
448  * edit-config
449  * XXX: It does not check double (more than one) key
450  * @see xml_yang_validate_list_key_only
451  */
452 static int
check_list_key(cxobj * xt,yang_stmt * yt,cxobj ** xret)453 check_list_key(cxobj     *xt,
454 	       yang_stmt *yt,
455 	       cxobj    **xret)
456 
457 {
458     int        retval = -1;
459     yang_stmt *yc;
460     cvec      *cvk = NULL; /* vector of index keys */
461     cg_var    *cvi;
462     char      *keyname;
463 
464     if (yt == NULL || !yang_config(yt) || yang_keyword_get(yt) != Y_LIST){
465 	clicon_err(OE_YANG, EINVAL, "yt is not a config true list node");
466 	goto done;
467     }
468     yc = NULL;
469     while ((yc = yn_each(yt, yc)) != NULL) {
470 	if (yang_keyword_get(yc) != Y_KEY)
471 	    continue;
472 	/* Check if a list does not have mandatory key leafs */
473 	cvk = yang_cvec_get(yt); /* Use Y_LIST cache, see ys_populate_list() */
474 	cvi = NULL;
475 	while ((cvi = cvec_each(cvk, cvi)) != NULL) {
476 	    keyname = cv_string_get(cvi);
477 	    if (xml_find_type(xt, NULL, keyname, CX_ELMNT) == NULL){
478 		if (netconf_missing_element_xml(xret, "application", keyname, "Mandatory key") < 0)
479 		    goto done;
480 		goto fail;
481 	    }
482 	}
483     }
484     retval = 1;
485  done:
486     return retval;
487  fail:
488     retval = 0;
489     goto done;
490 }
491 
492 /*! Check if an xml node lacks mandatory children
493  * @param[in]  xt    XML node to be validated
494  * @param[in]  yt    xt:s yang statement
495  * @param[out] xret  Error XML tree. Free with xml_free after use
496  * @retval     1     Validation OK
497  * @retval     0     Validation failed (cbret set)
498  * @retval    -1     Error
499  */
500 static int
check_mandatory(cxobj * xt,yang_stmt * yt,cxobj ** xret)501 check_mandatory(cxobj     *xt,
502 		yang_stmt *yt,
503 		cxobj    **xret)
504 
505 {
506     int        retval = -1;
507     cxobj     *x;
508     yang_stmt *y;
509     yang_stmt *yc;
510     yang_stmt *yp;
511     cbuf      *cb = NULL;
512     int        ret;
513 
514     if (yt == NULL || !yang_config(yt)){
515 	clicon_err(OE_YANG, EINVAL, "yt is not config true");
516 	goto done;
517     }
518     if (yang_keyword_get(yt) == Y_LIST){
519 	if ((ret = check_list_key(xt, yt, xret)) < 0)
520 	    goto done;
521 	if (ret == 0)
522 	    goto fail;
523     }
524     yc = NULL;
525     while ((yc = yn_each(yt, yc)) != NULL) {
526 	if (!yang_mandatory(yc))
527 	    continue;
528 	switch (yang_keyword_get(yc)){
529 	case Y_CONTAINER:
530 	case Y_ANYDATA:
531 	case Y_ANYXML:
532 	case Y_LEAF:
533 	    if (yang_config(yc)==0)
534 		 break;
535 	    /* Find a child with the mandatory yang */
536 	    x = NULL;
537 	    while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
538 		if ((y = xml_spec(x)) != NULL
539 		    && y==yc)
540 		    break; /* got it */
541 	    }
542 	    if (x == NULL){
543 		if ((cb = cbuf_new()) == NULL){
544 		    clicon_err(OE_UNIX, errno, "cbuf_new");
545 		    goto done;
546 		}
547 		cprintf(cb, "Mandatory variable of %s in module %s", xml_name(xt), yang_argument_get(ys_module(yc)));
548 		if (netconf_missing_element_xml(xret, "application", yang_argument_get(yc), cbuf_get(cb)) < 0)
549 			    goto done;
550 		goto fail;
551 	    }
552 	    break;
553 	case Y_CHOICE: /* More complex because of choice/case structure */
554 	    x = NULL;
555 	    while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
556 		if ((y = xml_spec(x)) != NULL &&
557 		    (yp = yang_choice(y)) != NULL &&
558 		    yp == yc){
559 		    break; /* leave loop with x set */
560 		}
561 	    }
562 	    if (x == NULL){
563 		/* @see RFC7950: 15.6 Error Message for Data That Violates
564 		 * a Mandatory "choice" Statement */
565 		if (netconf_data_missing_xml(xret, yang_argument_get(yc), NULL) < 0)
566 		    goto done;
567 		goto fail;
568 	    }
569 	    break;
570 	default:
571 	    break;
572 	} /* switch */
573     }
574     retval = 1;
575  done:
576     if (cb)
577 	cbuf_free(cb);
578     return retval;
579  fail:
580     retval = 0;
581     goto done;
582 }
583 
584 /*! New element last in list, check if already exists if sp return -1
585  * @param[in]  vec   Vector of existing entries (new is last)
586  * @param[in]  i1    The new entry is placed at vec[i1]
587  * @param[in]  vlen  Lenght of entry
588  * @param[in]  sorted Sorted by system, ie sorted by key, otherwise no assumption
589  * @retval     0     OK, entry is unique
590  * @retval    -1     Duplicate detected
591  * @note This is currently quadratic complexity. It could be improved by inserting new element sorted and binary search.
592  */
593 static int
check_insert_duplicate(char ** vec,int i1,int vlen,int sorted)594 check_insert_duplicate(char **vec,
595 		       int    i1,
596 		       int    vlen,
597 		       int    sorted)
598 {
599     int i;
600     int v;
601     char *b;
602 
603     if (sorted){
604 	/* Just go look at previous element to see if it is duplicate (sorted by system) */
605 	if (i1 == 0)
606 	    return 0;
607 	i = i1-1;
608 	for (v=0; v<vlen; v++){
609 	    b = vec[i*vlen+v];
610 	    if (b == NULL || strcmp(b, vec[i1*vlen+v]))
611 		return 0;
612 	}
613 	/* here we have passed thru all keys of previous element and they are all equal */
614 	return -1;
615     }
616     else{
617 	for (i=0; i<i1; i++){
618 	    for (v=0; v<vlen; v++){
619 		b = vec[i*vlen+v];
620 		if (b == NULL || strcmp(b, vec[i1*vlen+v]))
621 		    break;
622 	    }
623 	    if (v==vlen) /* duplicate */
624 		break;
625 	}
626 	return i==i1?0:-1;
627     }
628 }
629 
630 /*! Given a list with unique constraint, detect duplicates
631  * @param[in]  x     The first element in the list (on return the last)
632  * @param[in]  xt    The parent of x
633  * @param[in]  y     Its yang spec (Y_LIST)
634  * @param[in]  yu    A yang unique spec (Y_UNIQUE) for unique keyword or (Y_LIST) for list keys
635  * @param[out] xret    Error XML tree. Free with xml_free after use
636  * @retval     1     Validation OK
637  * @retval     0     Validation failed (cbret set)
638  * @retval    -1     Error
639  * @note It would be possible to cache the vector built below
640  */
641 static int
check_unique_list(cxobj * x,cxobj * xt,yang_stmt * y,yang_stmt * yu,cxobj ** xret)642 check_unique_list(cxobj     *x,
643 		  cxobj     *xt,
644 		  yang_stmt *y,
645 		  yang_stmt *yu,
646 		  cxobj    **xret)
647 
648 {
649     int       retval = -1;
650     cvec      *cvk; /* unique vector */
651     cg_var    *cvi; /* unique node name */
652     cxobj     *xi;
653     char     **vec = NULL; /* 2xmatrix */
654     int        vlen;
655     int        i;
656     int        v;
657     char      *bi;
658     int        sorted;
659 
660     /* If list and is sorted by system, then it is assumed elements are in key-order which is optimized
661      * Other cases are "unique" constraint or list sorted by user which is quadratic in complexity
662      * This second case COULD be optimized if binary insert is made on the vec vector.
663      */
664     sorted = (yang_keyword_get(yu) == Y_LIST &&
665 	      yang_find(y, Y_ORDERED_BY, "user") == NULL);
666     cvk = yang_cvec_get(yu);
667     vlen = cvec_len(cvk); /* nr of unique elements to check */
668     if ((vec = calloc(vlen*xml_child_nr(xt), sizeof(char*))) == NULL){
669 	clicon_err(OE_UNIX, errno, "calloc");
670 	goto done;
671     }
672     /* A vector is built with key-values, for each iteration check "backward" in the vector
673      * for duplicates
674      */
675     i = 0; /* x element index */
676     do {
677 	cvi = NULL;
678 	v = 0; /* index in each tuple */
679 	while ((cvi = cvec_each(cvk, cvi)) != NULL){
680 	    /* RFC7950: Sec 7.8.3.1: entries that do not have value for all
681 	     * referenced leafs are not taken into account */
682 	    if ((xi = xml_find(x, cv_string_get(cvi))) ==NULL)
683 		break;
684 	    if ((bi = xml_body(xi)) == NULL)
685 		break;
686 	    vec[i*vlen + v++] = bi;
687 	}
688 	if (cvi==NULL){
689 	    /* Last element (i) is newly inserted, see if it is already there */
690 	    if (check_insert_duplicate(vec, i, vlen, sorted) < 0){
691 		if (netconf_data_not_unique_xml(xret, x, cvk) < 0)
692 		    goto done;
693 		goto fail;
694 	    }
695 	}
696 	x = xml_child_each(xt, x, CX_ELMNT);
697 	i++;
698     } while (x && y == xml_spec(x));  /* stop if list ends, others may follow */
699     /* It would be possible to cache vec here as an optimization */
700     retval = 1;
701  done:
702     if (vec)
703 	free(vec);
704     return retval;
705  fail:
706     retval = 0;
707     goto done;
708 }
709 
710 /*! Given a list, check if any min/max-elemants constraints apply
711  * @param[in]  xp    Parent of the xml list there are too few/many
712  * @param[in]  y     Yang spec of the failing list
713  * @param[in]  nr    Number of elements (like x) in the list
714  * @param[out] xret  Error XML tree. Free with xml_free after use
715  * @retval     1     Validation OK
716  * @retval     0     Validation failed (cbret set)
717  * @retval    -1     Error
718  * @see RFC7950 7.7.5
719  */
720 static int
check_min_max(cxobj * xp,yang_stmt * y,int nr,cxobj ** xret)721 check_min_max(cxobj     *xp,
722 	      yang_stmt *y,
723 	      int        nr,
724 	      cxobj     **xret)
725 {
726     int         retval = -1;
727     yang_stmt  *ymin; /* yang min */
728     yang_stmt  *ymax; /* yang max */
729     cg_var     *cv;
730 
731     if ((ymin = yang_find(y, Y_MIN_ELEMENTS, NULL)) != NULL){
732 	cv = yang_cv_get(ymin);
733 	if (nr < cv_uint32_get(cv)){
734 	    if (netconf_minmax_elements_xml(xret, xp, yang_argument_get(y), 0) < 0)
735 		goto done;
736 	    goto fail;
737 	}
738     }
739     if ((ymax = yang_find(y, Y_MAX_ELEMENTS, NULL)) != NULL){
740 	cv = yang_cv_get(ymax);
741 	if (cv_uint32_get(cv) > 0 && /* 0 means unbounded */
742 	    nr > cv_uint32_get(cv)){
743 	    if (netconf_minmax_elements_xml(xret, xp, yang_argument_get(y), 1) < 0)
744 		goto done;
745 	    goto fail;
746 	}
747     }
748     retval = 1;
749  done:
750     return retval;
751  fail:
752     retval = 0;
753     goto done;
754 }
755 
756 /*! Detect unique constraint for duplicates from parent node and minmax
757  * @param[in]  xt    XML parent (may have lists w unique constraints as child)
758  * @param[out] xret  Error XML tree. Free with xml_free after use
759  * @retval     1     Validation OK
760  * @retval     0     Validation failed (xret set)
761  * @retval    -1     Error
762  * Assume xt:s children are sorted and yang populated.
763  * The function does two different things of the children of an XML node:
764  * (1) Check min/max element constraints
765  * (2) Check unique constraints
766  *
767  * The routine uses a node traversing mechanism as the following example, where
768  * two lists [x1,..] and [x2,..] are embedded:
769  *   xt:  {a, b, [x1, x1, x1], d, e, f, [x2, x2, x2], g}
770  * The function does this using a single iteration and uses the fact that the
771  * xml symbols share yang symbols: ie [x1..] has yang y1 and d has yd.
772  *
773  * Unique constraints:
774  * Lists are identified, then check_unique_list is called on each list.
775  * Example, x has an associated yang list node with list of unique constraints
776  *         y-list->y-unique - "a"
777  *      xt->x ->  ab
778  *          x ->  bc
779  *          x ->  ab
780  *
781  * Min-max constraints:
782  * Find upper and lower bound of existing lists and report violations
783  * Somewhat tricky to find violation of min-elements of empty
784  * lists, but this is done by a "gap-detection" mechanism, which detects
785  * gaps in the xml nodes given the ancestor Yang structure.
786  * But no gap analysis is done if the yang spec of the top-level xml is unknown
787  * Example:
788  *   Yang structure: y1, y2, y3,
789  *   XML structure: [x1, x1], [x3, x3] where [x2] list is missing
790  * @note min-element constraints on empty lists are not detected on top-level.
791  * Or more specifically, if no yang spec if associated with the top-level
792  * XML node. This may not be a large problem since it would mean empty configs
793  * are not allowed.
794  */
795 static int
check_list_unique_minmax(cxobj * xt,cxobj ** xret)796 check_list_unique_minmax(cxobj  *xt,
797 			 cxobj **xret)
798 {
799     int         retval = -1;
800     cxobj      *x = NULL;
801     yang_stmt  *y;
802     yang_stmt  *yt;
803     yang_stmt  *yprev = NULL; /* previous in list */
804     yang_stmt  *ye = NULL;    /* yang each list to catch emtpy */
805     yang_stmt  *ych;          /* y:s parent node (if choice that ye can compare to) */
806     yang_stmt  *yu;           /* yang unique */
807     int         ret;
808     int         nr=0;   /* Nr of list elements for min/max check */
809     enum rfc_6020 keyw;
810 
811     /* RFC 7950 7.7.5: regarding min-max elements check
812      * The behavior of the constraint depends on the type of the
813      * leaf-list's or list's closest ancestor node in the schema tree
814      * that is not a non-presence container (see Section 7.5.1):
815      * o If no such ancestor exists in the schema tree, the constraint
816      * is enforced.
817      * o Otherwise, if this ancestor is a case node, the constraint is
818      * enforced if any other node from the case exists.
819      * o  Otherwise, it is enforced if the ancestor node exists.
820      */
821     yt = xml_spec(xt); /* If yt == NULL, then no gap-analysis is done */
822     /* Traverse all elemenents */
823     while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
824 	if ((y = xml_spec(x)) == NULL)
825 	    continue;
826 	if ((ych = yang_choice(y)) == NULL)
827 	    ych = y;
828 	keyw = yang_keyword_get(y);
829 	if (keyw != Y_LIST && keyw != Y_LEAF_LIST){
830 	    if (yprev != NULL && y == yprev && yang_choice(y)==NULL){
831 		/* Only lists and leaf-lists are allowed to be many
832 		 * This checks duplicate container and leafs
833 		 */
834 		if (netconf_minmax_elements_xml(xret, xt, xml_name(x), 1) < 0)
835 		    goto done;
836 		goto fail;
837 	    }
838 	    yprev = y; /* Restart min/max count */
839 	    continue;
840 	}
841 	/* Here only (leaf)lists */
842 	if (yprev != NULL){ /* There exists a previous (leaf)list */
843 	    if (y == yprev){ /* If same yang as previous x, then skip (eg same list) */
844 		nr++;
845 		continue;
846 	    }
847 	    else {
848 		/* Check if the list length violates min/max */
849 		if ((ret = check_min_max(xt, yprev, nr, xret)) < 0)
850 		    goto done;
851 		if (ret == 0)
852 		    goto fail;
853 	    }
854 	}
855 	/* Here is only new list / leaf-list */
856 	yprev = y; /* Restart min/max count */
857 	nr = 1;
858 	/* Gap analysis: Check if there is any empty list between y and yprev
859 	 * Note, does not detect empty choice list (too complicated)
860 	 */
861 	if (yt != NULL && ych != ye){
862 	    /* Skip analysis if Yang spec is unknown OR
863 	     * if we are still iterating the same Y_CASE w multiple lists
864 	     */
865 	    ye = yn_each(yt, ye);
866 	    if (ye && ych != ye)
867 		do {
868 		    if (yang_config(ye) == 1 &&
869 			(yang_keyword_get(ye) == Y_LIST || yang_keyword_get(ye) == Y_LEAF_LIST)){
870 			/* Check if the list length violates min/max */
871 			if ((ret = check_min_max(xt, ye, 0, xret)) < 0)
872 			    goto done;
873 			if (ret == 0)
874 			    goto fail;
875 		    }
876 		    ye = yn_each(yt, ye);
877 		} while(ye != NULL && /* to avoid livelock (shouldnt happen) */
878 			ye != ych);
879 	}
880 	if (keyw != Y_LIST)
881 	    continue;
882 	/* Here new (first element) of lists only
883 	 * First check unique keys
884 	 */
885 	if ((ret = check_unique_list(x, xt, y, y, xret)) < 0)
886 	    goto done;
887 	if (ret == 0)
888 	    goto fail;
889 	/* Check if there is a unique constraint on the list
890 	 */
891 	yu = NULL;
892 	while ((yu = yn_each(y, yu)) != NULL) {
893 	    if (yang_keyword_get(yu) != Y_UNIQUE)
894 		continue;
895 	    /* Here is a list w unique constraints identified by:
896 	     * its first element x, its yang spec y, its parent xt, and
897 	     * a unique yang spec yu,
898 	     */
899 	    if ((ret = check_unique_list(x, xt, y, yu, xret)) < 0)
900 		goto done;
901 	    if (ret == 0)
902 		goto fail;
903 	}
904     } /* while x */
905 
906     /* yprev if set, is a list that has been traversed
907      * This check is made in the loop as well - this is for the last list
908      */
909     if (yprev){
910 	/* Check if the list length violates min/max */
911 	if ((ret = check_min_max(xt, yprev, nr, xret)) < 0)
912 	    goto done;
913 	if (ret == 0)
914 	    goto fail;
915     }
916     /* Check if there is any empty list between after last non-empty list
917      * Note, does not detect empty lists within choice/case (too complicated)
918      */
919     if ((ye = yn_each(yt, ye)) != NULL)
920 	do {
921 	    if (yang_config(ye) == 1 &&
922 		(yang_keyword_get(ye) == Y_LIST || yang_keyword_get(ye) == Y_LEAF_LIST)){
923 		/* Check if the list length violates min/max */
924 		if ((ret = check_min_max(xt, ye, 0, xret)) < 0)
925 		    goto done;
926 		if (ret == 0)
927 		    goto fail;
928 	    }
929 	} while((ye = yn_each(yt, ye)) != NULL);
930     retval = 1;
931  done:
932     return retval;
933  fail:
934     retval = 0;
935     goto done;
936 }
937 
938 /*! Validate a single XML node with yang specification for added entry
939  * 1. Check if mandatory leafs present as subs.
940  * 2. Check leaf values, eg int ranges and string regexps.
941  * @param[in]  xt    XML node to be validated
942  * @param[out] xret    Error XML tree. Free with xml_free after use
943  * @retval     1     Validation OK
944  * @retval     0     Validation failed (cbret set)
945  * @retval    -1     Error
946  * @code
947  *   cxobj *x;
948  *   cbuf *xret = NULL;
949  *   if ((ret = xml_yang_validate_add(h, x, &xret)) < 0)
950  *      err;
951  *   if (ret == 0)
952  *      fail;
953  * @endcode
954  * @see xml_yang_validate_all
955  * @see xml_yang_validate_rpc
956  * @note Should need a variant accepting cxobj **xret
957  */
958 int
xml_yang_validate_add(clicon_handle h,cxobj * xt,cxobj ** xret)959 xml_yang_validate_add(clicon_handle h,
960 		      cxobj        *xt,
961 		      cxobj       **xret)
962 {
963     int        retval = -1;
964     cg_var    *cv = NULL;
965     char      *reason = NULL;
966     yang_stmt *yt;   /* yang spec of xt going in */
967     char      *body;
968     int        ret;
969     cxobj     *x;
970     enum cv_type cvtype;
971 
972     /* if not given by argument (overide) use default link
973        and !Node has a config sub-statement and it is false */
974     if ((yt = xml_spec(xt)) != NULL && yang_config(yt) != 0){
975 	if ((ret = check_choice(xt, yt, xret)) < 0)
976 	    goto done;
977 	if (ret == 0)
978 	    goto fail;
979 	if ((ret = check_mandatory(xt, yt, xret)) < 0)
980 	    goto done;
981 	if (ret == 0)
982 	    goto fail;
983 	/* Check leaf values */
984 	switch (yang_keyword_get(yt)){
985 	case Y_LEAF:
986 	    /* fall thru */
987 	case Y_LEAF_LIST:
988 	    /* validate value against ranges, etc */
989 	    if ((cv = cv_dup(yang_cv_get(yt))) == NULL){
990 		clicon_err(OE_UNIX, errno, "cv_dup");
991 		goto done;
992 	    }
993 	    /* In the union case, value is parsed as generic REST type,
994 	     * needs to be reparsed when concrete type is selected
995 	     */
996 	    if ((body = xml_body(xt)) == NULL){
997 		/* We do not allow ints to be empty. Otherwise NULL strings
998 		 * are considered as "" */
999 		cvtype = cv_type_get(cv);
1000 		if (cv_isint(cvtype) || cvtype == CGV_BOOL || cvtype == CGV_DEC64){
1001 		    if (netconf_bad_element_xml(xret, "application",  yang_argument_get(yt), "Invalid NULL value") < 0)
1002 			goto done;
1003 		    goto fail;
1004 		}
1005 	    }
1006 	    else{
1007 		if (cv_parse1(body, cv, &reason) != 1){
1008 		    if (netconf_bad_element_xml(xret, "application",  yang_argument_get(yt), reason) < 0)
1009 			goto done;
1010 		    goto fail;
1011 		}
1012 	    }
1013 	    if ((ret = ys_cv_validate(h, cv, yt, &reason)) < 0)
1014 		goto done;
1015 	    if (ret == 0){
1016 		if (netconf_bad_element_xml(xret, "application",  yang_argument_get(yt), reason) < 0)
1017 		    goto done;
1018 		goto fail;
1019 	    }
1020 	    break;
1021 	default:
1022 	    break;
1023 	}
1024     }
1025     x = NULL;
1026     while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
1027 	if ((ret = xml_yang_validate_add(h, x, xret)) < 0)
1028 	    goto done;
1029 	if (ret == 0)
1030 	    goto fail;
1031     }
1032     retval = 1;
1033  done:
1034     if (cv)
1035 	cv_free(cv);
1036     if (reason)
1037 	free(reason);
1038     return retval;
1039  fail:
1040     retval = 0;
1041     goto done;
1042 }
1043 
1044 /*! Some checks done only at edit_config, eg keys in lists
1045  * @param[in]  xt     XML tree
1046  * @param[out] xret   Error XML tree. Free with xml_free after use
1047  */
1048 int
xml_yang_validate_list_key_only(cxobj * xt,cxobj ** xret)1049 xml_yang_validate_list_key_only(cxobj        *xt,
1050 				cxobj       **xret)
1051 {
1052     int        retval = -1;
1053     yang_stmt *yt;   /* yang spec of xt going in */
1054     int        ret;
1055     cxobj     *x;
1056 
1057     /* if not given by argument (overide) use default link
1058        and !Node has a config sub-statement and it is false */
1059     if ((yt = xml_spec(xt)) != NULL &&
1060 	yang_config(yt) != 0 &&
1061 	yang_keyword_get(yt) == Y_LIST){
1062 	if ((ret = check_list_key(xt, yt, xret)) < 0)
1063 	    goto done;
1064 	if (ret == 0)
1065 	    goto fail;
1066     }
1067     x = NULL;
1068     while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
1069 	if ((ret = xml_yang_validate_list_key_only(x, xret)) < 0)
1070 	    goto done;
1071 	if (ret == 0)
1072 	    goto fail;
1073     }
1074     retval = 1;
1075  done:
1076     return retval;
1077  fail:
1078     retval = 0;
1079     goto done;
1080 }
1081 
1082 /*! Validate a single XML node with yang specification for all (not only added) entries
1083  * 1. Check leafrefs. Eg you delete a leaf and a leafref references it.
1084  * @param[in]  xt  XML node to be validated
1085  * @param[out] xret  Error XML tree (if retval=0). Free with xml_free after use
1086  * @retval     1     Validation OK
1087  * @retval     0     Validation failed (cbret set)
1088  * @retval    -1     Error
1089  * @code
1090  *   cxobj *x;
1091  *   cbuf *xret = NULL;
1092  *   if ((ret = xml_yang_validate_all(h, x, &xret)) < 0)
1093  *      err;
1094  *   if (ret == 0)
1095  *      fail;
1096  *   xml_free(xret);
1097  * @endcode
1098  * @see xml_yang_validate_add
1099  * @see xml_yang_validate_rpc
1100  * @note Should need a variant accepting cxobj **xret
1101  */
1102 int
xml_yang_validate_all(clicon_handle h,cxobj * xt,cxobj ** xret)1103 xml_yang_validate_all(clicon_handle h,
1104 		      cxobj        *xt,
1105 		      cxobj       **xret)
1106 {
1107     int        retval = -1;
1108     yang_stmt *ys;  /* yang node */
1109     yang_stmt *yc;  /* yang child */
1110     yang_stmt *ye;  /* yang must error-message */
1111     char      *xpath;
1112     int        nr;
1113     int        ret;
1114     cxobj     *x;
1115     cxobj     *xp;
1116     char      *ns = NULL;
1117     cbuf      *cb = NULL;
1118     cvec      *nsc = NULL;
1119 
1120     /* if not given by argument (overide) use default link
1121        and !Node has a config sub-statement and it is false */
1122     ys=xml_spec(xt);
1123     if (ys==NULL){
1124 	if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1) {
1125 	    clicon_log(LOG_WARNING,
1126 		       "%s: %d: No YANG spec for %s, validation skipped",
1127 		       __FUNCTION__, __LINE__, xml_name(xt));
1128 	    goto ok;
1129 	}
1130 	if ((cb = cbuf_new()) == NULL){
1131 	    clicon_err(OE_UNIX, errno, "cbuf_new");
1132 	    goto done;
1133 	}
1134 	cprintf(cb, "Failed to find YANG spec of XML node: %s", xml_name(xt));
1135 	if ((xp = xml_parent(xt)) != NULL)
1136 	    cprintf(cb, " with parent: %s", xml_name(xp));
1137 	if (xml2ns(xt, xml_prefix(xt), &ns) < 0)
1138 	    goto done;
1139 	if (ns)
1140 	    cprintf(cb, " in namespace: %s", ns);
1141 	if (netconf_unknown_element_xml(xret, "application", xml_name(xt), cbuf_get(cb)) < 0)
1142 	    goto done;
1143 	goto fail;
1144     }
1145     if (yang_config(ys) != 0){
1146 	/* Node-specific validation */
1147 	switch (yang_keyword_get(ys)){
1148 	case Y_ANYXML:
1149 	case Y_ANYDATA:
1150 	    goto ok;
1151 	    break;
1152 	case Y_LEAF:
1153 	    /* fall thru */
1154 	case Y_LEAF_LIST:
1155 	    /* Special case if leaf is leafref, then first check against
1156 	       current xml tree
1157  	    */
1158 	    /* Get base type yc */
1159 	    if (yang_type_get(ys, NULL, &yc, NULL, NULL, NULL, NULL, NULL) < 0)
1160 		goto done;
1161 	    if (strcmp(yang_argument_get(yc), "leafref") == 0){
1162 		if ((ret = validate_leafref(xt, ys, yc, xret)) < 0)
1163 		    goto done;
1164 		if (ret == 0)
1165 		    goto fail;
1166 		}
1167 	    else if (strcmp(yang_argument_get(yc), "identityref") == 0){
1168 		if ((ret = validate_identityref(xt, ys, yc, xret)) < 0)
1169 		    goto done;
1170 		if (ret == 0)
1171 		    goto fail;
1172 	    }
1173 	    break;
1174 	default:
1175 	    break;
1176 	}
1177 	/* must sub-node RFC 7950 Sec 7.5.3. Can be several.
1178 	 * XXX. use yang path instead? */
1179 	yc = NULL;
1180 	while ((yc = yn_each(ys, yc)) != NULL) {
1181 	    if (yang_keyword_get(yc) != Y_MUST)
1182 		continue;
1183 	    xpath = yang_argument_get(yc); /* "must" has xpath argument */
1184 	    if (xml_nsctx_yang(yc, &nsc) < 0)
1185 		goto done;
1186 	    if ((nr = xpath_vec_bool(xt, nsc, "%s", xpath)) < 0)
1187 		goto done;
1188 	    if (!nr){
1189 		ye = yang_find(yc, Y_ERROR_MESSAGE, NULL);
1190 		if (netconf_operation_failed_xml(xret, "application",
1191 						 ye?yang_argument_get(ye):"must xpath validation failed") < 0)
1192 		    goto done;
1193 		goto fail;
1194 	    }
1195 	    if (nsc){
1196 		xml_nsctx_free(nsc);
1197 		nsc = NULL;
1198 	    }
1199 	}
1200 	/* "when" sub-node RFC 7950 Sec 7.21.5. Can only be one. */
1201 	if ((yc = yang_find(ys, Y_WHEN, NULL)) != NULL){
1202 	    xpath = yang_argument_get(yc); /* "when" has xpath argument */
1203 	    /* WHEN xpath needs namespace context */
1204 	    if (xml_nsctx_yang(ys, &nsc) < 0)
1205 		goto done;
1206 	    if ((nr = xpath_vec_bool(xt, nsc, "%s", xpath)) < 0)
1207 		goto done;
1208 	    if (nsc){
1209 		xml_nsctx_free(nsc);
1210 		nsc = NULL;
1211 	    }
1212 	    if (nr == 0){
1213 		if ((cb = cbuf_new()) == NULL){
1214 		    clicon_err(OE_UNIX, errno, "cbuf_new");
1215 		    goto done;
1216 		}
1217 		cprintf(cb, "Failed WHEN condition of %s in module %s",
1218 			xml_name(xt),
1219 			yang_argument_get(ys_module(ys)));
1220 		if (netconf_operation_failed_xml(xret, "application",
1221 						 cbuf_get(cb)) < 0)
1222 		    goto done;
1223 		goto fail;
1224 	    }
1225 	}
1226 	/* Augmented when using special struct. */
1227 	if ((xpath = yang_when_xpath_get(ys)) != NULL){
1228 	    if ((nr = xpath_vec_bool(xml_parent(xt), yang_when_nsc_get(ys),
1229 				     "%s", xpath)) < 0)
1230 		goto done;
1231 	    if (nr == 0){
1232 		if ((cb = cbuf_new()) == NULL){
1233 		    clicon_err(OE_UNIX, errno, "cbuf_new");
1234 		    goto done;
1235 		}
1236 		cprintf(cb, "Failed augmented WHEN condition %s of node %s in module %s",
1237 			xpath,
1238 			xml_name(xt),
1239 			yang_argument_get(ys_module(ys)));
1240 		if (netconf_operation_failed_xml(xret, "application",
1241 						 cbuf_get(cb)) < 0)
1242 		    goto done;
1243 		goto fail;
1244 	    }
1245 	}
1246     }
1247     x = NULL;
1248     while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
1249 	if ((ret = xml_yang_validate_all(h, x, xret)) < 0)
1250 	    goto done;
1251 	if (ret == 0)
1252 	    goto fail;
1253     }
1254     /* Check unique and min-max after choice test for example*/
1255     if (yang_config(ys) != 0){
1256 	/* Checks if next level contains any unique list constraints */
1257 	if ((ret = check_list_unique_minmax(xt, xret)) < 0)
1258 	    goto done;
1259 	if (ret == 0)
1260 	    goto fail;
1261     }
1262  ok:
1263     retval = 1;
1264  done:
1265     if (cb)
1266 	cbuf_free(cb);
1267     if (nsc)
1268 	xml_nsctx_free(nsc);
1269     return retval;
1270  fail:
1271     retval = 0;
1272     goto done;
1273 }
1274 /*! Translate a single xml node to a cligen variable vector. Note not recursive
1275  * @param[out] xret    Error XML tree (if ret == 0). Free with xml_free after use
1276  * @retval     1     Validation OK
1277  * @retval     0     Validation failed (xret set)
1278  * @retval    -1     Error
1279  */
1280 int
xml_yang_validate_all_top(clicon_handle h,cxobj * xt,cxobj ** xret)1281 xml_yang_validate_all_top(clicon_handle h,
1282 			  cxobj        *xt,
1283 			  cxobj       **xret)
1284 {
1285     int    ret;
1286     cxobj *x;
1287 
1288     x = NULL;
1289     while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
1290 	if ((ret = xml_yang_validate_all(h, x, xret)) < 1)
1291 	    return ret;
1292     }
1293     if ((ret = check_list_unique_minmax(xt, xret)) < 1)
1294 	return ret;
1295     return 1;
1296 }
1297