Coverage Report

Created: 2026-10-28 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libyang/src/parser_xml.c
Line
Count
Source
1
/**
2
 * @file parser_xml.c
3
 * @author Radek Krejci <rkrejci@cesnet.cz>
4
 * @brief XML data parser for libyang
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 <stdint.h>
17
#include <stdlib.h>
18
#include <string.h>
19
20
#include "common.h"
21
#include "context.h"
22
#include "dict.h"
23
#include "in_internal.h"
24
#include "log.h"
25
#include "parser_data.h"
26
#include "parser_internal.h"
27
#include "set.h"
28
#include "tree.h"
29
#include "tree_data.h"
30
#include "tree_data_internal.h"
31
#include "tree_schema.h"
32
#include "tree_schema_internal.h"
33
#include "validation.h"
34
#include "xml.h"
35
36
/**
37
 * @brief Internal context for XML YANG data parser.
38
 *
39
 * Note that the structure maps to the ::lyd_ctx which is common for all the data parsers
40
 */
41
struct lyd_xml_ctx {
42
    const struct lysc_ext_instance *ext; /**< extension instance possibly changing document root context of the data being parsed */
43
    uint32_t parse_opts;           /**< various @ref dataparseroptions. */
44
    uint32_t val_opts;             /**< various @ref datavalidationoptions. */
45
    uint32_t int_opts;             /**< internal data parser options */
46
    uint32_t path_len;             /**< used bytes in the path buffer */
47
    char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
48
    struct ly_set node_when;       /**< set of nodes with "when" conditions */
49
    struct ly_set node_exts;       /**< set of nodes and extensions connected with a plugin providing own validation callback */
50
    struct ly_set node_types;      /**< set of nodes validated with LY_EINCOMPLETE result */
51
    struct ly_set meta_types;      /**< set of metadata validated with LY_EINCOMPLETE result */
52
    struct lyd_node *op_node;      /**< if an RPC/action/notification is being parsed, store the pointer to it */
53
54
    /* callbacks */
55
    lyd_ctx_free_clb free;           /* destructor */
56
57
    struct lyxml_ctx *xmlctx;      /**< XML context */
58
};
59
60
void
61
lyd_xml_ctx_free(struct lyd_ctx *lydctx)
62
0
{
63
0
    struct lyd_xml_ctx *ctx = (struct lyd_xml_ctx *)lydctx;
64
65
0
    lyd_ctx_free(lydctx);
66
0
    lyxml_ctx_free(ctx->xmlctx);
67
0
    free(ctx);
68
0
}
69
70
static LY_ERR
71
lydxml_metadata(struct lyd_xml_ctx *lydctx, struct lyd_meta **meta)
72
0
{
73
0
    LY_ERR ret = LY_SUCCESS;
74
0
    const struct lyxml_ns *ns;
75
0
    struct lys_module *mod;
76
0
    const char *name;
77
0
    size_t name_len;
78
0
    struct lyxml_ctx *xmlctx = lydctx->xmlctx;
79
80
0
    *meta = NULL;
81
82
0
    while (xmlctx->status == LYXML_ATTRIBUTE) {
83
0
        if (!xmlctx->prefix_len) {
84
            /* in XML, all attributes must be prefixed
85
             * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
86
0
            if (lydctx->parse_opts & LYD_PARSE_STRICT) {
87
0
                ret = LY_EVALID;
88
0
                LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
89
0
                        (int)xmlctx->name_len, xmlctx->name);
90
0
                goto cleanup;
91
0
            }
92
93
0
skip_attr:
94
0
            LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
95
0
            assert(xmlctx->status == LYXML_ATTR_CONTENT);
96
0
            LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
97
0
            continue;
98
0
        }
99
100
        /* get namespace of the attribute to find its annotation definition */
101
0
        ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
102
0
        if (!ns) {
103
0
            ret = LY_ENOTFOUND;
104
            /* unknown namespace, XML error */
105
0
            LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
106
0
            goto cleanup;
107
0
        }
108
0
        mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
109
0
        if (!mod) {
110
            /* module is not implemented or not present in the schema */
111
0
            if (lydctx->parse_opts & LYD_PARSE_STRICT) {
112
0
                ret = LY_ENOTFOUND;
113
0
                LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
114
0
                        "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
115
0
                        ns->uri, (int)xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "",
116
0
                        (int)xmlctx->name_len, xmlctx->name);
117
0
                goto cleanup;
118
0
            }
119
0
            goto skip_attr;
120
0
        }
121
122
        /* remember meta name and get its content */
123
0
        name = xmlctx->name;
124
0
        name_len = xmlctx->name_len;
125
0
        LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
126
0
        assert(xmlctx->status == LYXML_ATTR_CONTENT);
127
128
        /* create metadata */
129
0
        ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, NULL, meta, mod, name, name_len, xmlctx->value,
130
0
                xmlctx->value_len, &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA);
131
0
        LY_CHECK_GOTO(ret, cleanup);
132
133
        /* next attribute */
134
0
        LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
135
0
    }
136
137
0
cleanup:
138
0
    if (ret) {
139
0
        lyd_free_meta_siblings(*meta);
140
0
        *meta = NULL;
141
0
    }
142
0
    return ret;
143
0
}
144
145
static LY_ERR
146
lydxml_attrs(struct lyxml_ctx *xmlctx, struct lyd_attr **attr)
147
0
{
148
0
    LY_ERR ret = LY_SUCCESS;
149
0
    const struct lyxml_ns *ns;
150
0
    void *val_prefix_data;
151
0
    LY_VALUE_FORMAT format;
152
0
    struct lyd_attr *attr2;
153
0
    const char *name, *prefix;
154
0
    size_t name_len, prefix_len;
155
156
0
    assert(attr);
157
0
    *attr = NULL;
158
159
0
    while (xmlctx->status == LYXML_ATTRIBUTE) {
160
0
        ns = NULL;
161
0
        if (xmlctx->prefix_len) {
162
            /* get namespace of the attribute */
163
0
            ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
164
0
            if (!ns) {
165
0
                LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
166
0
                ret = LY_EVALID;
167
0
                goto cleanup;
168
0
            }
169
0
        }
170
171
0
        if (*attr) {
172
0
            attr2 = *attr;
173
0
        } else {
174
0
            attr2 = NULL;
175
0
        }
176
177
        /* remember attr prefix, name, and get its content */
178
0
        prefix = xmlctx->prefix;
179
0
        prefix_len = xmlctx->prefix_len;
180
0
        name = xmlctx->name;
181
0
        name_len = xmlctx->name_len;
182
0
        LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
183
0
        assert(xmlctx->status == LYXML_ATTR_CONTENT);
184
185
        /* get value prefixes */
186
0
        val_prefix_data = NULL;
187
0
        LY_CHECK_GOTO(ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_VALUE_XML,
188
0
                &xmlctx->ns, &format, &val_prefix_data), cleanup);
189
190
        /* attr2 is always changed to the created attribute */
191
0
        ret = lyd_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, prefix, prefix_len, ns ? ns->uri : NULL,
192
0
                ns ? strlen(ns->uri) : 0, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, 0);
