2 * Copyright (C) 2017 "IoT.bzh"
3 * Author José Bollo <jose.bollo@iot.bzh>
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
28 /*********************************************************************
30 *********************************************************************/
37 Text, /**< text node */
48 enum type type; /**< type of the node */
50 struct node *children[2]; /**< possible subnodes */
51 char text[1]; /**< text of the node */
56 * make a text node and return it
57 * @param type type of the node (should be Text)
58 * @param text the text to set for the node
59 * @param length the length of the text
60 * @return the allocated node or NULL on memory depletion
62 static struct node *node_make_text(enum type type, const char *text, size_t length)
66 node = malloc(length + sizeof *node);
71 memcpy(node->text, text, length);
72 node->text[length] = 0;
78 * make a node with sub nodes and return it
79 * @param type type of the node (should be And, Or or Text)
80 * @param left the "left" sub node
81 * @param right the "right" sub node (if any or NULL)
82 * @return the allocated node or NULL on memory depletion
84 static struct node *node_make_parent(enum type type, struct node *left, struct node *right)
88 node = malloc(sizeof *node);
93 node->children[0] = left;
94 node->children[1] = right;
100 * Frees the node and its possible subnodes
101 * @param node the node to free
103 static void node_free(struct node *node)
105 struct node *left, *right;
108 switch (node->type) {
114 left = node->children[0];
115 right = node->children[1];
121 left = node->children[0];
130 * Checks the permissions for the 'node' using the 'check' function
132 * @param node the node to check
133 * @param check the function that checks if a pernmission of 'name' is granted for 'closure'
134 * @param closure the context closure for the function 'check'
135 * @return 1 if the permission is granted or 0 otherwise
137 static int node_check(struct node *node, int (*check)(void *closure, const char *name), void *closure)
140 switch (node->type) {
142 return check(closure, node->text);
144 if (!node_check(node->children[0], check, closure))
148 if (node_check(node->children[0], check, closure))
152 return !node_check(node->children[0], check, closure);
154 node = node->children[1];
158 /*********************************************************************
160 *********************************************************************/
167 TEXT, /**< a common text, name of a permission */
168 AND, /**< and keyword */
169 OR, /**< or keyword */
170 NOT, /**< not keyword */
171 OBRA, /**< open bracket */
172 CBRA, /**< close bracket */
173 END /**< end of input */
177 * structure for parsing permission description
181 const char *desc; /**< initial permission description */
182 const char *symbol; /**< current symbol parsed */
183 size_t symlen; /**< length of the current symbol */
184 enum symbol type; /**< type of the current symbol */
188 * updates parse to point to the next symbol if any
189 * @param parse parser state to update
191 static void parse_next(struct parse *parse)
196 /* skip current symbol */
197 scan = &parse->symbol[parse->symlen];
199 /* skip white spaces */
200 while (*scan && isspace(*scan))
203 /* scan the symbol */
218 /* compute the length */
220 while (scan[len] && !isspace(scan[len]) && scan[len] != ')' && scan[len] != '(')
224 /* fall to keyword if any */
227 if (!strncasecmp(scan, "or", len))
231 if (!strncasecmp(scan, "and", len))
233 else if (!strncasecmp(scan, "not", len))
239 parse->symbol = scan;
244 * Init the parser state 'parse' for the description 'desc'
245 * @param parse the parser state to initialise
246 * @param desc the description of the permissions to be parsed
248 static void parse_init(struct parse *parse, const char *desc)
251 parse->symbol = desc;
256 /*********************************************************************
257 *** SECTION node_parse
258 *********************************************************************/
260 static struct node *node_parse_or(struct parse *parse);
263 * Parse a permission name
264 * @param parser the parser state
265 * @return the parsed node or NULL in case of error
266 * in case of error errno is set to EINVAL or ENOMEM
268 static struct node *node_parse_text(struct parse *parse)
272 if (parse->type == TEXT) {
273 node = node_make_text(Text, parse->symbol, parse->symlen);
283 * Parse a term that is either a name (text) or a sub expression
284 * enclosed in brackets.
285 * @param parser the parser state
286 * @return the parsed node or NULL in case of error
287 * in case of error errno is set to EINVAL or ENOMEM
289 static struct node *node_parse_term(struct parse *parse)
293 if (parse->type != OBRA)
294 node = node_parse_text(parse);
297 node = node_parse_or(parse);
298 if (parse->type == CBRA)
310 * Parse a term potentially prefixed by not.
311 * @param parser the parser state
312 * @return the parsed node or NULL in case of error
313 * in case of error errno is set to EINVAL or ENOMEM
315 static struct node *node_parse_not(struct parse *parse)
317 struct node *node, *not;
319 if (parse->type != NOT)
320 node = node_parse_term(parse);
323 node = node_parse_term(parse);
325 not = node_make_parent(Not, node, NULL);
338 * Parse a potential sequence of terms connected with the
339 * given operator (AND or OR). The function takes care to
340 * create an evaluation tree that respects the order given
341 * by the description and that will limit the recursivity
343 * @param parser the parser state
344 * @param operator the symbol type of the operator scanned
345 * @param subparse the function for parsing terms of the sequence
346 * @param type the node type corresponding to the operator
347 * @return the parsed node or NULL in case of error
348 * in case of error errno is set to EINVAL or ENOMEM
350 static struct node *node_parse_infix(
352 enum symbol operator,
353 struct node *(*subparse)(struct parse*),
357 struct node *root, **up, *right, *node;
359 root = subparse(parse);
362 while (parse->type == operator) {
364 right = subparse(parse);
370 node = node_make_parent(type, *up, right);
378 up = &node->children[1];
385 * Parse a potential sequence of anded terms.
386 * @param parser the parser state
387 * @return the parsed node or NULL in case of error
388 * in case of error errno is set to EINVAL or ENOMEM
390 static struct node *node_parse_and(struct parse *parse)
392 return node_parse_infix(parse, AND, node_parse_not, And);
396 * Parse a potential sequence of ored terms.
397 * @param parser the parser state
398 * @return the parsed node or NULL in case of error
399 * in case of error errno is set to EINVAL or ENOMEM
401 static struct node *node_parse_or(struct parse *parse)
403 return node_parse_infix(parse, OR, node_parse_and, Or);
407 * Parse description of permissions.
408 * @param desc the description to parse
409 * @return the parsed node or NULL in case of error
410 * in case of error errno is set to EINVAL or ENOMEM
412 static struct node *node_parse(const char *desc)
417 parse_init(&parse, desc);
418 node = node_parse_or(&parse);
419 if (node && parse.type != END) {
426 /*********************************************************************
428 *********************************************************************/
431 * structure for storing permissions
435 struct node *root; /**< root node descripbing the permission */
436 int refcount; /**< the count of use of the structure */
440 * allocates the structure for the given root
441 * @param root the root node to keep
442 * @return the created permission object or NULL
444 static struct afb_perm *make_perm(struct node *root)
446 struct afb_perm *perm;
448 perm = malloc(sizeof *perm);
459 * Creates the permission for the given description
460 * @param desc the description of the permission to create
461 * @return the created permission object or NULL
463 struct afb_perm *afb_perm_parse(const char *desc)
466 struct afb_perm *perm;
468 root = node_parse(desc);
470 perm = make_perm(root);
479 * Adds a reference to the permissions
480 * @param perm the permission to reference
482 void afb_perm_addref(struct afb_perm *perm)
489 * Removes a reference to the permissions
490 * @param perm the permission to dereference
492 void afb_perm_unref(struct afb_perm *perm)
494 if (perm && !--perm->refcount) {
495 node_free(perm->root);
501 * Checks permission 'perm' using the 'check' function
503 * @param perm the permission to check
504 * @param check the function that checks if a pernmission of 'name' is granted for 'closure'
505 * @param closure the context closure for the function 'check'
506 * @return 1 if the permission is granted or 0 otherwise
508 int afb_perm_check(struct afb_perm *perm, int (*check)(void *closure, const char *name), void *closure)
510 return node_check(perm->root, check, closure);