blob: e2deb7a00e385354a9709ca47b58003249bbed7c [file] [log] [blame]
Michal Vaskocde73ac2019-11-14 16:10:27 +01001/**
2 * @file validation.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief Validation
5 *
6 * Copyright (c) 2019 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#include <assert.h>
16#include <string.h>
17
18#include "common.h"
19#include "xpath.h"
20#include "tree_data_internal.h"
Michal Vasko14654712020-02-06 08:35:21 +010021#include "tree_schema_internal.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010022
23/**
24 * @brief Evaluate a single "when" condition.
25 *
26 * @param[in] when When to evaluate.
27 * @param[in] node Node whose existence depends on this when.
28 * @param[in] trees Array of all data trees.
29 * @return LY_ERR value (LY_EINCOMPLETE if a referenced node does not have its when evaluated)
30 */
31static LY_ERR
32lyd_val_when(struct lysc_when *when, struct lyd_node *node, const struct lyd_node **trees)
33{
34 LY_ERR ret;
35 const struct lyd_node *ctx_node;
36 struct lyxp_set xp_set;
37
38 memset(&xp_set, 0, sizeof xp_set);
39
40 if (when->context == node->schema) {
41 ctx_node = node;
42 } else {
43 assert((!when->context && !node->parent) || (when->context == node->parent->schema));
44 ctx_node = (struct lyd_node *)node->parent;
45 }
46
47 /* evaluate when */
48 ret = lyxp_eval(when->cond, LYD_UNKNOWN, when->module, ctx_node, ctx_node ? LYXP_NODE_ELEM : LYXP_NODE_ROOT_CONFIG,
49 trees, &xp_set, LYXP_SCHEMA);
50 lyxp_set_cast(&xp_set, LYXP_SET_BOOLEAN);
51
52 /* return error or LY_EINCOMPLETE for dependant unresolved when */
53 LY_CHECK_RET(ret);
54
55 /* take action based on the result */
56 if (!xp_set.val.bool) {
57 if (node->flags & LYD_WHEN_TRUE) {
58 /* autodelete */
59 lyd_free_tree(node);
60 } else {
61 /* invalid data */
62 LOGVAL(node->schema->module->ctx, LY_VLOG_LYD, node, LY_VCODE_NOWHEN, when->cond->expr);
63 ret = LY_EVALID;
64 }
65 } else {
66 /* remember that when evaluated to true */
67 node->flags |= LYD_WHEN_TRUE;
68 }
69
70 return ret;
71}
72
73LY_ERR
74lyd_validate_unres(struct ly_set *node_types, struct ly_set *attr_types, struct ly_set *node_when, LYD_FORMAT format,
75 ly_clb_resolve_prefix get_prefix_clb, void *parser_data, const struct lyd_node **trees)
76{
77 LY_ERR ret = LY_SUCCESS;
78 uint32_t u;
79
80 /* finish incompletely validated terminal values */
81 for (u = 0; node_types && (u < node_types->count); u++) {
82 struct lyd_node_term *node = (struct lyd_node_term *)node_types->objs[u];
83
84 /* validate and store the value of the node */
85 ret = lyd_value_parse(node, node->value.original, strlen(node->value.original), 0, 1, get_prefix_clb,
86 parser_data, format, trees);
87 LY_CHECK_RET(ret);
88 }
89
90 /* ... and attribute values */
91 for (u = 0; attr_types && (u < attr_types->count); u++) {
92 struct lyd_attr *attr = (struct lyd_attr *)attr_types->objs[u];
93
94 /* validate and store the value of the node */
95 ret = lyd_value_parse_attr(attr, attr->value.original, strlen(attr->value.original), 0, 1, get_prefix_clb,
96 parser_data, format, trees);
97 LY_CHECK_RET(ret);
98 }
99
100 /* no when conditions */
101 if (!node_when || !node_when->count) {
102 return ret;
103 }
104
105 /* evaluate all when conditions */
106 uint32_t prev_count;
107 do {
108 prev_count = node_when->count;
109 u = 0;
110 while (u < node_when->count) {
111 /* evaluate all when expressions that affect this node's existence */
112 struct lyd_node *node = (struct lyd_node *)node_when->objs[u];
113 const struct lysc_node *schema = node->schema;
114 int unres_when = 0;
115
116 do {
117 uint32_t i;
118 LY_ARRAY_FOR(schema->when, i) {
119 ret = lyd_val_when(schema->when[i], node, trees);
120 if (ret) {
121 break;
122 }
123 }
124 if (ret == LY_EINCOMPLETE) {
125 /* could not evaluate this when */
126 unres_when = 1;
127 break;
128 } else if (ret) {
129 /* error */
130 return ret;
131 }
132 schema = schema->parent;
133 } while (schema && (schema->nodetype & (LYS_CASE | LYS_CHOICE)));
134
135 if (unres_when) {
136 /* keep in set and go to the next node */
137 ++u;
138 } else {
139 /* remove this node from the set */
140 ly_set_rm_index(node_when, u, NULL);
141 }
142 }
143
144 /* there must have been some when conditions resolved */
145 } while (prev_count > node_when->count);
146
147 /* there could have been no cyclic when dependencies, checked during compilation */
148 assert(!node_when->count);
149
150 return ret;
151}
152
153static const struct lys_module *
154lyd_val_next_module(const struct lys_module **modules, int mod_count, struct ly_ctx *ctx, uint32_t *i)
155{
156 if (modules && mod_count) {
157 return modules[(*i)++];
158 }
159
160 return ly_ctx_get_module_iter(ctx, i);
161}
162
163static LY_ERR
Michal Vaskoa3881362020-01-21 15:57:35 +0100164lyd_validate_mandatory(const struct lysc_node *snode, struct lyd_node *sibling)
165{
166 struct lyd_node *node;
167 int is_choice = 0;
168
169 if (snode->nodetype == LYS_CHOICE) {
170 is_choice = 1;
171 }
172
Michal Vaskoacd83e72020-02-04 14:12:01 +0100173 LY_LIST_FOR(sibling, node) {
Michal Vaskoa3881362020-01-21 15:57:35 +0100174 if (is_choice) {
175 if (node->schema->parent && (node->schema->parent->nodetype & LYS_CASE) && (node->schema->parent->parent == snode)) {
176 /* case data instance found */
177 return LY_SUCCESS;
178 }
179 } else {
180 if (node->schema == snode) {
181 /* data instance found */
182 return LY_SUCCESS;
183 }
184 }
185 }
186
187 /* node instance not found */
188 LOGVAL(snode->module->ctx, LY_VLOG_LYSC, snode, LY_VCODE_NOMAND, snode->name);
189 return LY_EVALID;
190}
191
192static LY_ERR
193lyd_validate_minmax(const struct lysc_node *snode, uint32_t min, uint32_t max, struct lyd_node *sibling)
194{
Michal Vaskoacd83e72020-02-04 14:12:01 +0100195 uint32_t count = 0;
196 struct lyd_node *iter;
197
198 LY_LIST_FOR(sibling, iter) {
199 if (iter->schema == snode) {
200 ++count;
201 }
202 }
203
204 if (min && (count < min)) {
205 LOGVAL(snode->module->ctx, LY_VLOG_LYSC, snode, LY_VCODE_NOMIN, snode->name);
206 return LY_EVALID;
207 } else if (max && (count > max)) {
208 LOGVAL(snode->module->ctx, LY_VLOG_LYSC, snode, LY_VCODE_NOMAX, snode->name);
209 return LY_EVALID;
210 }
211
Michal Vaskoa3881362020-01-21 15:57:35 +0100212 return LY_SUCCESS;
213}
214
Michal Vasko14654712020-02-06 08:35:21 +0100215static struct lyd_node *
216lyd_val_uniq_find_leaf(const struct lysc_node_leaf *uniq_leaf, struct lyd_node *list)
217{
218 struct ly_set *set;
219 struct lyd_node *node = NULL;
220
221 set = lyd_find_instance(lyd_node_children(list), (struct lysc_node *)uniq_leaf);
222 if (set && set->count) {
223 /* we were looking for a leaf */
224 assert(set->count == 1);
225 node = set->objs[0];
226 }
227 ly_set_free(set, NULL);
228 return node;
229}
230
231/*
232 * actions (cb_data):
233 * 0 - compare all uniques
234 * n - compare n-th unique
235 */
236static int
237lyd_val_uniq_list_equal(void *val1_p, void *val2_p, int UNUSED(mod), void *cb_data)
238{
239 struct ly_ctx *ctx;
240 struct lysc_node_list *slist;
241 struct lyd_node *diter, *first, *second;
242 struct lyd_value *val1, *val2;
243 char *path1, *path2, *uniq_str, *ptr;
244 uint32_t i, j, action;
245
246 assert(val1_p && val2_p);
247
248 first = *((struct lyd_node **)val1_p);
249 second = *((struct lyd_node **)val2_p);
250 action = (uintptr_t)cb_data;
251
252 assert(first && (first->schema->nodetype == LYS_LIST));
253 assert(second && (second->schema == first->schema));
254
255 ctx = first->schema->module->ctx;
256
257 slist = (struct lysc_node_list *)first->schema;
258
259 /* compare unique leaves */
260 if (action > 0) {
261 i = action - 1;
262 if (i < LY_ARRAY_SIZE(slist->uniques)) {
263 goto uniquecheck;
264 }
265 }
266 LY_ARRAY_FOR(slist->uniques, i) {
267uniquecheck:
268 LY_ARRAY_FOR(slist->uniques[i], j) {
269 /* first */
270 diter = lyd_val_uniq_find_leaf(slist->uniques[i][j], first);
271 if (diter) {
272 val1 = &((struct lyd_node_term *)diter)->value;
273 } else {
274 /* use default value */
275 val1 = slist->uniques[i][j]->dflt;
276 }
277
278 /* second */
279 diter = lyd_val_uniq_find_leaf(slist->uniques[i][j], second);
280 if (diter) {
281 val2 = &((struct lyd_node_term *)diter)->value;
282 } else {
283 /* use default value */
284 val2 = slist->uniques[i][j]->dflt;
285 }
286
287 if (!val1 || !val2 || val1->realtype->plugin->compare(val1, val2)) {
288 /* values differ or either one is not set */
289 break;
290 }
291 }
292 if (j && (j == LY_ARRAY_SIZE(slist->uniques[i]))) {
293 /* all unique leafs are the same in this set, create this nice error */
294 path1 = lyd_path(first, LYD_PATH_LOG, NULL, 0);
295 path2 = lyd_path(second, LYD_PATH_LOG, NULL, 0);
296
297 /* use buffer to rebuild the unique string */
298 uniq_str = malloc(1024);
299 uniq_str[0] = '\0';
300 ptr = uniq_str;
301 LY_ARRAY_FOR(slist->uniques[i], j) {
302 if (j) {
303 strcpy(ptr, " ");
304 ++ptr;
305 }
306 ptr = lysc_path_until((struct lysc_node *)slist->uniques[i][j], (struct lysc_node *)slist, LYSC_PATH_LOG,
307 ptr, 1024 - (ptr - uniq_str));
308 if (!ptr) {
309 /* path will be incomplete, whatever */
310 break;
311 }
312
313 ptr += strlen(ptr);
314 }
315 LOGVAL(ctx, LY_VLOG_LYD, second, LY_VCODE_NOUNIQ, uniq_str, path1, path2);
316
317 free(path1);
318 free(path2);
319 free(uniq_str);
320 return 1;
321 }
322
323 if (action > 0) {
324 /* done */
325 return 0;
326 }
327 }
328
329 return 0;
330}
331
Michal Vaskoa3881362020-01-21 15:57:35 +0100332static LY_ERR
333lyd_validate_unique(const struct lysc_node *snode, struct lysc_node_leaf ***uniques, struct lyd_node *sibling)
334{
Michal Vasko14654712020-02-06 08:35:21 +0100335 struct lyd_node *diter;
336 struct ly_set *set;
337 uint32_t i, j, n = 0;
338 LY_ERR ret = LY_SUCCESS;
339 uint32_t hash, u, usize = 0;
340 int dynamic;
341 const char *str;
342 struct hash_table **uniqtables = NULL;
343 struct lyd_value *val;
344 struct ly_ctx *ctx = snode->module->ctx;
345
346 assert(uniques);
347
348 /* get all list instances */
349 set = lyd_find_instance(sibling, snode);
350 LY_CHECK_RET(!set, LY_EINT);
351
352 if (set->count == 2) {
353 /* simple comparison */
354 if (lyd_val_uniq_list_equal(&set->objs[0], &set->objs[1], 0, (void *)0)) {
355 /* instance duplication */
356 ret = LY_EVALID;
357 goto cleanup;
358 }
359 } else if (set->count > 2) {
360 /* use hashes for comparison */
361 /* first, allocate the table, the size depends on number of items in the set */
362 for (u = 31; u > 0; u--) {
363 usize = set->count << u;
364 usize = usize >> u;
365 if (usize == set->count) {
366 break;
367 }
368 }
369 LY_CHECK_ERR_GOTO(!u, LOGINT(ctx); ret = LY_EINT, cleanup);
370 u = 32 - u;
371 usize = 1 << u;
372
373 uniqtables = malloc(LY_ARRAY_SIZE(uniques) * sizeof *uniqtables);
374 LY_CHECK_ERR_GOTO(!uniqtables, LOGMEM(ctx); ret = LY_EMEM, cleanup);
375 n = LY_ARRAY_SIZE(uniques);
376 for (j = 0; j < n; j++) {
377 uniqtables[j] = lyht_new(usize, sizeof(struct lyd_node *), lyd_val_uniq_list_equal, (void *)(j + 1L), 0);
378 LY_CHECK_ERR_GOTO(!uniqtables[j], LOGMEM(ctx); ret = LY_EMEM, cleanup);
379 }
380
381 for (u = 0; u < set->count; u++) {
382 /* loop for unique - get the hash for the instances */
383 for (i = 0; i < n; i++) {
384 val = NULL;
385 for (j = hash = 0; j < LY_ARRAY_SIZE(uniques[i]); j++) {
386 diter = lyd_val_uniq_find_leaf(uniques[i][j], set->objs[u]);
387 if (diter) {
388 val = &((struct lyd_node_term *)diter)->value;
389 } else {
390 /* use default value */
391 val = uniques[i][j]->dflt;
392 }
393 if (!val) {
394 /* unique item not present nor has default value */
395 break;
396 }
397
398 /* get canonical string value */
399 str = val->realtype->plugin->print(val, LYD_JSON, json_print_get_prefix, NULL, &dynamic);
400 hash = dict_hash_multi(hash, str, strlen(str));
401 if (dynamic) {
402 free((char *)str);
403 }
404 }
405 if (!val) {
406 /* skip this list instance since its unique set is incomplete */
407 continue;
408 }
409
410 /* finish the hash value */
411 hash = dict_hash_multi(hash, NULL, 0);
412
413 /* insert into the hashtable */
414 ret = lyht_insert(uniqtables[i], &set->objs[u], hash, NULL);
415 if (ret == LY_EEXIST) {
416 /* instance duplication */
417 ret = LY_EVALID;
418 }
419 LY_CHECK_GOTO(ret != LY_SUCCESS, cleanup);
420 }
421 }
422 }
423
424cleanup:
425 ly_set_free(set, NULL);
426 for (j = 0; j < n; j++) {
427 if (!uniqtables[j]) {
428 /* failed when allocating uniquetables[j], following j are not allocated */
429 break;
430 }
431 lyht_free(uniqtables[j]);
432 }
433 free(uniqtables);
434
435 return ret;
Michal Vaskoa3881362020-01-21 15:57:35 +0100436}
437
438static LY_ERR
439lyd_validate_cases(const struct lysc_node_case *cases, struct lyd_node *sibling)
440{
441 /* TODO check there are nodes only from a single case,
442 * what if not? validation error or autodelete */
443 return LY_SUCCESS;
444}
445
446static LY_ERR
Michal Vaskoacd83e72020-02-04 14:12:01 +0100447lyd_validate_siblings_schema_r(struct lyd_node *sibling, const struct lysc_node *sparent, const struct lysc_module *mod,
448 int options)
Michal Vaskocde73ac2019-11-14 16:10:27 +0100449{
Michal Vaskocde73ac2019-11-14 16:10:27 +0100450 const struct lysc_node *snode = NULL;
Michal Vaskoa3881362020-01-21 15:57:35 +0100451 struct lysc_node_list *slist;
Michal Vaskocde73ac2019-11-14 16:10:27 +0100452
Michal Vaskoa3881362020-01-21 15:57:35 +0100453 /* disabled nodes are skipped by lys_getnext */
454 while ((snode = lys_getnext(snode, sparent, mod, LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
Michal Vaskoa3881362020-01-21 15:57:35 +0100455 /* check min-elements and max-elements */
456 if (snode->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
457 slist = (struct lysc_node_list *)snode;
458 if (slist->min || slist->max) {
459 LY_CHECK_RET(lyd_validate_minmax(snode, slist->min, slist->max, sibling));
460 }
Michal Vaskoacd83e72020-02-04 14:12:01 +0100461
462 /* check generic mandatory existence */
463 } else if (snode->flags & LYS_MAND_TRUE) {
464 LY_CHECK_RET(lyd_validate_mandatory(snode, sibling));
Michal Vaskoa3881362020-01-21 15:57:35 +0100465 }
466
467 /* check unique */
468 if (snode->nodetype == LYS_LIST) {
469 slist = (struct lysc_node_list *)snode;
470 if (slist->uniques) {
471 LY_CHECK_RET(lyd_validate_unique(snode, slist->uniques, sibling));
472 }
473 }
474
475 /* check case duplicites */
476 if (snode->nodetype == LYS_CHOICE) {
477 LY_CHECK_RET(lyd_validate_cases(((struct lysc_node_choice *)snode)->cases, sibling));
478 }
Michal Vaskoacd83e72020-02-04 14:12:01 +0100479
480 if (snode->nodetype & (LYS_CHOICE | LYS_CASE)) {
481 /* go recursively for schema-only nodes */
482 LY_CHECK_RET(lyd_validate_siblings_schema_r(sibling, snode, mod, options));
483 }
Michal Vaskocde73ac2019-11-14 16:10:27 +0100484 }
485
Michal Vaskoacd83e72020-02-04 14:12:01 +0100486 return LY_SUCCESS;
487}
488
489static LY_ERR
490lyd_validate_siblings_r(struct lyd_node *sibling, const struct lysc_node *sparent, const struct lysc_module *mod, int options)
491{
492 struct lyd_node *node;
493
Michal Vasko14654712020-02-06 08:35:21 +0100494 /* validate all restrictions of nodes themselves */
Michal Vaskoacd83e72020-02-04 14:12:01 +0100495 LY_LIST_FOR(sibling, node) {
Michal Vaskocde73ac2019-11-14 16:10:27 +0100496 /* TODO node's must */
497 /* TODO node instance duplicites */
498 /* TODO node status */
Michal Vaskoa3881362020-01-21 15:57:35 +0100499 /* TODO node's if-features */
500 /* TODO node list keys */
501 /* node value including if-feature is checked by plugins */
Michal Vasko14654712020-02-06 08:35:21 +0100502 }
Michal Vaskocde73ac2019-11-14 16:10:27 +0100503
Michal Vasko14654712020-02-06 08:35:21 +0100504 /* validate schema-based restrictions */
505 LY_CHECK_RET(lyd_validate_siblings_schema_r(sibling, sparent, mod, options));
506
507 LY_LIST_FOR(sibling, node) {
508 /* validate all children recursively */
509 LY_CHECK_RET(lyd_validate_siblings_r((struct lyd_node *)lyd_node_children(node), node->schema, mod, options));
Michal Vaskocde73ac2019-11-14 16:10:27 +0100510 }
511
512 return LY_SUCCESS;
513}
514
515LY_ERR
Michal Vaskoacd83e72020-02-04 14:12:01 +0100516lyd_validate_data(const struct lyd_node **trees, const struct lys_module **modules, int mod_count, struct ly_ctx *ctx,
517 int options)
Michal Vaskocde73ac2019-11-14 16:10:27 +0100518{
Michal Vaskocde73ac2019-11-14 16:10:27 +0100519 uint32_t i = 0, j;
520 const struct lys_module *mod;
521 struct lyd_node *tree;
522
Michal Vaskoa3881362020-01-21 15:57:35 +0100523 if (options & LYD_OPT_VAL_DATA_ONLY) {
Michal Vaskocde73ac2019-11-14 16:10:27 +0100524 if (trees) {
525 for (j = 0; j < LY_ARRAY_SIZE(trees); ++j) {
Michal Vaskoa3881362020-01-21 15:57:35 +0100526 tree = (struct lyd_node *)trees[j];
527
528 /* validate all top-level nodes and then inner nodes recursively */
529 LY_CHECK_RET(lyd_validate_siblings_r(tree, NULL, tree->schema->module->compiled, options));
Michal Vaskocde73ac2019-11-14 16:10:27 +0100530 }
531 }
Michal Vaskoa3881362020-01-21 15:57:35 +0100532 } else {
533 while ((mod = lyd_val_next_module(modules, mod_count, ctx, &i))) {
534 if (!mod->implemented) {
535 continue;
536 }
Michal Vaskocde73ac2019-11-14 16:10:27 +0100537
Michal Vaskoa3881362020-01-21 15:57:35 +0100538 /* find data of this module, if any */
539 tree = NULL;
540 if (trees) {
541 for (j = 0; j < LY_ARRAY_SIZE(trees); ++j) {
542 if (trees[j]->schema->module == mod) {
543 tree = (struct lyd_node *)trees[j];
544 break;
545 }
546 }
547 }
548
549 /* validate all top-level nodes and then inner nodes recursively */
550 LY_CHECK_RET(lyd_validate_siblings_r(tree, NULL, mod->compiled, options));
551 }
Michal Vaskocde73ac2019-11-14 16:10:27 +0100552 }
553
554 return LY_SUCCESS;
555}