193
0
        LY_CHECK_GOTO(ret, cleanup);
194
195
0
        if (!*attr) {
196
0
            *attr = attr2;
197
0
        }
198
199
        /* next attribute */
200
0
        LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
201
0
    }
202
203
0
cleanup:
204
0
    if (ret) {
205
0
        lyd_free_attr_siblings(xmlctx->ctx, *attr);
206
0
        *attr = NULL;
207
0
    }
208
0
    return ret;
209
0
}
210
211
static LY_ERR
212
lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
213
0
{
214
0
    LY_ERR ret = LY_SUCCESS, r;
215
0
    enum LYXML_PARSER_STATUS next;
216
0
    struct ly_set key_set = {0};
217
0
    const struct lysc_node *snode;
218
0
    uint32_t i, parents_count;
219
220
0
    assert(list && (list->nodetype == LYS_LIST));
221
222
    /* get all keys into a set (keys do not have if-features or anything) */
223
0
    snode = NULL;
224
0
    while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
225
0
        ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
226
0
        LY_CHECK_GOTO(ret, cleanup);
227
0
    }
228
229
    /* remember parent count */
230
0
    parents_count = xmlctx->elements.count;
231
232
0
    while (xmlctx->status == LYXML_ELEMENT) {
233
        /* find key definition */
234
0
        for (i = 0; i < key_set.count; ++i) {
235
0
            snode = (const struct lysc_node *)key_set.objs[i];
236
0
            if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
237
0
                break;
238
0
            }
239
0
        }
240
0
        LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
241
242
        /* skip attributes */
243
0
        while (xmlctx->status == LYXML_ATTRIBUTE) {
244
0
            LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
245
0
            assert(xmlctx->status == LYXML_ATTR_CONTENT);
246
0
            LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
247
0
        }
248
249
0
        assert(xmlctx->status == LYXML_ELEM_CONTENT);
250
0
        if (i < key_set.count) {
251
            /* validate the value */
252
0
            r = lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns);
253
0
            if (!r) {
254
                /* key with a valid value, remove from the set */
255
0
                ly_set_rm_index(&key_set, i, NULL);
256
0
            }
257
0
        }
258
259
        /* parser next */
260
0
        LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
261
262
        /* skip any children, resursively */
263
0
        while (xmlctx->status == LYXML_ELEMENT) {
264
0
            while (parents_count < xmlctx->elements.count) {
265
0
                LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
266
0
            }
267
0
            assert(xmlctx->status == LYXML_ELEM_CLOSE);
268
0
            LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
269
0
        }
270
271
        /* parser next, but do not parse closing element of the list because it would remove its namespaces */
272
0
        assert(xmlctx->status == LYXML_ELEM_CLOSE);
273
0
        LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
274
0
        if (next != LYXML_ELEM_CLOSE) {
275
0
            LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
276
0
        }
277
0
    }
278
279
0
    if (key_set.count) {
280
        /* some keys are missing/did not validate */
281
0
        ret = LY_ENOT;
282
0
    }
283
284
0
cleanup:
285
0
    ly_set_erase(&key_set, NULL);
286
0
    return ret;
287
0
}
288
289
static LY_ERR
290
lydxml_data_skip(struct lyxml_ctx *xmlctx)
291
0
{
292
0
    uint32_t parents_count;
293
294
    /* remember current number of parents */
295
0
    parents_count = xmlctx->elements.count;
296
297
    /* skip after the content */
298
0
    while (xmlctx->status != LYXML_ELEM_CONTENT) {
299
0
        LY_CHECK_RET(lyxml_ctx_next(xmlctx));
300
0
    }
301
0
    LY_CHECK_RET(lyxml_ctx_next(xmlctx));
302
303
    /* skip all children elements, recursively, if any */
304
0
    while (parents_count < xmlctx->elements.count) {
305
0
        LY_CHECK_RET(lyxml_ctx_next(xmlctx));
306
0
    }
307
308
    /* close element */
309
0
    assert(xmlctx->status == LYXML_ELEM_CLOSE);
310
0
    LY_CHECK_RET(lyxml_ctx_next(xmlctx));
311
312
0
    return LY_SUCCESS;
313
0
}
314
315
static LY_ERR
316
lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
317
0
{
318
0
    LY_ERR ret = LY_SUCCESS;
319
0
    enum LYXML_PARSER_STATUS prev_status;
320
0
    const char *prev_current, *pname, *pprefix;
321
0
    size_t pprefix_len, pname_len;
322
0
    struct lyxml_ctx *xmlctx = lydctx->xmlctx;
323
324
0
    if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
325
        /* only checks specific to opaque nodes */
326
0
        return LY_SUCCESS;
327
0
    }
328
329
0
    if ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST)) {
330
        /* backup parser */
331
0
        prev_status = xmlctx->status;
332
0
        pprefix = xmlctx->prefix;
333
0
        pprefix_len = xmlctx->prefix_len;
334
0
        pname = xmlctx->name;
335
0
        pname_len = xmlctx->name_len;
336
0
        prev_current = xmlctx->in->current;
337
0
        if ((xmlctx->status == LYXML_ELEM_CONTENT) && xmlctx->dynamic) {
338
            /* it was backed up, do not free */
339
0
            xmlctx->dynamic = 0;
340
0
        }
341
342
        /* skip attributes */
343
0
        while (xmlctx->status == LYXML_ATTRIBUTE) {
344
0
            LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
345
0
            LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
346
0
        }
347
348
0
        if ((*snode)->nodetype & LYD_NODE_TERM) {
349
            /* value may not be valid in which case we parse it as an opaque node */
350
0
            if (lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns)) {
351
0
                *snode = NULL;
352
0
            }
353
0
        } else {
354
            /* skip content */
355
0
            LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
356
357
0
            if (lydxml_check_list(xmlctx, *snode)) {
358
                /* invalid list, parse as opaque if it missing/has invalid some keys */
359
0
                *snode = NULL;
360
0
            }
361
0
        }
