X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fafb-perm.c;h=23c262aa1abd58975ff115a7a7bebd0d43c4ebf7;hb=65353dce81a629e042800bb7b86fcd869a76727e;hp=b4d2b5e31c1d5ee7274948bc49d3431a6a7d31a1;hpb=5200d7022b34c0be646ae92de8c638c9437c7072;p=src%2Fapp-framework-binder.git diff --git a/src/afb-perm.c b/src/afb-perm.c index b4d2b5e3..23c262aa 100644 --- a/src/afb-perm.c +++ b/src/afb-perm.c @@ -1,6 +1,6 @@ /* - * Copyright (C) 2017 "IoT.bzh" - * Author José Bollo + * Copyright (C) 2015-2020 "IoT.bzh" + * Author: José Bollo * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,503 +15,79 @@ * limitations under the License. */ +#include -#include -#include -#include -#include -#include - -#include "afb-perm.h" +#include "afb-context.h" +#include "afb-cred.h" +#include "afb-token.h" +#include "afb-session.h" #include "verbose.h" -/********************************************************************* -*** SECTION node -*********************************************************************/ - -/** - * types of nodes - */ -enum type -{ - Text, /**< text node */ - And, /**< and node */ - Or, /**< or node */ - Not /**< not node */ -}; - -/** - * structure for nodes - */ -struct node -{ - enum type type; /**< type of the node */ - union { - struct node *children[2]; /**< possible subnodes */ - char text[1]; /**< text of the node */ - }; -}; +/*********************************************************************************/ -/** - * make a text node and return it - * @param type type of the node (should be Text) - * @param text the text to set for the node - * @param length the length of the text - * @return the allocated node or NULL on memory depletion - */ -static struct node *node_make_text(enum type type, const char *text, size_t length) +static inline const char *session_of_context(struct afb_context *context) { - struct node *node; - - node = malloc(length + sizeof *node); - if (!node) - errno = ENOMEM; - else { - node->type = type; - memcpy(node->text, text, length); - node->text[length] = 0; - } - return node; + return context->token ? afb_token_string(context->token) + : context->session ? afb_session_uuid(context->session) + : ""; } -/** - * make a node with sub nodes and return it - * @param type type of the node (should be And, Or or Text) - * @param left the "left" sub node - * @param right the "right" sub node (if any or NULL) - * @return the allocated node or NULL on memory depletion - */ -static struct node *node_make_parent(enum type type, struct node *left, struct node *right) -{ - struct node *node; +/*********************************************************************************/ +#ifdef BACKEND_PERMISSION_IS_CYNARA - node = malloc(sizeof *node); - if (!node) - errno = ENOMEM; - else { - node->type = type; - node->children[0] = left; - node->children[1] = right; - } - return node; -} +#include +#include -/** - * Frees the node and its possible subnodes - * @param node the node to free - */ -static void node_free(struct node *node) -{ - struct node *left, *right; +static cynara *handle; +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - if (node) { - switch (node->type) { - case Text: - free(node); - break; - case And: - case Or: - left = node->children[0]; - right = node->children[1]; - free(node); - node_free(left); - node_free(right); - break; - case Not: - left = node->children[0]; - free(node); - node_free(left); - break; - } - } -} - -/** - * Checks the permissions for the 'node' using the 'check' function - * and its 'closure'. - * @param node the node to check - * @param check the function that checks if a pernmission of 'name' is granted for 'closure' - * @param closure the context closure for the function 'check' - * @return 1 if the permission is granted or 0 otherwise - */ -static int node_check(struct node *node, int (*check)(void *closure, const char *name), void *closure) +int afb_perm_check(struct afb_context *context, const char *permission) { int rc; - switch (node->type) { - case Text: - rc = check(closure, node->text); - break; - case And: - rc = node_check(node->children[0], check, closure); - if (rc) - rc = node_check(node->children[1], check, closure); - break; - case Or: - rc = node_check(node->children[0], check, closure); - if (!rc) - rc = node_check(node->children[1], check, closure); - break; - case Not: - rc = !node_check(node->children[0], check, closure); - break; - } - return rc; -} - -/********************************************************************* -*** SECTION parse -*********************************************************************/ - -/** - * the symbol types - */ -enum symbol -{ - TEXT, /**< a common text, name of a permission */ - AND, /**< and keyword */ - OR, /**< or keyword */ - NOT, /**< not keyword */ - OBRA, /**< open bracket */ - CBRA, /**< close bracket */ - END /**< end of input */ -}; - -/** - * structure for parsing permission description - */ -struct parse -{ - const char *desc; /**< initial permission description */ - const char *symbol; /**< current symbol parsed */ - size_t symlen; /**< length of the current symbol */ - enum symbol type; /**< type of the current symbol */ -}; - -/** - * updates parse to point to the next symbol if any - * @param parse parser state to update - */ -static void parse_next(struct parse *parse) -{ - const char *scan; - size_t len; - - /* skip current symbol */ - scan = &parse->symbol[parse->symlen]; - - /* skip white spaces */ - while (*scan && isspace(*scan)) - scan++; - - /* scan the symbol */ - switch (*scan) { - case 0: - len = 0; - parse->type = END; - break; - case '(': - len = 1; - parse->type = OBRA; - break; - case ')': - len = 1; - parse->type = CBRA; - break; - default: - /* compute the length */ - len = 0; - while (scan[len] && !isspace(scan[len]) && scan[len] != ')' && scan[len] != '(') - len++; - parse->type = TEXT; - - /* fall to keyword if any */ - switch(len) { - case 2: - if (!strncasecmp(scan, "or", len)) - parse->type = OR; - break; - case 3: - if (!strncasecmp(scan, "and", len)) - parse->type = AND; - else if (!strncasecmp(scan, "not", len)) - parse->type = NOT; - break; - } - break; - } - parse->symbol = scan; - parse->symlen = len; -} - -/** - * Init the parser state 'parse' for the description 'desc' - * @param parse the parser state to initialise - * @param desc the description of the permissions to be parsed - */ -static void parse_init(struct parse *parse, const char *desc) -{ - parse->desc = desc; - parse->symbol = desc; - parse->symlen = 0; - parse_next(parse); -} - -/********************************************************************* -*** SECTION node_parse -*********************************************************************/ - -static struct node *node_parse_or(struct parse *parse); - -/** - * Parse a permission name - * @param parser the parser state - * @return the parsed node or NULL in case of error - * in case of error errno is set to EINVAL or ENOMEM - */ -static struct node *node_parse_text(struct parse *parse) -{ - struct node *node; - - if (parse->type == TEXT) { - node = node_make_text(Text, parse->symbol, parse->symlen); - parse_next(parse); - } else { - errno = EINVAL; - node = NULL; - } - return node; -} - -/** - * Parse a term that is either a name (text) or a sub expression - * enclosed in brackets. - * @param parser the parser state - * @return the parsed node or NULL in case of error - * in case of error errno is set to EINVAL or ENOMEM - */ -static struct node *node_parse_term(struct parse *parse) -{ - struct node *node; - - if (parse->type != OBRA) - node = node_parse_text(parse); - else { - parse_next(parse); - node = node_parse_or(parse); - if (parse->type == CBRA) - parse_next(parse); - else { - errno = EINVAL; - node_free(node); - node = NULL; - } + if (!context->credentials) { + /* case of permission for self */ + return 1; } - return node; -} - -/** - * Parse a term potentially prefixed by not. - * @param parser the parser state - * @return the parsed node or NULL in case of error - * in case of error errno is set to EINVAL or ENOMEM - */ -static struct node *node_parse_not(struct parse *parse) -{ - struct node *node, *not; - - if (parse->type != NOT) - node = node_parse_term(parse); - else { - parse_next(parse); - node = node_parse_term(parse); - if (node) { - not = node_make_parent(Not, node, NULL); - if (not) - node = not; - else { - node_free(node); - node = NULL; - } - } + if (!permission) { + ERROR("Got a null permission!"); + return 0; } - return node; -} -/** - * Parse a potential sequence of terms connected with the - * given operator (AND or OR). The function takes care to - * create an evaluation tree that respects the order given - * by the description and that will limit the recursivity - * depth. - * @param parser the parser state - * @param operator the symbol type of the operator scanned - * @param subparse the function for parsing terms of the sequence - * @param type the node type corresponding to the operator - * @return the parsed node or NULL in case of error - * in case of error errno is set to EINVAL or ENOMEM - */ -static struct node *node_parse_infix( - struct parse *parse, - enum symbol operator, - struct node *(*subparse)(struct parse*), - enum type type -) -{ - struct node *root, **up, *right, *node; + /* cynara isn't reentrant */ + pthread_mutex_lock(&mutex); - root = subparse(parse); - if (root) { - up = &root; - while (parse->type == operator) { - parse_next(parse); - right = subparse(parse); - if (!right) { - node_free(root); - root = NULL; - break; - } - node = node_make_parent(type, *up, right); - if (!node) { - node_free(right); - node_free(root); - root = NULL; - break; - } - *up = node; - up = &node->children[1]; + /* lazy initialisation */ + if (!handle) { + rc = cynara_initialize(&handle, NULL); + if (rc != CYNARA_API_SUCCESS) { + handle = NULL; + ERROR("cynara initialisation failed with code %d", rc); + return 0; } } - return root; -} -/** - * Parse a potential sequence of anded terms. - * @param parser the parser state - * @return the parsed node or NULL in case of error - * in case of error errno is set to EINVAL or ENOMEM - */ -static struct node *node_parse_and(struct parse *parse) -{ - return node_parse_infix(parse, AND, node_parse_not, And); -} + /* query cynara permission */ + rc = cynara_check(handle, context->credentials->label, session_of_context(context), context->credentials->user, permission); -/** - * Parse a potential sequence of ored terms. - * @param parser the parser state - * @return the parsed node or NULL in case of error - * in case of error errno is set to EINVAL or ENOMEM - */ -static struct node *node_parse_or(struct parse *parse) -{ - return node_parse_infix(parse, OR, node_parse_and, Or); + pthread_mutex_unlock(&mutex); + return rc == CYNARA_API_ACCESS_ALLOWED; } - -/** - * Parse description of permissions. - * @param desc the description to parse - * @return the parsed node or NULL in case of error - * in case of error errno is set to EINVAL or ENOMEM - */ -static struct node *node_parse(const char *desc) +/*********************************************************************************/ +#else +int afb_perm_check(struct afb_context *context, const char *permission) { - struct node *node; - struct parse parse; - - parse_init(&parse, desc); - node = node_parse_or(&parse); - if (node && parse.type != END) { - node_free(node); - node = NULL; - } - return node; + NOTICE("Granting permission %s by default of backend", permission ?: "(null)"); + return !!permission; } +#endif -/********************************************************************* -*** SECTION perm -*********************************************************************/ - -/** - * structure for storing permissions - */ -struct afb_perm -{ - struct node *root; /**< root node descripbing the permission */ - int refcount; /**< the count of use of the structure */ -}; - -/** - * allocates the structure for the given root - * @param root the root node to keep - * @return the created permission object or NULL - */ -static struct afb_perm *make_perm(struct node *root) -{ - struct afb_perm *perm; - - perm = malloc(sizeof *perm); - if (!perm) - errno = ENOMEM; - else { - perm->root = root; - perm->refcount = 1; - } - return perm; -} - -/** - * Creates the permission for the given description - * @param desc the description of the permission to create - * @return the created permission object or NULL - */ -struct afb_perm *afb_perm_parse(const char *desc) -{ - struct node *root; - struct afb_perm *perm; - - root = node_parse(desc); - if (root) { - perm = make_perm(root); - if (perm) - return perm; - node_free(root); - } - return NULL; -} - -/** - * Adds a reference to the permissions - * @param perm the permission to reference - */ -void afb_perm_addref(struct afb_perm *perm) -{ - assert(perm); - perm->refcount++; -} - -/** - * Removes a reference to the permissions - * @param perm the permission to dereference - */ -void afb_perm_unref(struct afb_perm *perm) -{ - if (perm && !--perm->refcount) { - node_free(perm->root); - free(perm); - } -} - -/** - * Checks permission 'perm' using the 'check' function - * and its 'closure'. - * @param perm the permission to check - * @param check the function that checks if a pernmission of 'name' is granted for 'closure' - * @param closure the context closure for the function 'check' - * @return 1 if the permission is granted or 0 otherwise - */ -int afb_perm_check(struct afb_perm *perm, int (*check)(void *closure, const char *name), void *closure) +void afb_perm_check_async( + struct afb_context *context, + const char *permission, + void (*callback)(void *closure, int status), + void *closure +) { - return node_check(perm->root, check, closure); + callback(closure, afb_perm_check(context, permission)); } - -