1 /**
2 * @file nacm.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief libyang extension plugin - NACM (RFC 6536)
5 *
6 * Copyright (c) 2016-2017 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 #ifdef __GNUC__
16 # define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
17 #else
18 # define UNUSED(x) UNUSED_ ## x
19 #endif
20
21 #include <stdlib.h>
22
23 #include "../extensions.h"
24
25 /**
26 * @brief Storage for ID used to check plugin API version compatibility.
27 */
28 LYEXT_VERSION_CHECK
29
30 /**
31 * @brief Callback to check that the NACM extension can be instantiated inside the provided node
32 *
33 * @param[in] parent The parent of the instantiated extension.
34 * @param[in] parent_type The type of the structure provided as \p parent.
35 * @param[in] substmt_type libyang does not store all the extension instances in the structures where they are
36 * instantiated in the module. In some cases (see #LYEXT_SUBSTMT) they are stored in parent
37 * structure and marked with flag to know in which substatement of the parent the extension
38 * was originally instantiated.
39 * @return 0 - ok
40 * 1 - error
41 */
nacm_position(const void * parent,LYEXT_PAR parent_type,LYEXT_SUBSTMT UNUSED (substmt_type))42 int nacm_position(const void *parent, LYEXT_PAR parent_type, LYEXT_SUBSTMT UNUSED(substmt_type))
43 {
44 if (parent_type != LYEXT_PAR_NODE) {
45 return 1;
46 }
47
48 if (((struct lys_node*)parent)->nodetype &
49 (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE | LYS_ANYDATA | LYS_AUGMENT | LYS_CASE |
50 LYS_USES | LYS_RPC | LYS_ACTION | LYS_NOTIF )) {
51 return 0;
52 } else {
53 return 1;
54 }
55 }
56
57 /**
58 * @brief Callback to decide whether the extension will be inherited into the provided schema node. The extension
59 * instance is always from some of the node's parents.
60 *
61 * @param[in] ext Extension instance to be inherited.
62 * @param[in] node Schema node where the node is supposed to be inherited.
63 * @return 0 - yes
64 * 1 - no (do not process the node's children)
65 * 2 - no, but continue with children
66 */
nacm_inherit(struct lys_ext_instance * UNUSED (ext),struct lys_node * node)67 int nacm_inherit(struct lys_ext_instance *UNUSED(ext), struct lys_node *node)
68 {
69 /* libyang already checks if there is explicit instance of the extension already present,
70 * in such a case the extension is never inherited and we don't need to check it here */
71
72 /* inherit into all the schema nodes that can be instantiated in data trees */
73 if (node->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_ACTION | LYS_NOTIF )) {
74 return 0;
75 } else {
76 return 2;
77 }
78 }
79
80 /**
81 * @brief Callback to check that the extension instance is correct - have
82 * the valid argument, cardinality, etc.
83 *
84 * In NACM case, we are checking only the cardinality.
85 *
86 * @param[in] ext Extension instance to be checked.
87 * @return 0 - ok
88 * 1 - error
89 */
90 int
nacm_cardinality(struct lys_ext_instance * ext)91 nacm_cardinality(struct lys_ext_instance *ext)
92 {
93 struct lys_ext_instance **extlist;
94 uint8_t extsize, i, c;
95 char *path;
96
97 if (ext->flags & LYEXT_OPT_PLUGIN1) {
98 /* already checked */
99 ext->flags &= ~LYEXT_OPT_PLUGIN1;
100 return 0;
101 }
102
103 extlist = ((struct lys_node *)ext->parent)->ext;
104 extsize = ((struct lys_node *)ext->parent)->ext_size;
105
106 for (i = c = 0; i < extsize; i++) {
107 if (extlist[i]->def == ext->def) {
108 /* note, that it is not necessary to check also ext->insubstmt since
109 * nacm_position() ensures that NACM's extension instances are placed only
110 * in schema nodes */
111 if (extlist[i] != ext) {
112 /* do not mark the instance being checked */
113 extlist[i]->flags |= LYEXT_OPT_PLUGIN1;
114 }
115 c++;
116 }
117 }
118
119 if (c > 1) {
120 path = lys_path((struct lys_node *)(ext->parent), LYS_PATH_FIRST_PREFIX);
121 LYEXT_LOG(ext->module->ctx, LY_LLERR, "NACM", "Extension nacm:%s can appear only once, but %d instances found in %s.",
122 ext->def->name, c, path);
123 free(path);
124 return 1;
125 } else {
126 return 0;
127 }
128 }
129
130 /**
131 * @brief Plugin for the NACM's default-deny-write extension
132 */
133 struct lyext_plugin nacm_deny_write = {
134 .type = LYEXT_FLAG,
135 .flags = LYEXT_OPT_INHERIT,
136 .check_position = &nacm_position,
137 .check_result = &nacm_cardinality,
138 .check_inherit = &nacm_inherit
139 };
140
141 /**
142 * @brief Plugin for the NACM's default-deny-all extension
143 */
144 struct lyext_plugin nacm_deny_all = {
145 .type = LYEXT_FLAG,
146 .flags = LYEXT_OPT_INHERIT,
147 .check_position = &nacm_position,
148 .check_result = &nacm_cardinality,
149 .check_inherit = &nacm_inherit
150 };
151
152 /**
153 * @brief list of all extension plugins implemented here
154 *
155 * MANDATORY object for all libyang extension plugins, the name must match the <name>.so
156 */
157 struct lyext_plugin_list nacm[] = {
158 {"ietf-netconf-acm", "2012-02-22", "default-deny-write", &nacm_deny_write},
159 {"ietf-netconf-acm", "2012-02-22", "default-deny-all", &nacm_deny_all},
160 {NULL, NULL, NULL, NULL} /* terminating item */
161 };
162