362
363
0
restore:
364
        /* restore parser */
365
0
        if (xmlctx->dynamic) {
366
0
            free((char *)xmlctx->value);
367
0
        }
368
0
        xmlctx->status = prev_status;
369
0
        xmlctx->prefix = pprefix;
370
0
        xmlctx->prefix_len = pprefix_len;
371
0
        xmlctx->name = pname;
372
0
        xmlctx->name_len = pname_len;
373
0
        xmlctx->in->current = prev_current;
374
0
    } else if ((*snode)->nodetype & LYD_NODE_INNER) {
375
        /* if there is a non-WS value, it cannot be parsed as an inner node */
376
0
        assert(xmlctx->status == LYXML_ELEM_CONTENT);
377
0
        if (!xmlctx->ws_only) {
378
0
            *snode = NULL;
379
0
        }
380
381
0
    }
382
383
0
    return ret;
384
0
}
385
386
/**
387
 * @brief Parse XML subtree.
388
 *
389
 * @param[in] lydctx XML YANG data parser context.
390
 * @param[in,out] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
391
 * @param[in,out] first_p Pointer to the first (@p parent or top-level) child. In case there were already some siblings,
392
 * this may point to a previously existing node.
393
 * @param[in,out] parsed Optional set to add all the parsed siblings into.
394
 * @return LY_ERR value.
395
 */
396
static LY_ERR
397
lydxml_subtree_r(struct lyd_xml_ctx *lydctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_set *parsed)
398
0
{
399
0
    LY_ERR ret = LY_SUCCESS;
400
0
    const char *prefix, *name, *val;
401
0
    size_t prefix_len, name_len;
402
0
    struct lyxml_ctx *xmlctx;
403
0
    const struct ly_ctx *ctx;
404
0
    const struct lyxml_ns *ns;
405
0
    struct lyd_meta *meta = NULL;
406
0
    struct lyd_attr *attr = NULL;
407
0
    const struct lysc_node *snode;
408
0
    struct lys_module *mod;
409
0
    uint32_t prev_opts;
410
0
    struct lyd_node *node = NULL, *anchor;
411
0
    void *val_prefix_data = NULL;
412
0
    LY_VALUE_FORMAT format;
413
0
    uint32_t getnext_opts;
414
415
0
    assert(parent || first_p);
416
417
0
    xmlctx = lydctx->xmlctx;
418
0
    ctx = xmlctx->ctx;
419
0
    getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
420
421
0
    assert(xmlctx->status == LYXML_ELEMENT);
422
423
    /* remember element prefix and name */
424
0
    prefix = xmlctx->prefix;
425
0
    prefix_len = xmlctx->prefix_len;
426
0
    name = xmlctx->name;
427
0
    name_len = xmlctx->name_len;
428
429
    /* get the element module */
430
0
    ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
431
0
    if (!ns) {
432
0
        LOGVAL(ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
433
0
        ret = LY_EVALID;
434
0
        goto error;
435
0
    }
436
0
    mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
437
0
    if (!mod) {
438
0
        if (lydctx->parse_opts & LYD_PARSE_STRICT) {
439
0
            LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
440
0
            ret = LY_EVALID;
441
0
            goto error;
442
0
        }
443
0
        if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
444
            /* skip element with children */
445
0
            LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
446
0
            return LY_SUCCESS;
447
0
        }
448
0
    }
449
450
    /* parser next */
451
0
    LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
452
453
    /* get the schema node */
454
0
    snode = NULL;
455
0
    if (mod && (!parent || parent->schema)) {
456
0
        if (!parent && lydctx->ext) {
457
0
            snode = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
458
0
        } else {
459
0
            snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
460
0
        }
461
0
        if (!snode) {
462
0
            if (lydctx->parse_opts & LYD_PARSE_STRICT) {
463
0
                if (parent) {
464
0
                    LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
465
0
                            (int)name_len, name, parent->schema->name);
466
0
                } else if (lydctx->ext) {
467
0
                    if (lydctx->ext->argument) {
468
0
                        LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
469
0
                                (int)name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
470
0
                    } else {
471
0
                        LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
472
0
                                (int)name_len, name, lydctx->ext->def->name);
473
0
                    }
474
0
                } else {
475
0
                    LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
476
0
                            (int)name_len, name, mod->name);
477
0
                }
478
0
                ret = LY_EVALID;
479
0
                goto error;
480
0
            } else if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
481
                /* skip element with children */
482
0
                LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
483
0
                return LY_SUCCESS;
484
0
            }
485
0
        } else {
486
            /* check that schema node is valid and can be used */
487
0
            LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
488
0
            LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
489
0
        }
490
0
    }
491
492
    /* create metadata/attributes */
493
0
    if (xmlctx->status == LYXML_ATTRIBUTE) {
494
0
        if (snode) {
495
0
            ret = lydxml_metadata(lydctx, &meta);
496
0
            LY_CHECK_GOTO(ret, error);
497
0
        } else {
498
0
            assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
499
0
            ret = lydxml_attrs(xmlctx, &attr);
500
0
            LY_CHECK_GOTO(ret, error);
501
0
        }
502
0
    }
503
504
0
    assert(xmlctx->status == LYXML_ELEM_CONTENT);
505
0
    if (!snode) {
506
0
        assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
507
508
0
        if (xmlctx->ws_only) {
509
            /* ignore WS-only value */
510
0
            if (xmlctx->dynamic) {
511
0
                free((char *) xmlctx->value);
512
0
            }
513
0
            xmlctx->dynamic = 0;
514
0
            xmlctx->value = "";
515
0
            xmlctx->value_len = 0;
516
0
            format = LY_VALUE_XML;
517
0
        } else {
518
            /* get value prefixes */
519
0
            ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_VALUE_XML,
520
0
                    &xmlctx->ns, &format, &val_prefix_data);
521
0
            LY_CHECK_GOTO(ret, error);
522
0
        }
