1 /**
2  * @file resolve.c
3  * @author Michal Vasko <mvasko@cesnet.cz>
4  * @brief libyang resolve functions
5  *
6  * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
7  *
8  * This source code is licensed under BSD 3-Clause License (the "License").
9  * You may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     https://opensource.org/licenses/BSD-3-Clause
13  */
14 
15 #define _GNU_SOURCE
16 
17 #include <stdlib.h>
18 #include <assert.h>
19 #include <string.h>
20 #include <ctype.h>
21 #include <inttypes.h>
22 #include <limits.h>
23 
24 #include "libyang.h"
25 #include "resolve.h"
26 #include "common.h"
27 #include "xpath.h"
28 #include "parser.h"
29 #include "parser_yang.h"
30 #include "xml_internal.h"
31 #include "hash_table.h"
32 #include "tree_internal.h"
33 #include "extensions.h"
34 #include "validation.h"
35 
36 /* internal parsed predicate structure */
37 struct parsed_pred {
38     const struct lys_node *schema;
39     const char *pred_str;
40     int pred_str_len;
41 
42     int len;
43     struct {
44         const char *mod_name;
45         int mod_name_len;
46         const char *name;
47         int nam_len;
48         const char *value;
49         int val_len;
50     } *pred;
51 };
52 
53 static int
check_overflow_mul(int64_t num1,int64_t num2)54 check_overflow_mul(int64_t num1, int64_t num2)
55 {
56     if (((num1 == -1) && (num2 == INT64_MIN)) || ((num2 == -1) && (num1 == INT64_MIN))) {
57         return 1;
58     }
59 
60     if ((num1 > INT64_MAX / num2) || (num1 < INT64_MIN / num2)) {
61         return 1;
62     }
63 
64     return 0;
65 }
66 
67 static int
check_overflow_sub(int64_t num1,int64_t num2)68 check_overflow_sub(int64_t num1, int64_t num2)
69 {
70     if (((num2 < 0) && (num1 > INT64_MAX + num2)) || ((num2 > 0) && (num1 < INT64_MIN + num2))) {
71         return 1;
72     }
73 
74     return 0;
75 }
76 
77 static int
check_overflow_add(int64_t num1,int64_t num2)78 check_overflow_add(int64_t num1, int64_t num2)
79 {
80     if (((num2 > 0) && (num1 > INT64_MAX - num2)) || ((num2 < 0) && (num1 < INT64_MIN - num2))) {
81         return 1;
82     }
83 
84     return 0;
85 }
86 
87 int
parse_range_dec64(const char ** str_num,uint8_t dig,int64_t * num)88 parse_range_dec64(const char **str_num, uint8_t dig, int64_t *num)
89 {
90     const char *ptr;
91     int minus = 0;
92     int64_t ret = 0;
93     int8_t str_exp, str_dig = -1, trailing_zeros = 0;
94 
95     ptr = *str_num;
96 
97     if (ptr[0] == '-') {
98         minus = 1;
99         ++ptr;
100     } else if (ptr[0] == '+') {
101         ++ptr;
102     }
103 
104     if (!isdigit(ptr[0])) {
105         /* there must be at least one */
106         return 1;
107     }
108 
109     for (str_exp = 0; isdigit(ptr[0]) || ((ptr[0] == '.') && (str_dig < 0)); ++ptr) {
110         if (str_exp > 18) {
111             return 1;
112         }
113 
114         if (ptr[0] == '.') {
115             if (ptr[1] == '.') {
116                 /* it's the next interval */
117                 break;
118             }
119             ++str_dig;
120         } else {
121             if (check_overflow_mul(ret, 10)) {
122                 return 1;
123             }
124             ret *= 10;
125 
126             if (minus) {
127                 if (check_overflow_sub(ret, ptr[0] - '0')) {
128                     return 1;
129                 }
130                 ret -= ptr[0] - '0';
131             } else {
132                 if (check_overflow_add(ret, ptr[0] - '0')) {
133                     return 1;
134                 }
135                 ret += ptr[0] - '0';
136             }
137             if (str_dig > -1) {
138                 ++str_dig;
139                 if (ptr[0] == '0') {
140                     /* possibly trailing zero */
141                     trailing_zeros++;
142                 } else {
143                     trailing_zeros = 0;
144                 }
145             }
146             ++str_exp;
147         }
148     }
149     if (str_dig == 0) {
150         /* no digits after '.' */
151         return 1;
152     } else if (str_dig == -1) {
153         /* there are 0 numbers after the floating point */
154         str_dig = 0;
155     }
156     /* remove trailing zeros */
157     if (trailing_zeros) {
158         str_dig -= trailing_zeros;
159         str_exp -= trailing_zeros;
160         ret = ret / dec_pow(trailing_zeros);
161     }
162 
163     /* it's parsed, now adjust the number based on fraction-digits, if needed */
164     if (str_dig < dig) {
165         if ((str_exp - 1) + (dig - str_dig) > 18) {
166             return 1;
167         }
168 
169         if (check_overflow_mul(ret, dec_pow(dig - str_dig))) {
170             return 1;
171         }
172         ret *= dec_pow(dig - str_dig);
173     }
174     if (str_dig > dig) {
175         return 1;
176     }
177 
178     *str_num = ptr;
179     *num = ret;
180 
181     return 0;
182 }
183 
184 /**
185  * @brief Parse an identifier.
186  *
187  * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
188  * identifier          = (ALPHA / "_")
189  *                       *(ALPHA / DIGIT / "_" / "-" / ".")
190  *
191  * @param[in] id Identifier to use.
192  *
193  * @return Number of characters successfully parsed.
194  */
195 unsigned int
parse_identifier(const char * id)196 parse_identifier(const char *id)
197 {
198     unsigned int parsed = 0;
199 
200     assert(id);
201 
202     if (!isalpha(id[0]) && (id[0] != '_')) {
203         return -parsed;
204     }
205 
206     ++parsed;
207     ++id;
208 
209     while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
210         ++parsed;
211         ++id;
212     }
213 
214     return parsed;
215 }
216 
217 /**
218  * @brief Parse a node-identifier.
219  *
220  * node-identifier     = [module-name ":"] identifier
221  *
222  * @param[in] id Identifier to use.
223  * @param[out] mod_name Points to the module name, NULL if there is not any.
224  * @param[out] mod_name_len Length of the module name, 0 if there is not any.
225  * @param[out] name Points to the node name.
226  * @param[out] nam_len Length of the node name.
227  * @param[out] all_desc Whether the path starts with '/', only supported in extended paths.
228  * @param[in] extended Whether to accept an extended path (support for [prefix:]*, /[prefix:]*, /[prefix:]., prefix:#identifier).
229  *
230  * @return Number of characters successfully parsed,
231  *         positive on success, negative on failure.
232  */
233 static int
parse_node_identifier(const char * id,const char ** mod_name,int * mod_name_len,const char ** name,int * nam_len,int * all_desc,int extended)234 parse_node_identifier(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
235                       int *all_desc, int extended)
236 {
237     int parsed = 0, ret, all_desc_local = 0, first_id_len;
238     const char *first_id;
239 
240     assert(id);
241     assert((mod_name && mod_name_len) || (!mod_name && !mod_name_len));
242     assert((name && nam_len) || (!name && !nam_len));
243 
244     if (mod_name) {
245         *mod_name = NULL;
246         *mod_name_len = 0;
247     }
248     if (name) {
249         *name = NULL;
250         *nam_len = 0;
251     }
252 
253     if (extended) {
254         /* try to parse only the extended expressions */
255         if (id[parsed] == '/') {
256             if (all_desc) {
257                 *all_desc = 1;
258             }
259             all_desc_local = 1;
260         } else {
261             if (all_desc) {
262                 *all_desc = 0;
263             }
264         }
265 
266         /* is there a prefix? */
267         ret = parse_identifier(id + all_desc_local);
268         if (ret > 0) {
269             if (id[all_desc_local + ret] != ':') {
270                 /* this is not a prefix, so not an extended id */
271                 goto standard_id;
272             }
273 
274             if (mod_name) {
275                 *mod_name = id + all_desc_local;
276                 *mod_name_len = ret;
277             }
278 
279             /* "/" and ":" */
280             ret += all_desc_local + 1;
281         } else {
282             ret = all_desc_local;
283         }
284 
285         /* parse either "*" or "." */
286         if (*(id + ret) == '*') {
287             if (name) {
288                 *name = id + ret;
289                 *nam_len = 1;
290             }
291             ++ret;
292 
293             return ret;
294         } else if (*(id + ret) == '.') {
295             if (!all_desc_local) {
296                 /* /. is redundant expression, we do not accept it */
297                 return -ret;
298             }
299 
300             if (name) {
301                 *name = id + ret;
302                 *nam_len = 1;
303             }
304             ++ret;
305 
306             return ret;
307         } else if (*(id + ret) == '#') {
308             if (all_desc_local || !ret) {
309                 /* no prefix */
310                 return 0;
311             }
312             parsed = ret + 1;
313             if ((ret = parse_identifier(id + parsed)) < 1) {
314                 return -parsed + ret;
315             }
316             *name = id + parsed - 1;
317             *nam_len = ret + 1;
318             return parsed + ret;
319         }
320         /* else a standard id, parse it all again */
321     }
322 
323 standard_id:
324     if ((ret = parse_identifier(id)) < 1) {
325         return ret;
326     }
327 
328     first_id = id;
329     first_id_len = ret;
330 
331     parsed += ret;
332     id += ret;
333 
334     /* there is prefix */
335     if (id[0] == ':') {
336         ++parsed;
337         ++id;
338 
339     /* there isn't */
340     } else {
341         if (name) {
342             *name = first_id;
343             *nam_len = first_id_len;
344         }
345 
346         return parsed;
347     }
348 
349     /* identifier (node name) */
350     if ((ret = parse_identifier(id)) < 1) {
351         return -parsed + ret;
352     }
353 
354     if (mod_name) {
355         *mod_name = first_id;
356         *mod_name_len = first_id_len;
357     }
358     if (name) {
359         *name = id;
360         *nam_len = ret;
361     }
362 
363     return parsed + ret;
364 }
365 
366 /**
367  * @brief Parse a path-predicate (leafref).
368  *
369  * path-predicate      = "[" *WSP path-equality-expr *WSP "]"
370  * path-equality-expr  = node-identifier *WSP "=" *WSP path-key-expr
371  *
372  * @param[in] id Identifier to use.
373  * @param[out] prefix Points to the prefix, NULL if there is not any.
374  * @param[out] pref_len Length of the prefix, 0 if there is not any.
375  * @param[out] name Points to the node name.
376  * @param[out] nam_len Length of the node name.
377  * @param[out] path_key_expr Points to the path-key-expr.
378  * @param[out] pke_len Length of the path-key-expr.
379  * @param[out] has_predicate Flag to mark whether there is another predicate following.
380  *
381  * @return Number of characters successfully parsed,
382  *         positive on success, negative on failure.
383  */
384 static int
parse_path_predicate(const char * id,const char ** prefix,int * pref_len,const char ** name,int * nam_len,const char ** path_key_expr,int * pke_len,int * has_predicate)385 parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
386                      const char **path_key_expr, int *pke_len, int *has_predicate)
387 {
388     const char *ptr;
389     int parsed = 0, ret;
390 
391     assert(id);
392     if (prefix) {
393         *prefix = NULL;
394     }
395     if (pref_len) {
396         *pref_len = 0;
397     }
398     if (name) {
399         *name = NULL;
400     }
401     if (nam_len) {
402         *nam_len = 0;
403     }
404     if (path_key_expr) {
405         *path_key_expr = NULL;
406     }
407     if (pke_len) {
408         *pke_len = 0;
409     }
410     if (has_predicate) {
411         *has_predicate = 0;
412     }
413 
414     if (id[0] != '[') {
415         return -parsed;
416     }
417 
418     ++parsed;
419     ++id;
420 
421     while (isspace(id[0])) {
422         ++parsed;
423         ++id;
424     }
425 
426     if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
427         return -parsed + ret;
428     }
429 
430     parsed += ret;
431     id += ret;
432 
433     while (isspace(id[0])) {
434         ++parsed;
435         ++id;
436     }
437 
438     if (id[0] != '=') {
439         return -parsed;
440     }
441 
442     ++parsed;
443     ++id;
444 
445     while (isspace(id[0])) {
446         ++parsed;
447         ++id;
448     }
449 
450     if ((ptr = strchr(id, ']')) == NULL) {
451         return -parsed;
452     }
453 
454     --ptr;
455     while (isspace(ptr[0])) {
456         --ptr;
457     }
458     ++ptr;
459 
460     ret = ptr-id;
461     if (path_key_expr) {
462         *path_key_expr = id;
463     }
464     if (pke_len) {
465         *pke_len = ret;
466     }
467 
468     parsed += ret;
469     id += ret;
470 
471     while (isspace(id[0])) {
472         ++parsed;
473         ++id;
474     }
475 
476     assert(id[0] == ']');
477 
478     if (id[1] == '[') {
479         *has_predicate = 1;
480     }
481 
482     return parsed+1;
483 }
484 
485 /**
486  * @brief Parse a path-key-expr (leafref). First call parses "current()", all
487  *        the ".." and the first node-identifier, other calls parse a single
488  *        node-identifier each.
489  *
490  * path-key-expr       = current-function-invocation *WSP "/" *WSP
491  *                       rel-path-keyexpr
492  * rel-path-keyexpr    = 1*(".." *WSP "/" *WSP)
493  *                       *(node-identifier *WSP "/" *WSP)
494  *                       node-identifier
495  *
496  * @param[in] id Identifier to use.
497  * @param[out] prefix Points to the prefix, NULL if there is not any.
498  * @param[out] pref_len Length of the prefix, 0 if there is not any.
499  * @param[out] name Points to the node name.
500  * @param[out] nam_len Length of the node name.
501  * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
502  *                          must not be changed between consecutive calls.
503  * @return Number of characters successfully parsed,
504  *         positive on success, negative on failure.
505  */
506 static int
parse_path_key_expr(const char * id,const char ** prefix,int * pref_len,const char ** name,int * nam_len,int * parent_times)507 parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
508                     int *parent_times)
509 {
510     int parsed = 0, ret, par_times = 0;
511 
512     assert(id);
513     assert(parent_times);
514     if (prefix) {
515         *prefix = NULL;
516     }
517     if (pref_len) {
518         *pref_len = 0;
519     }
520     if (name) {
521         *name = NULL;
522     }
523     if (nam_len) {
524         *nam_len = 0;
525     }
526 
527     if (!*parent_times) {
528         /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
529         if (strncmp(id, "current()", 9)) {
530             return -parsed;
531         }
532 
533         parsed += 9;
534         id += 9;
535 
536         while (isspace(id[0])) {
537             ++parsed;
538             ++id;
539         }
540 
541         if (id[0] != '/') {
542             return -parsed;
543         }
544 
545         ++parsed;
546         ++id;
547 
548         while (isspace(id[0])) {
549             ++parsed;
550             ++id;
551         }
552 
553         /* rel-path-keyexpr */
554         if (strncmp(id, "..", 2)) {
555             return -parsed;
556         }
557         ++par_times;
558 
559         parsed += 2;
560         id += 2;
561 
562         while (isspace(id[0])) {
563             ++parsed;
564             ++id;
565         }
566     }
567 
568     /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
569      *
570      * first parent reference with whitespaces already parsed
571      */
572     if (id[0] != '/') {
573         return -parsed;
574     }
575 
576     ++parsed;
577     ++id;
578 
579     while (isspace(id[0])) {
580         ++parsed;
581         ++id;
582     }
583 
584     while (!strncmp(id, "..", 2) && !*parent_times) {
585         ++par_times;
586 
587         parsed += 2;
588         id += 2;
589 
590         while (isspace(id[0])) {
591             ++parsed;
592             ++id;
593         }
594 
595         if (id[0] != '/') {
596             return -parsed;
597         }
598 
599         ++parsed;
600         ++id;
601 
602         while (isspace(id[0])) {
603             ++parsed;
604             ++id;
605         }
606     }
607 
608     if (!*parent_times) {
609         *parent_times = par_times;
610     }
611 
612     /* all parent references must be parsed at this point */
613     if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
614         return -parsed + ret;
615     }
616 
617     parsed += ret;
618     id += ret;
619 
620     return parsed;
621 }
622 
623 /**
624  * @brief Parse path-arg (leafref).
625  *
626  * path-arg            = absolute-path / relative-path
627  * absolute-path       = 1*("/" (node-identifier *path-predicate))
628  * relative-path       = 1*(".." "/") descendant-path
629  *
630  * @param[in] mod Module of the context node to get correct prefix in case it is not explicitly specified
631  * @param[in] id Identifier to use.
632  * @param[out] prefix Points to the prefix, NULL if there is not any.
633  * @param[out] pref_len Length of the prefix, 0 if there is not any.
634  * @param[out] name Points to the node name.
635  * @param[out] nam_len Length of the node name.
636  * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
637  *                          must not be changed between consecutive calls. -1 if the
638  *                          path is relative.
639  * @param[out] has_predicate Flag to mark whether there is a predicate specified.
640  *
641  * @return Number of characters successfully parsed,
642  *         positive on success, negative on failure.
643  */
644 static int
parse_path_arg(const struct lys_module * mod,const char * id,const char ** prefix,int * pref_len,const char ** name,int * nam_len,int * parent_times,int * has_predicate)645 parse_path_arg(const struct lys_module *mod, const char *id, const char **prefix, int *pref_len,
646                const char **name, int *nam_len, int *parent_times, int *has_predicate)
647 {
648     int parsed = 0, ret, par_times = 0;
649 
650     assert(id);
651     assert(parent_times);
652     if (prefix) {
653         *prefix = NULL;
654     }
655     if (pref_len) {
656         *pref_len = 0;
657     }
658     if (name) {
659         *name = NULL;
660     }
661     if (nam_len) {
662         *nam_len = 0;
663     }
664     if (has_predicate) {
665         *has_predicate = 0;
666     }
667 
668     if (!*parent_times && !strncmp(id, "..", 2)) {
669         ++par_times;
670 
671         parsed += 2;
672         id += 2;
673 
674         while (!strncmp(id, "/..", 3)) {
675             ++par_times;
676 
677             parsed += 3;
678             id += 3;
679         }
680     }
681 
682     if (!*parent_times) {
683         if (par_times) {
684             *parent_times = par_times;
685         } else {
686             *parent_times = -1;
687         }
688     }
689 
690     if (id[0] != '/') {
691         return -parsed;
692     }
693 
694     /* skip '/' */
695     ++parsed;
696     ++id;
697 
698     /* node-identifier ([prefix:]identifier) */
699     if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
700         return -parsed + ret;
701     }
702     if (prefix && !(*prefix)) {
703         /* actually we always need prefix even it is not specified */
704         *prefix = lys_main_module(mod)->name;
705         *pref_len = strlen(*prefix);
706     }
707 
708     parsed += ret;
709     id += ret;
710 
711     /* there is no predicate */
712     if ((id[0] == '/') || !id[0]) {
713         return parsed;
714     } else if (id[0] != '[') {
715         return -parsed;
716     }
717 
718     if (has_predicate) {
719         *has_predicate = 1;
720     }
721 
722     return parsed;
723 }
724 
725 /**
726  * @brief Parse instance-identifier in JSON data format. That means that prefixes
727  *        are actually model names.
728  *
729  * instance-identifier = 1*("/" (node-identifier *predicate))
730  *
731  * @param[in] id Identifier to use.
732  * @param[out] model Points to the model name.
733  * @param[out] mod_len Length of the model name.
734  * @param[out] name Points to the node name.
735  * @param[out] nam_len Length of the node name.
736  * @param[out] has_predicate Flag to mark whether there is a predicate specified.
737  *
738  * @return Number of characters successfully parsed,
739  *         positive on success, negative on failure.
740  */
741 static int
parse_instance_identifier(const char * id,const char ** model,int * mod_len,const char ** name,int * nam_len,int * has_predicate)742 parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
743                           int *has_predicate)
744 {
745     int parsed = 0, ret;
746 
747     assert(id && model && mod_len && name && nam_len);
748 
749     if (has_predicate) {
750         *has_predicate = 0;
751     }
752 
753     if (id[0] != '/') {
754         return -parsed;
755     }
756 
757     ++parsed;
758     ++id;
759 
760     if ((ret = parse_identifier(id)) < 1) {
761         return ret;
762     }
763 
764     *name = id;
765     *nam_len = ret;
766 
767     *model = NULL;
768     *mod_len = 0;
769 
770     parsed += ret;
771     id += ret;
772 
773     if (id[0] == ':') {
774         /* we have prefix */
775         *model = *name;
776         *mod_len = *nam_len;
777 
778         ++parsed;
779         ++id;
780 
781         if ((ret = parse_identifier(id)) < 1) {
782             return ret;
783         }
784 
785         *name = id;
786         *nam_len = ret;
787 
788         parsed += ret;
789         id += ret;
790     }
791 
792     if (id[0] == '[' && has_predicate) {
793         *has_predicate = 1;
794     }
795 
796     return parsed;
797 }
798 
799 /**
800  * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
801  *        (which are mandatory) are actually model names.
802  *
803  * predicate           = "[" *WSP (predicate-expr / pos) *WSP "]"
804  * predicate-expr      = (node-identifier / ".") *WSP "=" *WSP
805  *                       ((DQUOTE string DQUOTE) /
806  *                        (SQUOTE string SQUOTE))
807  * pos                 = non-negative-integer-value
808  *
809  * @param[in] id Identifier to use.
810  * @param[out] model Points to the model name.
811  * @param[out] mod_len Length of the model name.
812  * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
813  * @param[out] nam_len Length of the node name.
814  * @param[out] value Value the node-identifier must have (string from the grammar),
815  *                   NULL if there is not any.
816  * @param[out] val_len Length of the value, 0 if there is not any.
817  * @param[out] has_predicate Flag to mark whether there is a predicate specified.
818  *
819  * @return Number of characters successfully parsed,
820  *         positive on success, negative on failure.
821  */
822 static int
parse_predicate(const char * id,const char ** model,int * mod_len,const char ** name,int * nam_len,const char ** value,int * val_len,int * has_predicate)823 parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
824                 const char **value, int *val_len, int *has_predicate)
825 {
826     const char *ptr;
827     int parsed = 0, ret;
828     char quote;
829 
830     assert(id);
831     if (model) {
832         assert(mod_len);
833         *model = NULL;
834         *mod_len = 0;
835     }
836     if (name) {
837         assert(nam_len);
838         *name = NULL;
839         *nam_len = 0;
840     }
841     if (value) {
842         assert(val_len);
843         *value = NULL;
844         *val_len = 0;
845     }
846     if (has_predicate) {
847         *has_predicate = 0;
848     }
849 
850     if (id[0] != '[') {
851         return -parsed;
852     }
853 
854     ++parsed;
855     ++id;
856 
857     while (isspace(id[0])) {
858         ++parsed;
859         ++id;
860     }
861 
862     /* pos */
863     if (isdigit(id[0])) {
864         if (name) {
865             *name = id;
866         }
867 
868         if (id[0] == '0') {
869             return -parsed;
870         }
871 
872         while (isdigit(id[0])) {
873             ++parsed;
874             ++id;
875         }
876 
877         if (nam_len) {
878             *nam_len = id-(*name);
879         }
880 
881     /* "." or node-identifier */
882     } else {
883         if (id[0] == '.') {
884             if (name) {
885                 *name = id;
886             }
887             if (nam_len) {
888                 *nam_len = 1;
889             }
890 
891             ++parsed;
892             ++id;
893 
894         } else {
895             if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len, NULL, 0)) < 1) {
896                 return -parsed + ret;
897             }
898 
899             parsed += ret;
900             id += ret;
901         }
902 
903         while (isspace(id[0])) {
904             ++parsed;
905             ++id;
906         }
907 
908         if (id[0] != '=') {
909             return -parsed;
910         }
911 
912         ++parsed;
913         ++id;
914 
915         while (isspace(id[0])) {
916             ++parsed;
917             ++id;
918         }
919 
920         /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
921         if ((id[0] == '\"') || (id[0] == '\'')) {
922             quote = id[0];
923 
924             ++parsed;
925             ++id;
926 
927             for (ptr = id; ptr && ptr[0] != quote; ++ptr) {
928                 if (ptr[0] == '\\') {
929                     ++ptr;
930                 }
931             }
932             if (!ptr) {
933                 return -parsed;
934             }
935             ret = ptr - id;
936 
937             if (value) {
938                 *value = id;
939             }
940             if (val_len) {
941                 *val_len = ret;
942             }
943 
944             parsed += ret + 1;
945             id += ret + 1;
946         } else {
947             return -parsed;
948         }
949     }
950 
951     while (isspace(id[0])) {
952         ++parsed;
953         ++id;
954     }
955 
956     if (id[0] != ']') {
957         return -parsed;
958     }
959 
960     ++parsed;
961     ++id;
962 
963     if ((id[0] == '[') && has_predicate) {
964         *has_predicate = 1;
965     }
966 
967     return parsed;
968 }
969 
970 /**
971  * @brief Parse schema-nodeid.
972  *
973  * schema-nodeid       = absolute-schema-nodeid /
974  *                       descendant-schema-nodeid
975  * absolute-schema-nodeid = 1*("/" node-identifier)
976  * descendant-schema-nodeid = ["." "/"]
977  *                       node-identifier
978  *                       absolute-schema-nodeid
979  *
980  * @param[in] id Identifier to use.
981  * @param[out] mod_name Points to the module name, NULL if there is not any.
982  * @param[out] mod_name_len Length of the module name, 0 if there is not any.
983  * @param[out] name Points to the node name.
984  * @param[out] nam_len Length of the node name.
985  * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
986  *                         on the first call, must not be changed between consecutive calls.
987  * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
988  *                           based on the grammar, in those cases use NULL.
989  * @param[in] extended Whether to accept an extended path (support for /[prefix:]*, //[prefix:]*, //[prefix:].).
990  *
991  * @return Number of characters successfully parsed,
992  *         positive on success, negative on failure.
993  */
994 int
parse_schema_nodeid(const char * id,const char ** mod_name,int * mod_name_len,const char ** name,int * nam_len,int * is_relative,int * has_predicate,int * all_desc,int extended)995 parse_schema_nodeid(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
996                     int *is_relative, int *has_predicate, int *all_desc, int extended)
997 {
998     int parsed = 0, ret;
999 
1000     assert(id);
1001     assert(is_relative);
1002 
1003     if (has_predicate) {
1004         *has_predicate = 0;
1005     }
1006 
1007     if (id[0] != '/') {
1008         if (*is_relative != -1) {
1009             return -parsed;
1010         } else {
1011             *is_relative = 1;
1012         }
1013         if (!strncmp(id, "./", 2)) {
1014             parsed += 2;
1015             id += 2;
1016         }
1017     } else {
1018         if (*is_relative == -1) {
1019             *is_relative = 0;
1020         }
1021         ++parsed;
1022         ++id;
1023     }
1024 
1025     if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len, all_desc, extended)) < 1) {
1026         return -parsed + ret;
1027     }
1028 
1029     parsed += ret;
1030     id += ret;
1031 
1032     if ((id[0] == '[') && has_predicate) {
1033         *has_predicate = 1;
1034     }
1035 
1036     return parsed;
1037 }
1038 
1039 /**
1040  * @brief Parse schema predicate (special format internally used).
1041  *
1042  * predicate           = "[" *WSP predicate-expr *WSP "]"
1043  * predicate-expr      = "." / [prefix:]identifier / positive-integer / key-with-value
1044  * key-with-value      = identifier *WSP "=" *WSP
1045  *                       ((DQUOTE string DQUOTE) /
1046  *                        (SQUOTE string SQUOTE))
1047  *
1048  * @param[in] id Identifier to use.
1049  * @param[out] mod_name Points to the list key module name.
1050  * @param[out] mod_name_len Length of \p mod_name.
1051  * @param[out] name Points to the list key name.
1052  * @param[out] nam_len Length of \p name.
1053  * @param[out] value Points to the key value. If specified, key-with-value is expected.
1054  * @param[out] val_len Length of \p value.
1055  * @param[out] has_predicate Flag to mark whether there is another predicate specified.
1056  */
1057 int
parse_schema_json_predicate(const char * id,const char ** mod_name,int * mod_name_len,const char ** name,int * nam_len,const char ** value,int * val_len,int * has_predicate)1058 parse_schema_json_predicate(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
1059                             const char **value, int *val_len, int *has_predicate)
1060 {
1061     const char *ptr;
1062     int parsed = 0, ret;
1063     char quote;
1064 
1065     assert(id);
1066     if (mod_name) {
1067         *mod_name = NULL;
1068     }
1069     if (mod_name_len) {
1070         *mod_name_len = 0;
1071     }
1072     if (name) {
1073         *name = NULL;
1074     }
1075     if (nam_len) {
1076         *nam_len = 0;
1077     }
1078     if (value) {
1079         *value = NULL;
1080     }
1081     if (val_len) {
1082         *val_len = 0;
1083     }
1084     if (has_predicate) {
1085         *has_predicate = 0;
1086     }
1087 
1088     if (id[0] != '[') {
1089         return -parsed;
1090     }
1091 
1092     ++parsed;
1093     ++id;
1094 
1095     while (isspace(id[0])) {
1096         ++parsed;
1097         ++id;
1098     }
1099 
1100     /* identifier */
1101     if (id[0] == '.') {
1102         ret = 1;
1103 
1104         if (name) {
1105             *name = id;
1106         }
1107         if (nam_len) {
1108             *nam_len = ret;
1109         }
1110     } else if (isdigit(id[0])) {
1111         if (id[0] == '0') {
1112             return -parsed;
1113         }
1114         ret = 1;
1115         while (isdigit(id[ret])) {
1116             ++ret;
1117         }
1118 
1119         if (name) {
1120             *name = id;
1121         }
1122         if (nam_len) {
1123             *nam_len = ret;
1124         }
1125     } else if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len, NULL, 0)) < 1) {
1126         return -parsed + ret;
1127     }
1128 
1129     parsed += ret;
1130     id += ret;
1131 
1132     while (isspace(id[0])) {
1133         ++parsed;
1134         ++id;
1135     }
1136 
1137     /* there is value as well */
1138     if (id[0] == '=') {
1139         if (name && isdigit(**name)) {
1140             return -parsed;
1141         }
1142 
1143         ++parsed;
1144         ++id;
1145 
1146         while (isspace(id[0])) {
1147             ++parsed;
1148             ++id;
1149         }
1150 
1151         /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
1152         if ((id[0] == '\"') || (id[0] == '\'')) {
1153             quote = id[0];
1154 
1155             ++parsed;
1156             ++id;
1157 
1158             for (ptr = id; ptr[0] && ptr[0] != quote; ++ptr) {
1159                 if (ptr[0] == '\\') {
1160                     ++ptr;
1161                 }
1162             }
1163             if (!ptr[0]) {
1164                 return -parsed;
1165             }
1166             ret = ptr - id;
1167 
1168             if (value) {
1169                 *value = id;
1170             }
1171             if (val_len) {
1172                 *val_len = ret;
1173             }
1174 
1175             parsed += ret + 1;
1176             id += ret + 1;
1177         } else {
1178             return -parsed;
1179         }
1180 
1181         while (isspace(id[0])) {
1182             ++parsed;
1183             ++id;
1184         }
1185     }
1186 
1187     if (id[0] != ']') {
1188         return -parsed;
1189     }
1190 
1191     ++parsed;
1192     ++id;
1193 
1194     if ((id[0] == '[') && has_predicate) {
1195         *has_predicate = 1;
1196     }
1197 
1198     return parsed;
1199 }
1200 
1201 static struct lyd_node *
resolve_json_data_node_hash(struct lyd_node * siblings,struct parsed_pred pp)1202 resolve_json_data_node_hash(struct lyd_node *siblings, struct parsed_pred pp)
1203 {
1204     struct lyd_node *ret = NULL;
1205     char *key_or_value = NULL;
1206 
1207     if (pp.schema->nodetype == LYS_LEAFLIST) {
1208         assert((pp.len == 1) && (pp.pred[0].name[0] == '.') && (pp.pred[0].nam_len == 1));
1209 
1210         key_or_value = strndup(pp.pred[0].value, pp.pred[0].val_len);
1211     } else if (pp.schema->nodetype == LYS_LIST) {
1212         key_or_value = strndup(pp.pred_str, pp.pred_str_len);
1213     }
1214 
1215     /* try to find the node */
1216     lyd_find_sibling_val(siblings, pp.schema, key_or_value, &ret);
1217     free(key_or_value);
1218 
1219     return ret;
1220 }
1221 
1222 /**
1223  * @brief Resolve (find) a feature definition. Logs directly.
1224  *
1225  * @param[in] feat_name Feature name to resolve.
1226  * @param[in] len Length of \p feat_name.
1227  * @param[in] node Node with the if-feature expression.
1228  * @param[out] feature Pointer to be set to point to the feature definition, if feature not found
1229  * (return code 1), the pointer is untouched.
1230  *
1231  * @return 0 on success, 1 on forward reference, -1 on error.
1232  */
1233 static int
resolve_feature(const char * feat_name,uint16_t len,const struct lys_node * node,struct lys_feature ** feature)1234 resolve_feature(const char *feat_name, uint16_t len, const struct lys_node *node, struct lys_feature **feature)
1235 {
1236     char *str;
1237     const char *mod_name, *name;
1238     int mod_name_len, nam_len, i, j;
1239     const struct lys_module *module;
1240 
1241     assert(feature);
1242 
1243     /* check prefix */
1244     if ((i = parse_node_identifier(feat_name, &mod_name, &mod_name_len, &name, &nam_len, NULL, 0)) < 1) {
1245         LOGVAL(node->module->ctx, LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
1246         return -1;
1247     }
1248 
1249     module = lyp_get_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len, 0);
1250     if (!module) {
1251         /* identity refers unknown data model */
1252         LOGVAL(node->module->ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
1253         return -1;
1254     }
1255 
1256     if (module != node->module && module == lys_node_module(node)) {
1257         /* first, try to search directly in submodule where the feature was mentioned */
1258         for (j = 0; j < node->module->features_size; j++) {
1259             if (!strncmp(name, node->module->features[j].name, nam_len) && !node->module->features[j].name[nam_len]) {
1260                 /* check status */
1261                 if (lyp_check_status(node->flags, lys_node_module(node), node->name, node->module->features[j].flags,
1262                                      node->module->features[j].module, node->module->features[j].name, NULL)) {
1263                     return -1;
1264                 }
1265                 *feature = &node->module->features[j];
1266                 return 0;
1267             }
1268         }
1269     }
1270 
1271     /* search in the identified module ... */
1272     for (j = 0; j < module->features_size; j++) {
1273         if (!strncmp(name, module->features[j].name, nam_len) && !module->features[j].name[nam_len]) {
1274             /* check status */
1275             if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
1276                                  module->features[j].module, module->features[j].name, NULL)) {
1277                 return -1;
1278             }
1279             *feature = &module->features[j];
1280             return 0;
1281         }
1282     }
1283     /* ... and all its submodules */
1284     for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
1285         for (j = 0; j < module->inc[i].submodule->features_size; j++) {
1286             if (!strncmp(name, module->inc[i].submodule->features[j].name, nam_len)
1287                     && !module->inc[i].submodule->features[j].name[nam_len]) {
1288                 /* check status */
1289                 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1290                                      module->inc[i].submodule->features[j].flags,
1291                                      module->inc[i].submodule->features[j].module,
1292                                      module->inc[i].submodule->features[j].name, NULL)) {
1293                     return -1;
1294                 }
1295                 *feature = &module->inc[i].submodule->features[j];
1296                 return 0;
1297             }
1298         }
1299     }
1300 
1301     /* not found */
1302     str = strndup(feat_name, len);
1303     LOGVAL(node->module->ctx, LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
1304     free(str);
1305     return 1;
1306 }
1307 
1308 /*
1309  * @return
1310  *  -  1 if enabled
1311  *  -  0 if disabled
1312  */
1313 static int
resolve_feature_value(const struct lys_feature * feat)1314 resolve_feature_value(const struct lys_feature *feat)
1315 {
1316     int i;
1317 
1318     for (i = 0; i < feat->iffeature_size; i++) {
1319         if (!resolve_iffeature(&feat->iffeature[i])) {
1320             return 0;
1321         }
1322     }
1323 
1324     return feat->flags & LYS_FENABLED ? 1 : 0;
1325 }
1326 
1327 static int
resolve_iffeature_recursive(struct lys_iffeature * expr,int * index_e,int * index_f)1328 resolve_iffeature_recursive(struct lys_iffeature *expr, int *index_e, int *index_f)
1329 {
1330     uint8_t op;
1331     int a, b;
1332 
1333     op = iff_getop(expr->expr, *index_e);
1334     (*index_e)++;
1335 
1336     switch (op) {
1337     case LYS_IFF_F:
1338         /* resolve feature */
1339         return resolve_feature_value(expr->features[(*index_f)++]);
1340     case LYS_IFF_NOT:
1341         /* invert result */
1342         return resolve_iffeature_recursive(expr, index_e, index_f) ? 0 : 1;
1343     case LYS_IFF_AND:
1344     case LYS_IFF_OR:
1345         a = resolve_iffeature_recursive(expr, index_e, index_f);
1346         b = resolve_iffeature_recursive(expr, index_e, index_f);
1347         if (op == LYS_IFF_AND) {
1348             return a && b;
1349         } else { /* LYS_IFF_OR */
1350             return a || b;
1351         }
1352     }
1353 
1354     return 0;
1355 }
1356 
1357 int
resolve_iffeature(struct lys_iffeature * expr)1358 resolve_iffeature(struct lys_iffeature *expr)
1359 {
1360     int index_e = 0, index_f = 0;
1361 
1362     if (expr->expr && expr->features[0]) {
1363         return resolve_iffeature_recursive(expr, &index_e, &index_f);
1364     }
1365     return 0;
1366 }
1367 
1368 struct iff_stack {
1369     int size;
1370     int index;     /* first empty item */
1371     uint8_t *stack;
1372 };
1373 
1374 static int
iff_stack_push(struct iff_stack * stack,uint8_t value)1375 iff_stack_push(struct iff_stack *stack, uint8_t value)
1376 {
1377     if (stack->index == stack->size) {
1378         stack->size += 4;
1379         stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
1380         LY_CHECK_ERR_RETURN(!stack->stack, LOGMEM(NULL); stack->size = 0, EXIT_FAILURE);
1381     }
1382 
1383     stack->stack[stack->index++] = value;
1384     return EXIT_SUCCESS;
1385 }
1386 
1387 static uint8_t
iff_stack_pop(struct iff_stack * stack)1388 iff_stack_pop(struct iff_stack *stack)
1389 {
1390     stack->index--;
1391     return stack->stack[stack->index];
1392 }
1393 
1394 static void
iff_stack_clean(struct iff_stack * stack)1395 iff_stack_clean(struct iff_stack *stack)
1396 {
1397     stack->size = 0;
1398     free(stack->stack);
1399 }
1400 
1401 static void
iff_setop(uint8_t * list,uint8_t op,int pos)1402 iff_setop(uint8_t *list, uint8_t op, int pos)
1403 {
1404     uint8_t *item;
1405     uint8_t mask = 3;
1406 
1407     assert(pos >= 0);
1408     assert(op <= 3); /* max 2 bits */
1409 
1410     item = &list[pos / 4];
1411     mask = mask << 2 * (pos % 4);
1412     *item = (*item) & ~mask;
1413     *item = (*item) | (op << 2 * (pos % 4));
1414 }
1415 
1416 uint8_t
iff_getop(uint8_t * list,int pos)1417 iff_getop(uint8_t *list, int pos)
1418 {
1419     uint8_t *item;
1420     uint8_t mask = 3, result;
1421 
1422     assert(pos >= 0);
1423 
1424     item = &list[pos / 4];
1425     result = (*item) & (mask << 2 * (pos % 4));
1426     return result >> 2 * (pos % 4);
1427 }
1428 
1429 #define LYS_IFF_LP 0x04 /* ( */
1430 #define LYS_IFF_RP 0x08 /* ) */
1431 
1432 /* internal structure for passing data for UNRES_IFFEAT */
1433 struct unres_iffeat_data {
1434     struct lys_node *node;
1435     const char *fname;
1436     int infeature;
1437 };
1438 
1439 void
resolve_iffeature_getsizes(struct lys_iffeature * iffeat,unsigned int * expr_size,unsigned int * feat_size)1440 resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1441 {
1442     unsigned int e = 0, f = 0, r = 0;
1443     uint8_t op;
1444 
1445     assert(iffeat);
1446 
1447     if (!iffeat->expr) {
1448         goto result;
1449     }
1450 
1451     do {
1452         op = iff_getop(iffeat->expr, e++);
1453         switch (op) {
1454         case LYS_IFF_NOT:
1455             if (!r) {
1456                 r += 1;
1457             }
1458             break;
1459         case LYS_IFF_AND:
1460         case LYS_IFF_OR:
1461             if (!r) {
1462                 r += 2;
1463             } else {
1464                 r += 1;
1465             }
1466             break;
1467         case LYS_IFF_F:
1468             f++;
1469             if (r) {
1470                 r--;
1471             }
1472             break;
1473         }
1474     } while(r);
1475 
1476 result:
1477     if (expr_size) {
1478         *expr_size = e;
1479     }
1480     if (feat_size) {
1481         *feat_size = f;
1482     }
1483 }
1484 
1485 int
resolve_iffeature_compile(struct lys_iffeature * iffeat_expr,const char * value,struct lys_node * node,int infeature,struct unres_schema * unres)1486 resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
1487                           int infeature, struct unres_schema *unres)
1488 {
1489     const char *c = value;
1490     int r, rc = EXIT_FAILURE;
1491     int i, j, last_not, checkversion = 0;
1492     unsigned int f_size = 0, expr_size = 0, f_exp = 1;
1493     uint8_t op;
1494     struct iff_stack stack = {0, 0, NULL};
1495     struct unres_iffeat_data *iff_data;
1496     struct ly_ctx *ctx = node->module->ctx;
1497 
1498     assert(c);
1499 
1500     if (isspace(c[0])) {
1501         LOGVAL(ctx, LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
1502         return EXIT_FAILURE;
1503     }
1504 
1505     /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1506     for (i = j = last_not = 0; c[i]; i++) {
1507         if (c[i] == '(') {
1508             checkversion = 1;
1509             j++;
1510             continue;
1511         } else if (c[i] == ')') {
1512             j--;
1513             continue;
1514         } else if (isspace(c[i])) {
1515             continue;
1516         }
1517 
1518         if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1519             if (c[i + r] == '\0') {
1520                 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1521                 return EXIT_FAILURE;
1522             } else if (!isspace(c[i + r])) {
1523                 /* feature name starting with the not/and/or */
1524                 last_not = 0;
1525                 f_size++;
1526             } else if (c[i] == 'n') { /* not operation */
1527                 if (last_not) {
1528                     /* double not */
1529                     expr_size = expr_size - 2;
1530                     last_not = 0;
1531                 } else {
1532                     last_not = 1;
1533                 }
1534             } else { /* and, or */
1535                 f_exp++;
1536                 /* not a not operation */
1537                 last_not = 0;
1538             }
1539             i += r;
1540         } else {
1541             f_size++;
1542             last_not = 0;
1543         }
1544         expr_size++;
1545 
1546         while (!isspace(c[i])) {
1547             if (c[i] == '(') {
1548                 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1549                 return EXIT_FAILURE;
1550             } else if (!c[i] || c[i] == ')') {
1551                 i--;
1552                 break;
1553             }
1554             i++;
1555         }
1556     }
1557     if (j || f_exp != f_size) {
1558         /* not matching count of ( and ) */
1559         LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1560         return EXIT_FAILURE;
1561     }
1562 
1563     if (checkversion || expr_size > 1) {
1564         /* check that we have 1.1 module */
1565         if (node->module->version != LYS_VERSION_1_1) {
1566             LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1567             LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "YANG 1.1 if-feature expression found in 1.0 module.");
1568             return EXIT_FAILURE;
1569         }
1570     }
1571 
1572     /* allocate the memory */
1573     iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
1574     iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
1575     stack.stack = malloc(expr_size * sizeof *stack.stack);
1576     LY_CHECK_ERR_GOTO(!stack.stack || !iffeat_expr->expr || !iffeat_expr->features, LOGMEM(ctx), error);
1577     stack.size = expr_size;
1578     f_size--; expr_size--; /* used as indexes from now */
1579 
1580     for (i--; i >= 0; i--) {
1581         if (c[i] == ')') {
1582             /* push it on stack */
1583             iff_stack_push(&stack, LYS_IFF_RP);
1584             continue;
1585         } else if (c[i] == '(') {
1586             /* pop from the stack into result all operators until ) */
1587             while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1588                 iff_setop(iffeat_expr->expr, op, expr_size--);
1589             }
1590             continue;
1591         } else if (isspace(c[i])) {
1592             continue;
1593         }
1594 
1595         /* end operator or operand -> find beginning and get what is it */
1596         j = i + 1;
1597         while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1598             i--;
1599         }
1600         i++; /* get back by one step */
1601 
1602         if (!strncmp(&c[i], "not", 3) && isspace(c[i + 3])) {
1603             if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1604                 /* double not */
1605                 iff_stack_pop(&stack);
1606             } else {
1607                 /* not has the highest priority, so do not pop from the stack
1608                  * as in case of AND and OR */
1609                 iff_stack_push(&stack, LYS_IFF_NOT);
1610             }
1611         } else if (!strncmp(&c[i], "and", 3) && isspace(c[i + 3])) {
1612             /* as for OR - pop from the stack all operators with the same or higher
1613              * priority and store them to the result, then push the AND to the stack */
1614             while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1615                 op = iff_stack_pop(&stack);
1616                 iff_setop(iffeat_expr->expr, op, expr_size--);
1617             }
1618             iff_stack_push(&stack, LYS_IFF_AND);
1619         } else if (!strncmp(&c[i], "or", 2) && isspace(c[i + 2])) {
1620             while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1621                 op = iff_stack_pop(&stack);
1622                 iff_setop(iffeat_expr->expr, op, expr_size--);
1623             }
1624             iff_stack_push(&stack, LYS_IFF_OR);
1625         } else {
1626             /* feature name, length is j - i */
1627 
1628             /* add it to the result */
1629             iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1630 
1631             /* now get the link to the feature definition. Since it can be
1632              * forward referenced, we have to keep the feature name in auxiliary
1633              * structure passed into unres */
1634             iff_data = malloc(sizeof *iff_data);
1635             LY_CHECK_ERR_GOTO(!iff_data, LOGMEM(ctx), error);
1636             iff_data->node = node;
1637             iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
1638             iff_data->infeature = infeature;
1639             r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1640                                       (struct lys_node *)iff_data);
1641             f_size--;
1642 
1643             if (r == -1) {
1644                 lydict_remove(node->module->ctx, iff_data->fname);
1645                 free(iff_data);
1646                 goto error;
1647             }
1648         }
1649     }
1650     while (stack.index) {
1651         op = iff_stack_pop(&stack);
1652         iff_setop(iffeat_expr->expr, op, expr_size--);
1653     }
1654 
1655     if (++expr_size || ++f_size) {
1656         /* not all expected operators and operands found */
1657         LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1658         rc = EXIT_FAILURE;
1659     } else {
1660         rc = EXIT_SUCCESS;
1661     }
1662 
1663 error:
1664     /* cleanup */
1665     iff_stack_clean(&stack);
1666 
1667     return rc;
1668 }
1669 
1670 /**
1671  * @brief Resolve (find) a data node based on a schema-nodeid.
1672  *
1673  * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1674  * module).
1675  *
1676  */
1677 struct lyd_node *
resolve_data_descendant_schema_nodeid(const char * nodeid,struct lyd_node * start)1678 resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1679 {
1680     char *str, *token, *p;
1681     struct lyd_node *result = NULL, *iter;
1682     const struct lys_node *schema = NULL;
1683 
1684     assert(nodeid && start);
1685 
1686     if (nodeid[0] == '/') {
1687         return NULL;
1688     }
1689 
1690     str = p = strdup(nodeid);
1691     LY_CHECK_ERR_RETURN(!str, LOGMEM(start->schema->module->ctx), NULL);
1692 
1693     while (p) {
1694         token = p;
1695         p = strchr(p, '/');
1696         if (p) {
1697             *p = '\0';
1698             p++;
1699         }
1700 
1701         if (p) {
1702             /* inner node */
1703             if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
1704                                                  LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, &schema)
1705                     || !schema) {
1706                 result = NULL;
1707                 break;
1708             }
1709 
1710             if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1711                 continue;
1712             }
1713         } else {
1714             /* final node */
1715             if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF, 0, &schema)
1716                     || !schema) {
1717                 result = NULL;
1718                 break;
1719             }
1720         }
1721         LY_TREE_FOR(result ? result->child : start, iter) {
1722             if (iter->schema == schema) {
1723                 /* move in data tree according to returned schema */
1724                 result = iter;
1725                 break;
1726             }
1727         }
1728         if (!iter) {
1729             /* instance not found */
1730             result = NULL;
1731             break;
1732         }
1733     }
1734     free(str);
1735 
1736     return result;
1737 }
1738 
1739 int
schema_nodeid_siblingcheck(const struct lys_node * sibling,const struct lys_module * cur_module,const char * mod_name,int mod_name_len,const char * name,int nam_len)1740 schema_nodeid_siblingcheck(const struct lys_node *sibling, const struct lys_module *cur_module, const char *mod_name,
1741                            int mod_name_len, const char *name, int nam_len)
1742 {
1743     const struct lys_module *prefix_mod;
1744 
1745     /* handle special names */
1746     if (name[0] == '*') {
1747         return 2;
1748     } else if (name[0] == '.') {
1749         return 3;
1750     }
1751 
1752     /* name check */
1753     if (strncmp(name, sibling->name, nam_len) || sibling->name[nam_len]) {
1754         return 1;
1755     }
1756 
1757     /* module check */
1758     if (mod_name) {
1759         prefix_mod = lyp_get_module(cur_module, NULL, 0, mod_name, mod_name_len, 0);
1760         if (!prefix_mod) {
1761             return -1;
1762         }
1763     } else {
1764         prefix_mod = cur_module;
1765     }
1766     if (prefix_mod != lys_node_module(sibling)) {
1767         return 1;
1768     }
1769 
1770     /* match */
1771     return 0;
1772 }
1773 
1774 /* keys do not have to be ordered and do not have to be all of them */
1775 static int
resolve_extended_schema_nodeid_predicate(const char * nodeid,const struct lys_node * node,const struct lys_module * cur_module,int * nodeid_end)1776 resolve_extended_schema_nodeid_predicate(const char *nodeid, const struct lys_node *node,
1777                                          const struct lys_module *cur_module, int *nodeid_end)
1778 {
1779     int mod_len, nam_len, has_predicate, r, i;
1780     const char *model, *name;
1781     struct lys_node_list *list;
1782 
1783     if (!(node->nodetype & (LYS_LIST | LYS_LEAFLIST))) {
1784         return 1;
1785     }
1786 
1787     list = (struct lys_node_list *)node;
1788     do {
1789         r = parse_schema_json_predicate(nodeid, &model, &mod_len, &name, &nam_len, NULL, NULL, &has_predicate);
1790         if (r < 1) {
1791             LOGVAL(cur_module->ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, nodeid[r], &nodeid[r]);
1792             return -1;
1793         }
1794         nodeid += r;
1795 
1796         if (node->nodetype == LYS_LEAFLIST) {
1797             /* just check syntax */
1798             if (model || !name || (name[0] != '.') || has_predicate) {
1799                 return 1;
1800             }
1801             break;
1802         } else {
1803             /* check the key */
1804             for (i = 0; i < list->keys_size; ++i) {
1805                 if (strncmp(list->keys[i]->name, name, nam_len) || list->keys[i]->name[nam_len]) {
1806                     continue;
1807                 }
1808                 if (model) {
1809                     if (strncmp(lys_node_module((struct lys_node *)list->keys[i])->name, model, mod_len)
1810                             || lys_node_module((struct lys_node *)list->keys[i])->name[mod_len]) {
1811                         continue;
1812                     }
1813                 } else {
1814                     if (lys_node_module((struct lys_node *)list->keys[i]) != cur_module) {
1815                         continue;
1816                     }
1817                 }
1818 
1819                 /* match */
1820                 break;
1821             }
1822 
1823             if (i == list->keys_size) {
1824                 return 1;
1825             }
1826         }
1827     } while (has_predicate);
1828 
1829     if (!nodeid[0]) {
1830         *nodeid_end = 1;
1831     }
1832     return 0;
1833 }
1834 
1835 /* start_parent - relative, module - absolute, -1 error (logged), EXIT_SUCCESS ok
1836  */
1837 int
resolve_schema_nodeid(const char * nodeid,const struct lys_node * start_parent,const struct lys_module * cur_module,struct ly_set ** ret,int extended,int no_node_error)1838 resolve_schema_nodeid(const char *nodeid, const struct lys_node *start_parent, const struct lys_module *cur_module,
1839                       struct ly_set **ret, int extended, int no_node_error)
1840 {
1841     const char *name, *mod_name, *id, *backup_mod_name = NULL, *yang_data_name = NULL;
1842     const struct lys_node *sibling, *next, *elem;
1843     struct lys_node_augment *last_aug;
1844     int r, nam_len, mod_name_len = 0, is_relative = -1, all_desc, has_predicate, nodeid_end = 0;
1845     int yang_data_name_len, backup_mod_name_len = 0;
1846     /* resolved import module from the start module, it must match the next node-name-match sibling */
1847     const struct lys_module *start_mod, *aux_mod = NULL;
1848     char *str;
1849     struct ly_ctx *ctx;
1850 
1851     assert(nodeid && (start_parent || cur_module) && ret);
1852     *ret = NULL;
1853 
1854     if (!cur_module) {
1855         cur_module = lys_node_module(start_parent);
1856     }
1857     ctx = cur_module->ctx;
1858     id = nodeid;
1859 
1860     r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 1);
1861     if (r < 1) {
1862         LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
1863         return -1;
1864     }
1865 
1866     if (name[0] == '#') {
1867         if (is_relative) {
1868             LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, '#', name);
1869             return -1;
1870         }
1871         yang_data_name = name + 1;
1872         yang_data_name_len = nam_len - 1;
1873         backup_mod_name = mod_name;
1874         backup_mod_name_len = mod_name_len;
1875         id += r;
1876     } else {
1877         is_relative = -1;
1878     }
1879 
1880     r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate,
1881                             (extended ? &all_desc : NULL), extended);
1882     if (r < 1) {
1883         LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
1884         return -1;
1885     }
1886     id += r;
1887 
1888     if (backup_mod_name) {
1889         mod_name = backup_mod_name;
1890         mod_name_len = backup_mod_name_len;
1891     }
1892 
1893     if (is_relative && !start_parent) {
1894         LOGVAL(ctx, LYE_SPEC, LY_VLOG_STR, nodeid, "Starting node must be provided for relative paths.");
1895         return -1;
1896     }
1897 
1898     /* descendant-schema-nodeid */
1899     if (is_relative) {
1900         cur_module = start_mod = lys_node_module(start_parent);
1901 
1902     /* absolute-schema-nodeid */
1903     } else {
1904         start_mod = lyp_get_module(cur_module, NULL, 0, mod_name, mod_name_len, 0);
1905         if (!start_mod) {
1906             str = strndup(mod_name, mod_name_len);
1907             LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
1908             free(str);
1909             return -1;
1910         }
1911         start_parent = NULL;
1912         if (yang_data_name) {
1913             start_parent = lyp_get_yang_data_template(start_mod, yang_data_name, yang_data_name_len);
1914             if (!start_parent) {
1915                 str = strndup(nodeid, (yang_data_name + yang_data_name_len) - nodeid);
1916                 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
1917                 free(str);
1918                 return -1;
1919             }
1920         }
1921     }
1922 
1923     while (1) {
1924         sibling = NULL;
1925         last_aug = NULL;
1926 
1927         if (start_parent) {
1928             if (mod_name && (strncmp(mod_name, cur_module->name, mod_name_len)
1929                     || (mod_name_len != (signed)strlen(cur_module->name)))) {
1930                 /* we are getting into another module (augment) */
1931                 aux_mod = lyp_get_module(cur_module, NULL, 0, mod_name, mod_name_len, 0);
1932                 if (!aux_mod) {
1933                     str = strndup(mod_name, mod_name_len);
1934                     LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
1935                     free(str);
1936                     return -1;
1937                 }
1938             } else {
1939                 /* there is no mod_name, so why are we checking augments again?
1940                  * because this module may be not implemented and it augments something in another module and
1941                  * there is another augment augmenting that previous one */
1942                 aux_mod = cur_module;
1943             }
1944 
1945             /* look into augments */
1946             if (!extended) {
1947 get_next_augment:
1948                 last_aug = lys_getnext_target_aug(last_aug, aux_mod, start_parent);
1949             }
1950         }
1951 
1952         while ((sibling = lys_getnext(sibling, (last_aug ? (struct lys_node *)last_aug : start_parent), start_mod,
1953                 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_PARENTUSES | LYS_GETNEXT_NOSTATECHECK))) {
1954             r = schema_nodeid_siblingcheck(sibling, cur_module, mod_name, mod_name_len, name, nam_len);
1955 
1956             /* resolve predicate */
1957             if (extended && ((r == 0) || (r == 2) || (r == 3)) && has_predicate) {
1958                 r = resolve_extended_schema_nodeid_predicate(id, sibling, cur_module, &nodeid_end);
1959                 if (r == 1) {
1960                     continue;
1961                 } else if (r == -1) {
1962                     return -1;
1963                 }
1964             } else if (!id[0]) {
1965                 nodeid_end = 1;
1966             }
1967 
1968             if (r == 0) {
1969                 /* one matching result */
1970                 if (nodeid_end) {
1971                     *ret = ly_set_new();
1972                     LY_CHECK_ERR_RETURN(!*ret, LOGMEM(ctx), -1);
1973                     ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
1974                 } else {
1975                     if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
1976                         return -1;
1977                     }
1978                     start_parent = sibling;
1979                 }
1980                 break;
1981             } else if (r == 1) {
1982                 continue;
1983             } else if (r == 2) {
1984                 /* "*" */
1985                 if (!*ret) {
1986                     *ret = ly_set_new();
1987                     LY_CHECK_ERR_RETURN(!*ret, LOGMEM(ctx), -1);
1988                 }
1989                 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
1990                 if (all_desc) {
1991                     LY_TREE_DFS_BEGIN(sibling, next, elem) {
1992                         if (elem != sibling) {
1993                             ly_set_add(*ret, (void *)elem, LY_SET_OPT_USEASLIST);
1994                         }
1995 
1996                         LY_TREE_DFS_END(sibling, next, elem);
1997                     }
1998                 }
1999             } else if (r == 3) {
2000                 /* "." */
2001                 if (!*ret) {
2002                     *ret = ly_set_new();
2003                     LY_CHECK_ERR_RETURN(!*ret, LOGMEM(ctx), -1);
2004                     if (start_parent) {
2005                         ly_set_add(*ret, (void *)start_parent, LY_SET_OPT_USEASLIST);
2006                     }
2007                 }
2008                 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
2009                 if (all_desc) {
2010                     LY_TREE_DFS_BEGIN(sibling, next, elem) {
2011                         if (elem != sibling) {
2012                             ly_set_add(*ret, (void *)elem, LY_SET_OPT_USEASLIST);
2013                         }
2014 
2015                         LY_TREE_DFS_END(sibling, next, elem);
2016                     }
2017                 }
2018             } else {
2019                 LOGINT(ctx);
2020                 return -1;
2021             }
2022         }
2023 
2024         /* skip predicate */
2025         if (extended && has_predicate) {
2026             while (id[0] == '[') {
2027                 id = strchr(id, ']');
2028                 if (!id) {
2029                     LOGINT(ctx);
2030                     return -1;
2031                 }
2032                 ++id;
2033             }
2034         }
2035 
2036         if (nodeid_end && ((r == 0) || (r == 2) || (r == 3))) {
2037             return EXIT_SUCCESS;
2038         }
2039 
2040         /* no match */
2041         if (!sibling) {
2042             if (last_aug) {
2043                 /* it still could be in another augment */
2044                 goto get_next_augment;
2045             }
2046             if (no_node_error) {
2047                 str = strndup(nodeid, (name - nodeid) + nam_len);
2048                 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
2049                 free(str);
2050                 return -1;
2051             }
2052             *ret = NULL;
2053             return EXIT_SUCCESS;
2054         }
2055 
2056         r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate,
2057                                 (extended ? &all_desc : NULL), extended);
2058         if (r < 1) {
2059             LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2060             return -1;
2061         }
2062         id += r;
2063     }
2064 
2065     /* cannot get here */
2066     LOGINT(ctx);
2067     return -1;
2068 }
2069 
2070 /* unique, refine,
2071  * >0  - unexpected char on position (ret - 1),
2072  *  0  - ok (but ret can still be NULL),
2073  * -1  - error,
2074  * -2  - violated no_innerlist  */
2075 int
resolve_descendant_schema_nodeid(const char * nodeid,const struct lys_node * start,int ret_nodetype,int no_innerlist,const struct lys_node ** ret)2076 resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
2077                                  int no_innerlist, const struct lys_node **ret)
2078 {
2079     const char *name, *mod_name, *id;
2080     const struct lys_node *sibling, *start_parent;
2081     int r, nam_len, mod_name_len, is_relative = -1;
2082     /* resolved import module from the start module, it must match the next node-name-match sibling */
2083     const struct lys_module *module;
2084 
2085     assert(nodeid && ret);
2086     assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT | LYS_GROUPING)));
2087 
2088     if (!start) {
2089         /* leaf not found */
2090         return 0;
2091     }
2092 
2093     id = nodeid;
2094     module = lys_node_module(start);
2095 
2096     if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 0)) < 1) {
2097         return ((id - nodeid) - r) + 1;
2098     }
2099     id += r;
2100 
2101     if (!is_relative) {
2102         return -1;
2103     }
2104 
2105     start_parent = lys_parent(start);
2106     while ((start_parent->nodetype == LYS_USES) && lys_parent(start_parent)) {
2107         start_parent = lys_parent(start_parent);
2108     }
2109 
2110     while (1) {
2111         sibling = NULL;
2112         while ((sibling = lys_getnext(sibling, start_parent, module,
2113                 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_PARENTUSES
2114                 | LYS_GETNEXT_NOSTATECHECK))) {
2115             r = schema_nodeid_siblingcheck(sibling, module, mod_name, mod_name_len, name, nam_len);
2116             if (r == 0) {
2117                 if (!id[0]) {
2118                     if (!(sibling->nodetype & ret_nodetype)) {
2119                         /* wrong node type, too bad */
2120                         continue;
2121                     }
2122                     *ret = sibling;
2123                     return EXIT_SUCCESS;
2124                 }
2125                 start_parent = sibling;
2126                 break;
2127             } else if (r == 1) {
2128                 continue;
2129             } else {
2130                 return -1;
2131             }
2132         }
2133 
2134         /* no match */
2135         if (!sibling) {
2136             *ret = NULL;
2137             return EXIT_SUCCESS;
2138         } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
2139             *ret = NULL;
2140             return -2;
2141         }
2142 
2143         if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 0)) < 1) {
2144             return ((id - nodeid) - r) + 1;
2145         }
2146         id += r;
2147     }
2148 
2149     /* cannot get here */
2150     LOGINT(module->ctx);
2151     return -1;
2152 }
2153 
2154 /* choice default */
2155 int
resolve_choice_default_schema_nodeid(const char * nodeid,const struct lys_node * start,const struct lys_node ** ret)2156 resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
2157 {
2158     /* cannot actually be a path */
2159     if (strchr(nodeid, '/')) {
2160         return -1;
2161     }
2162 
2163     return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 0, ret);
2164 }
2165 
2166 /* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
2167 static int
resolve_uses_schema_nodeid(const char * nodeid,const struct lys_node * start,const struct lys_node_grp ** ret)2168 resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
2169 {
2170     const struct lys_module *module;
2171     const char *mod_prefix, *name;
2172     int i, mod_prefix_len, nam_len;
2173 
2174     /* parse the identifier, it must be parsed on one call */
2175     if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len, NULL, 0)) < 1) || nodeid[i]) {
2176         return -i + 1;
2177     }
2178 
2179     module = lyp_get_module(start->module, mod_prefix, mod_prefix_len, NULL, 0, 0);
2180     if (!module) {
2181         return -1;
2182     }
2183     if (module != lys_main_module(start->module)) {
2184         start = module->data;
2185     }
2186 
2187     *ret = lys_find_grouping_up(name, (struct lys_node *)start);
2188 
2189     return EXIT_SUCCESS;
2190 }
2191 
2192 int
resolve_absolute_schema_nodeid(const char * nodeid,const struct lys_module * module,int ret_nodetype,const struct lys_node ** ret)2193 resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
2194                                const struct lys_node **ret)
2195 {
2196     const char *name, *mod_name, *id;
2197     const struct lys_node *sibling, *start_parent;
2198     int r, nam_len, mod_name_len, is_relative = -1;
2199     const struct lys_module *abs_start_mod;
2200 
2201     assert(nodeid && module && ret);
2202     assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
2203 
2204     id = nodeid;
2205     start_parent = NULL;
2206 
2207     if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 0)) < 1) {
2208         return ((id - nodeid) - r) + 1;
2209     }
2210     id += r;
2211 
2212     if (is_relative) {
2213         return -1;
2214     }
2215 
2216     abs_start_mod = lyp_get_module(module, NULL, 0, mod_name, mod_name_len, 0);
2217     if (!abs_start_mod) {
2218         return -1;
2219     }
2220 
2221     while (1) {
2222         sibling = NULL;
2223         while ((sibling = lys_getnext(sibling, start_parent, abs_start_mod, LYS_GETNEXT_WITHCHOICE
2224                 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING | LYS_GETNEXT_NOSTATECHECK))) {
2225             r = schema_nodeid_siblingcheck(sibling, module, mod_name, mod_name_len, name, nam_len);
2226             if (r == 0) {
2227                 if (!id[0]) {
2228                     if (!(sibling->nodetype & ret_nodetype)) {
2229                         /* wrong node type, too bad */
2230                         continue;
2231                     }
2232                     *ret = sibling;
2233                     return EXIT_SUCCESS;
2234                 }
2235                 start_parent = sibling;
2236                 break;
2237             } else if (r == 1) {
2238                 continue;
2239             } else {
2240                 return -1;
2241             }
2242         }
2243 
2244         /* no match */
2245         if (!sibling) {
2246             *ret = NULL;
2247             return EXIT_SUCCESS;
2248         }
2249 
2250         if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 0)) < 1) {
2251             return ((id - nodeid) - r) + 1;
2252         }
2253         id += r;
2254     }
2255 
2256     /* cannot get here */
2257     LOGINT(module->ctx);
2258     return -1;
2259 }
2260 
2261 static int
resolve_json_schema_list_predicate(const char * predicate,const struct lys_node_list * list,int * parsed)2262 resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
2263 {
2264     const char *mod_name, *name;
2265     int mod_name_len, nam_len, has_predicate, i;
2266     struct lys_node *key;
2267 
2268     if (((i = parse_schema_json_predicate(predicate, &mod_name, &mod_name_len, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
2269             || !strncmp(name, ".", nam_len)) {
2270         LOGVAL(list->module->ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
2271         return -1;
2272     }
2273 
2274     predicate += i;
2275     *parsed += i;
2276 
2277     if (!isdigit(name[0])) {
2278         for (i = 0; i < list->keys_size; ++i) {
2279             key = (struct lys_node *)list->keys[i];
2280             if (!strncmp(key->name, name, nam_len) && !key->name[nam_len]) {
2281                 break;
2282             }
2283         }
2284 
2285         if (i == list->keys_size) {
2286             LOGVAL(list->module->ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
2287             return -1;
2288         }
2289     }
2290 
2291     /* more predicates? */
2292     if (has_predicate) {
2293         return resolve_json_schema_list_predicate(predicate, list, parsed);
2294     }
2295 
2296     return 0;
2297 }
2298 
2299 /* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
2300 const struct lys_node *
resolve_json_nodeid(const char * nodeid,const struct ly_ctx * ctx,const struct lys_node * start,int output)2301 resolve_json_nodeid(const char *nodeid, const struct ly_ctx *ctx, const struct lys_node *start, int output)
2302 {
2303     char *str;
2304     const char *name, *mod_name, *id, *backup_mod_name = NULL, *yang_data_name = NULL;
2305     const struct lys_node *sibling, *start_parent, *parent;
2306     int r, nam_len, mod_name_len, is_relative = -1, has_predicate;
2307     int yang_data_name_len, backup_mod_name_len;
2308     /* resolved import module from the start module, it must match the next node-name-match sibling */
2309     const struct lys_module *prefix_mod, *module, *prev_mod;
2310 
2311     assert(nodeid && (ctx || start));
2312     if (!ctx) {
2313         ctx = start->module->ctx;
2314     }
2315 
2316     id = nodeid;
2317 
2318     if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 1)) < 1) {
2319         LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2320         return NULL;
2321     }
2322 
2323     if (name[0] == '#') {
2324         if (is_relative) {
2325             LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, '#', name);
2326             return NULL;
2327         }
2328         yang_data_name = name + 1;
2329         yang_data_name_len = nam_len - 1;
2330         backup_mod_name = mod_name;
2331         backup_mod_name_len = mod_name_len;
2332         id += r;
2333     } else {
2334         is_relative = -1;
2335     }
2336 
2337     if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
2338         LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2339         return NULL;
2340     }
2341     id += r;
2342 
2343     if (backup_mod_name) {
2344         mod_name = backup_mod_name;
2345         mod_name_len = backup_mod_name_len;
2346     }
2347 
2348     if (is_relative) {
2349         assert(start);
2350         start_parent = start;
2351         while (start_parent && (start_parent->nodetype == LYS_USES)) {
2352             start_parent = lys_parent(start_parent);
2353         }
2354         module = start->module;
2355     } else {
2356         if (!mod_name) {
2357             str = strndup(nodeid, (name + nam_len) - nodeid);
2358             LOGVAL(ctx, LYE_PATH_MISSMOD, LY_VLOG_STR, str);
2359             free(str);
2360             return NULL;
2361         }
2362 
2363         str = strndup(mod_name, mod_name_len);
2364         module = ly_ctx_get_module(ctx, str, NULL, 1);
2365         free(str);
2366 
2367         if (!module) {
2368             str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2369             LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
2370             free(str);
2371             return NULL;
2372         }
2373         start_parent = NULL;
2374         if (yang_data_name) {
2375             start_parent = lyp_get_yang_data_template(module, yang_data_name, yang_data_name_len);
2376             if (!start_parent) {
2377                 str = strndup(nodeid, (yang_data_name + yang_data_name_len) - nodeid);
2378                 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
2379                 free(str);
2380                 return NULL;
2381             }
2382         }
2383 
2384         /* now it's as if there was no module name */
2385         mod_name = NULL;
2386         mod_name_len = 0;
2387     }
2388 
2389     prev_mod = module;
2390 
2391     while (1) {
2392         sibling = NULL;
2393         while ((sibling = lys_getnext(sibling, start_parent, module, 0))) {
2394             /* name match */
2395             if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
2396                 /* output check */
2397                 for (parent = lys_parent(sibling); parent && !(parent->nodetype & (LYS_INPUT | LYS_OUTPUT)); parent = lys_parent(parent));
2398                 if (parent) {
2399                     if (output && (parent->nodetype == LYS_INPUT)) {
2400                         continue;
2401                     } else if (!output && (parent->nodetype == LYS_OUTPUT)) {
2402                         continue;
2403                     }
2404                 }
2405 
2406                 /* module check */
2407                 if (mod_name) {
2408                     /* will also find an augment module */
2409                     prefix_mod = ly_ctx_nget_module(ctx, mod_name, mod_name_len, NULL, 1);
2410 
2411                     if (!prefix_mod) {
2412                         str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2413                         LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
2414                         free(str);
2415                         return NULL;
2416                     }
2417                 } else {
2418                     prefix_mod = prev_mod;
2419                 }
2420                 if (prefix_mod != lys_node_module(sibling)) {
2421                     continue;
2422                 }
2423 
2424                 /* do we have some predicates on it? */
2425                 if (has_predicate) {
2426                     r = 0;
2427                     if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
2428                         if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
2429                             LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2430                             return NULL;
2431                         }
2432                     } else if (sibling->nodetype == LYS_LIST) {
2433                         if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
2434                             return NULL;
2435                         }
2436                     } else {
2437                         LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2438                         return NULL;
2439                     }
2440                     id += r;
2441                 }
2442 
2443                 /* the result node? */
2444                 if (!id[0]) {
2445                     return sibling;
2446                 }
2447 
2448                 /* move down the tree, if possible */
2449                 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
2450                     LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2451                     return NULL;
2452                 }
2453                 start_parent = sibling;
2454 
2455                 /* update prev mod */
2456                 prev_mod = (start_parent->child ? lys_node_module(start_parent->child) : module);
2457                 break;
2458             }
2459         }
2460 
2461         /* no match */
2462         if (!sibling) {
2463             str = strndup(nodeid, (name + nam_len) - nodeid);
2464             LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
2465             free(str);
2466             return NULL;
2467         }
2468 
2469         if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
2470             LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2471             return NULL;
2472         }
2473         id += r;
2474     }
2475 
2476     /* cannot get here */
2477     LOGINT(ctx);
2478     return NULL;
2479 }
2480 
2481 static int
resolve_partial_json_data_list_predicate(struct parsed_pred pp,struct lyd_node * node,int position)2482 resolve_partial_json_data_list_predicate(struct parsed_pred pp, struct lyd_node *node, int position)
2483 {
2484     uint16_t i;
2485     char *val_str;
2486     struct lyd_node_leaf_list *key;
2487     struct lys_node_list *slist;
2488     struct ly_ctx *ctx;
2489 
2490     assert(node);
2491     assert(node->schema->nodetype == LYS_LIST);
2492     assert(pp.len);
2493 
2494     ctx = node->schema->module->ctx;
2495     slist = (struct lys_node_list *)node->schema;
2496 
2497     /* is the predicate a number? */
2498     if (isdigit(pp.pred[0].name[0])) {
2499         if (position == atoi(pp.pred[0].name)) {
2500             /* match */
2501             return 0;
2502         } else {
2503             /* not a match */
2504             return 1;
2505         }
2506     }
2507 
2508     key = (struct lyd_node_leaf_list *)node->child;
2509     if (!key) {
2510         /* it is not a position, so we need a key for it to be a match */
2511         return 1;
2512     }
2513 
2514     /* go through all the keys */
2515     for (i = 0; i < slist->keys_size; ++i) {
2516         if (strncmp(key->schema->name, pp.pred[i].name, pp.pred[i].nam_len) || key->schema->name[pp.pred[i].nam_len]) {
2517             LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
2518             return -1;
2519         }
2520 
2521         if (pp.pred[i].mod_name) {
2522             /* specific module, check that the found key is from that module */
2523             if (strncmp(lyd_node_module((struct lyd_node *)key)->name, pp.pred[i].mod_name, pp.pred[i].mod_name_len)
2524                     || lyd_node_module((struct lyd_node *)key)->name[pp.pred[i].mod_name_len]) {
2525                 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
2526                 return -1;
2527             }
2528 
2529             /* but if the module is the same as the parent, it should have been omitted */
2530             if (lyd_node_module((struct lyd_node *)key) == lyd_node_module(node)) {
2531                 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
2532                 return -1;
2533             }
2534         } else {
2535             /* no module, so it must be the same as the list (parent) */
2536             if (lyd_node_module((struct lyd_node *)key) != lyd_node_module(node)) {
2537                 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
2538                 return -1;
2539             }
2540         }
2541 
2542         /* get canonical value */
2543         val_str = lyd_make_canonical(key->schema, pp.pred[i].value, pp.pred[i].val_len);
2544         if (!val_str) {
2545             return -1;
2546         }
2547 
2548         /* value does not match */
2549         if (strcmp(key->value_str, val_str)) {
2550             free(val_str);
2551             return 1;
2552         }
2553         free(val_str);
2554 
2555         key = (struct lyd_node_leaf_list *)key->next;
2556     }
2557 
2558     return 0;
2559 }
2560 
2561 /**
2562  * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2563  *
2564  * @param[in] nodeid Node data path to find
2565  * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2566  * @param[in] options Bitmask of options flags, see @ref pathoptions.
2567  * @param[out] parsed Number of characters processed in \p id
2568  * @return The closes parent (or the node itself) from the path
2569  */
2570 struct lyd_node *
resolve_partial_json_data_nodeid(const char * nodeid,const char * llist_value,struct lyd_node * start,int options,int * parsed)2571 resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2572                                  int *parsed)
2573 {
2574     const char *id, *mod_name, *name, *data_val, *llval;
2575     int r, ret, mod_name_len, nam_len, is_relative = -1, list_instance_position;
2576     int has_predicate, last_parsed = 0, llval_len;
2577     struct lyd_node *sibling, *last_match = NULL;
2578     struct lyd_node_leaf_list *llist;
2579     const struct lys_module *prev_mod;
2580     struct ly_ctx *ctx;
2581     const struct lys_node *ssibling, *sparent;
2582     struct lys_node_list *slist;
2583     struct parsed_pred pp;
2584 
2585     assert(nodeid && start && parsed);
2586 
2587     memset(&pp, 0, sizeof pp);
2588     ctx = start->schema->module->ctx;
2589     id = nodeid;
2590 
2591     /* parse first nodeid in case it is yang-data extension */
2592     if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 1)) < 1) {
2593         LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2594         goto error;
2595     }
2596 
2597     if (name[0] == '#') {
2598         if (is_relative) {
2599             LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, '#', name);
2600             goto error;
2601         }
2602         id += r;
2603         last_parsed = r;
2604     } else {
2605         is_relative = -1;
2606     }
2607 
2608     /* parse first nodeid */
2609     if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
2610         LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2611         goto error;
2612     }
2613     id += r;
2614     /* add it to parsed only after the data node was actually found */
2615     last_parsed += r;
2616 
2617     if (is_relative) {
2618         prev_mod = lyd_node_module(start);
2619         start = (start->schema->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_RPC | LYS_ACTION | LYS_NOTIF)) ? start->child : NULL;
2620     } else {
2621         for (; start->parent; start = start->parent);
2622         prev_mod = lyd_node_module(start);
2623     }
2624     if (!start) {
2625         /* there are no siblings to search */
2626         return NULL;
2627     }
2628 
2629     /* do not duplicate code, use predicate parsing from the loop */
2630     goto parse_predicates;
2631 
2632     while (1) {
2633         /* find the correct schema node first */
2634         ssibling = NULL;
2635         sparent = (start && start->parent) ? start->parent->schema : NULL;
2636         while ((ssibling = lys_getnext(ssibling, sparent, prev_mod, 0))) {
2637             /* skip invalid input/output nodes */
2638             if (sparent && (sparent->nodetype & (LYS_RPC | LYS_ACTION))) {
2639                 if (options & LYD_PATH_OPT_OUTPUT) {
2640                     if (lys_parent(ssibling)->nodetype == LYS_INPUT) {
2641                         continue;
2642                     }
2643                 } else {
2644                     if (lys_parent(ssibling)->nodetype == LYS_OUTPUT) {
2645                         continue;
2646                     }
2647                 }
2648             }
2649 
2650             if (!schema_nodeid_siblingcheck(ssibling, prev_mod, mod_name, mod_name_len, name, nam_len)) {
2651                 break;
2652             }
2653         }
2654         if (!ssibling) {
2655             /* there is not even such a schema node */
2656             free(pp.pred);
2657             return last_match;
2658         }
2659         pp.schema = ssibling;
2660 
2661         /* unify leaf-list value - it is possible to specify last-node value as both a predicate or parameter if
2662          * is a leaf-list, unify both cases and the value will in both cases be in the predicate structure */
2663         if (!id[0] && !pp.len && (ssibling->nodetype == LYS_LEAFLIST)) {
2664             pp.len = 1;
2665             pp.pred = calloc(1, sizeof *pp.pred);
2666             LY_CHECK_ERR_GOTO(!pp.pred, LOGMEM(ctx), error);
2667 
2668             pp.pred[0].name = ".";
2669             pp.pred[0].nam_len = 1;
2670             pp.pred[0].value = (llist_value ? llist_value : "");
2671             pp.pred[0].val_len = strlen(pp.pred[0].value);
2672         }
2673 
2674         if (ssibling->nodetype & (LYS_LEAFLIST | LYS_LEAF)) {
2675             /* check leaf/leaf-list predicate */
2676             if (pp.len > 1) {
2677                 LOGVAL(ctx, LYE_PATH_PREDTOOMANY, LY_VLOG_NONE, NULL);
2678                 goto error;
2679             } else if (pp.len) {
2680                 if ((pp.pred[0].name[0] != '.') || (pp.pred[0].nam_len != 1)) {
2681                     LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, pp.pred[0].name[0], pp.pred[0].name);
2682                     goto error;
2683                 }
2684                 if ((((struct lys_node_leaf *)ssibling)->type.base == LY_TYPE_IDENT) && !strnchr(pp.pred[0].value, ':', pp.pred[0].val_len)) {
2685                     LOGVAL(ctx, LYE_PATH_INIDENTREF, LY_VLOG_LYS, ssibling, pp.pred[0].val_len, pp.pred[0].value);
2686                     goto error;
2687                 }
2688             }
2689         } else if (ssibling->nodetype == LYS_LIST) {
2690             /* list should have predicates for all the keys or position */
2691             slist = (struct lys_node_list *)ssibling;
2692             if (!pp.len) {
2693                 /* none match */
2694                 return last_match;
2695             } else if (!isdigit(pp.pred[0].name[0])) {
2696                 /* list predicate is not a position, so there must be all the keys */
2697                 if (pp.len > slist->keys_size) {
2698                     LOGVAL(ctx, LYE_PATH_PREDTOOMANY, LY_VLOG_NONE, NULL);
2699                     goto error;
2700                 } else if (pp.len < slist->keys_size) {
2701                     LOGVAL(ctx, LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, slist->keys[pp.len]->name);
2702                     goto error;
2703                 }
2704                 /* check that all identityrefs have module name, otherwise the hash of the list instance will never match!! */
2705                 for (r = 0; r < pp.len; ++r) {
2706                     if ((slist->keys[r]->type.base == LY_TYPE_IDENT) && !strnchr(pp.pred[r].value, ':', pp.pred[r].val_len)) {
2707                         LOGVAL(ctx, LYE_PATH_INIDENTREF, LY_VLOG_LYS, slist->keys[r], pp.pred[r].val_len, pp.pred[r].value);
2708                         goto error;
2709                     }
2710                 }
2711             }
2712         } else if (pp.pred) {
2713             /* no other nodes allow predicates */
2714             LOGVAL(ctx, LYE_PATH_PREDTOOMANY, LY_VLOG_NONE, NULL);
2715             goto error;
2716         }
2717 
2718         /* we will not be matching list position, keyless lists, or non-configuration leaf-lists this way */
2719         if (((pp.schema->nodetype != LYS_LIST) || (((struct lys_node_list *)pp.schema)->keys_size && !isdigit(pp.pred[0].name[0])))
2720                 && ((pp.schema->nodetype != LYS_LEAFLIST) || (pp.schema->flags & LYS_CONFIG_W))) {
2721             sibling = resolve_json_data_node_hash(start, pp);
2722         } else {
2723             list_instance_position = 0;
2724             LY_TREE_FOR(start, sibling) {
2725                 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
2726                 if (lys_parent(sibling->schema)) {
2727                     if (options & LYD_PATH_OPT_OUTPUT) {
2728                         if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
2729                             LOGERR(ctx, LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
2730                             goto error;
2731                         }
2732                     } else {
2733                         if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
2734                             LOGERR(ctx, LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
2735                             goto error;
2736                         }
2737                     }
2738                 }
2739 
2740                 if (sibling->schema != ssibling) {
2741                     /* wrong schema node */
2742                     continue;
2743                 }
2744 
2745                 /* leaf-list, did we find it with the correct value or not? */
2746                 if (ssibling->nodetype == LYS_LEAFLIST) {
2747                     if (!(ssibling->flags & LYS_CONFIG_W)) {
2748                         /* non-configuration leaf-lists will never match */
2749                         continue;
2750                     }
2751 
2752                     llist = (struct lyd_node_leaf_list *)sibling;
2753 
2754                     /* get the expected leaf-list value */
2755                     llval = NULL;
2756                     llval_len = 0;
2757                     if (pp.pred) {
2758                         /* it was already checked that it is correct */
2759                         llval = pp.pred[0].value;
2760                         llval_len = pp.pred[0].val_len;
2761 
2762                     }
2763 
2764                     /* make value canonical (remove module name prefix) unless it was specified with it */
2765                     if (llval && !strchr(llval, ':') && (llist->value_type & LY_TYPE_IDENT)
2766                             && !strncmp(llist->value_str, lyd_node_module(sibling)->name, strlen(lyd_node_module(sibling)->name))
2767                             && (llist->value_str[strlen(lyd_node_module(sibling)->name)] == ':')) {
2768                         data_val = llist->value_str + strlen(lyd_node_module(sibling)->name) + 1;
2769                     } else {
2770                         data_val = llist->value_str;
2771                     }
2772 
2773                     if ((!llval && data_val && data_val[0]) || (llval && (strncmp(llval, data_val, llval_len)
2774                             || data_val[llval_len]))) {
2775                         continue;
2776                     }
2777 
2778                 } else if (ssibling->nodetype == LYS_LIST) {
2779                     /* list, we likely need predicates'n'stuff then, but if without a predicate, we are always creating it */
2780                     ++list_instance_position;
2781                     ret = resolve_partial_json_data_list_predicate(pp, sibling, list_instance_position);
2782                     if (ret == -1) {
2783                         goto error;
2784                     } else if (ret == 1) {
2785                         /* this list instance does not match */
2786                         continue;
2787                     }
2788                 }
2789 
2790                 break;
2791             }
2792         }
2793 
2794         /* no match, return last match */
2795         if (!sibling) {
2796             free(pp.pred);
2797             return last_match;
2798         }
2799 
2800         /* we found a next matching node */
2801         *parsed += last_parsed;
2802         last_match = sibling;
2803         prev_mod = lyd_node_module(sibling);
2804 
2805         /* the result node? */
2806         if (!id[0]) {
2807             free(pp.pred);
2808             return last_match;
2809         }
2810 
2811         /* move down the tree, if possible, and continue */
2812         if (ssibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
2813             /* there can be no children even through expected, error */
2814             LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2815             goto error;
2816         } else if (!sibling->child) {
2817             /* there could be some children, but are not, return what we found so far */
2818             free(pp.pred);
2819             return last_match;
2820         }
2821         start = sibling->child;
2822 
2823         /* parse nodeid */
2824         if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
2825             LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2826             goto error;
2827         }
2828         id += r;
2829         last_parsed = r;
2830 
2831 parse_predicates:
2832         /* parse all the predicates */
2833         free(pp.pred);
2834         pp.schema = NULL;
2835         pp.pred_str = NULL;
2836         pp.pred_str_len = 0;
2837         pp.len = 0;
2838         pp.pred = NULL;
2839         while (has_predicate) {
2840             if (!pp.pred_str) {
2841                 pp.pred_str = id;
2842             }
2843 
2844             ++pp.len;
2845             pp.pred = ly_realloc(pp.pred, pp.len * sizeof *pp.pred);
2846             LY_CHECK_ERR_GOTO(!pp.pred, LOGMEM(ctx), error);
2847             if ((r = parse_schema_json_predicate(id, &pp.pred[pp.len - 1].mod_name, &pp.pred[pp.len - 1].mod_name_len,
2848                                                  &pp.pred[pp.len - 1].name, &pp.pred[pp.len - 1].nam_len, &pp.pred[pp.len - 1].value,
2849                                                  &pp.pred[pp.len - 1].val_len, &has_predicate)) < 1) {
2850                 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2851                 goto error;
2852             }
2853 
2854             id += r;
2855             last_parsed += r;
2856             pp.pred_str_len += r;
2857         }
2858     }
2859 
2860 error:
2861     *parsed = -1;
2862     free(pp.pred);
2863     return NULL;
2864 }
2865 
2866 /**
2867  * @brief Resolves length or range intervals. Does not log.
2868  * Syntax is assumed to be correct, *ret MUST be NULL.
2869  *
2870  * @param[in] ctx Context for errors.
2871  * @param[in] str_restr Restriction as a string.
2872  * @param[in] type Type of the restriction.
2873  * @param[out] ret Final interval structure that starts with
2874  * the interval of the initial type, continues with intervals
2875  * of any superior types derived from the initial one, and
2876  * finishes with intervals from our \p type.
2877  *
2878  * @return EXIT_SUCCESS on succes, -1 on error.
2879  */
2880 int
resolve_len_ran_interval(struct ly_ctx * ctx,const char * str_restr,struct lys_type * type,struct len_ran_intv ** ret)2881 resolve_len_ran_interval(struct ly_ctx *ctx, const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
2882 {
2883     /* 0 - unsigned, 1 - signed, 2 - floating point */
2884     int kind;
2885     int64_t local_smin = 0, local_smax = 0, local_fmin, local_fmax;
2886     uint64_t local_umin, local_umax = 0;
2887     uint8_t local_fdig = 0;
2888     const char *seg_ptr, *ptr;
2889     struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
2890 
2891     switch (type->base) {
2892     case LY_TYPE_BINARY:
2893         kind = 0;
2894         local_umin = 0;
2895         local_umax = 18446744073709551615UL;
2896 
2897         if (!str_restr && type->info.binary.length) {
2898             str_restr = type->info.binary.length->expr;
2899         }
2900         break;
2901     case LY_TYPE_DEC64:
2902         kind = 2;
2903         local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2904         local_fmax = __INT64_C(9223372036854775807);
2905         local_fdig = type->info.dec64.dig;
2906 
2907         if (!str_restr && type->info.dec64.range) {
2908             str_restr = type->info.dec64.range->expr;
2909         }
2910         break;
2911     case LY_TYPE_INT8:
2912         kind = 1;
2913         local_smin = __INT64_C(-128);
2914         local_smax = __INT64_C(127);
2915 
2916         if (!str_restr && type->info.num.range) {
2917             str_restr = type->info.num.range->expr;
2918         }
2919         break;
2920     case LY_TYPE_INT16:
2921         kind = 1;
2922         local_smin = __INT64_C(-32768);
2923         local_smax = __INT64_C(32767);
2924 
2925         if (!str_restr && type->info.num.range) {
2926             str_restr = type->info.num.range->expr;
2927         }
2928         break;
2929     case LY_TYPE_INT32:
2930         kind = 1;
2931         local_smin = __INT64_C(-2147483648);
2932         local_smax = __INT64_C(2147483647);
2933 
2934         if (!str_restr && type->info.num.range) {
2935             str_restr = type->info.num.range->expr;
2936         }
2937         break;
2938     case LY_TYPE_INT64:
2939         kind = 1;
2940         local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2941         local_smax = __INT64_C(9223372036854775807);
2942 
2943         if (!str_restr && type->info.num.range) {
2944             str_restr = type->info.num.range->expr;
2945         }
2946         break;
2947     case LY_TYPE_UINT8:
2948         kind = 0;
2949         local_umin = __UINT64_C(0);
2950         local_umax = __UINT64_C(255);
2951 
2952         if (!str_restr && type->info.num.range) {
2953             str_restr = type->info.num.range->expr;
2954         }
2955         break;
2956     case LY_TYPE_UINT16:
2957         kind = 0;
2958         local_umin = __UINT64_C(0);
2959         local_umax = __UINT64_C(65535);
2960 
2961         if (!str_restr && type->info.num.range) {
2962             str_restr = type->info.num.range->expr;
2963         }
2964         break;
2965     case LY_TYPE_UINT32:
2966         kind = 0;
2967         local_umin = __UINT64_C(0);
2968         local_umax = __UINT64_C(4294967295);
2969 
2970         if (!str_restr && type->info.num.range) {
2971             str_restr = type->info.num.range->expr;
2972         }
2973         break;
2974     case LY_TYPE_UINT64:
2975         kind = 0;
2976         local_umin = __UINT64_C(0);
2977         local_umax = __UINT64_C(18446744073709551615);
2978 
2979         if (!str_restr && type->info.num.range) {
2980             str_restr = type->info.num.range->expr;
2981         }
2982         break;
2983     case LY_TYPE_STRING:
2984         kind = 0;
2985         local_umin = __UINT64_C(0);
2986         local_umax = __UINT64_C(18446744073709551615);
2987 
2988         if (!str_restr && type->info.str.length) {
2989             str_restr = type->info.str.length->expr;
2990         }
2991         break;
2992     default:
2993         return -1;
2994     }
2995 
2996     /* process superior types */
2997     if (type->der) {
2998         if (resolve_len_ran_interval(ctx, NULL, &type->der->type, &intv)) {
2999             return -1;
3000         }
3001         assert(!intv || (intv->kind == kind));
3002     }
3003 
3004     if (!str_restr) {
3005         /* we do not have any restriction, return superior ones */
3006         *ret = intv;
3007         return EXIT_SUCCESS;
3008     }
3009 
3010     /* adjust local min and max */
3011     if (intv) {
3012         tmp_intv = intv;
3013 
3014         if (kind == 0) {
3015             local_umin = tmp_intv->value.uval.min;
3016         } else if (kind == 1) {
3017             local_smin = tmp_intv->value.sval.min;
3018         } else if (kind == 2) {
3019             local_fmin = tmp_intv->value.fval.min;
3020         }
3021 
3022         while (tmp_intv->next) {
3023             tmp_intv = tmp_intv->next;
3024         }
3025 
3026         if (kind == 0) {
3027             local_umax = tmp_intv->value.uval.max;
3028         } else if (kind == 1) {
3029             local_smax = tmp_intv->value.sval.max;
3030         } else if (kind == 2) {
3031             local_fmax = tmp_intv->value.fval.max;
3032         }
3033     }
3034 
3035     /* finally parse our restriction */
3036     seg_ptr = str_restr;
3037     tmp_intv = NULL;
3038     while (1) {
3039         if (!tmp_local_intv) {
3040             assert(!local_intv);
3041             local_intv = malloc(sizeof *local_intv);
3042             tmp_local_intv = local_intv;
3043         } else {
3044             tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
3045             tmp_local_intv = tmp_local_intv->next;
3046         }
3047         LY_CHECK_ERR_GOTO(!tmp_local_intv, LOGMEM(ctx), error);
3048 
3049         tmp_local_intv->kind = kind;
3050         tmp_local_intv->type = type;
3051         tmp_local_intv->next = NULL;
3052 
3053         /* min */
3054         ptr = seg_ptr;
3055         while (isspace(ptr[0])) {
3056             ++ptr;
3057         }
3058         if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
3059             if (kind == 0) {
3060                 tmp_local_intv->value.uval.min = strtoull(ptr, (char **)&ptr, 10);
3061             } else if (kind == 1) {
3062                 tmp_local_intv->value.sval.min = strtoll(ptr, (char **)&ptr, 10);
3063             } else if (kind == 2) {
3064                 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
3065                     LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
3066                     goto error;
3067                 }
3068             }
3069         } else if (!strncmp(ptr, "min", 3)) {
3070             if (kind == 0) {
3071                 tmp_local_intv->value.uval.min = local_umin;
3072             } else if (kind == 1) {
3073                 tmp_local_intv->value.sval.min = local_smin;
3074             } else if (kind == 2) {
3075                 tmp_local_intv->value.fval.min = local_fmin;
3076             }
3077 
3078             ptr += 3;
3079         } else if (!strncmp(ptr, "max", 3)) {
3080             if (kind == 0) {
3081                 tmp_local_intv->value.uval.min = local_umax;
3082             } else if (kind == 1) {
3083                 tmp_local_intv->value.sval.min = local_smax;
3084             } else if (kind == 2) {
3085                 tmp_local_intv->value.fval.min = local_fmax;
3086             }
3087 
3088             ptr += 3;
3089         } else {
3090             goto error;
3091         }
3092 
3093         while (isspace(ptr[0])) {
3094             ptr++;
3095         }
3096 
3097         /* no interval or interval */
3098         if ((ptr[0] == '|') || !ptr[0]) {
3099             if (kind == 0) {
3100                 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
3101             } else if (kind == 1) {
3102                 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
3103             } else if (kind == 2) {
3104                 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
3105             }
3106         } else if (!strncmp(ptr, "..", 2)) {
3107             /* skip ".." */
3108             ptr += 2;
3109             while (isspace(ptr[0])) {
3110                 ++ptr;
3111             }
3112 
3113             /* max */
3114             if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
3115                 if (kind == 0) {
3116                     tmp_local_intv->value.uval.max = strtoull(ptr, (char **)&ptr, 10);
3117                 } else if (kind == 1) {
3118                     tmp_local_intv->value.sval.max = strtoll(ptr, (char **)&ptr, 10);
3119                 } else if (kind == 2) {
3120                     if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
3121                         LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
3122                         goto error;
3123                     }
3124                 }
3125             } else if (!strncmp(ptr, "max", 3)) {
3126                 if (kind == 0) {
3127                     tmp_local_intv->value.uval.max = local_umax;
3128                 } else if (kind == 1) {
3129                     tmp_local_intv->value.sval.max = local_smax;
3130                 } else if (kind == 2) {
3131                     tmp_local_intv->value.fval.max = local_fmax;
3132                 }
3133             } else {
3134                 goto error;
3135             }
3136         } else {
3137             goto error;
3138         }
3139 
3140         /* check min and max in correct order */
3141         if (kind == 0) {
3142             /* current segment */
3143             if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
3144                 goto error;
3145             }
3146             if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
3147                 goto error;
3148             }
3149             /* segments sholud be ascending order */
3150             if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
3151                 goto error;
3152             }
3153         } else if (kind == 1) {
3154             if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
3155                 goto error;
3156             }
3157             if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
3158                 goto error;
3159             }
3160             if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
3161                 goto error;
3162             }
3163         } else if (kind == 2) {
3164             if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
3165                 goto error;
3166             }
3167             if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
3168                 goto error;
3169             }
3170             if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
3171                 /* fraction-digits value is always the same (it cannot be changed in derived types) */
3172                 goto error;
3173             }
3174         }
3175 
3176         /* next segment (next OR) */
3177         seg_ptr = strchr(seg_ptr, '|');
3178         if (!seg_ptr) {
3179             break;
3180         }
3181         seg_ptr++;
3182         tmp_intv = tmp_local_intv;
3183     }
3184 
3185     /* check local restrictions against superior ones */
3186     if (intv) {
3187         tmp_intv = intv;
3188         tmp_local_intv = local_intv;
3189 
3190         while (tmp_local_intv && tmp_intv) {
3191             /* reuse local variables */
3192             if (kind == 0) {
3193                 local_umin = tmp_local_intv->value.uval.min;
3194                 local_umax = tmp_local_intv->value.uval.max;
3195 
3196                 /* it must be in this interval */
3197                 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
3198                     /* this interval is covered, next one */
3199                     if (local_umax <= tmp_intv->value.uval.max) {
3200                         tmp_local_intv = tmp_local_intv->next;
3201                         continue;
3202                     /* ascending order of restrictions -> fail */
3203                     } else {
3204                         goto error;
3205                     }
3206                 }
3207             } else if (kind == 1) {
3208                 local_smin = tmp_local_intv->value.sval.min;
3209                 local_smax = tmp_local_intv->value.sval.max;
3210 
3211                 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
3212                     if (local_smax <= tmp_intv->value.sval.max) {
3213                         tmp_local_intv = tmp_local_intv->next;
3214                         continue;
3215                     } else {
3216                         goto error;
3217                     }
3218                 }
3219             } else if (kind == 2) {
3220                 local_fmin = tmp_local_intv->value.fval.min;
3221                 local_fmax = tmp_local_intv->value.fval.max;
3222 
3223                  if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
3224                         && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
3225                     if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
3226                         tmp_local_intv = tmp_local_intv->next;
3227                         continue;
3228                     } else {
3229                         goto error;
3230                     }
3231                 }
3232             }
3233 
3234             tmp_intv = tmp_intv->next;
3235         }
3236 
3237         /* some interval left uncovered -> fail */
3238         if (tmp_local_intv) {
3239             goto error;
3240         }
3241     }
3242 
3243     /* append the local intervals to all the intervals of the superior types, return it all */
3244     if (intv) {
3245         for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
3246         tmp_intv->next = local_intv;
3247     } else {
3248         intv = local_intv;
3249     }
3250     *ret = intv;
3251 
3252     return EXIT_SUCCESS;
3253 
3254 error:
3255     while (intv) {
3256         tmp_intv = intv->next;
3257         free(intv);
3258         intv = tmp_intv;
3259     }
3260     while (local_intv) {
3261         tmp_local_intv = local_intv->next;
3262         free(local_intv);
3263         local_intv = tmp_local_intv;
3264     }
3265 
3266     return -1;
3267 }
3268 
3269 static int
resolve_superior_type_check(struct lys_type * type)3270 resolve_superior_type_check(struct lys_type *type)
3271 {
3272     uint32_t i;
3273 
3274     if (type->base == LY_TYPE_DER) {
3275         /* check that the referenced typedef is resolved */
3276         return EXIT_FAILURE;
3277     } else if (type->base == LY_TYPE_UNION) {
3278         /* check that all union types are resolved */
3279         for (i = 0; i < type->info.uni.count; ++i) {
3280             if (resolve_superior_type_check(&type->info.uni.types[i])) {
3281                 return EXIT_FAILURE;
3282             }
3283         }
3284     } else if (type->base == LY_TYPE_LEAFREF) {
3285         /* check there is path in some derived type */
3286         while (!type->info.lref.path) {
3287             assert(type->der);
3288             type = &type->der->type;
3289         }
3290     }
3291 
3292     return EXIT_SUCCESS;
3293 }
3294 
3295 /**
3296  * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
3297  * resolved for this function to return it. Does not log.
3298  *
3299  * @param[in] name Typedef name.
3300  * @param[in] mod_name Typedef name module name.
3301  * @param[in] module Main module.
3302  * @param[in] parent Parent of the resolved type definition.
3303  * @param[out] ret Pointer to the resolved typedef. Can be NULL.
3304  *
3305  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3306  */
3307 int
resolve_superior_type(const char * name,const char * mod_name,const struct lys_module * module,const struct lys_node * parent,struct lys_tpdf ** ret)3308 resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
3309                       const struct lys_node *parent, struct lys_tpdf **ret)
3310 {
3311     int i, j;
3312     struct lys_tpdf *tpdf, *match;
3313     int tpdf_size;
3314 
3315     if (!mod_name) {
3316         /* no prefix, try built-in types */
3317         for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
3318             if (!strcmp(ly_types[i]->name, name)) {
3319                 if (ret) {
3320                     *ret = ly_types[i];
3321                 }
3322                 return EXIT_SUCCESS;
3323             }
3324         }
3325     } else {
3326         if (!strcmp(mod_name, module->name)) {
3327             /* prefix refers to the current module, ignore it */
3328             mod_name = NULL;
3329         }
3330     }
3331 
3332     if (!mod_name && parent) {
3333         /* search in local typedefs */
3334         while (parent) {
3335             switch (parent->nodetype) {
3336             case LYS_CONTAINER:
3337                 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
3338                 tpdf = ((struct lys_node_container *)parent)->tpdf;
3339                 break;
3340 
3341             case LYS_LIST:
3342                 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
3343                 tpdf = ((struct lys_node_list *)parent)->tpdf;
3344                 break;
3345 
3346             case LYS_GROUPING:
3347                 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
3348                 tpdf = ((struct lys_node_grp *)parent)->tpdf;
3349                 break;
3350 
3351             case LYS_RPC:
3352             case LYS_ACTION:
3353                 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
3354                 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
3355                 break;
3356 
3357             case LYS_NOTIF:
3358                 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
3359                 tpdf = ((struct lys_node_notif *)parent)->tpdf;
3360                 break;
3361 
3362             case LYS_INPUT:
3363             case LYS_OUTPUT:
3364                 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
3365                 tpdf = ((struct lys_node_inout *)parent)->tpdf;
3366                 break;
3367 
3368             default:
3369                 parent = lys_parent(parent);
3370                 continue;
3371             }
3372 
3373             for (i = 0; i < tpdf_size; i++) {
3374                 if (!strcmp(tpdf[i].name, name)) {
3375                     match = &tpdf[i];
3376                     goto check_typedef;
3377                 }
3378             }
3379 
3380             parent = lys_parent(parent);
3381         }
3382     } else {
3383         /* get module where to search */
3384         module = lyp_get_module(module, NULL, 0, mod_name, 0, 0);
3385         if (!module) {
3386             return -1;
3387         }
3388     }
3389 
3390     /* search in top level typedefs */
3391     for (i = 0; i < module->tpdf_size; i++) {
3392         if (!strcmp(module->tpdf[i].name, name)) {
3393             match = &module->tpdf[i];
3394             goto check_typedef;
3395         }
3396     }
3397 
3398     /* search in submodules */
3399     for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
3400         for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
3401             if (!strcmp(module->inc[i].submodule->tpdf[j].name, name)) {
3402                 match = &module->inc[i].submodule->tpdf[j];
3403                 goto check_typedef;
3404             }
3405         }
3406     }
3407 
3408     return EXIT_FAILURE;
3409 
3410 check_typedef:
3411     if (resolve_superior_type_check(&match->type)) {
3412         return EXIT_FAILURE;
3413     }
3414 
3415     if (ret) {
3416         *ret = match;
3417     }
3418     return EXIT_SUCCESS;
3419 }
3420 
3421 /**
3422  * @brief Check the default \p value of the \p type. Logs directly.
3423  *
3424  * @param[in] type Type definition to use.
3425  * @param[in] value Default value to check.
3426  * @param[in] module Type module.
3427  *
3428  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3429  */
3430 static int
check_default(struct lys_type * type,const char ** value,struct lys_module * module,int tpdf)3431 check_default(struct lys_type *type, const char **value, struct lys_module *module, int tpdf)
3432 {
3433     struct lys_tpdf *base_tpdf = NULL;
3434     struct lyd_node_leaf_list node;
3435     const char *dflt = NULL;
3436     char *s;
3437     int ret = EXIT_SUCCESS, r;
3438     struct ly_ctx *ctx = module->ctx;
3439 
3440     assert(value);
3441     memset(&node, 0, sizeof node);
3442 
3443     if (type->base <= LY_TYPE_DER) {
3444         /* the type was not resolved yet, nothing to do for now */
3445         ret = EXIT_FAILURE;
3446         goto cleanup;
3447     } else if (!module->implemented && ((type->base == LY_TYPE_IDENT) || (type->base == LY_TYPE_INST))) {
3448         /* /instidsidentityrefs are checked when instantiated in data instead of typedef,
3449          * but the value has to be modified to include the prefix */
3450         if (*value) {
3451             if (strchr(*value, ':')) {
3452                 dflt = transform_schema2json(module, *value);
3453             } else {
3454                 /* default prefix of the module where the typedef is defined */
3455                 if (asprintf(&s, "%s:%s", lys_main_module(module)->name, *value) == -1) {
3456                     LOGMEM(ctx);
3457                     ret = -1;
3458                     goto cleanup;
3459                 }
3460                 dflt = lydict_insert_zc(ctx, s);
3461             }
3462             lydict_remove(ctx, *value);
3463             *value = dflt;
3464             dflt = NULL;
3465         }
3466         goto cleanup;
3467     } else if (type->base == LY_TYPE_LEAFREF && tpdf) {
3468         /* leafref in typedef cannot be checked */
3469         goto cleanup;
3470     }
3471 
3472     dflt = lydict_insert(ctx, *value, 0);
3473     if (!dflt) {
3474         /* we do not have a new default value, so is there any to check even, in some base type? */
3475         for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
3476             if (base_tpdf->dflt) {
3477                 dflt = lydict_insert(ctx, base_tpdf->dflt, 0);
3478                 break;
3479             }
3480         }
3481 
3482         if (!dflt) {
3483             /* no default value, nothing to check, all is well */
3484             goto cleanup;
3485         }
3486 
3487         /* so there is a default value in a base type, but can the default value be no longer valid (did we define some new restrictions)? */
3488         switch (type->base) {
3489         case LY_TYPE_IDENT:
3490             if (lys_main_module(base_tpdf->type.parent->module)->implemented) {
3491                 goto cleanup;
3492             } else if ((type->base == LY_TYPE_IDENT) || (type->base == LY_TYPE_INST)) {
3493                 /* impossible to check with a non-implemented module */
3494                 goto cleanup;
3495             } else {
3496                 /* check the default value from typedef, but use also the typedef's module
3497                  * due to possible searching in imported modules which is expected in
3498                  * typedef's module instead of module where the typedef is used */
3499                 module = base_tpdf->module;
3500             }
3501             break;
3502         case LY_TYPE_INST:
3503         case LY_TYPE_LEAFREF:
3504         case LY_TYPE_BOOL:
3505         case LY_TYPE_EMPTY:
3506             /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
3507             goto cleanup;
3508         case LY_TYPE_BITS:
3509             /* the default value must match the restricted list of values, if the type was restricted */
3510             if (type->info.bits.count) {
3511                 break;
3512             }
3513             goto cleanup;
3514         case LY_TYPE_ENUM:
3515             /* the default value must match the restricted list of values, if the type was restricted */
3516             if (type->info.enums.count) {
3517                 break;
3518             }
3519             goto cleanup;
3520         case LY_TYPE_DEC64:
3521             if (type->info.dec64.range) {
3522                 break;
3523             }
3524             goto cleanup;
3525         case LY_TYPE_BINARY:
3526             if (type->info.binary.length) {
3527                 break;
3528             }
3529             goto cleanup;
3530         case LY_TYPE_INT8:
3531         case LY_TYPE_INT16:
3532         case LY_TYPE_INT32:
3533         case LY_TYPE_INT64:
3534         case LY_TYPE_UINT8:
3535         case LY_TYPE_UINT16:
3536         case LY_TYPE_UINT32:
3537         case LY_TYPE_UINT64:
3538             if (type->info.num.range) {
3539                 break;
3540             }
3541             goto cleanup;
3542         case LY_TYPE_STRING:
3543             if (type->info.str.length || type->info.str.patterns) {
3544                 break;
3545             }
3546             goto cleanup;
3547         case LY_TYPE_UNION:
3548             /* way too much trouble learning whether we need to check the default again, so just do it */
3549             break;
3550         default:
3551             LOGINT(ctx);
3552             ret = -1;
3553             goto cleanup;
3554         }
3555     } else if (type->base == LY_TYPE_EMPTY) {
3556         LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3557         LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3558         ret = -1;
3559         goto cleanup;
3560     }
3561 
3562     /* dummy leaf */
3563     memset(&node, 0, sizeof node);
3564     node.value_str = lydict_insert(ctx, dflt, 0);
3565     node.value_type = type->base;
3566 
3567     if (tpdf) {
3568         node.schema = calloc(1, sizeof (struct lys_node_leaf));
3569         if (!node.schema) {
3570             LOGMEM(ctx);
3571             ret = -1;
3572             goto cleanup;
3573         }
3574         r = asprintf((char **)&node.schema->name, "typedef-%s-default", ((struct lys_tpdf *)type->parent)->name);
3575         if (r == -1) {
3576             LOGMEM(ctx);
3577             ret = -1;
3578             goto cleanup;
3579         }
3580         node.schema->module = module;
3581         memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
3582     } else {
3583         node.schema = (struct lys_node *)type->parent;
3584     }
3585 
3586     if (type->base == LY_TYPE_LEAFREF) {
3587         if (!type->info.lref.target) {
3588             ret = EXIT_FAILURE;
3589             LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Default value \"%s\" cannot be checked in an unresolved leafref.",
3590                    dflt);
3591             goto cleanup;
3592         }
3593         ret = check_default(&type->info.lref.target->type, &dflt, module, 0);
3594         if (!ret) {
3595             /* adopt possibly changed default value to its canonical form */
3596             if (*value) {
3597                 lydict_remove(ctx, *value);
3598                 *value = dflt;
3599                 dflt = NULL;
3600             }
3601         }
3602     } else {
3603         if (!lyp_parse_value(type, &node.value_str, NULL, &node, NULL, module, 1, 1)) {
3604             /* possible forward reference */
3605             ret = EXIT_FAILURE;
3606             if (base_tpdf) {
3607                 /* default value is defined in some base typedef */
3608                 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3609                         (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3610                     /* we have refined bits/enums */
3611                     LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL,
3612                            "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
3613                            dflt, type->parent->name, base_tpdf->name);
3614                 }
3615             }
3616         } else {
3617             /* success - adopt canonical form from the node into the default value */
3618             if (!ly_strequal(dflt, node.value_str, 1)) {
3619                 /* this can happen only if we have non-inherited default value,
3620                  * inherited default values are already in canonical form */
3621                 assert(ly_strequal(dflt, *value, 1));
3622 
3623                 lydict_remove(ctx, *value);
3624                 *value = node.value_str;
3625                 node.value_str = NULL;
3626             }
3627         }
3628     }
3629 
3630 cleanup:
3631     lyd_free_value(node.value, node.value_type, node.value_flags, type, node.value_str, NULL, NULL, NULL);
3632     lydict_remove(ctx, node.value_str);
3633     if (tpdf && node.schema) {
3634         free((char *)node.schema->name);
3635         free(node.schema);
3636     }
3637     lydict_remove(ctx, dflt);
3638 
3639     return ret;
3640 }
3641 
3642 /**
3643  * @brief Check a key for mandatory attributes. Logs directly.
3644  *
3645  * @param[in] key The key to check.
3646  * @param[in] flags What flags to check.
3647  * @param[in] list The list of all the keys.
3648  * @param[in] index Index of the key in the key list.
3649  * @param[in] name The name of the keys.
3650  * @param[in] len The name length.
3651  *
3652  * @return EXIT_SUCCESS on success, -1 on error.
3653  */
3654 static int
check_key(struct lys_node_list * list,int index,const char * name,int len)3655 check_key(struct lys_node_list *list, int index, const char *name, int len)
3656 {
3657     struct lys_node_leaf *key = list->keys[index];
3658     char *dup = NULL;
3659     int j;
3660     struct ly_ctx *ctx = list->module->ctx;
3661 
3662     /* existence */
3663     if (!key) {
3664         if (name[len] != '\0') {
3665             dup = strdup(name);
3666             LY_CHECK_ERR_RETURN(!dup, LOGMEM(ctx), -1);
3667             dup[len] = '\0';
3668             name = dup;
3669         }
3670         LOGVAL(ctx, LYE_KEY_MISS, LY_VLOG_LYS, list, name);
3671         free(dup);
3672         return -1;
3673     }
3674 
3675     /* uniqueness */
3676     for (j = index - 1; j >= 0; j--) {
3677         if (key == list->keys[j]) {
3678             LOGVAL(ctx, LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
3679             return -1;
3680         }
3681     }
3682 
3683     /* key is a leaf */
3684     if (key->nodetype != LYS_LEAF) {
3685         LOGVAL(ctx, LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
3686         return -1;
3687     }
3688 
3689     /* type of the leaf is not built-in empty */
3690     if (key->type.base == LY_TYPE_EMPTY && key->module->version < LYS_VERSION_1_1) {
3691         LOGVAL(ctx, LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
3692         return -1;
3693     }
3694 
3695     /* config attribute is the same as of the list */
3696     if ((key->flags & LYS_CONFIG_MASK) && (list->flags & LYS_CONFIG_MASK)
3697             && ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK))) {
3698         LOGVAL(ctx, LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
3699         return -1;
3700     }
3701 
3702     /* key is not placed from augment */
3703     if (key->parent->nodetype == LYS_AUGMENT) {
3704         LOGVAL(ctx, LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
3705         LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Key inserted from augment.");
3706         return -1;
3707     }
3708 
3709     /* key is not when/if-feature -conditional
3710      * note that j is really assigned in condition to distinguish when and if-feature, it is not supposed to be a comparison */
3711     j = 0;
3712     if (key->when || (key->iffeature_size && (j = 1))) {
3713         LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
3714         LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Key definition cannot depend on a \"%s\" condition.",
3715                j ? "if-feature" : "when");
3716         return -1;
3717     }
3718 
3719     return EXIT_SUCCESS;
3720 }
3721 
3722 /**
3723  * @brief Resolve (test the target exists) unique. Logs directly.
3724  *
3725  * @param[in] parent The parent node of the unique structure.
3726  * @param[in] uniq_str_path One path from the unique string.
3727  *
3728  * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3729  */
3730 int
resolve_unique(struct lys_node * parent,const char * uniq_str_path,uint8_t * trg_type)3731 resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
3732 {
3733     int rc;
3734     const struct lys_node *leaf = NULL;
3735     struct ly_ctx *ctx = parent->module->ctx;
3736 
3737     rc = resolve_descendant_schema_nodeid(uniq_str_path, *lys_child(parent, LYS_LEAF), LYS_LEAF, 1, &leaf);
3738     if (rc || !leaf) {
3739         if (rc) {
3740             LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3741             if (rc > 0) {
3742                 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_PREV, NULL, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
3743             } else if (rc == -2) {
3744                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Unique argument references list.");
3745             }
3746             rc = -1;
3747         } else {
3748             LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3749             LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Target leaf not found.");
3750             rc = EXIT_FAILURE;
3751         }
3752         goto error;
3753     }
3754     if (leaf->nodetype != LYS_LEAF) {
3755         LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3756         LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Target is not a leaf.");
3757         return -1;
3758     }
3759 
3760     /* check status */
3761     if (parent->nodetype != LYS_EXT && lyp_check_status(parent->flags, parent->module, parent->name,
3762                                                         leaf->flags, leaf->module, leaf->name, leaf)) {
3763         return -1;
3764     }
3765 
3766     /* check that all unique's targets are of the same config type */
3767     if (*trg_type) {
3768         if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3769             LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3770             LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
3771                    "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3772                    uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3773             return -1;
3774         }
3775     } else {
3776         /* first unique */
3777         if (leaf->flags & LYS_CONFIG_W) {
3778             *trg_type = 1;
3779         } else {
3780             *trg_type = 2;
3781         }
3782     }
3783 
3784     /* set leaf's unique flag */
3785     ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3786 
3787     return EXIT_SUCCESS;
3788 
3789 error:
3790 
3791     return rc;
3792 }
3793 
3794 void
unres_data_del(struct unres_data * unres,uint32_t i)3795 unres_data_del(struct unres_data *unres, uint32_t i)
3796 {
3797     /* there are items after the one deleted */
3798     if (i+1 < unres->count) {
3799         /* we only move the data, memory is left allocated, why bother */
3800         memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
3801 
3802     /* deleting the last item */
3803     } else if (i == 0) {
3804         free(unres->node);
3805         unres->node = NULL;
3806     }
3807 
3808     /* if there are no items after and it is not the last one, just move the counter */
3809     --unres->count;
3810 }
3811 
3812 /**
3813  * @brief Resolve (find) a data node from a specific module. Does not log.
3814  *
3815  * @param[in] mod Module to search in.
3816  * @param[in] name Name of the data node.
3817  * @param[in] nam_len Length of the name.
3818  * @param[in] start Data node to start the search from.
3819  * @param[in,out] parents Resolved nodes. If there are some parents,
3820  *                        they are replaced (!!) with the resolvents.
3821  *
3822  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3823  */
3824 static int
resolve_data(const struct lys_module * mod,const char * name,int nam_len,struct lyd_node * start,struct unres_data * parents)3825 resolve_data(const struct lys_module *mod, const char *name, int nam_len, struct lyd_node *start, struct unres_data *parents)
3826 {
3827     struct lyd_node *node;
3828     int flag;
3829     uint32_t i;
3830 
3831     if (!parents->count) {
3832         parents->count = 1;
3833         parents->node = malloc(sizeof *parents->node);
3834         LY_CHECK_ERR_RETURN(!parents->node, LOGMEM(mod->ctx), -1);
3835         parents->node[0] = NULL;
3836     }
3837     for (i = 0; i < parents->count;) {
3838         if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
3839             /* skip */
3840             ++i;
3841             continue;
3842         }
3843         flag = 0;
3844         LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
3845             if (lyd_node_module(node) == mod && !strncmp(node->schema->name, name, nam_len)
3846                     && node->schema->name[nam_len] == '\0') {
3847                 /* matching target */
3848                 if (!flag) {
3849                     /* put node instead of the current parent */
3850                     parents->node[i] = node;
3851                     flag = 1;
3852                 } else {
3853                     /* multiple matching, so create a new node */
3854                     ++parents->count;
3855                     parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
3856                     LY_CHECK_ERR_RETURN(!parents->node, LOGMEM(mod->ctx), EXIT_FAILURE);
3857                     parents->node[parents->count-1] = node;
3858                     ++i;
3859                 }
3860             }
3861         }
3862 
3863         if (!flag) {
3864             /* remove item from the parents list */
3865             unres_data_del(parents, i);
3866         } else {
3867             ++i;
3868         }
3869     }
3870 
3871     return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
3872 }
3873 
3874 static int
resolve_schema_leafref_valid_dep_flag(const struct lys_node * op_node,const struct lys_module * local_mod,const struct lys_node * first_node,int abs_path)3875 resolve_schema_leafref_valid_dep_flag(const struct lys_node *op_node, const struct lys_module *local_mod,
3876                                       const struct lys_node *first_node, int abs_path)
3877 {
3878     const struct lys_node *node;
3879 
3880     if (!op_node) {
3881         /* leafref pointing to a different module */
3882         if (local_mod != lys_node_module(first_node)) {
3883             return 1;
3884         }
3885     } else if (lys_parent(op_node)) {
3886         /* inner operation (notif/action) */
3887         if (abs_path) {
3888             return 1;
3889         } else {
3890             /* if first_node parent is not op_node, it is external */
3891             for (node = first_node; node && (node != op_node); node = lys_parent(node));
3892             if (!node) {
3893                 return 1;
3894             }
3895         }
3896     } else {
3897         /* top-level operation (notif/rpc) */
3898         if (op_node != first_node) {
3899             return 1;
3900         }
3901     }
3902 
3903     return 0;
3904 }
3905 
3906 /**
3907  * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
3908  *
3909  * @param[in] path Path to use.
3910  * @param[in] context_node Predicate context node (where the predicate is placed).
3911  * @param[in] parent Path context node (where the path begins/is placed).
3912  * @param[in] node_set Set where to add nodes whose parent chain must be implemented.
3913  *
3914  * @return 0 on forward reference, otherwise the number
3915  *         of characters successfully parsed,
3916  *         positive on success, negative on failure.
3917  */
3918 static int
resolve_schema_leafref_predicate(const char * path,const struct lys_node * context_node,struct lys_node * parent,struct ly_set * node_set)3919 resolve_schema_leafref_predicate(const char *path, const struct lys_node *context_node, struct lys_node *parent,
3920                                  struct ly_set *node_set)
3921 {
3922     const struct lys_module *trg_mod;
3923     const struct lys_node *src_node, *dst_node, *tmp_parent;
3924     struct lys_node_augment *last_aug;
3925     const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
3926     int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3927     int has_predicate, dest_parent_times, i, rc;
3928     struct ly_ctx *ctx = context_node->module->ctx;
3929 
3930     do {
3931         if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
3932                                       &pke_len, &has_predicate)) < 1) {
3933             LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent, path[-i], path - i);
3934             return -parsed + i;
3935         }
3936         parsed += i;
3937         path += i;
3938 
3939         /* source (must be leaf) */
3940         if (sour_pref) {
3941             trg_mod = lyp_get_module(lys_node_module(parent), NULL, 0, sour_pref, sour_pref_len, 0);
3942         } else {
3943             trg_mod = lys_node_module(parent);
3944         }
3945         rc = lys_getnext_data(trg_mod, context_node, source, sour_len, LYS_LEAF | LYS_LEAFLIST, LYS_GETNEXT_NOSTATECHECK,
3946                               &src_node);
3947         if (rc) {
3948             LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path-parsed);
3949             return 0;
3950         }
3951 
3952         /* destination */
3953         dest_parent_times = 0;
3954         pke_parsed = 0;
3955         if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3956                                      &dest_parent_times)) < 1) {
3957             LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent, path_key_expr[-i], path_key_expr-i);
3958             return -parsed;
3959         }
3960         pke_parsed += i;
3961 
3962         for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
3963             if (!dst_node) {
3964                 /* we went too much into parents, there is no parent anymore */
3965                 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path_key_expr);
3966                 return 0;
3967             }
3968 
3969             if (dst_node->parent && (dst_node->parent->nodetype == LYS_AUGMENT)
3970                     && !((struct lys_node_augment *)dst_node->parent)->target) {
3971                 /* we are in an unresolved augment, cannot evaluate */
3972                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, dst_node->parent,
3973                        "Cannot resolve leafref predicate \"%s\" because it is in an unresolved augment.", path_key_expr);
3974                 return 0;
3975             }
3976 
3977             /* path is supposed to be evaluated in data tree, so we have to skip
3978              * all schema nodes that cannot be instantiated in data tree */
3979             for (dst_node = lys_parent(dst_node);
3980                  dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
3981                  dst_node = lys_parent(dst_node));
3982         }
3983         while (1) {
3984             last_aug = NULL;
3985 
3986             if (dest_pref) {
3987                 trg_mod = lyp_get_module(lys_node_module(parent), NULL, 0, dest_pref, dest_pref_len, 0);
3988             } else {
3989                 trg_mod = lys_node_module(parent);
3990             }
3991 
3992             if (!trg_mod->implemented && dst_node) {
3993     get_next_augment:
3994                 last_aug = lys_getnext_target_aug(last_aug, trg_mod, dst_node);
3995             }
3996 
3997             tmp_parent = (last_aug ? (struct lys_node *)last_aug : dst_node);
3998             rc = lys_getnext_data(trg_mod, tmp_parent, dest, dest_len, LYS_CONTAINER | LYS_LIST | LYS_LEAF,
3999                                   LYS_GETNEXT_NOSTATECHECK, &dst_node);
4000             if (rc) {
4001                 if (last_aug) {
4002                     /* restore the correct augment target */
4003                     dst_node = last_aug->target;
4004                     goto get_next_augment;
4005                 }
4006                 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path_key_expr);
4007                 return 0;
4008             }
4009 
4010             if (pke_len == pke_parsed) {
4011                 break;
4012             }
4013 
4014             if ((i = parse_path_key_expr(path_key_expr + pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
4015                                          &dest_parent_times)) < 1) {
4016                 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent,
4017                        (path_key_expr + pke_parsed)[-i], (path_key_expr + pke_parsed) - i);
4018                 return -parsed;
4019             }
4020             pke_parsed += i;
4021         }
4022 
4023         /* check source - dest match */
4024         if (dst_node->nodetype != src_node->nodetype) {
4025             LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path - parsed);
4026             LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Destination node is not a %s, but a %s.",
4027                    strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
4028             return -parsed;
4029         }
4030 
4031         /* add both nodes into node set */
4032         ly_set_add(node_set, (void *)dst_node, 0);
4033         ly_set_add(node_set, (void *)src_node, 0);
4034     } while (has_predicate);
4035 
4036     return parsed;
4037 }
4038 
4039 static int
check_leafref_features(struct lys_type * type)4040 check_leafref_features(struct lys_type *type)
4041 {
4042     struct lys_node *iter;
4043     struct ly_set *src_parents, *trg_parents, *features;
4044     struct lys_node_augment *aug;
4045     struct ly_ctx *ctx = ((struct lys_tpdf *)type->parent)->module->ctx;
4046     unsigned int i, j, size, x;
4047     int ret = EXIT_SUCCESS;
4048 
4049     assert(type->parent);
4050 
4051     src_parents = ly_set_new();
4052     trg_parents = ly_set_new();
4053     features = ly_set_new();
4054 
4055     /* get parents chain of source (leafref) */
4056     for (iter = (struct lys_node *)type->parent; iter; iter = lys_parent(iter)) {
4057         if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
4058             continue;
4059         }
4060         if (iter->parent && (iter->parent->nodetype == LYS_AUGMENT)) {
4061             aug = (struct lys_node_augment *)iter->parent;
4062             if ((aug->module->implemented && (aug->flags & LYS_NOTAPPLIED)) || !aug->target) {
4063                 /* unresolved augment, wait until it's resolved */
4064                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, aug,
4065                        "Cannot check leafref \"%s\" if-feature consistency because of an unresolved augment.", type->info.lref.path);
4066                 ret = EXIT_FAILURE;
4067                 goto cleanup;
4068             }
4069             /* also add this augment */
4070             ly_set_add(src_parents, aug, LY_SET_OPT_USEASLIST);
4071         }
4072         ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
4073     }
4074     /* get parents chain of target */
4075     for (iter = (struct lys_node *)type->info.lref.target; iter; iter = lys_parent(iter)) {
4076         if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
4077             continue;
4078         }
4079         if (iter->parent && (iter->parent->nodetype == LYS_AUGMENT)) {
4080             aug = (struct lys_node_augment *)iter->parent;
4081             if ((aug->module->implemented && (aug->flags & LYS_NOTAPPLIED)) || !aug->target) {
4082                 /* unresolved augment, wait until it's resolved */
4083                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, aug,
4084                        "Cannot check leafref \"%s\" if-feature consistency because of an unresolved augment.", type->info.lref.path);
4085                 ret = EXIT_FAILURE;
4086                 goto cleanup;
4087             }
4088         }
4089         ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
4090     }
4091 
4092     /* compare the features used in if-feature statements in the rest of both
4093      * chains of parents. The set of features used for target must be a subset
4094      * of features used for the leafref. This is not a perfect, we should compare
4095      * the truth tables but it could require too much resources, so we simplify that */
4096     for (i = 0; i < src_parents->number; i++) {
4097         iter = src_parents->set.s[i]; /* shortcut */
4098         if (!iter->iffeature_size) {
4099             continue;
4100         }
4101         for (j = 0; j < iter->iffeature_size; j++) {
4102             resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
4103             for (; size; size--) {
4104                 if (!iter->iffeature[j].features[size - 1]) {
4105                     /* not yet resolved feature, postpone this check */
4106                     ret = EXIT_FAILURE;
4107                     goto cleanup;
4108                 }
4109                 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
4110             }
4111         }
4112     }
4113     x = features->number;
4114     for (i = 0; i < trg_parents->number; i++) {
4115         iter = trg_parents->set.s[i]; /* shortcut */
4116         if (!iter->iffeature_size) {
4117             continue;
4118         }
4119         for (j = 0; j < iter->iffeature_size; j++) {
4120             resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
4121             for (; size; size--) {
4122                 if (!iter->iffeature[j].features[size - 1]) {
4123                     /* not yet resolved feature, postpone this check */
4124                     ret = EXIT_FAILURE;
4125                     goto cleanup;
4126                 }
4127                 if ((unsigned)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
4128                     /* the feature is not present in features set of target's parents chain */
4129                     LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, type->parent,
4130                            "Leafref is not conditional based on \"%s\" feature as its target.",
4131                            iter->iffeature[j].features[size - 1]->name);
4132                     for (iter = type->info.lref.target->parent; iter && (iter->nodetype != LYS_USES); iter = lys_parent(iter));
4133                     if (iter) {
4134                         /* we are in a uses so there can still be a refine that will add an if-feature */
4135                         ret = EXIT_FAILURE;
4136                     } else {
4137                         ret = -1;
4138                     }
4139                     goto cleanup;
4140                 }
4141             }
4142         }
4143     }
4144 
4145 cleanup:
4146     ly_set_free(features);
4147     ly_set_free(src_parents);
4148     ly_set_free(trg_parents);
4149 
4150     return ret;
4151 }
4152 
4153 /**
4154  * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
4155  *
4156  * @param[in] path Path to use.
4157  * @param[in] parent_node Parent of the leafref.
4158  * @param[out] ret Pointer to the resolved schema node. Can be NULL.
4159  *
4160  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
4161  */
4162 static int
resolve_schema_leafref(struct lys_type * type,struct lys_node * parent,struct unres_schema * unres)4163 resolve_schema_leafref(struct lys_type *type, struct lys_node *parent, struct unres_schema *unres)
4164 {
4165     const struct lys_node *node, *op_node = NULL, *tmp_parent;
4166     struct ly_set *node_set;
4167     struct lys_node_augment *last_aug;
4168     const struct lys_module *tmp_mod, *cur_module;
4169     const char *id, *prefix, *name;
4170     int pref_len, nam_len, parent_times, has_predicate;
4171     int i, first_iter;
4172     struct ly_ctx *ctx = parent->module->ctx;
4173 
4174     /* first check that we are not in an unresolved augment */
4175     for (node = parent; lys_parent(node); node = lys_parent(node));
4176     if (node->parent && (node->parent->nodetype == LYS_AUGMENT)) {
4177         LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, node->parent,
4178                "Cannot resolve leafref \"%s\" because it is in an unresolved augment.", type->info.lref.path);
4179         return EXIT_FAILURE;
4180     }
4181 
4182     first_iter = 1;
4183     parent_times = 0;
4184     id = type->info.lref.path;
4185     node_set = ly_set_new();
4186     if (!node_set) {
4187         LOGMEM(ctx);
4188         return -1;
4189     }
4190 
4191     /* find operation schema we are in */
4192     for (op_node = lys_parent(parent);
4193         op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
4194         op_node = lys_parent(op_node));
4195 
4196     if (type->der->module) {
4197         /* typedef, take its local module */
4198         cur_module = type->der->module;
4199     } else {
4200         cur_module = lys_node_module(parent);
4201     }
4202     do {
4203         if ((i = parse_path_arg(cur_module, id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
4204             LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent, id[-i], &id[-i]);
4205             ly_set_free(node_set);
4206             return -1;
4207         }
4208         id += i;
4209 
4210         /* get the current module */
4211         tmp_mod = prefix ? lyp_get_module(cur_module, NULL, 0, prefix, pref_len, 0) : cur_module;
4212         if (!tmp_mod) {
4213             LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
4214             ly_set_free(node_set);
4215             return EXIT_FAILURE;
4216         }
4217         last_aug = NULL;
4218 
4219         if (first_iter) {
4220             if (parent_times == -1) {
4221                 /* use module data */
4222                 node = NULL;
4223 
4224             } else if (parent_times > 0) {
4225                 /* we are looking for the right parent */
4226                 for (i = 0, node = parent; i < parent_times; i++) {
4227                     /* path is supposed to be evaluated in data tree, so we have to skip
4228                      * all schema nodes that cannot be instantiated in data tree */
4229                     for (node = lys_parent(node);
4230                         node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
4231                         node = lys_parent(node));
4232 
4233                     if (!node) {
4234                         if (i == parent_times - 1) {
4235                             /* top-level */
4236                             break;
4237                         }
4238 
4239                         /* higher than top-level */
4240                         LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
4241                         ly_set_free(node_set);
4242                         return EXIT_FAILURE;
4243                     }
4244                 }
4245             } else {
4246                 LOGINT(ctx);
4247                 ly_set_free(node_set);
4248                 return -1;
4249             }
4250         }
4251 
4252         /* find the next node (either in unconnected augment or as a schema sibling, node is NULL for top-level node -
4253          * - useless to search for that in augments) */
4254         if (!tmp_mod->implemented && node) {
4255     get_next_augment:
4256             last_aug = lys_getnext_target_aug(last_aug, tmp_mod, node);
4257         }
4258 
4259         tmp_parent = (last_aug ? (struct lys_node *)last_aug : node);
4260         node = NULL;
4261         while ((node = lys_getnext(node, tmp_parent, tmp_mod, LYS_GETNEXT_NOSTATECHECK))) {
4262             if (lys_node_module(node) != lys_main_module(tmp_mod)) {
4263                 continue;
4264             }
4265             if (strncmp(node->name, name, nam_len) || node->name[nam_len]) {
4266                 continue;
4267             }
4268             /* match */
4269             break;
4270         }
4271         if (!node) {
4272             if (last_aug) {
4273                 /* restore the correct augment target */
4274                 node = last_aug->target;
4275                 goto get_next_augment;
4276             }
4277             LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
4278             ly_set_free(node_set);
4279             return EXIT_FAILURE;
4280         }
4281 
4282         if (first_iter) {
4283             /* find module whose data will actually contain this leafref */
4284             for (tmp_parent = parent; lys_parent(tmp_parent); tmp_parent = lys_parent(tmp_parent));
4285 
4286             /* set external dependency flag, we can decide based on the first found node */
4287             if (resolve_schema_leafref_valid_dep_flag(op_node, lys_node_module(tmp_parent), node, (parent_times == -1 ? 1 : 0))) {
4288                 parent->flags |= LYS_LEAFREF_DEP;
4289             }
4290             first_iter = 0;
4291         }
4292 
4293         if (has_predicate) {
4294             /* we have predicate, so the current result must be list */
4295             if (node->nodetype != LYS_LIST) {
4296                 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
4297                 ly_set_free(node_set);
4298                 return -1;
4299             }
4300 
4301             i = resolve_schema_leafref_predicate(id, node, parent, node_set);
4302             if (!i) {
4303                 ly_set_free(node_set);
4304                 return EXIT_FAILURE;
4305             } else if (i < 0) {
4306                 ly_set_free(node_set);
4307                 return -1;
4308             }
4309             id += i;
4310             has_predicate = 0;
4311         }
4312     } while (id[0]);
4313 
4314     /* the target must be leaf or leaf-list (in YANG 1.1 only) */
4315     if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
4316         LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
4317         LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Leafref target \"%s\" is not a leaf nor a leaf-list.", type->info.lref.path);
4318         ly_set_free(node_set);
4319         return -1;
4320     }
4321 
4322     /* check status */
4323     if (lyp_check_status(parent->flags, parent->module, parent->name,
4324                     node->flags, node->module, node->name, node)) {
4325         ly_set_free(node_set);
4326         return -1;
4327     }
4328 
4329     /* assign */
4330     type->info.lref.target = (struct lys_node_leaf *)node;
4331 
4332     /* add the target node into a set so its parent chain modules can be implemented */
4333     ly_set_add(node_set, (void *)node, 0);
4334 
4335     /* find the actual module of this leafref, it can be in a foreign augment */
4336     for (node = parent; lys_parent(node); node = lys_parent(node));
4337     if (lys_node_module(node)->implemented) {
4338         /* make all the modules in the path implemented */
4339         for (i = 0; (unsigned)i < node_set->number; ++i) {
4340             for (node = node_set->set.s[i]; node; node = lys_parent(node)) {
4341                 if (!lys_node_module(node)->implemented) {
4342                     lys_node_module(node)->implemented = 1;
4343                     if (unres_schema_add_node(lys_node_module(node), unres, NULL, UNRES_MOD_IMPLEMENT, NULL) == -1) {
4344                         ly_set_free(node_set);
4345                         return -1;
4346                     }
4347                 }
4348             }
4349 
4350             /* check leafref that it is allowed */
4351             if (lys_leaf_check_leafref((struct lys_node_leaf *)node_set->set.s[i], (struct lys_node *)type->parent)) {
4352                 ly_set_free(node_set);
4353                 return -1;
4354             }
4355         }
4356     }
4357     ly_set_free(node_set);
4358 
4359     /* check if leafref and its target are under common if-features */
4360     return check_leafref_features(type);
4361 }
4362 
4363 /**
4364  * @brief Compare 2 data node values.
4365  *
4366  * Comparison performed on canonical forms, the first value
4367  * is first transformed into canonical form.
4368  *
4369  * @param[in] node Leaf/leaf-list with these values.
4370  * @param[in] noncan_val Non-canonical value.
4371  * @param[in] noncan_val_len Length of \p noncal_val.
4372  * @param[in] can_val Canonical value.
4373  * @return 1 if equal, 0 if not, -1 on error (logged).
4374  */
4375 static int
valequal(struct lys_node * node,const char * noncan_val,int noncan_val_len,const char * can_val)4376 valequal(struct lys_node *node, const char *noncan_val, int noncan_val_len, const char *can_val)
4377 {
4378     int ret;
4379     struct lyd_node_leaf_list leaf;
4380     struct lys_node_leaf *sleaf = (struct lys_node_leaf*)node;
4381 
4382     /* dummy leaf */
4383     memset(&leaf, 0, sizeof leaf);
4384     leaf.value_str = lydict_insert(node->module->ctx, noncan_val, noncan_val_len);
4385 
4386 repeat:
4387     leaf.value_type = sleaf->type.base;
4388     leaf.schema = node;
4389 
4390     if (leaf.value_type == LY_TYPE_LEAFREF) {
4391         if (!sleaf->type.info.lref.target) {
4392             /* it should either be unresolved leafref (leaf.value_type are ORed flags) or it will be resolved */
4393             LOGINT(node->module->ctx);
4394             ret = -1;
4395             goto finish;
4396         }
4397         sleaf = sleaf->type.info.lref.target;
4398         goto repeat;
4399     } else {
4400         if (!lyp_parse_value(&sleaf->type, &leaf.value_str, NULL, &leaf, NULL, NULL, 0, 0)) {
4401             ret = -1;
4402             goto finish;
4403         }
4404     }
4405 
4406     if (!strcmp(leaf.value_str, can_val)) {
4407         ret = 1;
4408     } else {
4409         ret = 0;
4410     }
4411 
4412 finish:
4413     lydict_remove(node->module->ctx, leaf.value_str);
4414     return ret;
4415 }
4416 
4417 /**
4418  * @brief Resolve instance-identifier predicate in JSON data format.
4419  *        Does not log.
4420  *
4421  * @param[in] prev_mod Previous module to use in case there is no prefix.
4422  * @param[in] pred Predicate to use.
4423  * @param[in,out] node Node matching the restriction without
4424  *                     the predicate. If it does not satisfy the predicate,
4425  *                     it is set to NULL.
4426  *
4427  * @return Number of characters successfully parsed,
4428  *         positive on success, negative on failure.
4429  */
4430 static int
resolve_instid_predicate(const struct lys_module * prev_mod,const char * pred,struct lyd_node ** node,int cur_idx)4431 resolve_instid_predicate(const struct lys_module *prev_mod, const char *pred, struct lyd_node **node, int cur_idx)
4432 {
4433     /* ... /node[key=value] ... */
4434     struct lyd_node_leaf_list *key;
4435     struct lys_node_leaf **list_keys = NULL;
4436     struct lys_node_list *slist = NULL;
4437     const char *model, *name, *value;
4438     int mod_len, nam_len, val_len, i, has_predicate, parsed;
4439     struct ly_ctx *ctx = prev_mod->ctx;
4440 
4441     assert(pred && node && *node);
4442 
4443     parsed = 0;
4444     do {
4445         if ((i = parse_predicate(pred + parsed, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
4446             return -parsed + i;
4447         }
4448         parsed += i;
4449 
4450         if (!(*node)) {
4451             /* just parse it all */
4452             continue;
4453         }
4454 
4455         /* target */
4456         if (name[0] == '.') {
4457             /* leaf-list value */
4458             if ((*node)->schema->nodetype != LYS_LEAFLIST) {
4459                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects leaf-list, but have %s \"%s\".",
4460                        strnodetype((*node)->schema->nodetype), (*node)->schema->name);
4461                 parsed = -1;
4462                 goto cleanup;
4463             }
4464 
4465             /* check the value */
4466             if (!valequal((*node)->schema, value, val_len, ((struct lyd_node_leaf_list *)*node)->value_str)) {
4467                 *node = NULL;
4468                 goto cleanup;
4469             }
4470 
4471         } else if (isdigit(name[0])) {
4472             assert(!value);
4473 
4474             /* keyless list position */
4475             if ((*node)->schema->nodetype != LYS_LIST) {
4476                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list, but have %s \"%s\".",
4477                        strnodetype((*node)->schema->nodetype), (*node)->schema->name);
4478                 parsed = -1;
4479                 goto cleanup;
4480             }
4481 
4482             if (((struct lys_node_list *)(*node)->schema)->keys) {
4483                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list without keys, but have list \"%s\".",
4484                        (*node)->schema->name);
4485                 parsed = -1;
4486                 goto cleanup;
4487             }
4488 
4489             /* check the index */
4490             if (atoi(name) != cur_idx) {
4491                 *node = NULL;
4492                 goto cleanup;
4493             }
4494 
4495         } else {
4496             /* list key value */
4497             if ((*node)->schema->nodetype != LYS_LIST) {
4498                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list, but have %s \"%s\".",
4499                        strnodetype((*node)->schema->nodetype), (*node)->schema->name);
4500                 parsed = -1;
4501                 goto cleanup;
4502             }
4503             slist = (struct lys_node_list *)(*node)->schema;
4504 
4505             /* prepare key array */
4506             if (!list_keys) {
4507                 list_keys = malloc(slist->keys_size * sizeof *list_keys);
4508                 LY_CHECK_ERR_RETURN(!list_keys, LOGMEM(ctx), -1);
4509                 for (i = 0; i < slist->keys_size; ++i) {
4510                     list_keys[i] = slist->keys[i];
4511                 }
4512             }
4513 
4514             /* find the schema key leaf */
4515             for (i = 0; i < slist->keys_size; ++i) {
4516                 if (list_keys[i] && !strncmp(list_keys[i]->name, name, nam_len) && !list_keys[i]->name[nam_len]) {
4517                     break;
4518                 }
4519             }
4520             if (i == slist->keys_size) {
4521                 /* this list has no such key */
4522                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list with the key \"%.*s\","
4523                        " but list \"%s\" does not define it.", nam_len, name, slist->name);
4524                 parsed = -1;
4525                 goto cleanup;
4526             }
4527 
4528             /* check module */
4529             if (model) {
4530                 if (strncmp(list_keys[i]->module->name, model, mod_len) || list_keys[i]->module->name[mod_len]) {
4531                     LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects key \"%s\" from module \"%.*s\", not \"%s\".",
4532                            list_keys[i]->name, model, mod_len, list_keys[i]->module->name);
4533                     parsed = -1;
4534                     goto cleanup;
4535                 }
4536             } else {
4537                 if (list_keys[i]->module != prev_mod) {
4538                     LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects key \"%s\" from module \"%s\", not \"%s\".",
4539                            list_keys[i]->name, prev_mod->name, list_keys[i]->module->name);
4540                     parsed = -1;
4541                     goto cleanup;
4542                 }
4543             }
4544 
4545             /* find the actual data key */
4546             for (key = (struct lyd_node_leaf_list *)(*node)->child; key; key = (struct lyd_node_leaf_list *)key->next) {
4547                 if (key->schema == (struct lys_node *)list_keys[i]) {
4548                     break;
4549                 }
4550             }
4551             if (!key) {
4552                 /* list instance is missing a key? definitely should not happen */
4553                 LOGINT(ctx);
4554                 parsed = -1;
4555                 goto cleanup;
4556             }
4557 
4558             /* check the value */
4559             if (!valequal(key->schema, value, val_len, key->value_str)) {
4560                 *node = NULL;
4561                 /* we still want to parse the whole predicate */
4562                 continue;
4563             }
4564 
4565             /* everything is fine, mark this key as resolved */
4566             list_keys[i] = NULL;
4567         }
4568     } while (has_predicate);
4569 
4570     /* check that all list keys were specified */
4571     if (*node && list_keys) {
4572         for (i = 0; i < slist->keys_size; ++i) {
4573             if (list_keys[i]) {
4574                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing list key \"%s\".", list_keys[i]->name);
4575                 parsed = -1;
4576                 goto cleanup;
4577             }
4578         }
4579     }
4580 
4581 cleanup:
4582     free(list_keys);
4583     return parsed;
4584 }
4585 
4586 static int
check_xpath(struct lys_node * node,int check_place)4587 check_xpath(struct lys_node *node, int check_place)
4588 {
4589     struct lys_node *parent;
4590     struct lyxp_set set;
4591     enum int_log_opts prev_ilo;
4592 
4593     if (check_place) {
4594         parent = node;
4595         while (parent) {
4596             if (parent->nodetype == LYS_GROUPING) {
4597                 /* unresolved grouping, skip for now (will be checked later) */
4598                 return EXIT_SUCCESS;
4599             }
4600             if (parent->nodetype == LYS_AUGMENT) {
4601                 if (!((struct lys_node_augment *)parent)->target) {
4602                     /* unresolved augment, skip for now (will be checked later) */
4603                     return EXIT_FAILURE;
4604                 } else {
4605                     parent = ((struct lys_node_augment *)parent)->target;
4606                     continue;
4607                 }
4608             }
4609             parent = parent->parent;
4610         }
4611     }
4612 
4613     memset(&set, 0, sizeof set);
4614 
4615     /* produce just warnings */
4616     ly_ilo_change(NULL, ILO_ERR2WRN, &prev_ilo, NULL);
4617     lyxp_node_atomize(node, &set, 1);
4618     ly_ilo_restore(NULL, prev_ilo, NULL, 0);
4619 
4620     if (set.val.snodes) {
4621         free(set.val.snodes);
4622     }
4623     return EXIT_SUCCESS;
4624 }
4625 
4626 static int
check_leafref_config(struct lys_node_leaf * leaf,struct lys_type * type)4627 check_leafref_config(struct lys_node_leaf *leaf, struct lys_type *type)
4628 {
4629     unsigned int i;
4630 
4631     if (type->base == LY_TYPE_LEAFREF) {
4632         if ((leaf->flags & LYS_CONFIG_W) && type->info.lref.target && type->info.lref.req != -1 &&
4633                 (type->info.lref.target->flags & LYS_CONFIG_R)) {
4634             LOGVAL(leaf->module->ctx, LYE_SPEC, LY_VLOG_LYS, leaf, "The leafref %s is config but refers to a non-config %s.",
4635                    strnodetype(leaf->nodetype), strnodetype(type->info.lref.target->nodetype));
4636             return -1;
4637         }
4638         /* we can skip the test in case the leafref is not yet resolved. In that case the test is done in the time
4639          * of leafref resolving (lys_leaf_add_leafref_target()) */
4640     } else if (type->base == LY_TYPE_UNION) {
4641         for (i = 0; i < type->info.uni.count; i++) {
4642             if (check_leafref_config(leaf, &type->info.uni.types[i])) {
4643                 return -1;
4644             }
4645         }
4646     }
4647     return 0;
4648 }
4649 
4650 /**
4651  * @brief Passes config flag down to children, skips nodes without config flags.
4652  * Logs.
4653  *
4654  * @param[in] node Siblings and their children to have flags changed.
4655  * @param[in] clear Flag to clear all config flags if parent is LYS_NOTIF, LYS_INPUT, LYS_OUTPUT, LYS_RPC.
4656  * @param[in] flags Flags to assign to all the nodes.
4657  * @param[in,out] unres List of unresolved items.
4658  *
4659  * @return 0 on success, -1 on error.
4660  */
4661 int
inherit_config_flag(struct lys_node * node,int flags,int clear)4662 inherit_config_flag(struct lys_node *node, int flags, int clear)
4663 {
4664     struct lys_node_leaf *leaf;
4665     struct ly_ctx *ctx;
4666 
4667     if (!node) {
4668         return 0;
4669     }
4670 
4671     assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
4672     ctx = node->module->ctx;
4673 
4674     LY_TREE_FOR(node, node) {
4675         if (clear) {
4676             node->flags &= ~LYS_CONFIG_MASK;
4677             node->flags &= ~LYS_CONFIG_SET;
4678         } else {
4679             if (node->flags & LYS_CONFIG_SET) {
4680                 /* skip nodes with an explicit config value */
4681                 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4682                     LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, node, "true", "config");
4683                     LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "State nodes cannot have configuration nodes as children.");
4684                     return -1;
4685                 }
4686                 continue;
4687             }
4688 
4689             if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4690                 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4691                 /* check that configuration lists have keys */
4692                 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
4693                         && !((struct lys_node_list *)node)->keys_size) {
4694                     LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4695                     return -1;
4696                 }
4697             }
4698         }
4699         if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
4700             if (inherit_config_flag(node->child, flags, clear)) {
4701                 return -1;
4702             }
4703         } else if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4704             leaf = (struct lys_node_leaf *)node;
4705             if (check_leafref_config(leaf, &leaf->type)) {
4706                 return -1;
4707             }
4708         }
4709     }
4710 
4711     return 0;
4712 }
4713 
4714 /**
4715  * @brief Resolve augment target. Logs directly.
4716  *
4717  * @param[in] aug Augment to use.
4718  * @param[in] uses Parent where to start the search in. If set, uses augment, if not, standalone augment.
4719  * @param[in,out] unres List of unresolved items.
4720  *
4721  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
4722  */
4723 static int
resolve_augment(struct lys_node_augment * aug,struct lys_node * uses,struct unres_schema * unres)4724 resolve_augment(struct lys_node_augment *aug, struct lys_node *uses, struct unres_schema *unres)
4725 {
4726     int rc;
4727     struct lys_node *sub, *next;
4728     struct lys_module *mod;
4729     struct ly_set *set;
4730     struct ly_ctx *ctx;
4731     struct lys_node_case *c;
4732 
4733     assert(aug);
4734     mod = lys_main_module(aug->module);
4735     ctx = mod->ctx;
4736 
4737     /* set it as not applied for now */
4738     aug->flags |= LYS_NOTAPPLIED;
4739 
4740     /* it can already be resolved in case we returned EXIT_FAILURE from if block below */
4741     if (!aug->target) {
4742         /* resolve target node */
4743         rc = resolve_schema_nodeid(aug->target_name, uses, (uses ? NULL : lys_node_module((struct lys_node *)aug)), &set, 0, 0);
4744         if (rc == -1) {
4745             LOGVAL(ctx, LYE_PATH, LY_VLOG_LYS, aug);
4746             return -1;
4747         }
4748         if (!set) {
4749             LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4750             return EXIT_FAILURE;
4751         }
4752         aug->target = set->set.s[0];
4753         ly_set_free(set);
4754     }
4755 
4756     /* make this module implemented if the target module is (if the target is in an unimplemented module,
4757      * it is fine because when we will be making that module implemented, its augment will be applied
4758      * and that augment target module made implemented, recursively) */
4759     if (mod->implemented && !lys_node_module(aug->target)->implemented) {
4760         lys_node_module(aug->target)->implemented = 1;
4761         if (unres_schema_add_node(lys_node_module(aug->target), unres, NULL, UNRES_MOD_IMPLEMENT, NULL) == -1) {
4762             return -1;
4763         }
4764     }
4765 
4766     /* check for mandatory nodes - if the target node is in another module
4767      * the added nodes cannot be mandatory
4768      */
4769     if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug->target))
4770             && (rc = lyp_check_mandatory_augment(aug, aug->target))) {
4771         return rc;
4772     }
4773 
4774     /* check augment target type and then augment nodes type */
4775     if (aug->target->nodetype & (LYS_CONTAINER | LYS_LIST)) {
4776         LY_TREE_FOR(aug->child, sub) {
4777             if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES
4778                                    | LYS_CHOICE | LYS_ACTION | LYS_NOTIF))) {
4779                 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4780                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
4781                        strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
4782                 return -1;
4783             }
4784         }
4785     } else if (aug->target->nodetype & (LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
4786         LY_TREE_FOR(aug->child, sub) {
4787             if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
4788                 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4789                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
4790                        strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
4791                 return -1;
4792             }
4793         }
4794     } else if (aug->target->nodetype == LYS_CHOICE) {
4795         LY_TREE_FOR(aug->child, sub) {
4796             if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
4797                 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4798                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
4799                        strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
4800                 return -1;
4801             }
4802         }
4803     } else {
4804         LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
4805         LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Invalid augment target node type \"%s\".", strnodetype(aug->target->nodetype));
4806         return -1;
4807     }
4808 
4809     /* check identifier uniqueness as in lys_node_addchild() */
4810     LY_TREE_FOR(aug->child, sub) {
4811         if (lys_check_id(sub, aug->target, NULL)) {
4812             return -1;
4813         }
4814     }
4815 
4816     if (aug->target->nodetype == LYS_CHOICE) {
4817         /* in the case of implicit cases, we have to create the nodes representing them
4818          * to serve as a target of the augments, they won't be printed, but they are expected in the tree */
4819         LY_TREE_FOR_SAFE(aug->child, next, sub) {
4820             if (sub->nodetype == LYS_CASE) {
4821                 /* explicit case */
4822                 continue;
4823             }
4824 
4825             c = calloc(1, sizeof *c);
4826             LY_CHECK_ERR_RETURN(!c, LOGMEM(ctx), EXIT_FAILURE);
4827             c->name = lydict_insert(ctx, sub->name, 0);
4828             c->flags = LYS_IMPLICIT | (sub->flags & LYS_CONFIG_MASK);
4829             c->module = sub->module;
4830             c->nodetype = LYS_CASE;
4831             c->parent = sub->parent;
4832             c->prev = sub->prev != sub ? sub->prev : (struct lys_node*)c;
4833             if (c->prev->next) {
4834                 c->prev->next = (struct lys_node*)c;
4835             } else {
4836                 c->parent->child = (struct lys_node*)c;
4837             }
4838             c->next = sub->next;
4839             if (c->next) {
4840                 c->next->prev = (struct lys_node*)c;
4841             } else {
4842                 c->parent->child->prev = (struct lys_node*)c;
4843             }
4844             c->child = sub;
4845             sub->prev = sub;
4846             sub->next = NULL;
4847             sub->parent = (struct lys_node*)c;
4848         }
4849     }
4850 
4851     LY_TREE_DFS_BEGIN(aug->child, next, sub) {
4852         if (sub->nodetype == LYS_ACTION) {
4853             /* we need to check parents */
4854             for (sub = aug->target; sub; sub = lys_parent(sub)) {
4855                 if ((sub->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF))
4856                         || ((sub->nodetype == LYS_LIST) && !((struct lys_node_list *)sub)->keys)) {
4857                     LOGVAL(ctx, LYE_INPAR, LY_VLOG_LYS, aug->target, strnodetype(sub->nodetype), "action");
4858                     LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4859                     return -1;
4860                 }
4861             }
4862             break;
4863         }
4864         LY_TREE_DFS_END(aug->child, next, sub);
4865     }
4866 
4867     if (!aug->child) {
4868         /* empty augment, nothing to connect, but it is techincally applied */
4869         LOGWRN(ctx, "Augment \"%s\" without children.", aug->target_name);
4870         aug->flags &= ~LYS_NOTAPPLIED;
4871     } else if ((aug->parent || mod->implemented) && apply_aug(aug, unres)) {
4872         /* we try to connect the augment only in case the module is implemented or
4873          * the augment applies on the used grouping, anyway we failed here */
4874         return -1;
4875     }
4876 
4877     return EXIT_SUCCESS;
4878 }
4879 
4880 static int
resolve_extension(struct unres_ext * info,struct lys_ext_instance ** ext,struct unres_schema * unres)4881 resolve_extension(struct unres_ext *info, struct lys_ext_instance **ext, struct unres_schema *unres)
4882 {
4883     enum LY_VLOG_ELEM vlog_type;
4884     void *vlog_node;
4885     unsigned int i, j;
4886     struct lys_ext *e;
4887     char *ext_name, *ext_prefix, *tmp;
4888     struct lyxml_elem *next_yin, *yin;
4889     const struct lys_module *mod;
4890     struct lys_ext_instance *tmp_ext;
4891     struct ly_ctx *ctx = NULL;
4892     LYEXT_TYPE etype;
4893     int rt = 0;
4894 
4895     switch (info->parent_type) {
4896     case LYEXT_PAR_NODE:
4897         vlog_node = info->parent;
4898         vlog_type = LY_VLOG_LYS;
4899         break;
4900     case LYEXT_PAR_MODULE:
4901     case LYEXT_PAR_IMPORT:
4902     case LYEXT_PAR_INCLUDE:
4903         vlog_node = NULL;
4904         vlog_type = LY_VLOG_LYS;
4905         break;
4906     default:
4907         vlog_node = NULL;
4908         vlog_type = LY_VLOG_NONE;
4909         break;
4910     }
4911 
4912     if (info->datatype == LYS_IN_YIN) {
4913         /* YIN */
4914 
4915         /* get the module where the extension is supposed to be defined */
4916         mod = lyp_get_import_module_ns(info->mod, info->data.yin->ns->value);
4917         if (!mod) {
4918             LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
4919             return EXIT_FAILURE;
4920         }
4921         ctx = mod->ctx;
4922 
4923         /* find the extension definition */
4924         e = NULL;
4925         for (i = 0; i < mod->extensions_size; i++) {
4926             if (ly_strequal(mod->extensions[i].name, info->data.yin->name, 1)) {
4927                 e = &mod->extensions[i];
4928                 break;
4929             }
4930         }
4931         /* try submodules */
4932         for (j = 0; !e && j < mod->inc_size; j++) {
4933             for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4934                 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, info->data.yin->name, 1)) {
4935                     e = &mod->inc[j].submodule->extensions[i];
4936                     break;
4937                 }
4938             }
4939         }
4940         if (!e) {
4941             LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
4942             return EXIT_FAILURE;
4943         }
4944 
4945         /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
4946 
4947         if (e->plugin && e->plugin->check_position) {
4948             /* common part - we have plugin with position checking function, use it first */
4949             rt = (*e->plugin->check_position)(info->parent, info->parent_type, info->substmt);
4950             if (rt == 1) {
4951                 /* extension is not allowed here */
4952                 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, e->name);
4953                 return -1;
4954             } else if (rt == 2) {
4955                 *ext = NULL;
4956                 return EXIT_SUCCESS;
4957             }
4958         }
4959 
4960         /* extension type-specific part - allocation */
4961         if (e->plugin) {
4962             etype = e->plugin->type;
4963         } else {
4964             /* default type */
4965             etype = LYEXT_FLAG;
4966         }
4967         switch (etype) {
4968         case LYEXT_FLAG:
4969             (*ext) = calloc(1, sizeof(struct lys_ext_instance));
4970             break;
4971         case LYEXT_COMPLEX:
4972             (*ext) = calloc(1, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
4973             break;
4974         case LYEXT_ERR:
4975             /* we never should be here */
4976             LOGINT(ctx);
4977             return -1;
4978         }
4979         LY_CHECK_ERR_RETURN(!*ext, LOGMEM(ctx), -1);
4980 
4981         /* common part for all extension types */
4982         (*ext)->def = e;
4983         (*ext)->parent = info->parent;
4984         (*ext)->parent_type = info->parent_type;
4985         (*ext)->insubstmt = info->substmt;
4986         (*ext)->insubstmt_index = info->substmt_index;
4987         (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
4988         (*ext)->flags |= e->plugin ? e->plugin->flags : 0;
4989 
4990         if (e->argument) {
4991             if (!(e->flags & LYS_YINELEM)) {
4992                 (*ext)->arg_value = lyxml_get_attr(info->data.yin, e->argument, NULL);
4993                 if (!(*ext)->arg_value) {
4994                     LOGVAL(ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, info->data.yin->name);
4995                     return -1;
4996                 }
4997 
4998                 (*ext)->arg_value = lydict_insert(mod->ctx, (*ext)->arg_value, 0);
4999             } else {
5000                 LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
5001                     if (ly_strequal(yin->name, e->argument, 1)) {
5002                         (*ext)->arg_value = lydict_insert(mod->ctx, yin->content, 0);
5003                         lyxml_free(mod->ctx, yin);
5004                         break;
5005                     }
5006                 }
5007             }
5008         }
5009 
5010         if ((*ext)->flags & LYEXT_OPT_VALID &&
5011             (info->parent_type == LYEXT_PAR_NODE || info->parent_type == LYEXT_PAR_TPDF)) {
5012             ((struct lys_node *)info->parent)->flags |= LYS_VALID_EXT;
5013         }
5014 
5015         (*ext)->nodetype = LYS_EXT;
5016         (*ext)->module = info->mod;
5017 
5018         /* extension type-specific part - parsing content */
5019         switch (etype) {
5020         case LYEXT_FLAG:
5021             LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
5022                 if (!yin->ns) {
5023                     /* garbage */
5024                     lyxml_free(mod->ctx, yin);
5025                     continue;
5026                 } else if (!strcmp(yin->ns->value, LY_NSYIN)) {
5027                     /* standard YANG statements are not expected here */
5028                     LOGVAL(ctx, LYE_INCHILDSTMT, vlog_type, vlog_node, yin->name, info->data.yin->name);
5029                     return -1;
5030                 } else if (yin->ns == info->data.yin->ns &&
5031                         (e->flags & LYS_YINELEM) && ly_strequal(yin->name, e->argument, 1)) {
5032                     /* we have the extension's argument */
5033                     if ((*ext)->arg_value) {
5034                         LOGVAL(ctx, LYE_TOOMANY, vlog_type, vlog_node, yin->name, info->data.yin->name);
5035                         return -1;
5036                     }
5037                     (*ext)->arg_value = yin->content;
5038                     yin->content = NULL;
5039                     lyxml_free(mod->ctx, yin);
5040                 } else {
5041                     /* extension instance */
5042                     if (lyp_yin_parse_subnode_ext(info->mod, *ext, LYEXT_PAR_EXTINST, yin,
5043                                                   LYEXT_SUBSTMT_SELF, 0, unres)) {
5044                         return -1;
5045                     }
5046 
5047                     continue;
5048                 }
5049             }
5050             break;
5051         case LYEXT_COMPLEX:
5052             ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
5053             if (lyp_yin_parse_complex_ext(info->mod, (struct lys_ext_instance_complex*)(*ext), info->data.yin, unres)) {
5054                 /* TODO memory cleanup */
5055                 return -1;
5056             }
5057             break;
5058         default:
5059             break;
5060         }
5061 
5062         /* TODO - lyext_check_result_clb, other than LYEXT_FLAG plugins */
5063 
5064     } else {
5065         /* YANG */
5066 
5067         ext_prefix = (char *)(*ext)->def;
5068         tmp = strchr(ext_prefix, ':');
5069         if (!tmp) {
5070             LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
5071             goto error;
5072         }
5073         ext_name = tmp + 1;
5074 
5075         /* get the module where the extension is supposed to be defined */
5076         mod = lyp_get_module(info->mod, ext_prefix, tmp - ext_prefix, NULL, 0, 0);
5077         if (!mod) {
5078             LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
5079             return EXIT_FAILURE;
5080         }
5081         ctx = mod->ctx;
5082 
5083         /* find the extension definition */
5084         e = NULL;
5085         for (i = 0; i < mod->extensions_size; i++) {
5086             if (ly_strequal(mod->extensions[i].name, ext_name, 0)) {
5087                 e = &mod->extensions[i];
5088                 break;
5089             }
5090         }
5091         /* try submodules */
5092         for (j = 0; !e && j < mod->inc_size; j++) {
5093             for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
5094                 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, ext_name, 0)) {
5095                     e = &mod->inc[j].submodule->extensions[i];
5096                     break;
5097                 }
5098             }
5099         }
5100         if (!e) {
5101             LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
5102             return EXIT_FAILURE;
5103         }
5104 
5105         (*ext)->flags &= ~LYEXT_OPT_YANG;
5106         (*ext)->def = NULL;
5107 
5108         /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
5109 
5110         if (e->plugin && e->plugin->check_position) {
5111             /* common part - we have plugin with position checking function, use it first */
5112             rt = (*e->plugin->check_position)(info->parent, info->parent_type, info->substmt);
5113             if (rt == 1) {
5114                 /* extension is not allowed here */
5115                 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, e->name);
5116                 goto error;
5117             } else if (rt == 2) {
5118                 lys_extension_instances_free(ctx, (*ext)->ext, (*ext)->ext_size, NULL);
5119                 lydict_remove(ctx, (*ext)->arg_value);
5120                 free(*ext);
5121                 *ext = NULL;
5122                 free(ext_prefix);
5123                 return EXIT_SUCCESS;
5124             }
5125         }
5126 
5127         if (e->argument && !(*ext)->arg_value) {
5128             LOGVAL(ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, ext_name);
5129             goto error;
5130         }
5131 
5132         /* extension common part */
5133         (*ext)->def = e;
5134         (*ext)->parent = info->parent;
5135         (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
5136         (*ext)->flags |= e->plugin ? e->plugin->flags : 0;
5137 
5138         if ((*ext)->flags & LYEXT_OPT_VALID &&
5139             (info->parent_type == LYEXT_PAR_NODE || info->parent_type == LYEXT_PAR_TPDF)) {
5140             ((struct lys_node *)info->parent)->flags |= LYS_VALID_EXT;
5141         }
5142 
5143         (*ext)->module = info->mod;
5144         (*ext)->nodetype = LYS_EXT;
5145 
5146         /* extension type-specific part */
5147         if (e->plugin) {
5148             etype = e->plugin->type;
5149         } else {
5150             /* default type */
5151             etype = LYEXT_FLAG;
5152         }
5153         switch (etype) {
5154         case LYEXT_FLAG:
5155             /* nothing change */
5156             break;
5157         case LYEXT_COMPLEX:
5158             tmp_ext = realloc(*ext, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
5159             LY_CHECK_ERR_GOTO(!tmp_ext, LOGMEM(ctx), error);
5160             memset((char *)tmp_ext + offsetof(struct lys_ext_instance_complex, content), 0,
5161                    ((struct lyext_plugin_complex*)e->plugin)->instance_size - offsetof(struct lys_ext_instance_complex, content));
5162             (*ext) = tmp_ext;
5163             ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
5164             if (info->data.yang) {
5165                 *tmp = ':';
5166                 if (yang_parse_ext_substatement(info->mod, unres, info->data.yang->ext_substmt, ext_prefix,
5167                                                 (struct lys_ext_instance_complex*)(*ext))) {
5168                     goto error;
5169                 }
5170                 if (yang_fill_extcomplex_module(info->mod->ctx, (struct lys_ext_instance_complex*)(*ext), ext_prefix,
5171                                                 info->data.yang->ext_modules, info->mod->implemented)) {
5172                     goto error;
5173                 }
5174             }
5175             if (lyp_mand_check_ext((struct lys_ext_instance_complex*)(*ext), ext_prefix)) {
5176                 goto error;
5177             }
5178             break;
5179         case LYEXT_ERR:
5180             /* we never should be here */
5181             LOGINT(ctx);
5182             goto error;
5183         }
5184 
5185         if (yang_check_ext_instance(info->mod, &(*ext)->ext, &(*ext)->ext_size, *ext, unres)) {
5186             goto error;
5187         }
5188 
5189         free(ext_prefix);
5190     }
5191 
5192     return EXIT_SUCCESS;
5193 error:
5194     free(ext_prefix);
5195     return -1;
5196 }
5197 
5198 /**
5199  * @brief Resolve (find) choice default case. Does not log.
5200  *
5201  * @param[in] choic Choice to use.
5202  * @param[in] dflt Name of the default case.
5203  *
5204  * @return Pointer to the default node or NULL.
5205  */
5206 static struct lys_node *
resolve_choice_dflt(struct lys_node_choice * choic,const char * dflt)5207 resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
5208 {
5209     struct lys_node *child, *ret;
5210 
5211     LY_TREE_FOR(choic->child, child) {
5212         if (child->nodetype == LYS_USES) {
5213             ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
5214             if (ret) {
5215                 return ret;
5216             }
5217         }
5218 
5219         if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
5220                 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
5221             return child;
5222         }
5223     }
5224 
5225     return NULL;
5226 }
5227 
5228 /**
5229  * @brief Resolve uses, apply augments, refines. Logs directly.
5230  *
5231  * @param[in] uses Uses to use.
5232  * @param[in,out] unres List of unresolved items.
5233  *
5234  * @return EXIT_SUCCESS on success, -1 on error.
5235  */
5236 static int
resolve_uses(struct lys_node_uses * uses,struct unres_schema * unres)5237 resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
5238 {
5239     struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
5240     struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
5241     struct lys_node *node_aux, *parent, *tmp;
5242     struct lys_node_leaflist *llist;
5243     struct lys_node_leaf *leaf;
5244     struct lys_refine *rfn;
5245     struct lys_restr *must, **old_must;
5246     struct lys_iffeature *iff, **old_iff;
5247     int i, j, k, rc;
5248     uint8_t size, *old_size;
5249     unsigned int usize, usize1, usize2;
5250 
5251     assert(uses->grp);
5252 
5253     /* check that the grouping is resolved (no unresolved uses inside) */
5254     assert(!uses->grp->unres_count);
5255 
5256     /* copy the data nodes from grouping into the uses context */
5257     LY_TREE_FOR(uses->grp->child, node_aux) {
5258         if (node_aux->nodetype & LYS_GROUPING) {
5259             /* do not instantiate groupings from groupings */
5260             continue;
5261         }
5262         node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, unres, 0);
5263         if (!node) {
5264             LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
5265             LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Copying data from grouping failed.");
5266             goto fail;
5267         }
5268         /* test the name of siblings */
5269         LY_TREE_FOR((uses->parent) ? *lys_child(uses->parent, LYS_USES) : lys_main_module(uses->module)->data, tmp) {
5270             if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
5271                 goto fail;
5272             }
5273         }
5274     }
5275 
5276     /* we managed to copy the grouping, the rest must be possible to resolve */
5277 
5278     if (uses->refine_size) {
5279         refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
5280         LY_CHECK_ERR_GOTO(!refine_nodes, LOGMEM(ctx), fail);
5281     }
5282 
5283     /* apply refines */
5284     for (i = 0; i < uses->refine_size; i++) {
5285         rfn = &uses->refine[i];
5286         rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child,
5287                                               LYS_NO_RPC_NOTIF_NODE | LYS_ACTION | LYS_NOTIF,
5288                                               0, (const struct lys_node **)&node);
5289         if (rc || !node) {
5290             LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
5291             goto fail;
5292         }
5293 
5294         if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
5295             LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
5296             LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Refine substatements not applicable to the target-node.");
5297             goto fail;
5298         }
5299         refine_nodes[i] = node;
5300 
5301         /* description on any nodetype */
5302         if (rfn->dsc) {
5303             lydict_remove(ctx, node->dsc);
5304             node->dsc = lydict_insert(ctx, rfn->dsc, 0);
5305         }
5306 
5307         /* reference on any nodetype */
5308         if (rfn->ref) {
5309             lydict_remove(ctx, node->ref);
5310             node->ref = lydict_insert(ctx, rfn->ref, 0);
5311         }
5312 
5313         /* config on any nodetype,
5314          * in case of notification or rpc/action, the config is not applicable (there is no config status) */
5315         if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
5316             node->flags &= ~LYS_CONFIG_MASK;
5317             node->flags |= (rfn->flags & LYS_CONFIG_MASK);
5318         }
5319 
5320         /* default value ... */
5321         if (rfn->dflt_size) {
5322             if (node->nodetype == LYS_LEAF) {
5323                 /* leaf */
5324                 leaf = (struct lys_node_leaf *)node;
5325 
5326                 /* replace default value */
5327                 lydict_remove(ctx, leaf->dflt);
5328                 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
5329 
5330                 /* check the default value */
5331                 if (unres_schema_add_node(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT,
5332                                           (struct lys_node *)(&leaf->dflt)) == -1) {
5333                     goto fail;
5334                 }
5335             } else if (node->nodetype == LYS_LEAFLIST) {
5336                 /* leaf-list */
5337                 llist = (struct lys_node_leaflist *)node;
5338 
5339                 /* remove complete set of defaults in target */
5340                 for (j = 0; j < llist->dflt_size; j++) {
5341                     lydict_remove(ctx, llist->dflt[j]);
5342                 }
5343                 free(llist->dflt);
5344 
5345                 /* copy the default set from refine */
5346                 llist->dflt = malloc(rfn->dflt_size * sizeof *llist->dflt);
5347                 LY_CHECK_ERR_GOTO(!llist->dflt, LOGMEM(ctx), fail);
5348                 llist->dflt_size = rfn->dflt_size;
5349                 for (j = 0; j < llist->dflt_size; j++) {
5350                     llist->dflt[j] = lydict_insert(ctx, rfn->dflt[j], 0);
5351                 }
5352 
5353                 /* check default value */
5354                 for (j = 0; j < llist->dflt_size; j++) {
5355                     if (unres_schema_add_node(llist->module, unres, &llist->type, UNRES_TYPE_DFLT,
5356                                               (struct lys_node *)(&llist->dflt[j])) == -1) {
5357                         goto fail;
5358                     }
5359                 }
5360             }
5361         }
5362 
5363         /* mandatory on leaf, anyxml or choice */
5364         if (rfn->flags & LYS_MAND_MASK) {
5365             /* remove current value */
5366             node->flags &= ~LYS_MAND_MASK;
5367 
5368             /* set new value */
5369             node->flags |= (rfn->flags & LYS_MAND_MASK);
5370 
5371             if (rfn->flags & LYS_MAND_TRUE) {
5372                 /* check if node has default value */
5373                 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
5374                     LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses,
5375                            "The \"mandatory\" statement is forbidden on leaf with \"default\".");
5376                     goto fail;
5377                 }
5378                 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
5379                     LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses,
5380                            "The \"mandatory\" statement is forbidden on choices with \"default\".");
5381                     goto fail;
5382                 }
5383             }
5384         }
5385 
5386         /* presence on container */
5387         if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
5388             lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
5389             ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
5390         }
5391 
5392         /* min/max-elements on list or leaf-list */
5393         if (node->nodetype == LYS_LIST) {
5394             if (rfn->flags & LYS_RFN_MINSET) {
5395                 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
5396             }
5397             if (rfn->flags & LYS_RFN_MAXSET) {
5398                 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
5399             }
5400         } else if (node->nodetype == LYS_LEAFLIST) {
5401             if (rfn->flags & LYS_RFN_MINSET) {
5402                 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
5403             }
5404             if (rfn->flags & LYS_RFN_MAXSET) {
5405                 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
5406             }
5407         }
5408 
5409         /* must in leaf, leaf-list, list, container or anyxml */
5410         if (rfn->must_size) {
5411             switch (node->nodetype) {
5412             case LYS_LEAF:
5413                 old_size = &((struct lys_node_leaf *)node)->must_size;
5414                 old_must = &((struct lys_node_leaf *)node)->must;
5415                 break;
5416             case LYS_LEAFLIST:
5417                 old_size = &((struct lys_node_leaflist *)node)->must_size;
5418                 old_must = &((struct lys_node_leaflist *)node)->must;
5419                 break;
5420             case LYS_LIST:
5421                 old_size = &((struct lys_node_list *)node)->must_size;
5422                 old_must = &((struct lys_node_list *)node)->must;
5423                 break;
5424             case LYS_CONTAINER:
5425                 old_size = &((struct lys_node_container *)node)->must_size;
5426                 old_must = &((struct lys_node_container *)node)->must;
5427                 break;
5428             case LYS_ANYXML:
5429             case LYS_ANYDATA:
5430                 old_size = &((struct lys_node_anydata *)node)->must_size;
5431                 old_must = &((struct lys_node_anydata *)node)->must;
5432                 break;
5433             default:
5434                 LOGINT(ctx);
5435                 goto fail;
5436             }
5437 
5438             size = *old_size + rfn->must_size;
5439             must = realloc(*old_must, size * sizeof *rfn->must);
5440             LY_CHECK_ERR_GOTO(!must, LOGMEM(ctx), fail);
5441             for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
5442                 must[j].ext_size = rfn->must[k].ext_size;
5443                 lys_ext_dup(ctx, rfn->module, rfn->must[k].ext, rfn->must[k].ext_size, &rfn->must[k], LYEXT_PAR_RESTR,
5444                             &must[j].ext, 0, unres);
5445                 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
5446                 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
5447                 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
5448                 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
5449                 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
5450                 must[j].flags = rfn->must[k].flags;
5451             }
5452 
5453             *old_must = must;
5454             *old_size = size;
5455 
5456             /* check XPath dependencies again */
5457             if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
5458                 goto fail;
5459             }
5460         }
5461 
5462         /* if-feature in leaf, leaf-list, list, container or anyxml */
5463         if (rfn->iffeature_size) {
5464             old_size = &node->iffeature_size;
5465             old_iff = &node->iffeature;
5466 
5467             size = *old_size + rfn->iffeature_size;
5468             iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
5469             LY_CHECK_ERR_GOTO(!iff, LOGMEM(ctx), fail);
5470             *old_iff = iff;
5471 
5472             for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
5473                 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
5474                 if (usize1) {
5475                     /* there is something to duplicate */
5476                     /* duplicate compiled expression */
5477                     usize = (usize1 / 4) + ((usize1 % 4) ? 1 : 0);
5478                     iff[j].expr = malloc(usize * sizeof *iff[j].expr);
5479                     LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM(ctx), fail);
5480                     memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
5481 
5482                     /* duplicate list of feature pointers */
5483                     iff[j].features = malloc(usize2 * sizeof *iff[k].features);
5484                     LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM(ctx), fail);
5485                     memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
5486 
5487                     /* duplicate extensions */
5488                     iff[j].ext_size = rfn->iffeature[k].ext_size;
5489                     lys_ext_dup(ctx, rfn->module, rfn->iffeature[k].ext, rfn->iffeature[k].ext_size,
5490                                 &rfn->iffeature[k], LYEXT_PAR_IFFEATURE, &iff[j].ext, 0, unres);
5491                 }
5492                 (*old_size)++;
5493             }
5494             assert(*old_size == size);
5495         }
5496     }
5497 
5498     /* apply augments */
5499     for (i = 0; i < uses->augment_size; i++) {
5500         rc = resolve_augment(&uses->augment[i], (struct lys_node *)uses, unres);
5501         if (rc) {
5502             goto fail;
5503         }
5504     }
5505 
5506     /* check refines */
5507     for (i = 0; i < uses->refine_size; i++) {
5508         node = refine_nodes[i];
5509         rfn = &uses->refine[i];
5510 
5511         /* config on any nodetype */
5512         if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
5513             for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
5514             if (parent && parent->nodetype != LYS_GROUPING && (parent->flags & LYS_CONFIG_MASK) &&
5515                     ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
5516                     (rfn->flags & LYS_CONFIG_W)) {
5517                 /* setting config true under config false is prohibited */
5518                 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
5519                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
5520                        "changing config from 'false' to 'true' is prohibited while "
5521                        "the target's parent is still config 'false'.");
5522                 goto fail;
5523             }
5524 
5525             /* inherit config change to the target children */
5526             LY_TREE_DFS_BEGIN(node->child, next, iter) {
5527                 if (rfn->flags & LYS_CONFIG_W) {
5528                     if (iter->flags & LYS_CONFIG_SET) {
5529                         /* config is set explicitely, go to next sibling */
5530                         next = NULL;
5531                         goto nextsibling;
5532                     }
5533                 } else { /* LYS_CONFIG_R */
5534                     if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
5535                         /* error - we would have config data under status data */
5536                         LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
5537                         LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
5538                                "changing config from 'true' to 'false' is prohibited while the target "
5539                                "has still a children with explicit config 'true'.");
5540                         goto fail;
5541                     }
5542                 }
5543                 /* change config */
5544                 iter->flags &= ~LYS_CONFIG_MASK;
5545                 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
5546 
5547                 /* select next iter - modified LY_TREE_DFS_END */
5548                 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
5549                     next = NULL;
5550                 } else {
5551                     next = iter->child;
5552                 }
5553 nextsibling:
5554                 if (!next) {
5555                     /* try siblings */
5556                     next = iter->next;
5557                 }
5558                 while (!next) {
5559                     /* parent is already processed, go to its sibling */
5560                     iter = lys_parent(iter);
5561 
5562                     /* no siblings, go back through parents */
5563                     if (iter == node) {
5564                         /* we are done, no next element to process */
5565                         break;
5566                     }
5567                     next = iter->next;
5568                 }
5569             }
5570         }
5571 
5572         /* default value */
5573         if (rfn->dflt_size) {
5574             if (node->nodetype == LYS_CHOICE) {
5575                 /* choice */
5576                 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
5577                                                                              rfn->dflt[0]);
5578                 if (!((struct lys_node_choice *)node)->dflt) {
5579                     LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
5580                     goto fail;
5581                 }
5582                 if (lyp_check_mandatory_choice(node)) {
5583                     goto fail;
5584                 }
5585             }
5586         }
5587 
5588         /* min/max-elements on list or leaf-list */
5589         if (node->nodetype == LYS_LIST && ((struct lys_node_list *)node)->max) {
5590             if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
5591                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5592                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
5593                 goto fail;
5594             }
5595         } else if (node->nodetype == LYS_LEAFLIST && ((struct lys_node_leaflist *)node)->max) {
5596             if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
5597                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5598                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
5599                 goto fail;
5600             }
5601         }
5602 
5603         /* additional checks */
5604         /* default value with mandatory/min-elements */
5605         if (node->nodetype == LYS_LEAFLIST) {
5606             llist = (struct lys_node_leaflist *)node;
5607             if (llist->dflt_size && llist->min) {
5608                 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "min-elements", "refine");
5609                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
5610                        "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
5611                 goto fail;
5612             }
5613         } else if (node->nodetype == LYS_LEAF) {
5614             leaf = (struct lys_node_leaf *)node;
5615             if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
5616                 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "mandatory", "refine");
5617                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
5618                        "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
5619                 goto fail;
5620             }
5621         }
5622 
5623         /* check for mandatory node in default case, first find the closest parent choice to the changed node */
5624         if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
5625             for (parent = node->parent;
5626                  parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
5627                  parent = parent->parent) {
5628                 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
5629                     /* stop also on presence containers */
5630                     break;
5631                 }
5632             }
5633             /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
5634             if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
5635                 if (lyp_check_mandatory_choice(parent)) {
5636                     goto fail;
5637                 }
5638             }
5639         }
5640     }
5641     free(refine_nodes);
5642 
5643     /* check list config after all the refines were applied */
5644     LY_TREE_DFS_BEGIN((struct lys_node *)uses, next, iter) {
5645         if ((iter->nodetype == LYS_LIST) && (iter->flags & LYS_CONFIG_W)
5646                 && !((struct lys_node_list *)iter)->keys_size) {
5647             LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_LYS, iter, "key", "list");
5648             goto fail;
5649         }
5650         LY_TREE_DFS_END((struct lys_node *)uses, next, iter);
5651     }
5652 
5653     return EXIT_SUCCESS;
5654 
5655 fail:
5656     LY_TREE_FOR_SAFE(uses->child, next, iter) {
5657         lys_node_free(ctx, iter, NULL, 0);
5658     }
5659     free(refine_nodes);
5660     return -1;
5661 }
5662 
5663 void
resolve_identity_backlink_update(struct lys_ident * der,struct lys_ident * base)5664 resolve_identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
5665 {
5666     int i;
5667 
5668     assert(der && base);
5669 
5670     if (!base->der) {
5671         /* create a set for backlinks if it does not exist */
5672         base->der = ly_set_new();
5673     }
5674     /* store backlink */
5675     ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
5676 
5677     /* do it recursively */
5678     for (i = 0; i < base->base_size; i++) {
5679         resolve_identity_backlink_update(der, base->base[i]);
5680     }
5681 }
5682 
5683 /**
5684  * @brief Resolve base identity recursively. Does not log.
5685  *
5686  * @param[in] module Main module.
5687  * @param[in] ident Identity to use.
5688  * @param[in] basename Base name of the identity.
5689  * @param[out] ret Pointer to the resolved identity. Can be NULL.
5690  *
5691  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
5692  */
5693 static int
resolve_base_ident_sub(const struct lys_module * module,struct lys_ident * ident,const char * basename,struct unres_schema * unres,struct lys_ident ** ret)5694 resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
5695                        struct unres_schema *unres, struct lys_ident **ret)
5696 {
5697     uint32_t i, j;
5698     struct lys_ident *base = NULL;
5699     struct ly_ctx *ctx = module->ctx;
5700 
5701     assert(ret);
5702 
5703     /* search module */
5704     for (i = 0; i < module->ident_size; i++) {
5705         if (!strcmp(basename, module->ident[i].name)) {
5706 
5707             if (!ident) {
5708                 /* just search for type, so do not modify anything, just return
5709                  * the base identity pointer */
5710                 *ret = &module->ident[i];
5711                 return EXIT_SUCCESS;
5712             }
5713 
5714             base = &module->ident[i];
5715             goto matchfound;
5716         }
5717     }
5718 
5719     /* search submodules */
5720     for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
5721         for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
5722             if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
5723 
5724                 if (!ident) {
5725                     *ret = &module->inc[j].submodule->ident[i];
5726                     return EXIT_SUCCESS;
5727                 }
5728 
5729                 base = &module->inc[j].submodule->ident[i];
5730                 goto matchfound;
5731             }
5732         }
5733     }
5734 
5735 matchfound:
5736     /* we found it somewhere */
5737     if (base) {
5738         /* is it already completely resolved? */
5739         for (i = 0; i < unres->count; i++) {
5740             if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
5741                 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
5742 
5743                 /* simple check for circular reference,
5744                  * the complete check is done as a side effect of using only completely
5745                  * resolved identities (previous check of unres content) */
5746                 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
5747                     LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
5748                     LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
5749                     return -1;
5750                 }
5751 
5752                 return EXIT_FAILURE;
5753             }
5754         }
5755 
5756         /* checks done, store the result */
5757         *ret = base;
5758         return EXIT_SUCCESS;
5759     }
5760 
5761     /* base not found (maybe a forward reference) */
5762     return EXIT_FAILURE;
5763 }
5764 
5765 /**
5766  * @brief Resolve base identity. Logs directly.
5767  *
5768  * @param[in] module Main module.
5769  * @param[in] ident Identity to use.
5770  * @param[in] basename Base name of the identity.
5771  * @param[in] parent Either "type" or "identity".
5772  * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
5773  *
5774  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
5775  */
5776 static int
resolve_base_ident(const struct lys_module * module,struct lys_ident * ident,const char * basename,const char * parent,struct lys_type * type,struct unres_schema * unres)5777 resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
5778                    struct lys_type *type, struct unres_schema *unres)
5779 {
5780     const char *name;
5781     int mod_name_len = 0, rc;
5782     struct lys_ident *target, **ret;
5783     uint16_t flags;
5784     struct lys_module *mod;
5785     struct ly_ctx *ctx = module->ctx;
5786 
5787     assert((ident && !type) || (!ident && type));
5788 
5789     if (!type) {
5790         /* have ident to resolve */
5791         ret = &target;
5792         flags = ident->flags;
5793         mod = ident->module;
5794     } else {
5795         /* have type to fill */
5796         ++type->info.ident.count;
5797         type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
5798         LY_CHECK_ERR_RETURN(!type->info.ident.ref, LOGMEM(ctx), -1);
5799 
5800         ret = &type->info.ident.ref[type->info.ident.count - 1];
5801         flags = type->parent->flags;
5802         mod = type->parent->module;
5803     }
5804     *ret = NULL;
5805 
5806     /* search for the base identity */
5807     name = strchr(basename, ':');
5808     if (name) {
5809         /* set name to correct position after colon */
5810         mod_name_len = name - basename;
5811         name++;
5812 
5813         if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
5814             /* prefix refers to the current module, ignore it */
5815             mod_name_len = 0;
5816         }
5817     } else {
5818         name = basename;
5819     }
5820 
5821     /* get module where to search */
5822     module = lyp_get_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len, 0);
5823     if (!module) {
5824         /* identity refers unknown data model */
5825         LOGVAL(ctx, LYE_INMOD, LY_VLOG_NONE, NULL, basename);
5826         return -1;
5827     }
5828 
5829     /* search in the identified module ... */
5830     rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5831     if (!rc) {
5832         assert(*ret);
5833 
5834         /* check status */
5835         if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5836                              (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5837             rc = -1;
5838         } else if (ident) {
5839             ident->base[ident->base_size++] = *ret;
5840             if (lys_main_module(mod)->implemented) {
5841                 /* in case of the implemented identity, maintain backlinks to it
5842                  * from the base identities to make it available when resolving
5843                  * data with the identity values (not implemented identity is not
5844                  * allowed as an identityref value). */
5845                 resolve_identity_backlink_update(ident, *ret);
5846             }
5847         }
5848     } else if (rc == EXIT_FAILURE) {
5849         LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
5850         if (type) {
5851             --type->info.ident.count;
5852         }
5853     }
5854 
5855     return rc;
5856 }
5857 
5858 /*
5859  * 1 - true (der is derived from base)
5860  * 0 - false (der is not derived from base)
5861  */
5862 static int
search_base_identity(struct lys_ident * der,struct lys_ident * base)5863 search_base_identity(struct lys_ident *der, struct lys_ident *base)
5864 {
5865     int i;
5866 
5867     if (der == base) {
5868         return 1;
5869     } else {
5870         for(i = 0; i < der->base_size; i++) {
5871             if (search_base_identity(der->base[i], base) == 1) {
5872                 return 1;
5873             }
5874         }
5875     }
5876 
5877     return 0;
5878 }
5879 
5880 /**
5881  * @brief Resolve JSON data format identityref. Logs directly.
5882  *
5883  * @param[in] type Identityref type.
5884  * @param[in] ident_name Identityref name.
5885  * @param[in] node Node where the identityref is being resolved
5886  * @param[in] dflt flag if we are resolving default value in the schema
5887  *
5888  * @return Pointer to the identity resolvent, NULL on error.
5889  */
5890 struct lys_ident *
resolve_identref(struct lys_type * type,const char * ident_name,struct lyd_node * node,struct lys_module * mod,int dflt)5891 resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node, struct lys_module *mod, int dflt)
5892 {
5893     const char *mod_name, *name;
5894     char *str;
5895     int mod_name_len, nam_len, rc;
5896     int need_implemented = 0;
5897     unsigned int i, j, found;
5898     struct lys_ident *der = NULL, *cur;
5899     struct lys_module *imod = NULL, *m, *tmod;
5900     struct ly_ctx *ctx;
5901 
5902     assert(type && ident_name && mod);
5903     ctx = mod->ctx;
5904 
5905     if (!type || (!type->info.ident.count && !type->der->module) || !ident_name) {
5906         return NULL;
5907     }
5908 
5909     rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, &nam_len, NULL, 0);
5910     if (rc < 1) {
5911         LOGVAL(ctx, LYE_INCHAR, node ? LY_VLOG_LYD : LY_VLOG_NONE, node, ident_name[-rc], &ident_name[-rc]);
5912         return NULL;
5913     } else if (rc < (signed)strlen(ident_name)) {
5914         LOGVAL(ctx, LYE_INCHAR, node ? LY_VLOG_LYD : LY_VLOG_NONE, node, ident_name[rc], &ident_name[rc]);
5915         return NULL;
5916     }
5917 
5918     m = lys_main_module(mod); /* shortcut */
5919     if (!mod_name || (!strncmp(mod_name, m->name, mod_name_len) && !m->name[mod_name_len])) {
5920         /* identity is defined in the same module as node */
5921         imod = m;
5922     } else if (dflt) {
5923         /* solving identityref in default definition in schema -
5924          * find the identity's module in the imported modules list to have a correct revision */
5925         for (i = 0; i < mod->imp_size; i++) {
5926             if (!strncmp(mod_name, mod->imp[i].module->name, mod_name_len) && !mod->imp[i].module->name[mod_name_len]) {
5927                 imod = mod->imp[i].module;
5928                 break;
5929             }
5930         }
5931 
5932         /* We may need to pull it from the module that the typedef came from */
5933         if (!imod && type && type->der->module) {
5934             tmod = type->der->module;
5935             for (i = 0; i < tmod->imp_size; i++) {
5936                 if (!strncmp(mod_name, tmod->imp[i].module->name, mod_name_len) && !tmod->imp[i].module->name[mod_name_len]) {
5937                     imod = tmod->imp[i].module;
5938                     break;
5939                 }
5940             }
5941         }
5942 
5943         /* it can still be a default value in a foreign grouping */
5944         if (!imod) {
5945             str = strndup(mod_name, mod_name_len);
5946             imod = (struct lys_module *)ly_ctx_get_module(ctx, str, NULL, 1);
5947             free(str);
5948         }
5949     } else {
5950         /* solving identityref in data - get the module from the context */
5951         for (i = 0; i < (unsigned)mod->ctx->models.used; ++i) {
5952             imod = mod->ctx->models.list[i];
5953             if (!strncmp(mod_name, imod->name, mod_name_len) && !imod->name[mod_name_len]) {
5954                 break;
5955             }
5956             imod = NULL;
5957         }
5958         if (!imod && mod->ctx->models.parsing_sub_modules_count) {
5959             /* we are currently parsing some module and checking XPath or a default value,
5960              * so take this module into account */
5961             for (i = 0; i < mod->ctx->models.parsing_sub_modules_count; i++) {
5962                 imod = mod->ctx->models.parsing_sub_modules[i];
5963                 if (imod->type) {
5964                     /* skip submodules */
5965                     continue;
5966                 }
5967                 if (!strncmp(mod_name, imod->name, mod_name_len) && !imod->name[mod_name_len]) {
5968                     break;
5969                 }
5970                 imod = NULL;
5971             }
5972         }
5973     }
5974 
5975     if (!dflt && (!imod || !imod->implemented) && ctx->data_clb) {
5976         /* the needed module was not found, but it may have been expected so call the data callback */
5977         if (imod) {
5978             ctx->data_clb(ctx, imod->name, imod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
5979         } else if (mod_name) {
5980             str = strndup(mod_name, mod_name_len);
5981             imod = (struct lys_module *)ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
5982             free(str);
5983         }
5984     }
5985     if (!imod) {
5986         goto fail;
5987     }
5988 
5989     /* find the type with base definitions */
5990     while (!type->info.ident.count && type->der) {
5991         type = &type->der->type;
5992     }
5993     if (!type->info.ident.count) {
5994         goto fail;
5995     }
5996 
5997     if (m != imod || lys_main_module(type->parent->module) != mod) {
5998         /* the type is not referencing the same schema,
5999          * THEN, we may need to make the module with the identity implemented, but only if it really
6000          * contains the identity */
6001         if (!imod->implemented) {
6002             cur = NULL;
6003             /* get the identity in the module */
6004             for (i = 0; i < imod->ident_size; i++) {
6005                 if (!strcmp(name, imod->ident[i].name)) {
6006                     cur = &imod->ident[i];
6007                     break;
6008                 }
6009             }
6010             if (!cur) {
6011                 /* go through includes */
6012                 for (j = 0; j < imod->inc_size; j++) {
6013                     for (i = 0; i < imod->inc[j].submodule->ident_size; i++) {
6014                         if (!strcmp(name, imod->inc[j].submodule->ident[i].name)) {
6015                             cur = &imod->inc[j].submodule->ident[i];
6016                             break;
6017                         }
6018                     }
6019                 }
6020                 if (!cur) {
6021                     goto fail;
6022                 }
6023             }
6024 
6025             /* check that identity is derived from one of the type's base */
6026             while (type->der) {
6027                 for (i = 0; i < type->info.ident.count; i++) {
6028                     if (search_base_identity(cur, type->info.ident.ref[i])) {
6029                         /* cur's base matches the type's base */
6030                         need_implemented = 1;
6031                         goto match;
6032                     }
6033                 }
6034                 type = &type->der->type;
6035             }
6036             /* matching base not found */
6037             LOGVAL(ctx, LYE_SPEC, node ? LY_VLOG_LYD : LY_VLOG_NONE, node, "Identity used as identityref value is not implemented.");
6038             goto fail;
6039         }
6040     }
6041 
6042     /* go through all the derived types of all the bases */
6043     found = 0;
6044     for (i = 0; i < type->info.ident.count; ++i) {
6045         cur = type->info.ident.ref[i];
6046         if (cur->der) {
6047             /* there are some derived identities */
6048             for (j = 0; j < cur->der->number; j++) {
6049                 der = (struct lys_ident *)cur->der->set.g[j]; /* shortcut */
6050                 if (!strcmp(der->name, name) && lys_main_module(der->module) == imod) {
6051                     /* we have a match on this base */
6052                     ++found;
6053                     break;
6054                 }
6055             }
6056         } else {
6057             LOGWRN(ctx, "Identity \"%s\" has no derived identities, identityref with this base can never be instatiated.",
6058                    cur->name);
6059         }
6060     }
6061     if (found == type->info.ident.count) {
6062         /* match found for all bases */
6063         cur = der;
6064         goto match;
6065     } else {
6066         LOGVAL(ctx, LYE_SPEC, node ? LY_VLOG_LYD : LY_VLOG_NONE, node, "Identityref value is not derived from all its bases.");
6067         goto fail;
6068     }
6069 
6070 fail:
6071     LOGVAL(ctx, LYE_INRESOLV, node ? LY_VLOG_LYD : LY_VLOG_NONE, node, "identityref", ident_name);
6072     return NULL;
6073 
6074 match:
6075     if (!dflt) {
6076         for (i = 0; i < cur->iffeature_size; i++) {
6077             if (!resolve_iffeature(&cur->iffeature[i])) {
6078                 if (node) {
6079                     LOGVAL(ctx, LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
6080                 }
6081                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Identity \"%s\" is disabled by its %d. if-feature condition.",
6082                        cur->name, i);
6083                 return NULL;
6084             }
6085         }
6086     }
6087     if (need_implemented) {
6088         if (dflt) {
6089             /* later try to make the module implemented */
6090             LOGVRB("Making \"%s\" module implemented because of identityref default value \"%s\" used in the implemented \"%s\" module",
6091                    imod->name, cur->name, mod->name);
6092             /* to be more effective we should use UNRES_MOD_IMPLEMENT but that would require changing prototype of
6093              * several functions with little gain */
6094             if (lys_set_implemented(imod)) {
6095                 LOGERR(ctx, ly_errno, "Setting the module \"%s\" implemented because of used default identity \"%s\" failed.",
6096                        imod->name, cur->name);
6097                 goto fail;
6098             }
6099         } else {
6100             /* just say that it was found, but in a non-implemented module */
6101             LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Identity found, but in a non-implemented module \"%s\".",
6102                    lys_main_module(cur->module)->name);
6103             goto fail;
6104         }
6105     }
6106     return cur;
6107 }
6108 
6109 /**
6110  * @brief Resolve unresolved uses. Logs directly.
6111  *
6112  * @param[in] uses Uses to use.
6113  * @param[in] unres Specific unres item.
6114  *
6115  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6116  */
6117 static int
resolve_unres_schema_uses(struct lys_node_uses * uses,struct unres_schema * unres)6118 resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
6119 {
6120     int rc;
6121     struct lys_node *par_grp;
6122     struct ly_ctx *ctx = uses->module->ctx;
6123 
6124     /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself is used
6125      *       in some uses. When we see such a uses, the grouping's unres counter is used to store number of so far
6126      *       unresolved uses. The grouping cannot be used unless this counter is decreased back to 0. To remember
6127      *       that the uses already increased grouping's counter, the LYS_USESGRP flag is used. */
6128     for (par_grp = lys_parent((struct lys_node *)uses); par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6129     if (par_grp && ly_strequal(par_grp->name, uses->name, 1)) {
6130         LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
6131         return -1;
6132     }
6133 
6134     if (!uses->grp) {
6135         rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
6136         if (rc == -1) {
6137             LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
6138             return -1;
6139         } else if (rc > 0) {
6140             LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
6141             return -1;
6142         } else if (!uses->grp) {
6143             if (par_grp && !(uses->flags & LYS_USESGRP)) {
6144                 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
6145                     LOGERR(ctx, LY_EINT, "Too many unresolved items (uses) inside a grouping.");
6146                     return -1;
6147                 }
6148                 uses->flags |= LYS_USESGRP;
6149             }
6150             LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
6151             return EXIT_FAILURE;
6152         }
6153     }
6154 
6155     if (uses->grp->unres_count) {
6156         if (par_grp && !(uses->flags & LYS_USESGRP)) {
6157             if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
6158                 LOGERR(ctx, LY_EINT, "Too many unresolved items (uses) inside a grouping.");
6159                 return -1;
6160             }
6161             uses->flags |= LYS_USESGRP;
6162         } else {
6163             /* instantiate grouping only when it is completely resolved */
6164             uses->grp = NULL;
6165         }
6166         LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
6167         return EXIT_FAILURE;
6168     }
6169 
6170     rc = resolve_uses(uses, unres);
6171     if (!rc) {
6172         /* decrease unres count only if not first try */
6173         if (par_grp && (uses->flags & LYS_USESGRP)) {
6174             assert(((struct lys_node_grp *)par_grp)->unres_count);
6175             ((struct lys_node_grp *)par_grp)->unres_count--;
6176             uses->flags &= ~LYS_USESGRP;
6177         }
6178 
6179         /* check status */
6180         if (lyp_check_status(uses->flags, uses->module, "of uses",
6181                          uses->grp->flags, uses->grp->module, uses->grp->name,
6182                          (struct lys_node *)uses)) {
6183             return -1;
6184         }
6185 
6186         return EXIT_SUCCESS;
6187     }
6188 
6189     return rc;
6190 }
6191 
6192 /**
6193  * @brief Resolve list keys. Logs directly.
6194  *
6195  * @param[in] list List to use.
6196  * @param[in] keys_str Keys node value.
6197  *
6198  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6199  */
6200 static int
resolve_list_keys(struct lys_node_list * list,const char * keys_str)6201 resolve_list_keys(struct lys_node_list *list, const char *keys_str)
6202 {
6203     int i, len, rc;
6204     const char *value;
6205     char *s = NULL;
6206     struct ly_ctx *ctx = list->module->ctx;
6207 
6208     for (i = 0; i < list->keys_size; ++i) {
6209         assert(keys_str);
6210 
6211         if (!list->child) {
6212             /* no child, possible forward reference */
6213             LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
6214             return EXIT_FAILURE;
6215         }
6216         /* get the key name */
6217         if ((value = strpbrk(keys_str, " \t\n"))) {
6218             len = value - keys_str;
6219             while (isspace(value[0])) {
6220                 value++;
6221             }
6222         } else {
6223             len = strlen(keys_str);
6224         }
6225 
6226         rc = lys_getnext_data(lys_node_module((struct lys_node *)list), (struct lys_node *)list, keys_str, len, LYS_LEAF,
6227                               LYS_GETNEXT_NOSTATECHECK, (const struct lys_node **)&list->keys[i]);
6228         if (rc) {
6229             LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, list, "list key", keys_str);
6230             return EXIT_FAILURE;
6231         }
6232 
6233         if (check_key(list, i, keys_str, len)) {
6234             /* check_key logs */
6235             return -1;
6236         }
6237 
6238         /* check status */
6239         if (lyp_check_status(list->flags, list->module, list->name,
6240                              list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
6241                              (struct lys_node *)list->keys[i])) {
6242             return -1;
6243         }
6244 
6245         /* default value - is ignored, keep it but print a warning */
6246         if (list->keys[i]->dflt) {
6247             /* log is not hidden only in case this resolving fails and in such a case
6248              * we cannot get here
6249              */
6250             assert(log_opt == ILO_STORE);
6251             log_opt = ILO_LOG;
6252             LOGWRN(ctx, "Default value \"%s\" in the list key \"%s\" is ignored. (%s)", list->keys[i]->dflt,
6253                    list->keys[i]->name, s = lys_path((struct lys_node*)list, LYS_PATH_FIRST_PREFIX));
6254             log_opt = ILO_STORE;
6255             free(s);
6256         }
6257 
6258         /* prepare for next iteration */
6259         while (value && isspace(value[0])) {
6260             value++;
6261         }
6262         keys_str = value;
6263     }
6264 
6265     return EXIT_SUCCESS;
6266 }
6267 
6268 /**
6269  * @brief Resolve (check) all must conditions of \p node.
6270  * Logs directly.
6271  *
6272  * @param[in] node Data node with optional must statements.
6273  * @param[in] inout_parent If set, must in input or output parent of node->schema will be resolved.
6274  * @param[in] ignore_fail 0 - no, 1 - yes, 2 - yes, but only for external dependencies.
6275  * @param[in] multi_error 0 - no, 1 - yes.
6276  *
6277  * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
6278  */
6279 static int
resolve_must(struct lyd_node * node,int inout_parent,int ignore_fail,int multi_error)6280 resolve_must(struct lyd_node *node, int inout_parent, int ignore_fail, int multi_error)
6281 {
6282     uint8_t i, must_size;
6283     struct lys_node *schema;
6284     struct lys_restr *must;
6285     struct lyxp_set set;
6286     struct ly_ctx *ctx = node->schema->module->ctx;
6287     int rc = EXIT_SUCCESS;
6288 
6289     assert(node);
6290     memset(&set, 0, sizeof set);
6291 
6292     if (inout_parent) {
6293         for (schema = lys_parent(node->schema);
6294              schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
6295              schema = lys_parent(schema));
6296         if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
6297             LOGINT(ctx);
6298             return -1;
6299         }
6300         must_size = ((struct lys_node_inout *)schema)->must_size;
6301         must = ((struct lys_node_inout *)schema)->must;
6302 
6303         /* context node is the RPC/action */
6304         node = node->parent;
6305         if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
6306             LOGINT(ctx);
6307             return -1;
6308         }
6309     } else {
6310         switch (node->schema->nodetype) {
6311         case LYS_CONTAINER:
6312             must_size = ((struct lys_node_container *)node->schema)->must_size;
6313             must = ((struct lys_node_container *)node->schema)->must;
6314             break;
6315         case LYS_LEAF:
6316             must_size = ((struct lys_node_leaf *)node->schema)->must_size;
6317             must = ((struct lys_node_leaf *)node->schema)->must;
6318             break;
6319         case LYS_LEAFLIST:
6320             must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
6321             must = ((struct lys_node_leaflist *)node->schema)->must;
6322             break;
6323         case LYS_LIST:
6324             must_size = ((struct lys_node_list *)node->schema)->must_size;
6325             must = ((struct lys_node_list *)node->schema)->must;
6326             break;
6327         case LYS_ANYXML:
6328         case LYS_ANYDATA:
6329             must_size = ((struct lys_node_anydata *)node->schema)->must_size;
6330             must = ((struct lys_node_anydata *)node->schema)->must;
6331             break;
6332         case LYS_NOTIF:
6333             must_size = ((struct lys_node_notif *)node->schema)->must_size;
6334             must = ((struct lys_node_notif *)node->schema)->must;
6335             break;
6336         default:
6337             must_size = 0;
6338             must = NULL;
6339             break;
6340         }
6341     }
6342 
6343     for (i = 0; i < must_size; ++i) {
6344         if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, lyd_node_module(node), &set, LYXP_MUST)) {
6345             return -1;
6346         }
6347 
6348         lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_MUST);
6349 
6350         if (!set.val.bool) {
6351             if ((ignore_fail == 1) || ((must[i].flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP)) && (ignore_fail == 2))) {
6352                 LOGVRB("Must condition \"%s\" not satisfied, but it is not required.", must[i].expr);
6353             } else {
6354                 LOGVAL(ctx, LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
6355                 if (must[i].emsg) {
6356                     ly_err_last_set_msg(ctx, must[i].emsg);
6357                 }
6358                 if (must[i].eapptag) {
6359                     ly_err_last_set_apptag(ctx, must[i].eapptag);
6360                 }
6361                 rc = 1;
6362                 if (!multi_error) {
6363                     break;
6364                 }
6365             }
6366         }
6367     }
6368 
6369     return rc;
6370 }
6371 
6372 /**
6373  * @brief Resolve (find) when condition schema context node. Does not log.
6374  *
6375  * @param[in] schema Schema node with the when condition.
6376  * @param[out] ctx_snode When schema context node.
6377  * @param[out] ctx_snode_type Schema context node type.
6378  */
6379 void
resolve_when_ctx_snode(const struct lys_node * schema,struct lys_node ** ctx_snode,enum lyxp_node_type * ctx_snode_type)6380 resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
6381 {
6382     const struct lys_node *sparent;
6383 
6384     /* find a not schema-only node */
6385     *ctx_snode_type = LYXP_NODE_ELEM;
6386     while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
6387         if (schema->nodetype == LYS_AUGMENT) {
6388             sparent = ((struct lys_node_augment *)schema)->target;
6389         } else {
6390             sparent = schema->parent;
6391         }
6392         if (!sparent) {
6393             /* context node is the document root (fake root in our case) */
6394             if (schema->flags & LYS_CONFIG_W) {
6395                 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
6396             } else {
6397                 *ctx_snode_type = LYXP_NODE_ROOT;
6398             }
6399             /* we need the first top-level sibling, but no uses or groupings */
6400             schema = lys_getnext(NULL, NULL, lys_node_module(schema), LYS_GETNEXT_NOSTATECHECK);
6401             break;
6402         }
6403         schema = sparent;
6404     }
6405 
6406     *ctx_snode = (struct lys_node *)schema;
6407 }
6408 
6409 /**
6410  * @brief Resolve (find) when condition context node. Does not log.
6411  *
6412  * @param[in] node Data node, whose conditional definition is being decided.
6413  * @param[in] schema Schema node with the when condition.
6414  * @param[out] ctx_node Context node.
6415  * @param[out] ctx_node_type Context node type.
6416  *
6417  * @return EXIT_SUCCESS on success, -1 on error.
6418  */
6419 static int
resolve_when_ctx_node(struct lyd_node * node,struct lys_node * schema,struct lyd_node ** ctx_node,enum lyxp_node_type * ctx_node_type)6420 resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
6421                       enum lyxp_node_type *ctx_node_type)
6422 {
6423     struct lyd_node *parent;
6424     struct lys_node *sparent;
6425     enum lyxp_node_type node_type;
6426     uint16_t i, data_depth, schema_depth;
6427 
6428     resolve_when_ctx_snode(schema, &schema, &node_type);
6429 
6430     if (node_type == LYXP_NODE_ELEM) {
6431         /* standard element context node */
6432         for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
6433         for (sparent = schema, schema_depth = 0;
6434                 sparent;
6435                 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
6436             if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
6437                 ++schema_depth;
6438             }
6439         }
6440         if (data_depth < schema_depth) {
6441             return -1;
6442         }
6443 
6444         /* find the corresponding data node */
6445         for (i = 0; i < data_depth - schema_depth; ++i) {
6446             node = node->parent;
6447         }
6448         if (node->schema != schema) {
6449             return -1;
6450         }
6451     } else {
6452         /* root context node */
6453         while (node->parent) {
6454             node = node->parent;
6455         }
6456         while (node->prev->next) {
6457             node = node->prev;
6458         }
6459     }
6460 
6461     *ctx_node = node;
6462     *ctx_node_type = node_type;
6463     return EXIT_SUCCESS;
6464 }
6465 
6466 /**
6467  * @brief Temporarily unlink nodes as per YANG 1.1 RFC section 7.21.5 for when XPath evaluation.
6468  * The context node is adjusted if needed.
6469  *
6470  * @param[in] snode Schema node, whose children instances need to be unlinked.
6471  * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
6472  * it is moved to point to another sibling still in the original tree.
6473  * @param[in,out] ctx_node When context node, adjusted if needed.
6474  * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
6475  * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
6476  * Ordering may change, but there will be no semantic change.
6477  *
6478  * @return EXIT_SUCCESS on success, -1 on error.
6479  */
6480 static int
resolve_when_unlink_nodes(struct lys_node * snode,struct lyd_node ** node,struct lyd_node ** ctx_node,enum lyxp_node_type ctx_node_type,struct lyd_node ** unlinked_nodes)6481 resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
6482                           enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
6483 {
6484     struct lyd_node *next, *elem;
6485     const struct lys_node *slast;
6486     struct ly_ctx *ctx = snode->module->ctx;
6487 
6488     switch (snode->nodetype) {
6489     case LYS_AUGMENT:
6490     case LYS_USES:
6491     case LYS_CHOICE:
6492     case LYS_CASE:
6493         slast = NULL;
6494         while ((slast = lys_getnext(slast, snode, NULL, LYS_GETNEXT_PARENTUSES))) {
6495             if (slast->nodetype & (LYS_ACTION | LYS_NOTIF)) {
6496                 continue;
6497             }
6498 
6499             if (resolve_when_unlink_nodes((struct lys_node *)slast, node, ctx_node, ctx_node_type, unlinked_nodes)) {
6500                 return -1;
6501             }
6502         }
6503         break;
6504     case LYS_CONTAINER:
6505     case LYS_LIST:
6506     case LYS_LEAF:
6507     case LYS_LEAFLIST:
6508     case LYS_ANYXML:
6509     case LYS_ANYDATA:
6510         LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
6511             if (elem->schema == snode) {
6512 
6513                 if (elem == *ctx_node) {
6514                     /* We are going to unlink our context node! This normally cannot happen,
6515                      * but we use normal top-level data nodes for faking a document root node,
6516                      * so if this is the context node, we just use the next top-level node.
6517                      * Additionally, it can even happen that there are no top-level data nodes left,
6518                      * all were unlinked, so in this case we pass NULL as the context node/data tree,
6519                      * lyxp_eval() can handle this special situation.
6520                      */
6521                     if (ctx_node_type == LYXP_NODE_ELEM) {
6522                         LOGINT(ctx);
6523                         return -1;
6524                     }
6525 
6526                     if (elem->prev == elem) {
6527                         /* unlinking last top-level element, use an empty data tree */
6528                         *ctx_node = NULL;
6529                     } else {
6530                         /* in this case just use the previous/last top-level data node */
6531                         *ctx_node = elem->prev;
6532                     }
6533                 } else if (elem == *node) {
6534                     /* We are going to unlink the currently processed node. This does not matter that
6535                      * much, but we would lose access to the original data tree, so just move our
6536                      * pointer somewhere still inside it.
6537                      */
6538                     if ((*node)->prev != *node) {
6539                         *node = (*node)->prev;
6540                     } else {
6541                         /* the processed node with sibings were all unlinked, oh well */
6542                         *node = NULL;
6543                     }
6544                 }
6545 
6546                 /* temporarily unlink the node */
6547                 lyd_unlink_internal(elem, 0);
6548                 if (*unlinked_nodes) {
6549                     if (lyd_insert_after((*unlinked_nodes)->prev, elem)) {
6550                         LOGINT(ctx);
6551                         return -1;
6552                     }
6553                 } else {
6554                     *unlinked_nodes = elem;
6555                 }
6556 
6557                 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
6558                     /* there can be only one instance */
6559                     break;
6560                 }
6561             }
6562         }
6563         break;
6564     default:
6565         LOGINT(ctx);
6566         return -1;
6567     }
6568 
6569     return EXIT_SUCCESS;
6570 }
6571 
6572 /**
6573  * @brief Relink the unlinked nodes back.
6574  *
6575  * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
6576  * we simply need a sibling from the original data tree.
6577  * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
6578  * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
6579  * or the sibling of \p unlinked_nodes.
6580  *
6581  * @return EXIT_SUCCESS on success, -1 on error.
6582  */
6583 static int
resolve_when_relink_nodes(struct lyd_node * node,struct lyd_node * unlinked_nodes,enum lyxp_node_type ctx_node_type)6584 resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
6585 {
6586     struct lyd_node *elem;
6587 
6588     LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
6589         lyd_unlink_internal(elem, 0);
6590         if (ctx_node_type == LYXP_NODE_ELEM) {
6591             if (lyd_insert_common(node, NULL, elem, 0)) {
6592                 return -1;
6593             }
6594         } else {
6595             if (lyd_insert_nextto(node, elem, 0, 0)) {
6596                 return -1;
6597             }
6598         }
6599     }
6600 
6601     return EXIT_SUCCESS;
6602 }
6603 
6604 int
resolve_applies_must(const struct lyd_node * node)6605 resolve_applies_must(const struct lyd_node *node)
6606 {
6607     int ret = 0;
6608     uint8_t must_size;
6609     struct lys_node *schema, *iter;
6610 
6611     assert(node);
6612 
6613     schema = node->schema;
6614 
6615     /* their own must */
6616     switch (schema->nodetype) {
6617     case LYS_CONTAINER:
6618         must_size = ((struct lys_node_container *)schema)->must_size;
6619         break;
6620     case LYS_LEAF:
6621         must_size = ((struct lys_node_leaf *)schema)->must_size;
6622         break;
6623     case LYS_LEAFLIST:
6624         must_size = ((struct lys_node_leaflist *)schema)->must_size;
6625         break;
6626     case LYS_LIST:
6627         must_size = ((struct lys_node_list *)schema)->must_size;
6628         break;
6629     case LYS_ANYXML:
6630     case LYS_ANYDATA:
6631         must_size = ((struct lys_node_anydata *)schema)->must_size;
6632         break;
6633     case LYS_NOTIF:
6634         must_size = ((struct lys_node_notif *)schema)->must_size;
6635         break;
6636     default:
6637         must_size = 0;
6638         break;
6639     }
6640 
6641     if (must_size) {
6642         ++ret;
6643     }
6644 
6645     /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
6646     if (!node->prev->next) {
6647         for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
6648         if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
6649             ret += 0x2;
6650         }
6651     }
6652 
6653     return ret;
6654 }
6655 
6656 static struct lys_when *
snode_get_when(const struct lys_node * schema)6657 snode_get_when(const struct lys_node *schema)
6658 {
6659     switch (schema->nodetype) {
6660     case LYS_CONTAINER:
6661         return ((struct lys_node_container *)schema)->when;
6662     case LYS_CHOICE:
6663         return ((struct lys_node_choice *)schema)->when;
6664     case LYS_LEAF:
6665         return ((struct lys_node_leaf *)schema)->when;
6666     case LYS_LEAFLIST:
6667         return ((struct lys_node_leaflist *)schema)->when;
6668     case LYS_LIST:
6669         return ((struct lys_node_list *)schema)->when;
6670     case LYS_ANYDATA:
6671     case LYS_ANYXML:
6672         return ((struct lys_node_anydata *)schema)->when;
6673     case LYS_CASE:
6674         return ((struct lys_node_case *)schema)->when;
6675     case LYS_USES:
6676         return ((struct lys_node_uses *)schema)->when;
6677     case LYS_AUGMENT:
6678         return ((struct lys_node_augment *)schema)->when;
6679     default:
6680         return NULL;
6681     }
6682 }
6683 
6684 int
resolve_applies_when(const struct lys_node * schema,int mode,const struct lys_node * stop)6685 resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
6686 {
6687     const struct lys_node *parent;
6688 
6689     assert(schema);
6690 
6691     if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && snode_get_when(schema)) {
6692         return 1;
6693     }
6694 
6695     parent = schema;
6696     goto check_augment;
6697 
6698     while (parent) {
6699         /* stop conditions */
6700         if (!mode) {
6701             /* stop on node that can be instantiated in data tree */
6702             if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
6703                 break;
6704             }
6705         } else {
6706             /* stop on the specified node */
6707             if (parent == stop) {
6708                 break;
6709             }
6710         }
6711 
6712         if (snode_get_when(parent)) {
6713             return 1;
6714         }
6715 check_augment:
6716 
6717         if (parent->parent && (parent->parent->nodetype == LYS_AUGMENT) && snode_get_when(parent->parent)) {
6718             return 1;
6719         }
6720         parent = lys_parent(parent);
6721     }
6722 
6723     return 0;
6724 }
6725 
6726 /**
6727  * @brief Resolve (check) all when conditions relevant for \p node.
6728  * Logs directly.
6729  *
6730  * @param[in] node Data node, whose conditional reference, if such, is being decided.
6731  * @param[in] ignore_fail 1 if when does not have to be satisfied, 2 if it does not have to be satisfied
6732  * only when requiring external dependencies.
6733  *
6734  * @return
6735  *  -1 - error, ly_errno is set
6736  *   0 - all "when" statements true
6737  *   0, ly_vecode = LYVE_NOWHEN - some "when" statement false, returned in failed_when
6738  *   1, ly_vecode = LYVE_INWHEN - nodes needed to resolve are conditional and not yet resolved (under another "when")
6739  */
6740 int
resolve_when(struct lyd_node * node,int ignore_fail,struct lys_when ** failed_when)6741 resolve_when(struct lyd_node *node, int ignore_fail, struct lys_when **failed_when)
6742 {
6743     struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
6744     struct lys_node *sparent;
6745     struct lyxp_set set;
6746     enum lyxp_node_type ctx_node_type;
6747     struct ly_ctx *ctx = node->schema->module->ctx;
6748     int rc = 0;
6749 
6750     assert(node);
6751     memset(&set, 0, sizeof set);
6752 
6753     if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION)) && snode_get_when(node->schema)) {
6754         /* make the node dummy for the evaluation */
6755         node->validity |= LYD_VAL_INUSE;
6756         rc = lyxp_eval(snode_get_when(node->schema)->cond, node, LYXP_NODE_ELEM, lyd_node_module(node),
6757                        &set, LYXP_WHEN);
6758         node->validity &= ~LYD_VAL_INUSE;
6759         if (rc) {
6760             if (rc == 1) {
6761                 LOGVAL(ctx, LYE_INWHEN, LY_VLOG_LYD, node, snode_get_when(node->schema)->cond);
6762             }
6763             goto cleanup;
6764         }
6765 
6766         /* set boolean result of the condition */
6767         lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_WHEN);
6768         if (!set.val.bool) {
6769             node->when_status |= LYD_WHEN_FALSE;
6770             if ((ignore_fail == 1) || ((snode_get_when(node->schema)->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP))
6771                     && (ignore_fail == 2))) {
6772                 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.", snode_get_when(node->schema)->cond);
6773             } else {
6774                 LOGVAL(ctx, LYE_NOWHEN, LY_VLOG_LYD, node, snode_get_when(node->schema)->cond);
6775                 if (failed_when) {
6776                     *failed_when = snode_get_when(node->schema);
6777                 }
6778                 goto cleanup;
6779             }
6780         }
6781 
6782         /* free xpath set content */
6783         lyxp_set_cast(&set, LYXP_SET_EMPTY, node, lyd_node_module(node), 0);
6784     }
6785 
6786     sparent = node->schema;
6787     goto check_augment;
6788 
6789     /* check when in every schema node that affects node */
6790     while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
6791         if (snode_get_when(sparent)) {
6792             if (!ctx_node) {
6793                 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
6794                 if (rc) {
6795                     LOGINT(ctx);
6796                     goto cleanup;
6797                 }
6798             }
6799 
6800             unlinked_nodes = NULL;
6801             /* we do not want our node pointer to change */
6802             tmp_node = node;
6803             rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6804             if (rc) {
6805                 goto cleanup;
6806             }
6807 
6808             rc = lyxp_eval(snode_get_when(sparent)->cond, ctx_node, ctx_node_type, lys_node_module(sparent),
6809                            &set, LYXP_WHEN);
6810 
6811             if (unlinked_nodes && ctx_node) {
6812                 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6813                     rc = -1;
6814                     goto cleanup;
6815                 }
6816             }
6817 
6818             if (rc) {
6819                 if (rc == 1) {
6820                     LOGVAL(ctx, LYE_INWHEN, LY_VLOG_LYD, node, snode_get_when(sparent)->cond);
6821                 }
6822                 goto cleanup;
6823             }
6824 
6825             lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent), LYXP_WHEN);
6826             if (!set.val.bool) {
6827                 if ((ignore_fail == 1) || ((snode_get_when(sparent)->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP))
6828                         && (ignore_fail == 2))) {
6829                     LOGVRB("When condition \"%s\" is not satisfied, but it is not required.", snode_get_when(sparent)->cond);
6830                 } else {
6831                     node->when_status |= LYD_WHEN_FALSE;
6832                     LOGVAL(ctx, LYE_NOWHEN, LY_VLOG_LYD, node, snode_get_when(sparent)->cond);
6833                     if (failed_when) {
6834                         *failed_when = snode_get_when(sparent);
6835                     }
6836                     goto cleanup;
6837                 }
6838             }
6839 
6840             /* free xpath set content */
6841             lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent), 0);
6842         }
6843 
6844 check_augment:
6845         if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && snode_get_when(sparent->parent))) {
6846             if (!ctx_node) {
6847                 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
6848                 if (rc) {
6849                     LOGINT(ctx);
6850                     goto cleanup;
6851                 }
6852             }
6853 
6854             unlinked_nodes = NULL;
6855             tmp_node = node;
6856             rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6857             if (rc) {
6858                 goto cleanup;
6859             }
6860 
6861             rc = lyxp_eval(snode_get_when(sparent->parent)->cond, ctx_node, ctx_node_type,
6862                            lys_node_module(sparent->parent), &set, LYXP_WHEN);
6863 
6864             /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
6865              * so the tree did not actually change and there is nothing for us to do
6866              */
6867             if (unlinked_nodes && ctx_node) {
6868                 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6869                     rc = -1;
6870                     goto cleanup;
6871                 }
6872             }
6873 
6874             if (rc) {
6875                 if (rc == 1) {
6876                     LOGVAL(ctx, LYE_INWHEN, LY_VLOG_LYD, node, snode_get_when(sparent->parent)->cond);
6877                 }
6878                 goto cleanup;
6879             }
6880 
6881             lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent->parent), LYXP_WHEN);
6882             if (!set.val.bool) {
6883                 node->when_status |= LYD_WHEN_FALSE;
6884                 if ((ignore_fail == 1) || ((snode_get_when(sparent->parent)->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP))
6885                         && (ignore_fail == 2))) {
6886                     LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
6887                            snode_get_when(sparent->parent)->cond);
6888                 } else {
6889                     LOGVAL(ctx, LYE_NOWHEN, LY_VLOG_LYD, node, snode_get_when(sparent->parent)->cond);
6890                     if (failed_when) {
6891                         *failed_when = snode_get_when(sparent->parent);
6892                     }
6893                     goto cleanup;
6894                 }
6895             }
6896 
6897             /* free xpath set content */
6898             lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent->parent), 0);
6899         }
6900 
6901         sparent = lys_parent(sparent);
6902     }
6903 
6904     node->when_status |= LYD_WHEN_TRUE;
6905 
6906 cleanup:
6907     /* free xpath set content */
6908     lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, NULL, 0);
6909     return rc;
6910 }
6911 
6912 static int
check_type_union_leafref(struct lys_type * type)6913 check_type_union_leafref(struct lys_type *type)
6914 {
6915     uint8_t i;
6916 
6917     if ((type->base == LY_TYPE_UNION) && type->info.uni.count) {
6918         /* go through unions and look for leafref */
6919         for (i = 0; i < type->info.uni.count; ++i) {
6920             switch (type->info.uni.types[i].base) {
6921             case LY_TYPE_LEAFREF:
6922                 return 1;
6923             case LY_TYPE_UNION:
6924                 if (check_type_union_leafref(&type->info.uni.types[i])) {
6925                     return 1;
6926                 }
6927                 break;
6928             default:
6929                 break;
6930             }
6931         }
6932 
6933         return 0;
6934     }
6935 
6936     /* just inherit the flag value */
6937     return type->der->has_union_leafref;
6938 }
6939 
6940 static void
free_ext_data(struct ly_ctx * ctx,struct unres_ext * ext_data)6941 free_ext_data(struct ly_ctx *ctx, struct unres_ext *ext_data)
6942 {
6943     /* cleanup on success or fatal error */
6944     if (ext_data->datatype == LYS_IN_YIN) {
6945         /* YIN */
6946         lyxml_free(ctx, ext_data->data.yin);
6947     } else {
6948         /* YANG */
6949         yang_free_ext_data(ext_data->data.yang);
6950     }
6951 
6952     free(ext_data);
6953 }
6954 
6955 /**
6956  * @brief Resolve a single unres schema item. Logs indirectly.
6957  *
6958  * @param[in] mod Main module.
6959  * @param[in] item Item to resolve. Type determined by \p type.
6960  * @param[in] type Type of the unresolved item.
6961  * @param[in] str_snode String, a schema node, or NULL.
6962  * @param[in] unres Unres schema structure to use.
6963  * @param[in] final_fail Whether we are just printing errors of the failed unres items.
6964  *
6965  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6966  */
6967 static int
resolve_unres_schema_item(struct lys_module * mod,void * item,enum UNRES_ITEM type,void * str_snode,struct unres_schema * unres)6968 resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
6969                           struct unres_schema *unres)
6970 {
6971     /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
6972     int rc = -1, has_str = 0, parent_type = 0, i, k;
6973     unsigned int j;
6974     struct ly_ctx * ctx = mod->ctx;
6975     struct lys_node *root, *next, *node, *par_grp;
6976     const char *expr;
6977     uint8_t *u;
6978 
6979     struct ly_set *refs, *procs;
6980     struct lys_feature *ref, *feat;
6981     struct lys_ident *ident;
6982     struct lys_type *stype;
6983     struct lys_node_choice *choic;
6984     struct lyxml_elem *yin;
6985     struct yang_type *yang;
6986     struct unres_list_uniq *unique_info;
6987     struct unres_iffeat_data *iff_data;
6988     struct unres_ext *ext_data;
6989     struct lys_ext_instance *ext, **extlist;
6990     struct lyext_plugin *eplugin;
6991 
6992     switch (type) {
6993     case UNRES_IDENT:
6994         expr = str_snode;
6995         has_str = 1;
6996         ident = item;
6997 
6998         rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
6999         break;
7000     case UNRES_TYPE_IDENTREF:
7001         expr = str_snode;
7002         has_str = 1;
7003         stype = item;
7004 
7005         rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
7006         break;
7007     case UNRES_TYPE_LEAFREF:
7008         node = str_snode;
7009         stype = item;
7010 
7011         rc = resolve_schema_leafref(stype, node, unres);
7012         break;
7013     case UNRES_TYPE_DER_EXT:
7014         parent_type++;
7015         /* falls through */
7016     case UNRES_TYPE_DER_TPDF:
7017         parent_type++;
7018         /* falls through */
7019     case UNRES_TYPE_DER:
7020         /* parent */
7021         node = str_snode;
7022         stype = item;
7023 
7024         /* HACK type->der is temporarily unparsed type statement */
7025         yin = (struct lyxml_elem *)stype->der;
7026         stype->der = NULL;
7027 
7028         if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
7029             yang = (struct yang_type *)yin;
7030             rc = yang_check_type(mod, node, yang, stype, parent_type, unres);
7031 
7032             if (rc) {
7033                 /* may try again later */
7034                 stype->der = (struct lys_tpdf *)yang;
7035             } else {
7036                 /* we need to always be able to free this, it's safe only in this case */
7037                 lydict_remove(ctx, yang->name);
7038                 free(yang);
7039             }
7040 
7041         } else {
7042             rc = fill_yin_type(mod, node, yin, stype, parent_type, unres);
7043             if (!rc || rc == -1) {
7044                 /* we need to always be able to free this, it's safe only in this case */
7045                 lyxml_free(ctx, yin);
7046             } else {
7047                 /* may try again later, put all back how it was */
7048                 stype->der = (struct lys_tpdf *)yin;
7049             }
7050         }
7051         if (rc == EXIT_SUCCESS) {
7052             /* it does not make sense to have leaf-list of empty type */
7053             if (!parent_type && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
7054                 LOGWRN(ctx, "The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
7055             }
7056 
7057             if ((type == UNRES_TYPE_DER_TPDF) && (stype->base == LY_TYPE_UNION)) {
7058                 /* fill typedef union leafref flag */
7059                 ((struct lys_tpdf *)stype->parent)->has_union_leafref = check_type_union_leafref(stype);
7060             } else if ((type == UNRES_TYPE_DER) && stype->der->has_union_leafref) {
7061                 /* copy the type in case it has union leafref flag */
7062                 if (lys_copy_union_leafrefs(mod, node, stype, NULL, unres)) {
7063                     LOGERR(ctx, LY_EINT, "Failed to duplicate type.");
7064                     return -1;
7065                 }
7066             }
7067         } else if (rc == EXIT_FAILURE && !(stype->value_flags & LY_VALUE_UNRESGRP)) {
7068             /* forward reference - in case the type is in grouping, we have to make the grouping unusable
7069              * by uses statement until the type is resolved. We do that the same way as uses statements inside
7070              * grouping. The grouping cannot be used unless the unres counter is 0.
7071              * To remember that the grouping already increased the counter, the LYTYPE_GRP is used as value
7072              * of the type's base member. */
7073             for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
7074             if (par_grp) {
7075                 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
7076                     LOGERR(ctx, LY_EINT, "Too many unresolved items (type) inside a grouping.");
7077                     return -1;
7078                 }
7079                 stype->value_flags |= LY_VALUE_UNRESGRP;
7080             }
7081         }
7082         break;
7083     case UNRES_IFFEAT:
7084         iff_data = str_snode;
7085         rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
7086         if (!rc) {
7087             /* success */
7088             if (iff_data->infeature) {
7089                 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
7090                 feat = *((struct lys_feature **)item);
7091                 if (!feat->depfeatures) {
7092                     feat->depfeatures = ly_set_new();
7093                 }
7094                 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
7095             }
7096             /* cleanup temporary data */
7097             lydict_remove(ctx, iff_data->fname);
7098             free(iff_data);
7099         }
7100         break;
7101     case UNRES_FEATURE:
7102         feat = (struct lys_feature *)item;
7103 
7104         if (feat->iffeature_size) {
7105             refs = ly_set_new();
7106             procs = ly_set_new();
7107             ly_set_add(procs, feat, 0);
7108 
7109             while (procs->number) {
7110                 ref = procs->set.g[procs->number - 1];
7111                 ly_set_rm_index(procs, procs->number - 1);
7112 
7113                 for (i = 0; i < ref->iffeature_size; i++) {
7114                     resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
7115                     for (; j > 0 ; j--) {
7116                         if (ref->iffeature[i].features[j - 1]) {
7117                             if (ref->iffeature[i].features[j - 1] == feat) {
7118                                 LOGVAL(ctx, LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
7119                                 goto featurecheckdone;
7120                             }
7121 
7122                             if (ref->iffeature[i].features[j - 1]->iffeature_size) {
7123                                 k = refs->number;
7124                                 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
7125                                     /* not yet seen feature, add it for processing */
7126                                     ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
7127                                 }
7128                             }
7129                         } else {
7130                             /* forward reference */
7131                             rc = EXIT_FAILURE;
7132                             goto featurecheckdone;
7133                         }
7134                     }
7135 
7136                 }
7137             }
7138             rc = EXIT_SUCCESS;
7139 
7140 featurecheckdone:
7141             ly_set_free(refs);
7142             ly_set_free(procs);
7143         }
7144 
7145         break;
7146     case UNRES_USES:
7147         rc = resolve_unres_schema_uses(item, unres);
7148         break;
7149     case UNRES_TYPEDEF_DFLT:
7150         parent_type++;
7151         /* falls through */
7152     case UNRES_TYPE_DFLT:
7153         stype = item;
7154         rc = check_default(stype, (const char **)str_snode, mod, parent_type);
7155         if ((rc == EXIT_FAILURE) && !parent_type && (stype->base == LY_TYPE_LEAFREF)) {
7156             for (par_grp = (struct lys_node *)stype->parent;
7157                  par_grp && (par_grp->nodetype != LYS_GROUPING);
7158                  par_grp = lys_parent(par_grp));
7159             if (par_grp) {
7160                 /* checking default value in a grouping finished with forward reference means we cannot check the value */
7161                 rc = EXIT_SUCCESS;
7162             }
7163         }
7164         break;
7165     case UNRES_CHOICE_DFLT:
7166         expr = str_snode;
7167         has_str = 1;
7168         choic = item;
7169 
7170         if (!choic->dflt) {
7171             choic->dflt = resolve_choice_dflt(choic, expr);
7172         }
7173         if (choic->dflt) {
7174             rc = lyp_check_mandatory_choice((struct lys_node *)choic);
7175         } else {
7176             rc = EXIT_FAILURE;
7177         }
7178         break;
7179     case UNRES_LIST_KEYS:
7180         rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
7181         break;
7182     case UNRES_LIST_UNIQ:
7183         unique_info = (struct unres_list_uniq *)item;
7184         rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
7185         break;
7186     case UNRES_AUGMENT:
7187         rc = resolve_augment(item, NULL, unres);
7188         break;
7189     case UNRES_XPATH:
7190         node = (struct lys_node *)item;
7191         rc = check_xpath(node, 1);
7192         break;
7193     case UNRES_MOD_IMPLEMENT:
7194         rc = lys_make_implemented_r(mod, unres);
7195         break;
7196     case UNRES_EXT:
7197         ext_data = (struct unres_ext *)str_snode;
7198         extlist = &(*(struct lys_ext_instance ***)item)[ext_data->ext_index];
7199         rc = resolve_extension(ext_data, extlist, unres);
7200         if (!rc && extlist[0]) {
7201             /* success */
7202             /* is there a callback to be done to finalize the extension? */
7203             eplugin = extlist[0]->def->plugin;
7204             if (eplugin) {
7205                 if (eplugin->check_result || (eplugin->flags & LYEXT_OPT_INHERIT)) {
7206                     u = malloc(sizeof *u);
7207                     LY_CHECK_ERR_RETURN(!u, LOGMEM(ctx), -1);
7208                     (*u) = ext_data->ext_index;
7209                     if (unres_schema_add_node(mod, unres, item, UNRES_EXT_FINALIZE, (struct lys_node *)u) == -1) {
7210                         /* something really bad happened since the extension finalization is not actually
7211                          * being resolved while adding into unres, so something more serious with the unres
7212                          * list itself must happened */
7213                         return -1;
7214                     }
7215                 }
7216             }
7217         }
7218         break;
7219     case UNRES_EXT_FINALIZE:
7220         u = (uint8_t *)str_snode;
7221         ext = (*(struct lys_ext_instance ***)item)[*u];
7222         free(u);
7223 
7224         eplugin = ext->def->plugin;
7225 
7226         /* inherit */
7227         if ((eplugin->flags & LYEXT_OPT_INHERIT) && (ext->parent_type == LYEXT_PAR_NODE)) {
7228             root = (struct lys_node *)ext->parent;
7229             if (!(root->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
7230                 LY_TREE_DFS_BEGIN(root->child, next, node) {
7231                     /* first, check if the node already contain instance of the same extension,
7232                      * in such a case we won't inherit. In case the node was actually defined as
7233                      * augment data, we are supposed to check the same way also the augment node itself */
7234                     if (lys_ext_instance_presence(ext->def, node->ext, node->ext_size) != -1) {
7235                         goto inherit_dfs_sibling;
7236                     } else if (node->parent != root && node->parent->nodetype == LYS_AUGMENT &&
7237                             lys_ext_instance_presence(ext->def, node->parent->ext, node->parent->ext_size) != -1) {
7238                         goto inherit_dfs_sibling;
7239                     }
7240 
7241                     if (eplugin->check_inherit) {
7242                         /* we have a callback to check the inheritance, use it */
7243                         switch ((rc = (*eplugin->check_inherit)(ext, node))) {
7244                         case 0:
7245                             /* yes - continue with the inheriting code */
7246                             break;
7247                         case 1:
7248                             /* no - continue with the node's sibling */
7249                             goto inherit_dfs_sibling;
7250                         case 2:
7251                             /* no, but continue with the children, just skip the inheriting code for this node */
7252                             goto inherit_dfs_child;
7253                         default:
7254                             LOGERR(ctx, LY_EINT, "Plugin's (%s:%s) check_inherit callback returns invalid value (%d),",
7255                                    ext->def->module->name, ext->def->name, rc);
7256                         }
7257                     }
7258 
7259                     /* inherit the extension */
7260                     extlist = realloc(node->ext, (node->ext_size + 1) * sizeof *node->ext);
7261                     LY_CHECK_ERR_RETURN(!extlist, LOGMEM(ctx), -1);
7262                     extlist[node->ext_size] = malloc(sizeof **extlist);
7263                     LY_CHECK_ERR_RETURN(!extlist[node->ext_size], LOGMEM(ctx); node->ext = extlist, -1);
7264                     memcpy(extlist[node->ext_size], ext, sizeof *ext);
7265                     extlist[node->ext_size]->flags |= LYEXT_OPT_INHERIT;
7266 
7267                     node->ext = extlist;
7268                     node->ext_size++;
7269 
7270 inherit_dfs_child:
7271                     /* modification of - select element for the next run - children first */
7272                     if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
7273                         next = NULL;
7274                     } else {
7275                         next = node->child;
7276                     }
7277                     if (!next) {
7278 inherit_dfs_sibling:
7279                         /* no children, try siblings */
7280                         next = node->next;
7281                     }
7282                     while (!next) {
7283                         /* go to the parent */
7284                         node = lys_parent(node);
7285 
7286                         /* we are done if we are back in the root (the starter's parent */
7287                         if (node == root) {
7288                             break;
7289                         }
7290 
7291                         /* parent is already processed, go to its sibling */
7292                         next = node->next;
7293                     }
7294                 }
7295             }
7296         }
7297 
7298         /* final check */
7299         if (eplugin->check_result) {
7300             if ((*eplugin->check_result)(ext)) {
7301                 LOGERR(ctx, LY_EPLUGIN, "Resolving extension failed.");
7302                 return -1;
7303             }
7304         }
7305 
7306         rc = 0;
7307         break;
7308     default:
7309         LOGINT(ctx);
7310         break;
7311     }
7312 
7313     if (has_str && !rc) {
7314         /* the string is no more needed in case of success.
7315          * In case of forward reference, we will try to resolve the string later */
7316         lydict_remove(ctx, str_snode);
7317     }
7318 
7319     return rc;
7320 }
7321 
7322 /* logs directly */
7323 static void
print_unres_schema_item_fail(void * item,enum UNRES_ITEM type,void * str_node)7324 print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
7325 {
7326     struct lyxml_elem *xml;
7327     struct lyxml_attr *attr;
7328     struct unres_iffeat_data *iff_data;
7329     const char *name = NULL;
7330     struct unres_ext *extinfo;
7331 
7332     switch (type) {
7333     case UNRES_IDENT:
7334         LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
7335         break;
7336     case UNRES_TYPE_IDENTREF:
7337         LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
7338         break;
7339     case UNRES_TYPE_LEAFREF:
7340         LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
7341                ((struct lys_type *)item)->info.lref.path);
7342         break;
7343     case UNRES_TYPE_DER_EXT:
7344     case UNRES_TYPE_DER_TPDF:
7345     case UNRES_TYPE_DER:
7346         xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
7347         if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
7348             name = ((struct yang_type *)xml)->name;
7349         } else {
7350             LY_TREE_FOR(xml->attr, attr) {
7351                 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
7352                     name = attr->value;
7353                     break;
7354                 }
7355             }
7356             assert(attr);
7357         }
7358         LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", name);
7359         break;
7360     case UNRES_IFFEAT:
7361         iff_data = str_node;
7362         LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
7363         break;
7364     case UNRES_FEATURE:
7365         LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
7366                ((struct lys_feature *)item)->name);
7367         break;
7368     case UNRES_USES:
7369         LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
7370         break;
7371     case UNRES_TYPEDEF_DFLT:
7372     case UNRES_TYPE_DFLT:
7373         if (*(char **)str_node) {
7374             LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", *(char **)str_node);
7375         }   /* else no default value in the type itself, but we are checking some restrictions against
7376              *  possible default value of some base type. The failure is caused by not resolved base type,
7377              *  so it was already reported */
7378         break;
7379     case UNRES_CHOICE_DFLT:
7380         LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
7381         break;
7382     case UNRES_LIST_KEYS:
7383         LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
7384         break;
7385     case UNRES_LIST_UNIQ:
7386         LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
7387         break;
7388     case UNRES_AUGMENT:
7389         LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
7390                ((struct lys_node_augment *)item)->target_name);
7391         break;
7392     case UNRES_XPATH:
7393         LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "XPath expressions of",
7394                ((struct lys_node *)item)->name);
7395         break;
7396     case UNRES_EXT:
7397         extinfo = (struct unres_ext *)str_node;
7398         name = extinfo->datatype == LYS_IN_YIN ? extinfo->data.yin->name : NULL; /* TODO YANG extension */
7399         LOGVRB("Resolving extension \"%s\" failed, it will be attempted later.", name);
7400         break;
7401     default:
7402         LOGINT(NULL);
7403         break;
7404     }
7405 }
7406 
7407 /**
7408  * @brief Save extension instance parent for Compacting later.
7409  *
7410  * @param[in] ext_parents Extension instance parent set
7411  * @param[in] ext_par_types Extension instance parent type list, same size with ext_parents
7412  * @param[in] ext_list Extension instance array
7413  * @param[in] ext_data Unsolved extension instance data
7414  *
7415  * @return 0 on success, -1 on failure.
7416  */
7417 static int
save_skipped_ext_parent(struct ly_set * ext_parents,struct ly_set * ext_par_types,struct lys_ext_instance ** ext_list,struct unres_ext * ext_data)7418 save_skipped_ext_parent(struct ly_set *ext_parents, struct ly_set *ext_par_types,
7419         struct lys_ext_instance **ext_list, struct unres_ext *ext_data)
7420 {
7421     int rt;
7422 
7423     if(!ext_list[ext_data->ext_index]) {
7424         rt = ly_set_add(ext_parents, ext_data->parent, 0);
7425         LY_CHECK_RETURN(rt == -1, rt);
7426         if (ext_parents->number != ext_par_types->number) {
7427             // a new skipped extension instance parent
7428             rt = ly_set_add(ext_par_types, (void *)ext_data->datatype, 1);
7429             LY_CHECK_RETURN(rt == -1, rt);
7430         }
7431     }
7432 
7433     return 0;
7434 }
7435 
7436 /**
7437  * @brief Remove all NULL items from the extension instance array of given parent.
7438  *
7439  * @param[in] ctx Context with the modules
7440  * @param[in] elem Extension instance parent
7441  * @param[in] elem_type Extension instance parent type
7442  *
7443  * @return 0 on success, -1 on failure.
7444  */
7445 static int
compact_ext_list(struct ly_ctx * ctx,void * elem,LYEXT_PAR elem_type)7446 compact_ext_list(struct ly_ctx *ctx, void *elem, LYEXT_PAR elem_type)
7447 {
7448     int rt;
7449     uint8_t *ext_size = 0, orig_size, i = 0, j = 0;
7450     struct lys_ext_instance ***ext_list = NULL;
7451 
7452     rt = lyp_get_ext_list(ctx, elem, elem_type, &ext_list, &ext_size, NULL);
7453     LY_CHECK_RETURN(rt, -1);
7454 
7455     orig_size = *ext_size;
7456 
7457     while (i < *ext_size) {
7458         if (!(*ext_list)[i]) {
7459             /* this extension is skipped, move all extensions after it */
7460             for (j = i; j < *ext_size - 1; j++) {
7461                 (*ext_list)[j] = (*ext_list)[j + 1];
7462             }
7463             --(*ext_size);
7464         } else {
7465             ++i;
7466         }
7467     }
7468 
7469     lyp_reduce_ext_list(ext_list, *ext_size, orig_size);
7470 
7471     return 0;
7472 }
7473 
7474 static int
resolve_unres_schema_types(struct unres_schema * unres,enum UNRES_ITEM types,struct ly_ctx * ctx,int forward_ref,int print_all_errors,uint32_t * resolved)7475 resolve_unres_schema_types(struct unres_schema *unres, enum UNRES_ITEM types, struct ly_ctx *ctx, int forward_ref,
7476                            int print_all_errors, uint32_t *resolved)
7477 {
7478     uint32_t i, unres_count, res_count;
7479     int ret = 0, rc;
7480     struct ly_err_item *prev_eitem;
7481     enum int_log_opts prev_ilo;
7482     LY_ERR prev_ly_errno = LY_SUCCESS;
7483     struct ly_set *ext_parents = NULL, *ext_par_types = NULL;
7484 
7485     /* if there can be no forward references, every failure is final, so we can print it directly */
7486     if (forward_ref) {
7487         prev_ly_errno = ly_errno;
7488         ly_ilo_change(ctx, ILO_STORE, &prev_ilo, &prev_eitem);
7489     }
7490 
7491     if ((types & UNRES_EXT)) {
7492         ext_parents = ly_set_new();
7493         ext_par_types = ly_set_new();
7494         LY_CHECK_ERR_GOTO(!ext_parents || !ext_par_types, ret = -1, finish);
7495     }
7496 
7497     do {
7498         unres_count = 0;
7499         res_count = 0;
7500 
7501         for (i = 0; i < unres->count; ++i) {
7502             /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
7503              * if-features are resolved here to make sure that we will have all if-features for
7504              * later check of feature circular dependency */
7505             if (unres->type[i] & types) {
7506                 ++unres_count;
7507                 rc = resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres);
7508                 if (unres->type[i] == UNRES_EXT_FINALIZE) {
7509                     /* to avoid double free */
7510                     unres->type[i] = UNRES_RESOLVED;
7511                 }
7512 
7513                 if (unres->type[i] == UNRES_EXT) {
7514                     if (!rc) {
7515                         ret = save_skipped_ext_parent(ext_parents, ext_par_types,
7516                                 *(struct lys_ext_instance***) unres->item[i],
7517                                 (struct unres_ext*) unres->str_snode[i]);
7518                     }
7519                     if (!rc || rc == -1) {
7520                         free_ext_data(ctx, unres->str_snode[i]);
7521                     }
7522                     LY_CHECK_GOTO(ret, finish);
7523                 }
7524 
7525                 if (!rc || (unres->type[i] == UNRES_XPATH)) {
7526                     /* invalid XPath can never cause an error, only a warning */
7527                     if (unres->type[i] == UNRES_LIST_UNIQ) {
7528                         /* free the allocated structure */
7529                         free(unres->item[i]);
7530                     }
7531 
7532                     unres->type[i] = UNRES_RESOLVED;
7533 
7534                     ++(*resolved);
7535                     ++res_count;
7536                 } else if ((rc == EXIT_FAILURE) && forward_ref) {
7537                     /* forward reference, erase errors */
7538                     ly_err_free_next(ctx, prev_eitem);
7539                 } else if (print_all_errors) {
7540                     /* just so that we quit the loop */
7541                     ++res_count;
7542                     ret = -1;
7543                 } else {
7544                     if (forward_ref) {
7545                         ly_ilo_restore(ctx, prev_ilo, prev_eitem, 1);
7546                     }
7547                     ret = -1;
7548                     goto finish;
7549                 }
7550             }
7551         }
7552     } while (res_count && (res_count < unres_count));
7553 
7554     if (res_count < unres_count) {
7555         assert(forward_ref);
7556         /* just print the errors (but we must free the ones we have and get them again :-/ ) */
7557         ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
7558 
7559         for (i = 0; i < unres->count; ++i) {
7560             if (unres->type[i] & types) {
7561                 resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres);
7562             }
7563         }
7564         ret = -1;
7565         goto finish;
7566     }
7567 
7568     if (forward_ref) {
7569         /* restore log */
7570         ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
7571         ly_errno = prev_ly_errno;
7572     }
7573 
7574     if ((types & UNRES_EXT)) {
7575         assert(ext_parents->number == ext_par_types->number);
7576         for (i = 0; i < ext_parents->number; ++i) {
7577             ret = compact_ext_list(ctx, ext_parents->set.g[i], (LYEXT_PAR)(uintptr_t)ext_parents->set.g[i]);
7578             LY_CHECK_GOTO(ret == -1, finish);
7579         }
7580     }
7581 
7582 finish:
7583     ly_set_free(ext_parents);
7584     ly_set_free(ext_par_types);
7585     return ret;
7586 }
7587 
7588 /**
7589  * @brief Resolve every unres schema item in the structure. Logs directly.
7590  *
7591  * @param[in] mod Main module.
7592  * @param[in] unres Unres schema structure to use.
7593  *
7594  * @return EXIT_SUCCESS on success, -1 on error.
7595  */
7596 int
resolve_unres_schema(struct lys_module * mod,struct unres_schema * unres)7597 resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
7598 {
7599     uint32_t resolved = 0;
7600 
7601     assert(unres);
7602 
7603     LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
7604 
7605     /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
7606      * if-features are resolved here to make sure that we will have all if-features for
7607      * later check of feature circular dependency */
7608     if (resolve_unres_schema_types(unres, UNRES_USES | UNRES_IFFEAT | UNRES_TYPE_DER | UNRES_TYPE_DER_TPDF | UNRES_TYPE_DER_TPDF
7609                                    | UNRES_AUGMENT | UNRES_CHOICE_DFLT | UNRES_IDENT,
7610                                    mod->ctx, 1, 0, &resolved)) {
7611         return -1;
7612     }
7613 
7614     if (resolve_unres_schema_types(unres, UNRES_MOD_IMPLEMENT, mod->ctx, 1, 0, &resolved)) {
7615         return -1;
7616     }
7617 
7618     /* another batch of resolved items (UNRES_MOD_IMPLEMENT must be set again because it can be added again) */
7619     if (resolve_unres_schema_types(unres, UNRES_TYPE_IDENTREF | UNRES_FEATURE | UNRES_TYPEDEF_DFLT | UNRES_TYPE_DFLT
7620                                    | UNRES_TYPE_LEAFREF | UNRES_LIST_KEYS | UNRES_LIST_UNIQ | UNRES_EXT | UNRES_MOD_IMPLEMENT,
7621                                    mod->ctx, 1, 0, &resolved)) {
7622         return -1;
7623     }
7624 
7625     /* print xpath warnings and finalize extensions, keep it last to provide the complete schema tree information to the plugin's checkers */
7626     if (resolve_unres_schema_types(unres, UNRES_XPATH | UNRES_EXT_FINALIZE, mod->ctx, 0, 1, &resolved)) {
7627         return -1;
7628     }
7629 
7630     LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
7631     unres->count = 0;
7632     return EXIT_SUCCESS;
7633 }
7634 
7635 /**
7636  * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
7637  *
7638  * @param[in] mod Main module.
7639  * @param[in] unres Unres schema structure to use.
7640  * @param[in] item Item to resolve. Type determined by \p type.
7641  * @param[in] type Type of the unresolved item.
7642  * @param[in] str String argument.
7643  *
7644  * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
7645  */
7646 int
unres_schema_add_str(struct lys_module * mod,struct unres_schema * unres,void * item,enum UNRES_ITEM type,const char * str)7647 unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
7648                      const char *str)
7649 {
7650     int rc;
7651     const char *dictstr;
7652 
7653     dictstr = lydict_insert(mod->ctx, str, 0);
7654     rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
7655 
7656     if (rc < 0) {
7657         lydict_remove(mod->ctx, dictstr);
7658     }
7659     return rc;
7660 }
7661 
7662 /**
7663  * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
7664  *
7665  * @param[in] mod Main module.
7666  * @param[in] unres Unres schema structure to use.
7667  * @param[in] item Item to resolve. Type determined by \p type.
7668  * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
7669  * @param[in] snode Schema node argument.
7670  *
7671  * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
7672  */
7673 int
unres_schema_add_node(struct lys_module * mod,struct unres_schema * unres,void * item,enum UNRES_ITEM type,struct lys_node * snode)7674 unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
7675                       struct lys_node *snode)
7676 {
7677     int rc;
7678     uint32_t u;
7679     enum int_log_opts prev_ilo;
7680     struct ly_err_item *prev_eitem;
7681     LY_ERR prev_ly_errno;
7682     struct lyxml_elem *yin;
7683     struct lys_type *stype;
7684     struct ly_ctx *ctx = mod->ctx;
7685 
7686     assert(unres && (item || (type == UNRES_MOD_IMPLEMENT)) && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID)
7687            && (type != UNRES_WHEN) && (type != UNRES_MUST)));
7688 
7689     /* check for duplicities in unres */
7690     for (u = 0; u < unres->count; u++) {
7691         if (unres->type[u] == type && unres->item[u] == item &&
7692                 unres->str_snode[u] == snode && unres->module[u] == mod) {
7693             /* duplication can happen when the node contains multiple statements of the same type to check,
7694              * this can happen for example when refinement is being applied, so we just postpone the processing
7695              * and do not duplicate the information */
7696             return EXIT_FAILURE;
7697         }
7698     }
7699 
7700     if ((type == UNRES_EXT_FINALIZE) || (type == UNRES_XPATH) || (type == UNRES_MOD_IMPLEMENT)) {
7701         /* extension finalization is not even tried when adding the item into the inres list,
7702          * xpath is not tried because it would hide some potential warnings,
7703          * implementing module must be deferred because some other nodes can be added that will need to be traversed
7704          * and their targets made implemented */
7705         rc = EXIT_FAILURE;
7706     } else {
7707         prev_ly_errno = ly_errno;
7708         ly_ilo_change(ctx, ILO_STORE, &prev_ilo, &prev_eitem);
7709 
7710         rc = resolve_unres_schema_item(mod, item, type, snode, unres);
7711         if (rc != EXIT_FAILURE) {
7712             if (type == UNRES_EXT) {
7713                 free_ext_data(mod->ctx, (struct unres_ext*)snode);
7714             }
7715             ly_ilo_restore(ctx, prev_ilo, prev_eitem, rc == -1 ? 1 : 0);
7716             if (rc != -1) {
7717                 /* print warnings here so that they are actually printed */
7718                 if ((type == UNRES_TYPE_DER_TPDF) || (type == UNRES_TYPE_DER)) {
7719                     stype = item;
7720                     if (stype->der->module && (((stype->base == LY_TYPE_LEAFREF)
7721                             && (stype->info.lref.req != stype->der->type.info.lref.req)) || ((stype->base == LY_TYPE_INST)
7722                             && (stype->info.inst.req != stype->der->type.info.inst.req)))) {
7723                         if (type == UNRES_TYPE_DER_TPDF) {
7724                             /* typedef */
7725                             LOGWRN(ctx, "Derived typedef \"%s\" is changing the \"require-instance\" property, "
7726                                    "which is discouraged.", stype->parent->name);
7727                         } else {
7728                             /* leaf */
7729                             LOGWRN(ctx, "Node \"%s\" type is changing the \"require-instance\" property, "
7730                                    "which is discouraged.", snode->name);
7731                         }
7732                     }
7733                 }
7734                 ly_errno = prev_ly_errno;
7735             }
7736 
7737             if (type == UNRES_LIST_UNIQ) {
7738                 /* free the allocated structure */
7739                 free(item);
7740             } else if (rc == -1 && type == UNRES_IFFEAT) {
7741                 /* free the allocated resources */
7742                 free(*((char **)item));
7743             }
7744             return rc;
7745         } else {
7746             /* erase info about validation errors */
7747             ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
7748             ly_errno = prev_ly_errno;
7749         }
7750 
7751         print_unres_schema_item_fail(item, type, snode);
7752 
7753         /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
7754         if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
7755             yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
7756             if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
7757                 lyxml_unlink_elem(mod->ctx, yin, 1);
7758                 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
7759             }
7760         }
7761     }
7762 
7763     unres->count++;
7764     unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
7765     LY_CHECK_ERR_RETURN(!unres->item, LOGMEM(ctx), -1);
7766     unres->item[unres->count-1] = item;
7767     unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
7768     LY_CHECK_ERR_RETURN(!unres->type, LOGMEM(ctx), -1);
7769     unres->type[unres->count-1] = type;
7770     unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
7771     LY_CHECK_ERR_RETURN(!unres->str_snode, LOGMEM(ctx), -1);
7772     unres->str_snode[unres->count-1] = snode;
7773     unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
7774     LY_CHECK_ERR_RETURN(!unres->module, LOGMEM(ctx), -1);
7775     unres->module[unres->count-1] = mod;
7776 
7777     return rc;
7778 }
7779 
7780 /**
7781  * @brief Duplicate an unres schema item. Logs indirectly.
7782  *
7783  * @param[in] mod Main module.
7784  * @param[in] unres Unres schema structure to use.
7785  * @param[in] item Old item to be resolved.
7786  * @param[in] type Type of the old unresolved item.
7787  * @param[in] new_item New item to use in the duplicate.
7788  *
7789  * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
7790  */
7791 int
unres_schema_dup(struct lys_module * mod,struct unres_schema * unres,void * item,enum UNRES_ITEM type,void * new_item)7792 unres_schema_dup(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type, void *new_item)
7793 {
7794     int i;
7795     struct unres_list_uniq aux_uniq;
7796     struct unres_iffeat_data *iff_data;
7797 
7798     assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
7799 
7800     /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
7801     if (type == UNRES_LIST_UNIQ) {
7802         aux_uniq.list = item;
7803         aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
7804         item = &aux_uniq;
7805     }
7806     i = unres_schema_find(unres, -1, item, type);
7807 
7808     if (i == -1) {
7809         if (type == UNRES_LIST_UNIQ) {
7810             free(new_item);
7811         }
7812         return EXIT_FAILURE;
7813     }
7814 
7815     if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
7816             (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
7817         if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
7818             LOGINT(mod->ctx);
7819             return -1;
7820         }
7821     } else if (type == UNRES_IFFEAT) {
7822         /* duplicate unres_iffeature_data */
7823         iff_data = malloc(sizeof *iff_data);
7824         LY_CHECK_ERR_RETURN(!iff_data, LOGMEM(mod->ctx), -1);
7825         iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
7826         iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
7827         iff_data->infeature = ((struct unres_iffeat_data *)unres->str_snode[i])->infeature;
7828         if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
7829             LOGINT(mod->ctx);
7830             return -1;
7831         }
7832     } else {
7833         if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
7834             LOGINT(mod->ctx);
7835             return -1;
7836         }
7837     }
7838 
7839     return EXIT_SUCCESS;
7840 }
7841 
7842 /* does not log */
7843 int
unres_schema_find(struct unres_schema * unres,int start_on_backwards,void * item,enum UNRES_ITEM type)7844 unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
7845 {
7846     int i;
7847     struct unres_list_uniq *aux_uniq1, *aux_uniq2;
7848 
7849     if (!unres->count) {
7850         return -1;
7851     }
7852 
7853     if (start_on_backwards >= 0) {
7854         i = start_on_backwards;
7855     } else {
7856         i = unres->count - 1;
7857     }
7858     for (; i > -1; i--) {
7859         if (unres->type[i] != type) {
7860             continue;
7861         }
7862         if (type != UNRES_LIST_UNIQ) {
7863             if (unres->item[i] == item) {
7864                 break;
7865             }
7866         } else {
7867             aux_uniq1 = (struct unres_list_uniq *)unres->item[i];
7868             aux_uniq2 = (struct unres_list_uniq *)item;
7869             if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
7870                 break;
7871             }
7872         }
7873     }
7874 
7875     return i;
7876 }
7877 
7878 static void
unres_schema_free_item(struct ly_ctx * ctx,struct unres_schema * unres,uint32_t i)7879 unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
7880 {
7881     struct lyxml_elem *yin;
7882     struct yang_type *yang;
7883     struct unres_iffeat_data *iff_data;
7884 
7885     switch (unres->type[i]) {
7886     case UNRES_TYPE_DER_TPDF:
7887     case UNRES_TYPE_DER:
7888         yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
7889         if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
7890             yang =(struct yang_type *)yin;
7891             ((struct lys_type *)unres->item[i])->base = yang->base;
7892             lydict_remove(ctx, yang->name);
7893             free(yang);
7894             if (((struct lys_type *)unres->item[i])->base == LY_TYPE_UNION) {
7895                 yang_free_type_union(ctx, (struct lys_type *)unres->item[i]);
7896             }
7897         } else {
7898             lyxml_free(ctx, yin);
7899         }
7900         break;
7901     case UNRES_IFFEAT:
7902         iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
7903         lydict_remove(ctx, iff_data->fname);
7904         free(unres->str_snode[i]);
7905         break;
7906     case UNRES_IDENT:
7907     case UNRES_TYPE_IDENTREF:
7908     case UNRES_CHOICE_DFLT:
7909     case UNRES_LIST_KEYS:
7910         lydict_remove(ctx, (const char *)unres->str_snode[i]);
7911         break;
7912     case UNRES_LIST_UNIQ:
7913         free(unres->item[i]);
7914         break;
7915     case UNRES_EXT:
7916         free_ext_data(ctx, unres->str_snode[i]);
7917         break;
7918     case UNRES_EXT_FINALIZE:
7919         free(unres->str_snode[i]);
7920     default:
7921         break;
7922     }
7923     unres->type[i] = UNRES_RESOLVED;
7924 }
7925 
7926 void
unres_schema_free(struct lys_module * module,struct unres_schema ** unres,int all)7927 unres_schema_free(struct lys_module *module, struct unres_schema **unres, int all)
7928 {
7929     uint32_t i;
7930     unsigned int unresolved = 0;
7931 
7932     if (!unres || !(*unres)) {
7933         return;
7934     }
7935 
7936     assert(module || ((*unres)->count == 0));
7937 
7938     for (i = 0; i < (*unres)->count; ++i) {
7939         if (!all && ((*unres)->module[i] != module)) {
7940             if ((*unres)->type[i] != UNRES_RESOLVED) {
7941                 unresolved++;
7942             }
7943             continue;
7944         }
7945 
7946         /* free heap memory for the specific item */
7947         unres_schema_free_item(module->ctx, *unres, i);
7948     }
7949 
7950     /* free it all */
7951     if (!module || all || (!unresolved && !module->type)) {
7952         free((*unres)->item);
7953         free((*unres)->type);
7954         free((*unres)->str_snode);
7955         free((*unres)->module);
7956         free((*unres));
7957         (*unres) = NULL;
7958     }
7959 }
7960 
7961 /* check whether instance-identifier points outside its data subtree (for operation it is any node
7962  * outside the operation subtree, otherwise it is a node from a foreign model) */
7963 static int
check_instid_ext_dep(const struct lys_node * sleaf,const char * json_instid)7964 check_instid_ext_dep(const struct lys_node *sleaf, const char *json_instid)
7965 {
7966     const struct lys_node *op_node, *first_node;
7967     enum int_log_opts prev_ilo;
7968     char *buf, *tmp;
7969 
7970     if (!json_instid || !json_instid[0]) {
7971         /* no/empty value */
7972         return 0;
7973     }
7974 
7975     for (op_node = lys_parent(sleaf);
7976          op_node && !(op_node->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION));
7977          op_node = lys_parent(op_node));
7978 
7979     if (op_node && lys_parent(op_node)) {
7980         /* nested operation - any absolute path is external */
7981         return 1;
7982     }
7983 
7984     /* get the first node from the instid */
7985     tmp = strchr(json_instid + 1, '/');
7986     buf = strndup(json_instid, tmp ? (size_t)(tmp - json_instid) : strlen(json_instid));
7987     if (!buf) {
7988         /* so that we do not have to bother with logging, say it is not external */
7989         return 0;
7990     }
7991 
7992     /* find the first schema node, do not log */
7993     ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, NULL);
7994     first_node = ly_ctx_get_node(NULL, sleaf, buf, 0);
7995     ly_ilo_restore(NULL, prev_ilo, NULL, 0);
7996 
7997     free(buf);
7998     if (!first_node) {
7999         /* unknown path, say it is external */
8000         return 1;
8001     }
8002 
8003     /* based on the first schema node in the path we can decide whether it points to an external tree or not */
8004 
8005     if (op_node) {
8006         if (op_node != first_node) {
8007             /* it is a top-level operation, so we're good if it points somewhere inside it */
8008             return 1;
8009         }
8010     } else {
8011         if (lys_node_module(sleaf) != lys_node_module(first_node)) {
8012             /* modules differ */
8013             return 1;
8014         }
8015     }
8016 
8017     return 0;
8018 }
8019 
8020 int
resolve_instid(struct lyd_node * data,const char * path,int req_inst,struct lyd_node ** ret)8021 resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd_node **ret)
8022 {
8023     int i = 0, j, parsed, cur_idx;
8024     const struct lys_module *mod, *prev_mod = NULL;
8025     struct ly_ctx *ctx = data->schema->module->ctx;
8026     struct lyd_node *root, *node;
8027     const char *model = NULL, *name;
8028     char *str;
8029     int mod_len, name_len, has_predicate;
8030     struct unres_data node_match;
8031 
8032     memset(&node_match, 0, sizeof node_match);
8033     *ret = NULL;
8034 
8035     /* we need root to resolve absolute path */
8036     for (root = data; root->parent; root = root->parent);
8037     /* we're still parsing it and the pointer is not correct yet */
8038     if (root->prev) {
8039         for (; root->prev->next; root = root->prev);
8040     }
8041 
8042     /* search for the instance node */
8043     while (path[i]) {
8044         j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
8045         if (j <= 0) {
8046             LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
8047             goto error;
8048         }
8049         i += j;
8050 
8051         if (model) {
8052             str = strndup(model, mod_len);
8053             if (!str) {
8054                 LOGMEM(ctx);
8055                 goto error;
8056             }
8057             mod = ly_ctx_get_module(ctx, str, NULL, 1);
8058             if (ctx->data_clb) {
8059                 if (!mod) {
8060                     mod = ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
8061                 } else if (!mod->implemented) {
8062                     mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
8063                 }
8064             }
8065             free(str);
8066 
8067             if (!mod || !mod->implemented || mod->disabled) {
8068                 break;
8069             }
8070         } else if (!prev_mod) {
8071             /* first iteration and we are missing module name */
8072             LOGVAL(ctx, LYE_INELEM_LEN, LY_VLOG_LYD, data, name_len, name);
8073             LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Instance-identifier is missing prefix in the first node.");
8074             goto error;
8075         } else {
8076             mod = prev_mod;
8077         }
8078 
8079         if (resolve_data(mod, name, name_len, root, &node_match)) {
8080             /* no instance exists */
8081             break;
8082         }
8083 
8084         if (has_predicate) {
8085             /* we have predicate, so the current results must be list or leaf-list */
8086             parsed = j = 0;
8087             /* index of the current node (for lists with position predicates) */
8088             cur_idx = 1;
8089             while (j < (signed)node_match.count) {
8090                 node = node_match.node[j];
8091                 parsed = resolve_instid_predicate(mod, &path[i], &node, cur_idx);
8092                 if (parsed < 1) {
8093                     LOGVAL(ctx, LYE_INPRED, LY_VLOG_LYD, data, &path[i - parsed]);
8094                     goto error;
8095                 }
8096 
8097                 if (!node) {
8098                     /* current node does not satisfy the predicate */
8099                     unres_data_del(&node_match, j);
8100                 } else {
8101                     ++j;
8102                 }
8103                 ++cur_idx;
8104             }
8105 
8106             i += parsed;
8107         } else if (node_match.count) {
8108             /* check that we are not addressing lists */
8109             for (j = 0; (unsigned)j < node_match.count; ++j) {
8110                 if (node_match.node[j]->schema->nodetype == LYS_LIST) {
8111                     unres_data_del(&node_match, j--);
8112                 }
8113             }
8114             if (!node_match.count) {
8115                 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYD, data, "Instance identifier is missing list keys.");
8116             }
8117         }
8118 
8119         prev_mod = mod;
8120     }
8121 
8122     if (!node_match.count) {
8123         /* no instance exists */
8124         if (req_inst > -1) {
8125             LOGVAL(ctx, LYE_NOREQINS, LY_VLOG_LYD, data, path);
8126             return EXIT_FAILURE;
8127         }
8128         LOGVRB("There is no instance of \"%s\", but it is not required.", path);
8129         return EXIT_SUCCESS;
8130     } else if (node_match.count > 1) {
8131         /* instance identifier must resolve to a single node */
8132         LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
8133         goto error;
8134     } else {
8135         /* we have required result, remember it and cleanup */
8136         *ret = node_match.node[0];
8137         free(node_match.node);
8138         return EXIT_SUCCESS;
8139     }
8140 
8141 error:
8142     /* cleanup */
8143     free(node_match.node);
8144     return -1;
8145 }
8146 
8147 int
resolve_leafref(struct lyd_node_leaf_list * leaf,const char * path,int req_inst,struct lyd_node ** ret)8148 resolve_leafref(struct lyd_node_leaf_list *leaf, const char *path, int req_inst, struct lyd_node **ret)
8149 {
8150     struct lyxp_set xp_set;
8151     uint32_t i;
8152 
8153     memset(&xp_set, 0, sizeof xp_set);
8154     *ret = NULL;
8155 
8156     /* syntax was already checked, so just evaluate the path using standard XPath */
8157     if (lyxp_eval(path, (struct lyd_node *)leaf, LYXP_NODE_ELEM, lyd_node_module((struct lyd_node *)leaf), &xp_set, 0) != EXIT_SUCCESS) {
8158         return -1;
8159     }
8160 
8161     if (xp_set.type == LYXP_SET_NODE_SET) {
8162         for (i = 0; i < xp_set.used; ++i) {
8163             if ((xp_set.val.nodes[i].type != LYXP_NODE_ELEM) || !(xp_set.val.nodes[i].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
8164                 continue;
8165             }
8166 
8167             /* not that the value is already in canonical form since the parsers does the conversion,
8168              * so we can simply compare just the values */
8169             if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)xp_set.val.nodes[i].node)->value_str, 1)) {
8170                 /* we have the match */
8171                 *ret = xp_set.val.nodes[i].node;
8172                 break;
8173             }
8174         }
8175     }
8176 
8177     lyxp_set_cast(&xp_set, LYXP_SET_EMPTY, (struct lyd_node *)leaf, NULL, 0);
8178 
8179     if (!*ret) {
8180         /* reference not found */
8181         if (req_inst > -1) {
8182             LOGVAL(leaf->schema->module->ctx, LYE_NOLEAFREF, LY_VLOG_LYD, leaf, path, leaf->value_str);
8183             return EXIT_FAILURE;
8184         } else {
8185             LOGVRB("There is no leafref \"%s\" with the value \"%s\", but it is not required.", path, leaf->value_str);
8186         }
8187     }
8188 
8189     return EXIT_SUCCESS;
8190 }
8191 
8192 /* ignore fail because we are parsing edit-config, get, or get-config - but only if the union includes leafref or instid */
8193 int
resolve_union(struct lyd_node_leaf_list * leaf,struct lys_type * type,int store,int ignore_fail,struct lys_type ** resolved_type)8194 resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type, int store, int ignore_fail,
8195               struct lys_type **resolved_type)
8196 {
8197     struct ly_ctx *ctx = leaf->schema->module->ctx;
8198     struct lys_type *t;
8199     struct lyd_node *ret;
8200     enum int_log_opts prev_ilo;
8201     int found, success = 0, ext_dep, req_inst;
8202     const char *json_val = NULL;
8203 
8204     assert(type->base == LY_TYPE_UNION);
8205 
8206     if ((leaf->value_type == LY_TYPE_UNION) || ((leaf->value_type == LY_TYPE_INST) && (leaf->value_flags & LY_VALUE_UNRES))) {
8207         /* either NULL or instid previously converted to JSON */
8208         json_val = lydict_insert(ctx, leaf->value.string, 0);
8209     }
8210 
8211     if (store) {
8212         lyd_free_value(leaf->value, leaf->value_type, leaf->value_flags, &((struct lys_node_leaf *)leaf->schema)->type,
8213                        leaf->value_str, NULL, NULL, NULL);
8214         memset(&leaf->value, 0, sizeof leaf->value);
8215     }
8216 
8217     /* turn logging off, we are going to try to validate the value with all the types in order */
8218     ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, 0);
8219 
8220     t = NULL;
8221     found = 0;
8222     while ((t = lyp_get_next_union_type(type, t, &found))) {
8223         found = 0;
8224 
8225         switch (t->base) {
8226         case LY_TYPE_LEAFREF:
8227             if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
8228                 req_inst = -1;
8229             } else {
8230                 req_inst = t->info.lref.req;
8231             }
8232 
8233             if (!resolve_leafref(leaf, t->info.lref.path, req_inst, &ret)) {
8234                 if (store) {
8235                     if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
8236                         /* valid resolved */
8237                         leaf->value.leafref = ret;
8238                         leaf->value_type = LY_TYPE_LEAFREF;
8239                     } else {
8240                         /* valid unresolved */
8241                         ly_ilo_restore(NULL, prev_ilo, NULL, 0);
8242                         if (!lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, NULL, 1, 0)) {
8243                             return -1;
8244                         }
8245                         ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, NULL);
8246                     }
8247                 }
8248 
8249                 success = 1;
8250             }
8251             break;
8252         case LY_TYPE_INST:
8253             ext_dep = check_instid_ext_dep(leaf->schema, (json_val ? json_val : leaf->value_str));
8254             if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
8255                 req_inst = -1;
8256             } else {
8257                 req_inst = t->info.inst.req;
8258             }
8259 
8260             if (!resolve_instid((struct lyd_node *)leaf, (json_val ? json_val : leaf->value_str), req_inst, &ret)) {
8261                 if (store) {
8262                     if (ret && !ext_dep) {
8263                         /* valid resolved */
8264                         leaf->value.instance = ret;
8265                         leaf->value_type = LY_TYPE_INST;
8266 
8267                         if (json_val) {
8268                             lydict_remove(leaf->schema->module->ctx, leaf->value_str);
8269                             leaf->value_str = json_val;
8270                             json_val = NULL;
8271                         }
8272                     } else {
8273                         /* valid unresolved */
8274                         if (json_val) {
8275                             /* put the JSON val back */
8276                             leaf->value.string = json_val;
8277                             json_val = NULL;
8278                         } else {
8279                             leaf->value.instance = NULL;
8280                         }
8281                         leaf->value_type = LY_TYPE_INST;
8282                         leaf->value_flags |= LY_VALUE_UNRES;
8283                     }
8284                 }
8285 
8286                 success = 1;
8287             }
8288             break;
8289         default:
8290             if (lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, NULL, store, 0)) {
8291                 success = 1;
8292             }
8293             break;
8294         }
8295 
8296         if (success) {
8297             break;
8298         }
8299 
8300         /* erase possible present and invalid value data */
8301         if (store) {
8302             lyd_free_value(leaf->value, leaf->value_type, leaf->value_flags, t, leaf->value_str, NULL, NULL, NULL);
8303             memset(&leaf->value, 0, sizeof leaf->value);
8304         }
8305     }
8306 
8307     /* turn logging back on */
8308     ly_ilo_restore(NULL, prev_ilo, NULL, 0);
8309 
8310     if (json_val) {
8311         if (!success) {
8312             /* put the value back for now */
8313             assert(leaf->value_type == LY_TYPE_UNION);
8314             leaf->value.string = json_val;
8315         } else {
8316             /* value was ultimately useless, but we could not have known */
8317             lydict_remove(leaf->schema->module->ctx, json_val);
8318         }
8319     }
8320 
8321     if (success) {
8322         if (resolved_type) {
8323             *resolved_type = t;
8324         }
8325     } else if (!ignore_fail || !type->info.uni.has_ptr_type) {
8326         /* not found and it is required */
8327         LOGVAL(ctx, LYE_INVAL, LY_VLOG_LYD, leaf, leaf->value_str ? leaf->value_str : "", leaf->schema->name);
8328         return EXIT_FAILURE;
8329     }
8330 
8331     return EXIT_SUCCESS;
8332 
8333 }
8334 
8335 /**
8336  * @brief Resolve a single unres data item. Logs directly.
8337  *
8338  * @param[in] node Data node to resolve.
8339  * @param[in] type Type of the unresolved item.
8340  * @param[in] ignore_fail 0 - no, 1 - yes, 2 - yes, but only for external dependencies.
8341  * @param[in] multi_error 0 - no, 1 - yes.
8342  *
8343  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
8344  */
8345 int
resolve_unres_data_item(struct lyd_node * node,enum UNRES_ITEM type,int ignore_fail,int multi_error,struct lys_when ** failed_when)8346 resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int ignore_fail, int multi_error,
8347         struct lys_when **failed_when)
8348 {
8349     int rc, req_inst, ext_dep;
8350     struct lyd_node_leaf_list *leaf;
8351     struct lyd_node *ret;
8352     struct lys_node_leaf *sleaf;
8353 
8354     leaf = (struct lyd_node_leaf_list *)node;
8355     sleaf = (struct lys_node_leaf *)leaf->schema;
8356 
8357     switch (type) {
8358     case UNRES_LEAFREF:
8359         assert(sleaf->type.base == LY_TYPE_LEAFREF);
8360         if (ignore_fail) {
8361             req_inst = -1;
8362         } else {
8363             req_inst = sleaf->type.info.lref.req;
8364         }
8365         if ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2)) {
8366             /* do not even try to resolve */
8367             rc = 0;
8368             ret = NULL;
8369         } else {
8370             rc = resolve_leafref(leaf, sleaf->type.info.lref.path, req_inst, &ret);
8371         }
8372         if (!rc) {
8373             if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
8374                 /* valid resolved */
8375                 if (leaf->value_type == LY_TYPE_BITS) {
8376                     free(leaf->value.bit);
8377                 }
8378                 leaf->value.leafref = ret;
8379                 leaf->value_type = LY_TYPE_LEAFREF;
8380                 leaf->value_flags &= ~LY_VALUE_UNRES;
8381             } else {
8382                 /* valid unresolved */
8383                 if (!(leaf->value_flags & LY_VALUE_UNRES)) {
8384                     if (!lyp_parse_value(&sleaf->type, &leaf->value_str, NULL, leaf, NULL, NULL, 1, 0)) {
8385                         return -1;
8386                     }
8387                 }
8388             }
8389         } else {
8390             return rc;
8391         }
8392         break;
8393 
8394     case UNRES_INSTID:
8395         assert(sleaf->type.base == LY_TYPE_INST);
8396         ext_dep = check_instid_ext_dep(leaf->schema, leaf->value_str);
8397         if (ext_dep == -1) {
8398             return -1;
8399         }
8400 
8401         if (ignore_fail) {
8402             req_inst = -1;
8403         } else {
8404             req_inst = sleaf->type.info.inst.req;
8405         }
8406         if (ext_dep && (ignore_fail == 2)) {
8407             /* do not even try to resolve */
8408             rc = 0;
8409             ret = NULL;
8410         } else {
8411             rc = resolve_instid(node, leaf->value_str, req_inst, &ret);
8412         }
8413         if (!rc) {
8414             if (ret && !ext_dep) {
8415                 /* valid resolved */
8416                 leaf->value.instance = ret;
8417                 leaf->value_type = LY_TYPE_INST;
8418                 leaf->value_flags &= ~LY_VALUE_UNRES;
8419             } else {
8420                 /* valid unresolved */
8421                 leaf->value.instance = NULL;
8422                 leaf->value_type = LY_TYPE_INST;
8423                 leaf->value_flags |= LY_VALUE_UNRES;
8424             }
8425         } else {
8426             return rc;
8427         }
8428         break;
8429 
8430     case UNRES_UNION:
8431         assert(sleaf->type.base == LY_TYPE_UNION);
8432         return resolve_union(leaf, &sleaf->type, 1, ignore_fail, NULL);
8433 
8434     case UNRES_WHEN:
8435         if ((rc = resolve_when(node, ignore_fail, failed_when))) {
8436             return rc;
8437         }
8438         break;
8439 
8440     case UNRES_MUST:
8441         if ((rc = resolve_must(node, 0, ignore_fail, multi_error))) {
8442             return rc;
8443         }
8444         break;
8445 
8446     case UNRES_MUST_INOUT:
8447         if ((rc = resolve_must(node, 1, ignore_fail, multi_error))) {
8448             return rc;
8449         }
8450         break;
8451 
8452     case UNRES_UNIQ_LEAVES:
8453         if (lyv_data_unique(node)) {
8454             return -1;
8455         }
8456         break;
8457 
8458     default:
8459         LOGINT(NULL);
8460         return -1;
8461     }
8462 
8463     return EXIT_SUCCESS;
8464 }
8465 
8466 /**
8467  * @brief add data unres item
8468  *
8469  * @param[in] unres Unres data structure to use.
8470  * @param[in] node Data node to use.
8471  *
8472  * @return 0 on success, -1 on error.
8473  */
8474 int
unres_data_add(struct unres_data * unres,struct lyd_node * node,enum UNRES_ITEM type)8475 unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
8476 {
8477     assert(unres && node);
8478     assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
8479            || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION) || (type == UNRES_UNIQ_LEAVES));
8480 
8481     unres->count++;
8482     unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
8483     LY_CHECK_ERR_RETURN(!unres->node, LOGMEM(NULL), -1);
8484     unres->node[unres->count - 1] = node;
8485     unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
8486     LY_CHECK_ERR_RETURN(!unres->type, LOGMEM(NULL), -1);
8487     unres->type[unres->count - 1] = type;
8488 
8489     return 0;
8490 }
8491 
8492 static void
resolve_unres_data_autodel_diff(struct unres_data * unres,uint32_t unres_i)8493 resolve_unres_data_autodel_diff(struct unres_data *unres, uint32_t unres_i)
8494 {
8495     struct lyd_node *next, *child, *parent;
8496     uint32_t i;
8497 
8498     for (i = 0; i < unres->diff_idx; ++i) {
8499         if (unres->diff->type[i] == LYD_DIFF_DELETED) {
8500             /* only leaf(-list) default could be removed and there is nothing to be checked in that case */
8501             continue;
8502         }
8503 
8504         if (unres->diff->second[i] == unres->node[unres_i]) {
8505             /* 1) default value was supposed to be created, but is disabled by when
8506              * -> remove it from diff altogether
8507              */
8508             unres_data_diff_rem(unres, i);
8509             /* if diff type is CREATED, the value was just a pointer, it can be freed normally (unlike in 4) */
8510             return;
8511         } else {
8512             parent = unres->diff->second[i]->parent;
8513             while (parent && (parent != unres->node[unres_i])) {
8514                 parent = parent->parent;
8515             }
8516             if (parent) {
8517                 /* 2) default value was supposed to be created but is disabled by when in some parent
8518                  * -> remove this default subtree and add the rest into diff as deleted instead in 4)
8519                  */
8520                 unres_data_diff_rem(unres, i);
8521                 break;
8522             }
8523 
8524             LY_TREE_DFS_BEGIN(unres->diff->second[i], next, child) {
8525                 if (child == unres->node[unres_i]) {
8526                     /* 3) some default child of a default value was supposed to be created but has false when
8527                      * -> the subtree will be freed later and automatically disconnected from the diff parent node
8528                      */
8529                     return;
8530                 }
8531 
8532                 LY_TREE_DFS_END(unres->diff->second[i], next, child);
8533             }
8534         }
8535     }
8536 
8537     /* 4) it does not overlap with created default values in any way
8538      * -> just add it into diff as deleted
8539      */
8540     unres_data_diff_new(unres, unres->node[unres_i], unres->node[unres_i]->parent, 0);
8541     lyd_unlink(unres->node[unres_i]);
8542 
8543     /* should not be freed anymore */
8544     unres->node[unres_i] = NULL;
8545 }
8546 
8547 /**
8548  * @brief Resolve every unres data item in the structure. Logs directly.
8549  *
8550  * If options include #LYD_OPT_TRUSTED, the data are considered trusted (must conditions are not expected,
8551  * unresolved leafrefs/instids are accepted, when conditions are normally resolved because at least some implicit
8552  * non-presence containers may need to be deleted).
8553  *
8554  * If options includes #LYD_OPT_WHENAUTODEL, the non-default nodes with false when conditions are auto-deleted.
8555  *
8556  * @param[in] ctx Context used.
8557  * @param[in] unres Unres data structure to use.
8558  * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
8559  * @param[in] options Data options as described above.
8560  *
8561  * @return EXIT_SUCCESS on success, -1 on error.
8562  */
8563 int
resolve_unres_data(struct ly_ctx * ctx,struct unres_data * unres,struct lyd_node ** root,int options)8564 resolve_unres_data(struct ly_ctx *ctx, struct unres_data *unres, struct lyd_node **root, int options)
8565 {
8566     uint32_t i, j, first, resolved, del_items, stmt_count;
8567     uint8_t prev_when_status;
8568     int rc, rc2, progress, ignore_fail, multi_error;
8569     enum int_log_opts prev_ilo;
8570     struct ly_err_item *prev_eitem = NULL;
8571     LY_ERR prev_ly_errno = ly_errno;
8572     struct lyd_node *parent;
8573     struct lys_when *when;
8574 
8575     assert(root);
8576     assert(unres);
8577 
8578     if (!unres->count) {
8579         return EXIT_SUCCESS;
8580     }
8581 
8582     if (options & (LYD_OPT_NOTIF_FILTER | LYD_OPT_GET | LYD_OPT_GETCONFIG | LYD_OPT_EDIT)) {
8583         ignore_fail = 1;
8584     } else if (options & LYD_OPT_NOEXTDEPS) {
8585         ignore_fail = 2;
8586     } else {
8587         ignore_fail = 0;
8588     }
8589 
8590     multi_error = (options & LYD_OPT_MULTI_ERRORS) ? 1 : 0;
8591 
8592     LOGVRB("Resolving unresolved data nodes and their constraints...");
8593     if (!ignore_fail) {
8594         /* remember logging state only if errors are generated and valid */
8595         ly_ilo_change(ctx, ILO_STORE, &prev_ilo, &prev_eitem);
8596     }
8597 
8598     /*
8599      * when-stmt first
8600      */
8601     first = 1;
8602     stmt_count = 0;
8603     resolved = 0;
8604     del_items = 0;
8605     do {
8606         if (!ignore_fail) {
8607             ly_err_free_next(ctx, prev_eitem);
8608         }
8609         progress = 0;
8610         for (i = 0; i < unres->count; i++) {
8611             if (unres->type[i] != UNRES_WHEN) {
8612                 continue;
8613             }
8614             if (first) {
8615                 /* count when-stmt nodes in unres list */
8616                 stmt_count++;
8617             }
8618 
8619             /* resolve when condition only when all parent when conditions are already resolved */
8620             for (parent = unres->node[i]->parent;
8621                  parent && LYD_WHEN_DONE(parent->when_status);
8622                  parent = parent->parent) {
8623                 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
8624                     /* the parent node was already unlinked, do not resolve this node,
8625                      * it will be removed anyway, so just mark it as resolved
8626                      */
8627                     unres->node[i]->when_status |= LYD_WHEN_FALSE;
8628                     unres->type[i] = UNRES_RESOLVED;
8629                     resolved++;
8630                     break;
8631                 }
8632             }
8633             if (parent) {
8634                 continue;
8635             }
8636 
8637             prev_when_status = unres->node[i]->when_status;
8638             rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, 0, &when);
8639             if (!rc) {
8640                 /* finish with error/delete the node only if when was changed from true to false, an external
8641                  * dependency was not required, or it was not provided (the flag would not be passed down otherwise,
8642                  * checked in upper functions) */
8643                 if ((unres->node[i]->when_status & LYD_WHEN_FALSE)
8644                         && (!(when->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP)) || !(options & LYD_OPT_NOEXTDEPS))) {
8645                     if ((!(prev_when_status & LYD_WHEN_TRUE) || !(options & LYD_OPT_WHENAUTODEL)) && !unres->node[i]->dflt) {
8646                         /* false when condition */
8647                         goto error;
8648                     } /* follows else */
8649 
8650                     /* auto-delete */
8651                     LOGVRB("Auto-deleting node \"%s\" due to when condition (%s)", ly_errpath(ctx), when->cond);
8652 
8653                     /* do not delete yet, the subtree can contain another nodes stored in the unres list */
8654                     /* if it has parent non-presence containers that would be empty, we should actually
8655                      * remove the container
8656                      */
8657                     for (parent = unres->node[i];
8658                             parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
8659                             parent = parent->parent) {
8660                         if (((struct lys_node_container *)parent->parent->schema)->presence) {
8661                             /* presence container */
8662                             break;
8663                         }
8664                         if (parent->next || parent->prev != parent) {
8665                             /* non empty (the child we are in and we are going to remove is not the only child) */
8666                             break;
8667                         }
8668                     }
8669                     unres->node[i] = parent;
8670 
8671                     if (*root && *root == unres->node[i]) {
8672                         *root = (*root)->next;
8673                     }
8674 
8675                     unres->type[i] = UNRES_DELETE;
8676                     del_items++;
8677 
8678                     /* update the rest of unres items */
8679                     for (j = 0; j < unres->count; j++) {
8680                         if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
8681                             continue;
8682                         }
8683 
8684                         /* test if the node is in subtree to be deleted */
8685                         for (parent = unres->node[j]; parent; parent = parent->parent) {
8686                             if (parent == unres->node[i]) {
8687                                 /* yes, it is */
8688                                 unres->type[j] = UNRES_RESOLVED;
8689                                 resolved++;
8690                                 break;
8691                             }
8692                         }
8693                     }
8694                 } else {
8695                     unres->type[i] = UNRES_RESOLVED;
8696                 }
8697                 if (!ignore_fail) {
8698                     ly_err_free_next(ctx, prev_eitem);
8699                 }
8700                 resolved++;
8701                 progress = 1;
8702             } else if (rc == -1) {
8703                 goto error;
8704             } /* else forward reference */
8705         }
8706         first = 0;
8707     } while (progress && resolved < stmt_count);
8708 
8709     /* do we have some unresolved when-stmt? */
8710     if (stmt_count > resolved) {
8711         goto error;
8712     }
8713 
8714     for (i = 0; del_items && i < unres->count; i++) {
8715         /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
8716         if (unres->type[i] != UNRES_DELETE) {
8717             continue;
8718         }
8719         if (!unres->node[i]) {
8720             unres->type[i] = UNRES_RESOLVED;
8721             del_items--;
8722             continue;
8723         }
8724 
8725         if (unres->store_diff) {
8726             resolve_unres_data_autodel_diff(unres, i);
8727         }
8728 
8729         /* really remove the complete subtree */
8730         lyd_free(unres->node[i]);
8731         unres->type[i] = UNRES_RESOLVED;
8732         del_items--;
8733     }
8734 
8735     /*
8736      * now leafrefs
8737      */
8738     if (options & LYD_OPT_TRUSTED) {
8739         /* we want to attempt to resolve leafrefs */
8740         assert(!ignore_fail);
8741         ignore_fail = 1;
8742 
8743         ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
8744         ly_errno = prev_ly_errno;
8745     }
8746     first = 1;
8747     stmt_count = 0;
8748     resolved = 0;
8749     do {
8750         progress = 0;
8751         for (i = 0; i < unres->count; i++) {
8752             if (unres->type[i] != UNRES_LEAFREF) {
8753                 continue;
8754             }
8755             if (first) {
8756                 /* count leafref nodes in unres list */
8757                 stmt_count++;
8758             }
8759 
8760             rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, 0, NULL);
8761             if (!rc) {
8762                 unres->type[i] = UNRES_RESOLVED;
8763                 if (!ignore_fail) {
8764                     ly_err_free_next(ctx, prev_eitem);
8765                 }
8766                 resolved++;
8767                 progress = 1;
8768             } else if (rc == -1) {
8769                 goto error;
8770             } /* else forward reference */
8771         }
8772         first = 0;
8773     } while (progress && resolved < stmt_count);
8774 
8775     /* do we have some unresolved leafrefs? */
8776     if (stmt_count > resolved) {
8777         goto error;
8778     }
8779 
8780     if (!ignore_fail) {
8781         /* log normally now, throw away irrelevant errors */
8782         ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
8783         ly_errno = prev_ly_errno;
8784     }
8785 
8786     rc = 0;
8787 
8788     /*
8789      * rest
8790      */
8791     for (i = 0; i < unres->count; ++i) {
8792         if (unres->type[i] == UNRES_RESOLVED) {
8793             continue;
8794         }
8795         assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
8796 
8797         rc2 = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, multi_error, NULL);
8798         if (rc2) {
8799             if (!multi_error) {
8800                 /* since when was already resolved, a forward reference is an error */
8801                 return -1;
8802             }
8803             rc = -1;
8804         }
8805 
8806         unres->type[i] = UNRES_RESOLVED;
8807     }
8808 
8809     LOGVRB("All data nodes and constraints resolved.");
8810     unres->count = 0;
8811     return rc;
8812 
8813 error:
8814     if (!ignore_fail) {
8815         /* print all the new errors */
8816         ly_ilo_restore(ctx, prev_ilo, prev_eitem, 1);
8817         /* do not restore ly_errno, it was udpated properly */
8818     }
8819     return -1;
8820 }
8821