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)
141 switch (node->type) {
143 rc = check(closure, node->text);
146 rc = node_check(node->children[0], check, closure);
148 rc = node_check(node->children[1], check, closure);
151 rc = node_check(node->children[0], check, closure);
153 rc = node_check(node->children[1], check, closure);
156 rc = !node_check(node->children[0], check, closure);
162 /*********************************************************************
164 *********************************************************************/
171 TEXT, /**< a common text, name of a permission */
172 AND, /**< and keyword */
173 OR, /**< or keyword */
174 NOT, /**< not keyword */
175 OBRA, /**< open bracket */
176 CBRA, /**< close bracket */
177 END /**< end of input */
181 * structure for parsing permission description
185 const char *desc; /**< initial permission description */
186 const char *symbol; /**< current symbol parsed */
187 size_t symlen; /**< length of the current symbol */
188 enum symbol type; /**< type of the current symbol */
192 * updates parse to point to the next symbol if any
193 * @param parse parser state to update
195 static void parse_next(struct parse *parse)
200 /* skip current symbol */
201 scan = &parse->symbol[parse->symlen];
203 /* skip white spaces */
204 while (*scan && isspace(*scan))
207 /* scan the symbol */
222 /* compute the length */
224 while (scan[len] && !isspace(scan[len]) && scan[len] != ')' && scan[len] != '(')
228 /* fall to keyword if any */
231 if (!strncasecmp(scan, "or", len))
235 if (!strncasecmp(scan, "and", len))
237 else if (!strncasecmp(scan, "not", len))
243 parse->symbol = scan;
248 * Init the parser state 'parse' for the description 'desc'
249 * @param parse the parser state to initialise
250 * @param desc the description of the permissions to be parsed
252 static void parse_init(struct parse *parse, const char *desc)
255 parse->symbol = desc;
260 /*********************************************************************
261 *** SECTION node_parse
262 *********************************************************************/
264 static struct node *node_parse_or(struct parse *parse);
267 * Parse a permission name
268 * @param parser the parser state
269 * @return the parsed node or NULL in case of error
270 * in case of error errno is set to EINVAL or ENOMEM
272 static struct node *node_parse_text(struct parse *parse)
276 if (parse->type == TEXT) {
277 node = node_make_text(Text, parse->symbol, parse->symlen);
287 * Parse a term that is either a name (text) or a sub expression
288 * enclosed in brackets.
289 * @param parser the parser state
290 * @return the parsed node or NULL in case of error
291 * in case of error errno is set to EINVAL or ENOMEM
293 static struct node *node_parse_term(struct parse *parse)
297 if (parse->type != OBRA)
298 node = node_parse_text(parse);
301 node = node_parse_or(parse);
302 if (parse->type == CBRA)
314 * Parse a term potentially prefixed by not.
315 * @param parser the parser state
316 * @return the parsed node or NULL in case of error
317 * in case of error errno is set to EINVAL or ENOMEM
319 static struct node *node_parse_not(struct parse *parse)
321 struct node *node, *not;
323 if (parse->type != NOT)
324 node = node_parse_term(parse);
327 node = node_parse_term(parse);
329 not = node_make_parent(Not, node, NULL);
342 * Parse a potential sequence of terms connected with the
343 * given operator (AND or OR). The function takes care to
344 * create an evaluation tree that respects the order given
345 * by the description and that will limit the recursivity
347 * @param parser the parser state
348 * @param operator the symbol type of the operator scanned
349 * @param subparse the function for parsing terms of the sequence
350 * @param type the node type corresponding to the operator
351 * @return the parsed node or NULL in case of error
352 * in case of error errno is set to EINVAL or ENOMEM
354 static struct node *node_parse_infix(
356 enum symbol operator,
357 struct node *(*subparse)(struct parse*),
361 struct node *root, **up, *right, *node;
363 root = subparse(parse);
366 while (parse->type == operator) {
368 right = subparse(parse);
374 node = node_make_parent(type, *up, right);
382 up = &node->children[1];
389 * Parse a potential sequence of anded terms.
390 * @param parser the parser state
391 * @return the parsed node or NULL in case of error
392 * in case of error errno is set to EINVAL or ENOMEM
394 static struct node *node_parse_and(struct parse *parse)
396 return node_parse_infix(parse, AND, node_parse_not, And);
400 * Parse a potential sequence of ored terms.
401 * @param parser the parser state
402 * @return the parsed node or NULL in case of error
403 * in case of error errno is set to EINVAL or ENOMEM
405 static struct node *node_parse_or(struct parse *parse)
407 return node_parse_infix(parse, OR, node_parse_and, Or);
411 * Parse description of permissions.
412 * @param desc the description to parse
413 * @return the parsed node or NULL in case of error
414 * in case of error errno is set to EINVAL or ENOMEM
416 static struct node *node_parse(const char *desc)
421 parse_init(&parse, desc);
422 node = node_parse_or(&parse);
423 if (node && parse.type != END) {
430 /*********************************************************************
432 *********************************************************************/
435 * structure for storing permissions
439 struct node *root; /**< root node descripbing the permission */
440 int refcount; /**< the count of use of the structure */
444 * allocates the structure for the given root
445 * @param root the root node to keep
446 * @return the created permission object or NULL
448 static struct afb_perm *make_perm(struct node *root)
450 struct afb_perm *perm;
452 perm = malloc(sizeof *perm);
463 * Creates the permission for the given description
464 * @param desc the description of the permission to create
465 * @return the created permission object or NULL
467 struct afb_perm *afb_perm_parse(const char *desc)
470 struct afb_perm *perm;
472 root = node_parse(desc);
474 perm = make_perm(root);
483 * Adds a reference to the permissions
484 * @param perm the permission to reference
486 void afb_perm_addref(struct afb_perm *perm)
493 * Removes a reference to the permissions
494 * @param perm the permission to dereference
496 void afb_perm_unref(struct afb_perm *perm)
498 if (perm && !--perm->refcount) {
499 node_free(perm->root);
505 * Checks permission 'perm' using the 'check' function
507 * @param perm the permission to check
508 * @param check the function that checks if a pernmission of 'name' is granted for 'closure'
509 * @param closure the context closure for the function 'check'
510 * @return 1 if the permission is granted or 0 otherwise
512 int afb_perm_check(struct afb_perm *perm, int (*check)(void *closure, const char *name), void *closure)
514 return node_check(perm->root, check, closure);