523
524
        /* create node */
525
0
        ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
526
0
                xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
527
0
        LY_CHECK_GOTO(ret, error);
528
529
        /* parser next */
530
0
        LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
531
532
        /* process children */
533
0
        while (xmlctx->status == LYXML_ELEMENT) {
534
0
            ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
535
0
            LY_CHECK_GOTO(ret, error);
536
0
        }
537
0
    } else if (snode->nodetype & LYD_NODE_TERM) {
538
        /* create node */
539
0
        LY_CHECK_GOTO(ret = lyd_parser_create_term((struct lyd_ctx *)lydctx, snode, xmlctx->value, xmlctx->value_len,
540
0
                &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
541
0
        LOG_LOCSET(snode, node, NULL, NULL);
542
543
0
        if (parent && (node->schema->flags & LYS_KEY)) {
544
            /* check the key order, the anchor must never be a key */
545
0
            anchor = lyd_insert_get_next_anchor(lyd_child(parent), node);
546
0
            if (anchor && (anchor->schema->flags & LYS_KEY)) {
547
0
                if (lydctx->parse_opts & LYD_PARSE_STRICT) {
548
0
                    LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
549
0
                    ret = LY_EVALID;
550
0
                    goto error;
551
0
                } else {
552
0
                    LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
553
0
                }
554
0
            }
555
0
        }
556
557
        /* parser next */
558
0
        LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
559
560
        /* no children expected */
561
0
        if (xmlctx->status == LYXML_ELEMENT) {
562
0
            LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
563
0
                    (int)xmlctx->name_len, xmlctx->name, snode->name);
564
0
            ret = LY_EVALID;
565
0
            goto error;
566
0
        }
567
0
    } else if (snode->nodetype & LYD_NODE_INNER) {
568
0
        if (!xmlctx->ws_only) {
569
            /* value in inner node */
570
0
            LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
571
0
                    (int)xmlctx->value_len, xmlctx->value, snode->name);
572
0
            ret = LY_EVALID;
573
0
            goto error;
574
0
        }
575
576
        /* create node */
577
0
        ret = lyd_create_inner(snode, &node);
578
0
        LY_CHECK_GOTO(ret, error);
579
580
0
        LOG_LOCSET(snode, node, NULL, NULL);
581
582
        /* parser next */
583
0
        LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
584
585
        /* process children */
586
0
        while (xmlctx->status == LYXML_ELEMENT) {
587
0
            ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
588
0
            LY_CHECK_GOTO(ret, error);
589
0
        }
590
591
0
        if (snode->nodetype == LYS_LIST) {
592
            /* check all keys exist */
593
0
            LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
594
0
        }
595
596
0
        if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
597
            /* new node validation, autodelete CANNOT occur, all nodes are new */
598
0
            ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
599
0
            LY_CHECK_GOTO(ret, error);
600
601
            /* add any missing default children */
602
0
            ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_when, &lydctx->node_exts,
603
0
                    &lydctx->node_types, (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
604
0
            LY_CHECK_GOTO(ret, error);
605
0
        }
606
607
0
        if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
608
            /* rememeber the RPC/action/notification */
609
0
            lydctx->op_node = node;
610
0
        }
611
0
    } else if (snode->nodetype & LYD_NODE_ANY) {
612
0
        if ((snode->nodetype == LYS_ANYDATA) && !xmlctx->ws_only) {
613
            /* value in anydata node, we expect a tree */
614
0
            LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an anydata node \"%s\" found.",
615
0
                    (int)xmlctx->value_len < 20 ? xmlctx->value_len : 20, xmlctx->value, snode->name);
616
0
            ret = LY_EVALID;
617
0
            goto error;
618
0
        }
619
620
0
        if (!xmlctx->ws_only) {
621
            /* use an arbitrary text value for anyxml */
622
0
            lydict_insert(xmlctx->ctx, xmlctx->value, xmlctx->value_len, &val);
623
624
            /* parser next */
625
0
            LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
626
627
            /* create node */
628
0
            ret = lyd_create_any(snode, val, LYD_ANYDATA_STRING, 1, &node);
629
0
            LY_CHECK_GOTO(ret, error);
630
0
        } else {
631
            /* parser next */
632
0
            LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
633
634
            /* parse any data tree with correct options */
635
0
            prev_opts = lydctx->parse_opts;
636
0
            lydctx->parse_opts &= ~LYD_PARSE_STRICT;
637
0
            lydctx->parse_opts |= LYD_PARSE_OPAQ;
638
0
            anchor = NULL;
639
0
            while (xmlctx->status == LYXML_ELEMENT) {
640
0
                ret = lydxml_subtree_r(lydctx, NULL, &anchor, NULL);
641
0
                LY_CHECK_ERR_GOTO(ret, lydctx->parse_opts = prev_opts, error);
642
0
            }
643
0
            lydctx->parse_opts = prev_opts;
644
645
            /* create node */
646
0
            ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
647
0
            LY_CHECK_GOTO(ret, error);
648
0
        }
649
0
    }
650
0
    assert(node);
651
652
    /* add/correct flags */
653
0
    if (snode) {
654
0
        lyd_parse_set_data_flags(node, &lydctx->node_when, &lydctx->node_exts, &meta, lydctx->parse_opts);
655
0
    }
656
657
    /* parser next */
658
0
    assert(xmlctx->status == LYXML_ELEM_CLOSE);
659
0
    LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
660
661
    /* add metadata/attributes */
662
0
    if (snode) {
663
0
        lyd_insert_meta(node, meta, 0);
664
0
    } else {
665
0
        lyd_insert_attr(node, attr);
666
0
    }
667
668
    /* insert, keep first pointer correct */
669
0
    lyd_insert_node(parent, first_p, node);
670
0
    while (!parent && (*first_p)->prev->next) {
671
0
        *first_p = (*first_p)->prev;
672
0
    }
673
674
    /* rememeber a successfully parsed node */
675
0
    if (parsed) {
676
0
        ly_set_add(parsed, node, 1, NULL);
677
0
    }
678
679
0
    LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
680
0
    return LY_SUCCESS;
681
682
0
error:
683
0
    LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
684
0
    lyd_free_meta_siblings(meta);
685
0
    lyd_free_attr_siblings(ctx, attr);
