LCOV - code coverage report
Current view: top level - providers/ipa - hbac_evaluator.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 100 112 89.3 %
Date: 2012-11-29 Functions: 8 8 100.0 %
Branches: 77 102 75.5 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :     SSSD
       3                 :            : 
       4                 :            :     IPA Backend Module -- Access control
       5                 :            : 
       6                 :            :     Authors:
       7                 :            :         Sumit Bose <sbose@redhat.com>
       8                 :            :         Stephen Gallagher <sgallagh@redhat.com>
       9                 :            : 
      10                 :            :     Copyright (C) 2011 Red Hat
      11                 :            : 
      12                 :            :     This program is free software; you can redistribute it and/or modify
      13                 :            :     it under the terms of the GNU General Public License as published by
      14                 :            :     the Free Software Foundation; either version 3 of the License, or
      15                 :            :     (at your option) any later version.
      16                 :            : 
      17                 :            :     This program is distributed in the hope that it will be useful,
      18                 :            :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      19                 :            :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      20                 :            :     GNU General Public License for more details.
      21                 :            : 
      22                 :            :     You should have received a copy of the GNU General Public License
      23                 :            :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      24                 :            : */
      25                 :            : 
      26                 :            : #include <stdlib.h>
      27                 :            : #include <string.h>
      28                 :            : #include <errno.h>
      29                 :            : #include "providers/ipa/ipa_hbac.h"
      30                 :            : #include "util/sss_utf8.h"
      31                 :            : 
      32                 :            : #ifndef HAVE_ERRNO_T
      33                 :            : #define HAVE_ERRNO_T
      34                 :            : typedef int errno_t;
      35                 :            : #endif
      36                 :            : 
      37                 :            : #ifndef EOK
      38                 :            : #define EOK 0
      39                 :            : #endif
      40                 :            : 
      41                 :            : /* Placeholder structure for future HBAC time-based
      42                 :            :  * evaluation rules
      43                 :            :  */
      44                 :            : struct hbac_time_rules {
      45                 :            :     int not_yet_implemented;
      46                 :            : };
      47                 :            : 
      48                 :            : enum hbac_eval_result_int {
      49                 :            :     HBAC_EVAL_MATCH_ERROR = -1,
      50                 :            :     HBAC_EVAL_MATCHED,
      51                 :            :     HBAC_EVAL_UNMATCHED
      52                 :            : };
      53                 :            : 
      54                 :         76 : static bool hbac_rule_element_is_complete(struct hbac_rule_element *el)
      55                 :            : {
      56         [ +  + ]:         76 :     if (el == NULL) return false;
      57         [ +  + ]:         72 :     if (el->category == HBAC_CATEGORY_ALL) return true;
      58                 :            : 
      59 [ +  + ][ +  - ]:         30 :     if (el->names == NULL && el->groups == NULL) return false;
      60                 :            : 
      61 [ +  + ][ +  + ]:         30 :     if ((el->names && el->names[0] != NULL)
      62 [ +  - ][ +  + ]:         12 :             || (el->groups && el->groups[0] != NULL))
      63                 :            :         return true;
      64                 :            : 
      65                 :            :     /* If other categories are added, handle them here */
      66                 :            : 
      67                 :         76 :     return false;
      68                 :            : }
      69                 :            : 
      70                 :         19 : bool hbac_rule_is_complete(struct hbac_rule *rule, uint32_t *missing_attrs)
      71                 :            : {
      72                 :         19 :     bool complete = true;
      73                 :            : 
      74                 :         19 :     *missing_attrs = 0;
      75                 :            : 
      76         [ +  - ]:         19 :     if (rule == NULL) {
      77                 :            :         /* No rule passed in? */
      78                 :            :         return false;
      79                 :            :     }
      80                 :            : 
      81                 :            :     /* Make sure we have all elements */
      82         [ +  + ]:         19 :     if (!hbac_rule_element_is_complete(rule->users)) {
      83                 :          2 :         complete = false;
      84                 :          2 :         *missing_attrs |= HBAC_RULE_ELEMENT_USERS;
      85                 :            :     }
      86                 :            : 
      87         [ +  + ]:         19 :     if (!hbac_rule_element_is_complete(rule->services)) {
      88                 :          2 :         complete = false;
      89                 :          2 :         *missing_attrs |= HBAC_RULE_ELEMENT_SERVICES;
      90                 :            :     }
      91                 :            : 
      92         [ +  + ]:         19 :     if (!hbac_rule_element_is_complete(rule->targethosts)) {
      93                 :          3 :         complete = false;
      94                 :          3 :         *missing_attrs |= HBAC_RULE_ELEMENT_TARGETHOSTS;
      95                 :            :     }
      96                 :            : 
      97         [ +  + ]:         19 :     if (!hbac_rule_element_is_complete(rule->srchosts)) {
      98                 :          3 :         complete = false;
      99                 :          3 :         *missing_attrs |= HBAC_RULE_ELEMENT_SOURCEHOSTS;
     100                 :            :     }
     101                 :            : 
     102                 :         19 :     return complete;
     103                 :            : }
     104                 :            : 
     105                 :            : enum hbac_eval_result_int hbac_evaluate_rule(struct hbac_rule *rule,
     106                 :            :                                              struct hbac_eval_req *hbac_req,
     107                 :            :                                              enum hbac_error_code *error);
     108                 :            : 
     109                 :         19 : enum hbac_eval_result hbac_evaluate(struct hbac_rule **rules,
     110                 :            :                                     struct hbac_eval_req *hbac_req,
     111                 :            :                                     struct hbac_info **info)
     112                 :            : {
     113                 :            :     enum hbac_error_code ret;
     114                 :         19 :     enum hbac_eval_result result = HBAC_EVAL_DENY;
     115                 :            :     enum hbac_eval_result_int intermediate_result;
     116                 :            : 
     117         [ +  - ]:         19 :     if (info) {
     118                 :         19 :         *info = malloc(sizeof(struct hbac_info));
     119         [ +  - ]:         19 :         if (!*info) {
     120                 :            :             return HBAC_EVAL_OOM;
     121                 :            :         }
     122                 :         19 :         (*info)->code = HBAC_ERROR_UNKNOWN;
     123                 :         19 :         (*info)->rule_name = NULL;
     124                 :            :     }
     125                 :            :     uint32_t i;
     126                 :            : 
     127         [ +  + ]:         38 :     for (i = 0; rules[i]; i++) {
     128                 :         19 :         intermediate_result = hbac_evaluate_rule(rules[i], hbac_req, &ret);
     129         [ +  + ]:         19 :         if (intermediate_result == HBAC_EVAL_UNMATCHED) {
     130                 :            :             /* This rule did not match at all. Skip it */
     131                 :          9 :             continue;
     132         [ +  - ]:         10 :         } else if (intermediate_result == HBAC_EVAL_MATCHED) {
     133                 :            :             /* This request matched an ALLOW rule
     134                 :            :              * Set the result to ALLOW but continue checking
     135                 :            :              * the other rules in case a DENY rule trumps it.
     136                 :            :              */
     137                 :         10 :             result = HBAC_EVAL_ALLOW;
     138         [ +  - ]:         10 :             if (info) {
     139                 :         10 :                 (*info)->code = HBAC_SUCCESS;
     140                 :         10 :                 (*info)->rule_name = strdup(rules[i]->name);
     141         [ -  + ]:         10 :                 if (!(*info)->rule_name) {
     142                 :          0 :                     result = HBAC_EVAL_ERROR;
     143                 :          0 :                     (*info)->code = HBAC_ERROR_OUT_OF_MEMORY;
     144                 :            :                 }
     145                 :            :             }
     146                 :            :             break;
     147                 :            :         } else {
     148                 :            :             /* An error occurred processing this rule */
     149                 :          0 :             result = HBAC_EVAL_ERROR;
     150         [ #  # ]:          0 :             if (info) {
     151                 :          0 :                 (*info)->code = ret;
     152                 :          0 :                 (*info)->rule_name = strdup(rules[i]->name);
     153                 :            :             }
     154                 :            :             /* Explicitly not checking the result of strdup(), since if
     155                 :            :              * it's NULL, we can't do anything anyway.
     156                 :            :              */
     157                 :            :             goto done;
     158                 :            :         }
     159                 :            :     }
     160                 :            : 
     161                 :            :     /* If we've reached the end of the loop, we have either set the
     162                 :            :      * result to ALLOW explicitly or we'll stick with the default DENY.
     163                 :            :      */
     164                 :            : done:
     165                 :            : 
     166                 :            :     return result;
     167                 :            : }
     168                 :            : 
     169                 :            : static errno_t hbac_evaluate_element(struct hbac_rule_element *rule_el,
     170                 :            :                                      struct hbac_request_element *req_el,
     171                 :            :                                      bool *matched);
     172                 :            : 
     173                 :         19 : enum hbac_eval_result_int hbac_evaluate_rule(struct hbac_rule *rule,
     174                 :            :                                              struct hbac_eval_req *hbac_req,
     175                 :            :                                              enum hbac_error_code *error)
     176                 :            : {
     177                 :            :     errno_t ret;
     178                 :            :     bool matched;
     179                 :            : 
     180         [ +  - ]:         19 :     if (!rule->enabled) return HBAC_EVAL_UNMATCHED;
     181                 :            : 
     182                 :            :     /* Make sure we have all elements */
     183         [ +  - ]:         19 :     if (!rule->users
     184         [ +  - ]:         19 :      || !rule->services
     185         [ +  - ]:         19 :      || !rule->targethosts
     186         [ -  + ]:         19 :      || !rule->srchosts) {
     187                 :          0 :         *error = HBAC_ERROR_UNPARSEABLE_RULE;
     188                 :            :         return HBAC_EVAL_MATCH_ERROR;
     189                 :            :     }
     190                 :            : 
     191                 :            :     /* Check users */
     192                 :         19 :     ret = hbac_evaluate_element(rule->users,
     193                 :            :                                 hbac_req->user,
     194                 :            :                                 &matched);
     195         [ -  + ]:         19 :     if (ret != EOK) {
     196                 :          0 :         *error = HBAC_ERROR_UNPARSEABLE_RULE;
     197                 :            :         return HBAC_EVAL_MATCH_ERROR;
     198         [ +  + ]:         19 :     } else if (!matched) {
     199                 :            :         return HBAC_EVAL_UNMATCHED;
     200                 :            :     }
     201                 :            : 
     202                 :            :     /* Check services */
     203                 :         14 :     ret = hbac_evaluate_element(rule->services,
     204                 :            :                                 hbac_req->service,
     205                 :            :                                 &matched);
     206         [ -  + ]:         14 :     if (ret != EOK) {
     207                 :          0 :         *error = HBAC_ERROR_UNPARSEABLE_RULE;
     208                 :            :         return HBAC_EVAL_MATCH_ERROR;
     209         [ +  + ]:         14 :     } else if (!matched) {
     210                 :            :         return HBAC_EVAL_UNMATCHED;
     211                 :            :     }
     212                 :            : 
     213                 :            :     /* Check target hosts */
     214                 :         12 :     ret = hbac_evaluate_element(rule->targethosts,
     215                 :            :                                 hbac_req->targethost,
     216                 :            :                                 &matched);
     217         [ -  + ]:         12 :     if (ret != EOK) {
     218                 :          0 :         *error = HBAC_ERROR_UNPARSEABLE_RULE;
     219                 :            :         return HBAC_EVAL_MATCH_ERROR;
     220         [ +  - ]:         12 :     } else if (!matched) {
     221                 :            :         return HBAC_EVAL_UNMATCHED;
     222                 :            :     }
     223                 :            : 
     224                 :            :     /* Check source hosts */
     225                 :         12 :     ret = hbac_evaluate_element(rule->srchosts,
     226                 :            :                                 hbac_req->srchost,
     227                 :            :                                 &matched);
     228         [ -  + ]:         12 :     if (ret != EOK) {
     229                 :          0 :         *error = HBAC_ERROR_UNPARSEABLE_RULE;
     230                 :            :         return HBAC_EVAL_MATCH_ERROR;
     231         [ +  + ]:         19 :     } else if (!matched) {
     232                 :            :         return HBAC_EVAL_UNMATCHED;
     233                 :            :     }
     234                 :            :     return HBAC_EVAL_MATCHED;
     235                 :            : }
     236                 :            : 
     237                 :         57 : static errno_t hbac_evaluate_element(struct hbac_rule_element *rule_el,
     238                 :            :                                      struct hbac_request_element *req_el,
     239                 :            :                                      bool *matched)
     240                 :            : {
     241                 :            :     size_t i, j;
     242                 :            :     const uint8_t *rule_name;
     243                 :            :     const uint8_t *req_name;
     244                 :            :     int ret;
     245                 :            : 
     246         [ +  + ]:         57 :     if (rule_el->category & HBAC_CATEGORY_ALL) {
     247                 :         32 :         *matched = true;
     248                 :         32 :         return EOK;
     249                 :            :     }
     250                 :            : 
     251                 :            :     /* First check the name list */
     252         [ +  + ]:         25 :     if (rule_el->names) {
     253         [ +  + ]:         25 :         for (i = 0; rule_el->names[i]; i++) {
     254         [ +  - ]:         19 :             if (req_el->name != NULL) {
     255                 :         19 :                 rule_name = (const uint8_t *) rule_el->names[i];
     256                 :         19 :                 req_name = (const uint8_t *) req_el->name;
     257                 :            : 
     258                 :            :                 /* Do a case-insensitive comparison. */
     259                 :         19 :                 ret = sss_utf8_case_eq(rule_name, req_name);
     260         [ +  - ]:         19 :                 if (ret != EOK && ret != ENOMATCH) {
     261                 :            :                     return ret;
     262         [ +  + ]:         19 :                 } else if (ret == EOK) {
     263                 :         13 :                     *matched = true;
     264                 :         13 :                     return EOK;
     265                 :            :                 }
     266                 :            :             }
     267                 :            :         }
     268                 :            :     }
     269                 :            : 
     270         [ +  + ]:         12 :     if (rule_el->groups) {
     271                 :            :         /* Not found in the name list
     272                 :            :          * Check for group membership
     273                 :            :          */
     274         [ +  + ]:         10 :         for (i = 0; rule_el->groups[i]; i++) {
     275                 :            :             rule_name = (const uint8_t *) rule_el->groups[i];
     276                 :            : 
     277         [ +  + ]:         12 :             for (j = 0; req_el->groups[j]; j++) {
     278                 :          9 :                 req_name = (const uint8_t *) req_el->groups[j];
     279                 :            : 
     280                 :            :                 /* Do a case-insensitive comparison. */
     281                 :          9 :                 ret = sss_utf8_case_eq(rule_name, req_name);
     282         [ +  - ]:          9 :                 if (ret != EOK && ret != ENOMATCH) {
     283                 :            :                     return ret;
     284         [ +  + ]:          9 :                 } else if (ret == EOK) {
     285                 :          3 :                     *matched = true;
     286                 :          3 :                     return EOK;
     287                 :            :                 }
     288                 :            :             }
     289                 :            :         }
     290                 :            :     }
     291                 :            : 
     292                 :            :     /* Not found in groups either */
     293                 :          9 :     *matched = false;
     294                 :         57 :     return EOK;
     295                 :            : }
     296                 :            : 
     297                 :         35 : const char *hbac_result_string(enum hbac_eval_result result)
     298                 :            : {
     299   [ +  +  -  -  :         35 :     switch(result) {
                      + ]
     300                 :            :     case HBAC_EVAL_ALLOW:
     301                 :            :         return "HBAC_EVAL_ALLOW";
     302                 :            :     case HBAC_EVAL_DENY:
     303                 :         17 :         return "HBAC_EVAL_DENY";
     304                 :            :     case HBAC_EVAL_ERROR:
     305                 :          1 :         return "HBAC_EVAL_ERROR";
     306                 :            :     case HBAC_EVAL_OOM:
     307                 :          0 :         return "Could not allocate memory for hbac_info object";
     308                 :            :     }
     309                 :         35 :     return "HBAC_EVAL_ERROR";
     310                 :            : }
     311                 :            : 
     312                 :          7 : void hbac_free_info(struct hbac_info *info)
     313                 :            : {
     314         [ +  + ]:         10 :     if (info == NULL) return;
     315                 :            : 
     316                 :          3 :     free(info->rule_name);
     317                 :          3 :     free(info);
     318                 :          3 :     info = NULL;
     319                 :            : }
     320                 :            : 
     321                 :         21 : const char *hbac_error_string(enum hbac_error_code code)
     322                 :            : {
     323   [ +  +  +  +  :         21 :     switch(code) {
                      + ]
     324                 :            :     case HBAC_SUCCESS:
     325                 :            :         return "Success";
     326                 :            :     case HBAC_ERROR_NOT_IMPLEMENTED:
     327                 :          1 :         return "Function is not yet implemented";
     328                 :            :     case HBAC_ERROR_OUT_OF_MEMORY:
     329                 :          1 :         return "Out of memory";
     330                 :            :     case HBAC_ERROR_UNPARSEABLE_RULE:
     331                 :          1 :         return "Rule could not be evaluated";
     332                 :            :     case HBAC_ERROR_UNKNOWN:
     333                 :            :     default:
     334                 :         21 :         return "Unknown error code";
     335                 :            :     }
     336                 :            : }

Generated by: LCOV version 1.9