686
0
    lyd_free_tree(node);
687
0
    return ret;
688
0
}
689
690
/**
691
 * @brief Parse a specific XML element into an opaque node.
692
 *
693
 * @param[in] xmlctx XML parser context.
694
 * @param[in] name Name of the element.
695
 * @param[in] uri URI of the element.
696
 * @param[in] value Whether a value is expected in the element.
697
 * @param[out] evnp Parsed envelope (opaque node).
698
 * @return LY_SUCCESS on success.
699
 * @return LY_ENOT if the specified element did not match.
700
 * @return LY_ERR value on error.
701
 */
702
static LY_ERR
703
lydxml_envelope(struct lyxml_ctx *xmlctx, const char *name, const char *uri, ly_bool value, struct lyd_node **envp)
704
0
{
705
0
    LY_ERR rc = LY_SUCCESS;
706
0
    const struct lyxml_ns *ns;
707
0
    struct lyd_attr *attr = NULL;
708
0
    const char *prefix;
709
0
    size_t prefix_len;
710
711
0
    assert(xmlctx->status == LYXML_ELEMENT);
712
0
    if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
713
        /* not the expected element */
714
0
        return LY_ENOT;
715
0
    }
716
717
0
    prefix = xmlctx->prefix;
718
0
    prefix_len = xmlctx->prefix_len;
719
0
    ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
720
0
    if (!ns) {
721
0
        LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
722
0
        return LY_EVALID;
723
0
    } else if (strcmp(ns->uri, uri)) {
724
        /* different namespace */
725
0
        return LY_ENOT;
726
0
    }
727
728
0
    LY_CHECK_RET(lyxml_ctx_next(xmlctx));
729
730
    /* create attributes */
731
0
    if (xmlctx->status == LYXML_ATTRIBUTE) {
732
0
        LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
733
0
    }
734
735
0
    assert(xmlctx->status == LYXML_ELEM_CONTENT);
736
0
    if (!value && !xmlctx->ws_only) {
737
0
        LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
738
0
                (int)xmlctx->value_len, xmlctx->value, name);
739
0
        rc = LY_EVALID;
740
0
        goto cleanup;
741
0
    }
742
743
    /* create node */
744
0
    rc = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), xmlctx->value,
745
0
            xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, envp);
746
0
    LY_CHECK_GOTO(rc, cleanup);
747
748
    /* assign atributes */
749
0
    ((struct lyd_node_opaq *)(*envp))->attr = attr;
750
0
    attr = NULL;
751
752
    /* parser next element */
753
0
    LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
754
755
0
cleanup:
756
0
    lyd_free_attr_siblings(xmlctx->ctx, attr);
757
0
    if (rc) {
758
0
        lyd_free_tree(*envp);
759
0
        *envp = NULL;
760
0
    }
761
0
    return rc;
762
0
}
763
764
/**
765
 * @brief Parse all expected non-data XML elements of a NETCONF rpc message.
766
 *
767
 * @param[in] xmlctx XML parser context.
768
 * @param[out] evnp Parsed envelope(s) (opaque node).
769
 * @param[out] int_opts Internal options for parsing the rest of YANG data.
770
 * @param[out] close_elem Number of parsed opened elements that need to be closed.
771
 * @return LY_SUCCESS on success.
772
 * @return LY_ERR value on error.
773
 */
774
static LY_ERR
775
lydxml_env_netconf_rpc(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
776
0
{
777
0
    LY_ERR rc = LY_SUCCESS, r;
778
0
    struct lyd_node *child;
779
780
0
    assert(envp && !*envp);
781
782
    /* parse "rpc" */
783
0
    r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
784
0
    LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
785
786
    /* parse "action", if any */
787
0
    r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
788
0
    if (r == LY_SUCCESS) {
789
        /* insert */
790
0
        lyd_insert_node(*envp, NULL, child);
791
792
        /* NETCONF action */
793
0
        *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
794
0
        *close_elem = 2;
795
0
    } else if (r == LY_ENOT) {
796
        /* NETCONF RPC */
797
0
        *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
798
0
        *close_elem = 1;
799
0
    } else {
800
0
        rc = r;
801
0
        goto cleanup;
802
0
    }
803
804
0
cleanup:
805
0
    if (rc) {
806
0
        lyd_free_tree(*envp);
807
0
        *envp = NULL;
808
0
    }
809
0
    return rc;
810
0
}
811
812
/**
813
 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
814
 *
815
 * @param[in] xmlctx XML parser context.
816
 * @param[out] evnp Parsed envelope(s) (opaque node).
817
 * @param[out] int_opts Internal options for parsing the rest of YANG data.
818
 * @param[out] close_elem Number of parsed opened elements that need to be closed.
819
 * @return LY_SUCCESS on success.
820
 * @return LY_ERR value on error.
821
 */
822
static LY_ERR
823
lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
824
0
{
825
0
    LY_ERR rc = LY_SUCCESS, r;
826
0
    struct lyd_node *child;
827
828
0
    assert(envp && !*envp);
829
830
    /* parse "notification" */
831
0
    r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
832
0
    LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
833
834
    /* parse "eventTime" */
835
0
    r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
836
0
    if (r == LY_ENOT) {
837
0
        LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".",
838
0
                (int)xmlctx->name_len, xmlctx->name);
839
0
        r = LY_EVALID;
840
0
    }
841
0
    LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
842
843
    /* insert */
844
0
    lyd_insert_node(*envp, NULL, child);
845
846
    /* validate value */
847
    /* TODO validate child->value as yang:date-and-time */
848
849
    /* finish child parsing */
850
0
    if (xmlctx->status != LYXML_ELEM_CLOSE) {
851
0
        assert(xmlctx->status == LYXML_ELEMENT);
852
0
        LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
853
0
                (int)xmlctx->name_len, xmlctx->name);
854
0
        rc = LY_EVALID;
855
0
        goto cleanup;
856
0
    }
857
0
    LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
858
859
    /* NETCONF notification */
860
0
    *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
861
0
    *close_elem = 1;
862
863
0
cleanup:
864
0
    if (rc) {
865
0
        lyd_free_tree(*envp);
866
0
        *envp = NULL;
867
0
    }
868
0
    return rc;
869
0
}
870
871
/**
872
 * @brief Parse an XML element as an opaque node subtree.
873
 *
874
 * @param[in] xmlctx XML parser context.
875
 * @param[in] parent Parent to append nodes to.
876
 * @return LY_ERR value.
877
 */
878
static LY_ERR
879
lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
880
0
{
881
0
    LY_ERR rc = LY_SUCCESS;
882
0
    const struct lyxml_ns *ns;
883
0
    struct lyd_attr *attr = NULL;
884
0
    struct lyd_node *child = NULL;
885
0
    const char *name, *prefix;
886
0
    size_t name_len, prefix_len;
887
888
0
    assert(xmlctx->status == LYXML_ELEMENT);
889
890
0
    name = xmlctx->name;
891
0
    name_len = xmlctx->name_len;
892
0
    prefix = xmlctx->prefix;
893
0
    prefix_len = xmlctx->prefix_len;
894
0
    ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
895
0
    if (!ns) {
896
0
        LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
897
0
        return LY_EVALID;
898
0
    }
899
900
0
    LY_CHECK_RET(lyxml_ctx_next(xmlctx));
901
902
    /* create attributes */
903
0
    if (xmlctx->status == LYXML_ATTRIBUTE) {
904
0
        LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
905
0
    }
906
907
    /* create node */
908
0
    assert(xmlctx->status == LYXML_ELEM_CONTENT);
909
0
    rc = lyd_create_opaq(xmlctx->ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
910
0
            xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, &child);
911
0
    LY_CHECK_GOTO(rc, cleanup);
912
913
    /* assign atributes */
914
0
    ((struct lyd_node_opaq *)child)->attr = attr;
915
0
    attr = NULL;
916
917
    /* parser next element */
918
0
    LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
919
920
    /* parse all the descendants */
921
0
    while (xmlctx->status == LYXML_ELEMENT) {
922
0
        rc = lydxml_opaq_r(xmlctx, child);
923
0
        LY_CHECK_GOTO(rc, cleanup);
924
0
    }
925
926
    /* insert */
927
0
    lyd_insert_node(parent, NULL, child);
928
929
0
cleanup:
930
0
    lyd_free_attr_siblings(xmlctx->ctx, attr);
931
0
    if (rc) {
932
0
        lyd_free_tree(child);
933
0
    }
934
0
    return rc;
935
0
}
936
937
/**
938
 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
939
 *
940
 * @param[in] xmlctx XML parser context.
941
 * @param[in] parent Parent to append nodes to.
942
 * @return LY_ERR value.
943
 */
944
static LY_ERR
945
lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
946
0
{
947
0
    LY_ERR r;
948
0
    struct lyd_node *child, *iter;
949
0
    const struct lyxml_ns *ns;
950
0
    ly_bool no_dup;
951
952
    /* there must be some child */
953
0
    if (xmlctx->status == LYXML_ELEM_CLOSE) {
954
0
        LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
955
0
        return LY_EVALID;
956
0
    }
957
958
0
    while (xmlctx->status == LYXML_ELEMENT) {
959
0
        child = NULL;
960
961
        /*
962
         * session-id
963
         */
964
0
        r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
965
0
        if (r == LY_SUCCESS) {
966
0
            no_dup = 1;
967
0
            goto check_child;
968
0
        } else if (r != LY_ENOT) {
969
0
            goto error;
970
0
        }
971
972
        /*
973
         * bad-attribute
974
         */
975
0
        r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
976
0
        if (r == LY_SUCCESS) {
977
0
            no_dup = 1;
978
0
            goto check_child;
979
0
        } else if (r != LY_ENOT) {
980
0
            goto error;
981
0
        }
982
983
        /*
984
         * bad-element
985
         */
986
0
        r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
987
0
        if (r == LY_SUCCESS) {
988
0
            no_dup = 1;
989
0
            goto check_child;
990
0
        } else if (r != LY_ENOT) {
991
0
            goto error;
992
0
        }
993
994
        /*
995
         * bad-namespace
996
         */
997
0
        r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
998
0
        if (r == LY_SUCCESS) {
999
0
            no_dup = 1;
1000
0
            goto check_child;
1001
0
        } else if (r != LY_ENOT) {
1002
0
            goto error;
1003
0
        }
1004
1005
0
        if (r == LY_ENOT) {
1006
0
            assert(xmlctx->status == LYXML_ELEMENT);
1007
1008
            /* learn namespace */
1009
0
            ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
1010
0
            if (!ns) {
1011
0
                LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
1012
0
                r = LY_EVALID;
1013
0
                goto error;
1014
0
            } else if (!strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
1015
0
                LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
1016
0
                        (int)xmlctx->name_len, xmlctx->name);
1017
0
                r = LY_EVALID;
1018
0
                goto error;
1019
0
            }
1020
1021
            /* custom elements */
1022
0
            r = lydxml_opaq_r(xmlctx, parent);
1023
0
            LY_CHECK_GOTO(r, error);
1024
1025
0
            no_dup = 0;
1026
0
        }
1027
1028
0
check_child:
1029
        /* check for duplicates */
1030
0
        if (no_dup) {
1031
0
            LY_LIST_FOR(lyd_child(parent), iter) {
1032
0
                if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1033
0
                        (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1034
0
                    LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
1035
0
                            ((struct lyd_node_opaq *)child)->name.name);
1036
0
                    r = LY_EVALID;
1037
0
                    goto error;
1038
0
                }
1039
0
            }
1040
0
        }
1041
1042
        /* finish child parsing */
1043
0
        if (xmlctx->status != LYXML_ELEM_CLOSE) {
1044
0
            assert(xmlctx->status == LYXML_ELEMENT);
1045
0
            LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
1046
0
                    (int)xmlctx->name_len, xmlctx->name);
1047
0
            r = LY_EVALID;
1048
0
            goto error;
1049
0
        }
1050
0
        LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1051
1052
        /* insert */
1053
0
        lyd_insert_node(parent, NULL, child);
1054
0
    }
1055
1056
0
    return LY_SUCCESS;
1057
1058
0
error:
1059
0
    lyd_free_tree(child);
1060
0
    return r;
1061
0
}
1062
1063
/**
1064
 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1065
 *
1066
 * @param[in] xmlctx XML parser context.
1067
 * @param[in] parent Parent to append nodes to.
1068
 * @return LY_ERR value.
1069
 */
1070
static LY_ERR
1071
lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1072
0
{
1073
0
    LY_ERR r;
1074
0
    struct lyd_node *child, *iter;
1075
0
    const char *val;
1076
0
    ly_bool no_dup;
1077
1078
    /* there must be some child */
1079
0
    if (xmlctx->status == LYXML_ELEM_CLOSE) {
1080
0
        LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1081
0
        return LY_EVALID;
1082
0
    }
1083
1084
0
    while (xmlctx->status == LYXML_ELEMENT) {
1085
0
        child = NULL;
1086
1087
        /*
1088
         * error-type
1089
         */
1090
0
        r = lydxml_envelope(xmlctx, "error-type", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1091
0
        if (r == LY_SUCCESS) {
1092
0
            val = ((struct lyd_node_opaq *)child)->value;
1093
0
            if (strcmp(val, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1094
0
                LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1095
0
                        ((struct lyd_node_opaq *)child)->name.name);
1096
0
                r = LY_EVALID;
1097
0
                goto error;
1098
0
            }
1099
1100
0
            no_dup = 1;
1101
0
            goto check_child;
1102
0
        } else if (r != LY_ENOT) {
1103
0
            goto error;
1104
0
        }
1105
1106
        /*
1107
         * error-tag
1108
         */
1109
0
        r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1110
0
        if (r == LY_SUCCESS) {
1111
0
            val = ((struct lyd_node_opaq *)child)->value;
1112
0
            if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1113
0
                    strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1114
0
                    strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1115
0
                    strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1116
0
                    strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1117
0
                    strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1118
0
                    strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
1119
0
                LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1120
0
                        ((struct lyd_node_opaq *)child)->name.name);
1121
0
                r = LY_EVALID;
1122
0
                goto error;
1123
0
            }
1124
1125
0
            no_dup = 1;
1126
0
            goto check_child;
1127
0
        } else if (r != LY_ENOT) {
1128
0
            goto error;
1129
0
        }
1130
1131
        /*
1132
         * error-severity
1133
         */
1134
0
        r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1135
0
        if (r == LY_SUCCESS) {
1136
0
            val = ((struct lyd_node_opaq *)child)->value;
1137
0
            if (strcmp(val, "error") && strcmp(val, "warning")) {
1138
0
                LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1139
0
                        ((struct lyd_node_opaq *)child)->name.name);
1140
0
                r = LY_EVALID;
1141
0
                goto error;
1142
0
            }
1143
1144
0
            no_dup = 1;
1145
0
            goto check_child;
1146
0
        } else if (r != LY_ENOT) {
1147
0
            goto error;
1148
0
        }
1149
1150
        /*
1151
         * error-app-tag
1152
         */
1153
0
        r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1154
0
        if (r == LY_SUCCESS) {
1155
0
            no_dup = 1;
1156
0
            goto check_child;
1157
0
        } else if (r != LY_ENOT) {
1158
0
            goto error;
1159
0
        }
1160
1161
        /*
1162
         * error-path
1163
         */
1164
0
        r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1165
0
        if (r == LY_SUCCESS) {
1166
0
            no_dup = 1;
1167
0
            goto check_child;
1168
0
        } else if (r != LY_ENOT) {
1169
0
            goto error;
1170
0
        }
1171
1172
        /*
1173
         * error-message
1174
         */
1175
0
        r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1176
0
        if (r == LY_SUCCESS) {
1177
0
            no_dup = 1;
1178
0
            goto check_child;
1179
0
        } else if (r != LY_ENOT) {
1180
0
            goto error;
1181
0
        }
1182
1183
        /* error-info */
1184
0
        r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1185
0
        if (r == LY_SUCCESS) {
1186
            /* parse all the descendants */
1187
0
            LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1188
1189
0
            no_dup = 0;
1190
0
            goto check_child;
1191
0
        } else if (r != LY_ENOT) {
1192
0
            goto error;
1193
0
        }
1194
1195
0
        if (r == LY_ENOT) {
1196
0
            assert(xmlctx->status == LYXML_ELEMENT);
1197
0
            LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
1198
0
                    (int)xmlctx->name_len, xmlctx->name);
1199
0
            r = LY_EVALID;
1200
0
            goto error;
1201
0
        }
1202
1203
0
check_child:
1204
        /* check for duplicates */
1205
0
        if (no_dup) {
1206
0
            LY_LIST_FOR(lyd_child(parent), iter) {
1207
0
                if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1208
0
                        (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1209
0
                    LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1210
0
                            ((struct lyd_node_opaq *)child)->name.name);
1211
0
                    r = LY_EVALID;
1212
0
                    goto error;
1213
0
                }
1214
0
            }
1215
0
        }
1216
1217
        /* finish child parsing */
1218
0
        if (xmlctx->status != LYXML_ELEM_CLOSE) {
1219
0
            assert(xmlctx->status == LYXML_ELEMENT);
1220
0
            LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
1221
0
                    (int)xmlctx->name_len, xmlctx->name);
1222
0
            r = LY_EVALID;
1223
0
            goto error;
1224
0
        }
1225
0
        LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1226
1227
        /* insert */
1228
0
        lyd_insert_node(parent, NULL, child);
1229
0
    }
1230
1231
0
    return LY_SUCCESS;
1232
1233
0
error:
1234
0
    lyd_free_tree(child);
1235
0
    return r;
1236
0
}
1237
1238
/**
1239
 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1240
 *
1241
 * @param[in] xmlctx XML parser context.
1242
 * @param[out] evnp Parsed envelope(s) (opaque node).
1243
 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1244
 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1245
 * @return LY_SUCCESS on success.
1246
 * @return LY_ERR value on error.
1247
 */
1248
static LY_ERR
1249
lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1250
0
{
1251
0
    LY_ERR rc = LY_SUCCESS, r;
1252
0
    struct lyd_node *child = NULL;
1253
0
    const char *parsed_elem = NULL;
1254
1255
0
    assert(envp && !*envp);
1256
1257
    /* parse "rpc-reply" */
1258
0
    r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
1259
0
    LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1260
1261
    /* there must be some child */
1262
0
    if (xmlctx->status == LYXML_ELEM_CLOSE) {
1263
0
        LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1264
0
        rc = LY_EVALID;
1265
0
        goto cleanup;
1266
0
    }
1267
1268
    /* try to parse "ok" */
1269
0
    r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1270
0
    if (r == LY_SUCCESS) {
1271
        /* insert */
1272
0
        lyd_insert_node(*envp, NULL, child);
1273
1274
        /* finish child parsing */
1275
0
        if (xmlctx->status != LYXML_ELEM_CLOSE) {
1276
0
            assert(xmlctx->status == LYXML_ELEMENT);
1277
0
            LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
1278
0
                    (int)xmlctx->name_len, xmlctx->name);
1279
0
            rc = LY_EVALID;
1280
0
            goto cleanup;
1281
0
        }
1282
0
        LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1283
1284
        /* success */
1285
0
        parsed_elem = "ok";
1286
0
        goto finish;
1287
0
    } else if (r != LY_ENOT) {
1288
0
        rc = r;
1289
0
        goto cleanup;
1290
0
    }
1291
1292
    /* try to parse all "rpc-error" elements */
1293
0
    while (xmlctx->status == LYXML_ELEMENT) {
1294
0
        r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1295
0
        if (r == LY_ENOT) {
1296
0
            break;
1297
0
        } else if (r) {
1298
0
            rc = r;
1299
0
            goto cleanup;
1300
0
        }
1301
1302
        /* insert */
1303
0
        lyd_insert_node(*envp, NULL, child);
1304
1305
        /* parse all children of "rpc-error" */
1306
0
        LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1307
1308
        /* finish child parsing */
1309
0
        assert(xmlctx->status == LYXML_ELEM_CLOSE);
1310
0
        LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1311
1312
0
        parsed_elem = "rpc-error";
1313
0
    }
1314
1315
0
finish:
1316
0
    if (parsed_elem) {
1317
        /* NETCONF rpc-reply with no data */
1318
0
        if (xmlctx->status != LYXML_ELEM_CLOSE) {
1319
0
            assert(xmlctx->status == LYXML_ELEMENT);
1320
0
            LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
1321
0
                    (int)xmlctx->name_len, xmlctx->name, parsed_elem);
1322
0
            rc = LY_EVALID;
1323
0
            goto cleanup;
1324
0
        }
1325
0
    }
1326
1327
    /* NETCONF rpc-reply */
1328
0
    *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_REPLY;
1329
0
    *close_elem = 1;
1330
1331
0
cleanup:
1332
0
    if (rc) {
1333
0
        lyd_free_tree(*envp);
1334
0
        *envp = NULL;
1335
0
    }
1336
0
    return rc;
1337
0
}
1338
1339
LY_ERR
1340
lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1341
        struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
1342
        struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
1343
0
{
1344
0
    LY_ERR rc = LY_SUCCESS;
1345
0
    struct lyd_xml_ctx *lydctx;
1346
0
    uint32_t i, int_opts, close_elem = 0;
1347
0
    ly_bool parsed_data_nodes = 0;
1348
1349
0
    assert(ctx && in && lydctx_p);
1350
0
    assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1351
0
    assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
1352
1353
    /* init context */
1354
0
    lydctx = calloc(1, sizeof *lydctx);
1355
0
    LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1356
0
    LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1357
0
    lydctx->parse_opts = parse_opts;
1358
0
    lydctx->val_opts = val_opts;
1359
0
    lydctx->free = lyd_xml_ctx_free;
1360
0
    lydctx->ext = ext;
1361
1362
0
    switch (data_type) {
1363
0
    case LYD_TYPE_DATA_YANG:
1364
0
        int_opts = LYD_INTOPT_WITH_SIBLINGS;
1365
0
        break;
1366
0
    case LYD_TYPE_RPC_YANG:
1367
0
        int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1368
0
        break;
1369
0
    case LYD_TYPE_NOTIF_YANG:
1370
0
        int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1371
0
        break;
1372
0
    case LYD_TYPE_REPLY_YANG:
1373
0
        int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1374
0
        break;
1375
0
    case LYD_TYPE_RPC_NETCONF:
1376
0
        assert(!parent);
1377
0
        LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1378
0
        break;
1379
0
    case LYD_TYPE_NOTIF_NETCONF:
1380
0
        assert(!parent);
1381
0
        LY_CHECK_GOTO(rc = lydxml_env_netconf_notif(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1382
0
        break;
1383
0
    case LYD_TYPE_REPLY_NETCONF:
1384
0
        assert(parent);
1385
0
        LY_CHECK_GOTO(rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1386
0
        break;
1387
0
    }
1388
0
    lydctx->int_opts = int_opts;
1389
1390
    /* find the operation node if it exists already */
1391
0
    LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1392
1393
    /* parse XML data */
1394
0
    while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1395
0
        LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1396
0
        parsed_data_nodes = 1;
1397
1398
0
        if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1399
0
            break;
1400
0
        }
1401
0
    }
1402
1403
    /* close all opened elements */
1404
0
    for (i = 0; i < close_elem; ++i) {
1405
0
        if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1406
0
            assert(lydctx->xmlctx->status == LYXML_ELEMENT);
1407
0
            LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".",
1408
0
                    (int)lydctx->xmlctx->name_len, lydctx->xmlctx->name);
1409
0
            rc = LY_EVALID;
1410
0
            goto cleanup;
1411
0
        }
1412
1413
0
        LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
1414
0
    }
1415
1416
    /* check final state */
1417
0
    if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1418
0
        LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1419
0
        rc = LY_EVALID;
1420
0
        goto cleanup;
1421
0
    }
1422
0
    if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lydctx->op_node) {
1423
0
        LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1424
0
        rc = LY_EVALID;
1425
0
        goto cleanup;
1426
0
    }
1427
1428
0
    if (!parsed_data_nodes) {
1429
        /* no data nodes were parsed */
1430
0
        lydctx->op_node = NULL;
1431
0
    }
1432
1433
0
cleanup:
1434
    /* there should be no unres stored if validation should be skipped */
1435
0
    assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
1436
0
            !lydctx->node_when.count && !lydctx->node_exts.count));
1437
1438
0
    if (rc) {
1439
0
        lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1440
0
    } else {
1441
0
        *lydctx_p = (struct lyd_ctx *)lydctx;
1442
1443
        /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1444
0
        lyxml_ctx_free(lydctx->xmlctx);
1445
        lydctx->xmlctx = NULL;
1446
0
    }
1447
0
    return rc;
1448
0
}