LCOV - code coverage report
Current view: top level - providers/ipa - hbac_evaluator.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 173 210 82.4 %
Date: 2015-10-19 Functions: 12 13 92.3 %

          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             : /* HBAC logging system */
      42             : 
      43             : /* debug macro */
      44             : #define HBAC_DEBUG(level, format, ...) do { \
      45             :     if (hbac_debug_fn != NULL) { \
      46             :         hbac_debug_fn(__FILE__, __LINE__, level, format, ##__VA_ARGS__); \
      47             :     } \
      48             : } while (0)
      49             : 
      50             : /* static pointer to external logging function */
      51             : static hbac_debug_fn_t hbac_debug_fn = NULL;
      52             : 
      53             : /* setup function for external logging function */
      54           0 : void hbac_enable_debug(hbac_debug_fn_t external_debug_fn)
      55             : {
      56           0 :     hbac_debug_fn = external_debug_fn;
      57           0 : }
      58             : 
      59             : /* auxiliary function for hbac_request_element logging */
      60             : static void hbac_request_element_debug_print(struct hbac_request_element *el,
      61             :                                              const char *label);
      62             : 
      63             : /* auxiliary function for hbac_eval_req logging */
      64             : static void hbac_req_debug_print(struct hbac_eval_req *req);
      65             : 
      66             : /* auxiliary function for hbac_rule_element logging */
      67             : static void hbac_rule_element_debug_print(struct hbac_rule_element *el,
      68             :                                           const char *label);
      69             : 
      70             : /* auxiliary function for hbac_rule logging */
      71             : static void hbac_rule_debug_print(struct hbac_rule *rule);
      72             : 
      73             : 
      74             : /* Placeholder structure for future HBAC time-based
      75             :  * evaluation rules
      76             :  */
      77             : struct hbac_time_rules {
      78             :     int not_yet_implemented;
      79             : };
      80             : 
      81             : enum hbac_eval_result_int {
      82             :     HBAC_EVAL_MATCH_ERROR = -1,
      83             :     HBAC_EVAL_MATCHED,
      84             :     HBAC_EVAL_UNMATCHED
      85             : };
      86             : 
      87          88 : static bool hbac_rule_element_is_complete(struct hbac_rule_element *el)
      88             : {
      89          88 :     if (el == NULL) return false;
      90          84 :     if (el->category == HBAC_CATEGORY_ALL) return true;
      91             : 
      92          42 :     if (el->names == NULL && el->groups == NULL) return false;
      93             : 
      94          42 :     if ((el->names && el->names[0] != NULL)
      95          18 :             || (el->groups && el->groups[0] != NULL))
      96          30 :         return true;
      97             : 
      98             :     /* If other categories are added, handle them here */
      99             : 
     100          12 :     return false;
     101             : }
     102             : 
     103          22 : bool hbac_rule_is_complete(struct hbac_rule *rule, uint32_t *missing_attrs)
     104             : {
     105          22 :     bool complete = true;
     106             : 
     107          22 :     *missing_attrs = 0;
     108             : 
     109          22 :     if (rule == NULL) {
     110             :         /* No rule passed in? */
     111           0 :         return false;
     112             :     }
     113             : 
     114             :     /* Make sure we have all elements */
     115          22 :     if (!hbac_rule_element_is_complete(rule->users)) {
     116           3 :         complete = false;
     117           3 :         *missing_attrs |= HBAC_RULE_ELEMENT_USERS;
     118             :     }
     119             : 
     120          22 :     if (!hbac_rule_element_is_complete(rule->services)) {
     121           3 :         complete = false;
     122           3 :         *missing_attrs |= HBAC_RULE_ELEMENT_SERVICES;
     123             :     }
     124             : 
     125          22 :     if (!hbac_rule_element_is_complete(rule->targethosts)) {
     126           5 :         complete = false;
     127           5 :         *missing_attrs |= HBAC_RULE_ELEMENT_TARGETHOSTS;
     128             :     }
     129             : 
     130          22 :     if (!hbac_rule_element_is_complete(rule->srchosts)) {
     131           5 :         complete = false;
     132           5 :         *missing_attrs |= HBAC_RULE_ELEMENT_SOURCEHOSTS;
     133             :     }
     134             : 
     135          22 :     return complete;
     136             : }
     137             : 
     138             : enum hbac_eval_result_int hbac_evaluate_rule(struct hbac_rule *rule,
     139             :                                              struct hbac_eval_req *hbac_req,
     140             :                                              enum hbac_error_code *error);
     141             : 
     142          22 : enum hbac_eval_result hbac_evaluate(struct hbac_rule **rules,
     143             :                                     struct hbac_eval_req *hbac_req,
     144             :                                     struct hbac_info **info)
     145             : {
     146             :     enum hbac_error_code ret;
     147          22 :     enum hbac_eval_result result = HBAC_EVAL_DENY;
     148             :     enum hbac_eval_result_int intermediate_result;
     149             : 
     150          22 :     HBAC_DEBUG(HBAC_DBG_INFO, "[< hbac_evaluate()\n");
     151          22 :     hbac_req_debug_print(hbac_req);
     152             : 
     153          22 :     if (info) {
     154          22 :         *info = malloc(sizeof(struct hbac_info));
     155          22 :         if (!*info) {
     156           0 :             HBAC_DEBUG(HBAC_DBG_ERROR, "Out of memory.\n");
     157           0 :             return HBAC_EVAL_OOM;
     158             :         }
     159          22 :         (*info)->code = HBAC_ERROR_UNKNOWN;
     160          22 :         (*info)->rule_name = NULL;
     161             :     }
     162             : 
     163          64 :     for (uint32_t i = 0; rules[i]; i++) {
     164          22 :         hbac_rule_debug_print(rules[i]);
     165          22 :         intermediate_result = hbac_evaluate_rule(rules[i], hbac_req, &ret);
     166          22 :         if (intermediate_result == HBAC_EVAL_UNMATCHED) {
     167             :             /* This rule did not match at all. Skip it */
     168          10 :             HBAC_DEBUG(HBAC_DBG_INFO, "The rule [%s] did not match.\n",
     169             :                        rules[i]->name);
     170          10 :             continue;
     171          12 :         } else if (intermediate_result == HBAC_EVAL_MATCHED) {
     172          12 :             HBAC_DEBUG(HBAC_DBG_INFO, "ALLOWED by rule [%s].\n", rules[i]->name);
     173          12 :             result = HBAC_EVAL_ALLOW;
     174          12 :             if (info) {
     175          12 :                 (*info)->code = HBAC_SUCCESS;
     176          12 :                 (*info)->rule_name = strdup(rules[i]->name);
     177          12 :                 if (!(*info)->rule_name) {
     178           0 :                     HBAC_DEBUG(HBAC_DBG_ERROR, "Out of memory.\n");
     179           0 :                     result = HBAC_EVAL_ERROR;
     180           0 :                     (*info)->code = HBAC_ERROR_OUT_OF_MEMORY;
     181             :                 }
     182             :             }
     183          12 :             break;
     184             :         } else {
     185             :             /* An error occurred processing this rule */
     186           0 :             HBAC_DEBUG(HBAC_DBG_ERROR,
     187             :                        "Error occurred during evaluating of rule [%s].\n",
     188             :                        rules[i]->name);
     189           0 :             result = HBAC_EVAL_ERROR;
     190           0 :             if (info) {
     191           0 :                 (*info)->code = ret;
     192           0 :                 (*info)->rule_name = strdup(rules[i]->name);
     193             :             }
     194             :             /* Explicitly not checking the result of strdup(), since if
     195             :              * it's NULL, we can't do anything anyway.
     196             :              */
     197           0 :             goto done;
     198             :         }
     199             :     }
     200             : 
     201             :     /* If we've reached the end of the loop, we have either set the
     202             :      * result to ALLOW explicitly or we'll stick with the default DENY.
     203             :      */
     204             : done:
     205             : 
     206          22 :     HBAC_DEBUG(HBAC_DBG_INFO, "hbac_evaluate() >]\n");
     207          22 :     return result;
     208             : }
     209             : 
     210             : static errno_t hbac_evaluate_element(struct hbac_rule_element *rule_el,
     211             :                                      struct hbac_request_element *req_el,
     212             :                                      bool *matched);
     213             : 
     214          22 : enum hbac_eval_result_int hbac_evaluate_rule(struct hbac_rule *rule,
     215             :                                              struct hbac_eval_req *hbac_req,
     216             :                                              enum hbac_error_code *error)
     217             : {
     218             :     errno_t ret;
     219             :     bool matched;
     220             : 
     221          22 :     if (!rule->enabled) return HBAC_EVAL_UNMATCHED;
     222             : 
     223             :     /* Make sure we have all elements */
     224          22 :     if (!rule->users
     225          22 :      || !rule->services
     226          22 :      || !rule->targethosts
     227          22 :      || !rule->srchosts) {
     228           0 :         *error = HBAC_ERROR_UNPARSEABLE_RULE;
     229           0 :         return HBAC_EVAL_MATCH_ERROR;
     230             :     }
     231             : 
     232             :     /* Check users */
     233          22 :     ret = hbac_evaluate_element(rule->users,
     234             :                                 hbac_req->user,
     235             :                                 &matched);
     236          22 :     if (ret != EOK) {
     237           0 :         *error = HBAC_ERROR_UNPARSEABLE_RULE;
     238           0 :         return HBAC_EVAL_MATCH_ERROR;
     239          22 :     } else if (!matched) {
     240           6 :         return HBAC_EVAL_UNMATCHED;
     241             :     }
     242             : 
     243             :     /* Check services */
     244          16 :     ret = hbac_evaluate_element(rule->services,
     245             :                                 hbac_req->service,
     246             :                                 &matched);
     247          16 :     if (ret != EOK) {
     248           0 :         *error = HBAC_ERROR_UNPARSEABLE_RULE;
     249           0 :         return HBAC_EVAL_MATCH_ERROR;
     250          16 :     } else if (!matched) {
     251           2 :         return HBAC_EVAL_UNMATCHED;
     252             :     }
     253             : 
     254             :     /* Check target hosts */
     255          14 :     ret = hbac_evaluate_element(rule->targethosts,
     256             :                                 hbac_req->targethost,
     257             :                                 &matched);
     258          14 :     if (ret != EOK) {
     259           0 :         *error = HBAC_ERROR_UNPARSEABLE_RULE;
     260           0 :         return HBAC_EVAL_MATCH_ERROR;
     261          14 :     } else if (!matched) {
     262           0 :         return HBAC_EVAL_UNMATCHED;
     263             :     }
     264             : 
     265             :     /* Check source hosts */
     266          14 :     ret = hbac_evaluate_element(rule->srchosts,
     267             :                                 hbac_req->srchost,
     268             :                                 &matched);
     269          14 :     if (ret != EOK) {
     270           0 :         *error = HBAC_ERROR_UNPARSEABLE_RULE;
     271           0 :         return HBAC_EVAL_MATCH_ERROR;
     272          14 :     } else if (!matched) {
     273           2 :         return HBAC_EVAL_UNMATCHED;
     274             :     }
     275          12 :     return HBAC_EVAL_MATCHED;
     276             : }
     277             : 
     278          66 : static errno_t hbac_evaluate_element(struct hbac_rule_element *rule_el,
     279             :                                      struct hbac_request_element *req_el,
     280             :                                      bool *matched)
     281             : {
     282             :     size_t i, j;
     283             :     const uint8_t *rule_name;
     284             :     const uint8_t *req_name;
     285             :     int ret;
     286             : 
     287          66 :     if (rule_el->category & HBAC_CATEGORY_ALL) {
     288          33 :         *matched = true;
     289          33 :         return EOK;
     290             :     }
     291             : 
     292             :     /* First check the name list */
     293          33 :     if (rule_el->names) {
     294          34 :         for (i = 0; rule_el->names[i]; i++) {
     295          27 :             if (req_el->name != NULL) {
     296          27 :                 rule_name = (const uint8_t *) rule_el->names[i];
     297          27 :                 req_name = (const uint8_t *) req_el->name;
     298             : 
     299             :                 /* Do a case-insensitive comparison. */
     300          27 :                 ret = sss_utf8_case_eq(rule_name, req_name);
     301          27 :                 if (ret != EOK && ret != ENOMATCH) {
     302           0 :                     return ret;
     303          27 :                 } else if (ret == EOK) {
     304          20 :                     *matched = true;
     305          20 :                     return EOK;
     306             :                 }
     307             :             }
     308             :         }
     309             :     }
     310             : 
     311          13 :     if (rule_el->groups) {
     312             :         /* Not found in the name list
     313             :          * Check for group membership
     314             :          */
     315          11 :         for (i = 0; rule_el->groups[i]; i++) {
     316           6 :             rule_name = (const uint8_t *) rule_el->groups[i];
     317             : 
     318          12 :             for (j = 0; req_el->groups[j]; j++) {
     319           9 :                 req_name = (const uint8_t *) req_el->groups[j];
     320             : 
     321             :                 /* Do a case-insensitive comparison. */
     322           9 :                 ret = sss_utf8_case_eq(rule_name, req_name);
     323           9 :                 if (ret != EOK && ret != ENOMATCH) {
     324           0 :                     return ret;
     325           9 :                 } else if (ret == EOK) {
     326           3 :                     *matched = true;
     327           3 :                     return EOK;
     328             :                 }
     329             :             }
     330             :         }
     331             :     }
     332             : 
     333             :     /* Not found in groups either */
     334          10 :     *matched = false;
     335          10 :     return EOK;
     336             : }
     337             : 
     338           6 : const char *hbac_result_string(enum hbac_eval_result result)
     339             : {
     340           6 :     switch(result) {
     341             :     case HBAC_EVAL_ALLOW:
     342           2 :         return "HBAC_EVAL_ALLOW";
     343             :     case HBAC_EVAL_DENY:
     344           2 :         return "HBAC_EVAL_DENY";
     345             :     case HBAC_EVAL_ERROR:
     346           2 :         return "HBAC_EVAL_ERROR";
     347             :     case HBAC_EVAL_OOM:
     348           0 :         return "Could not allocate memory for hbac_info object";
     349             :     }
     350           0 :     return "HBAC_EVAL_ERROR";
     351             : }
     352             : 
     353          30 : void hbac_free_info(struct hbac_info *info)
     354             : {
     355          30 :     if (info == NULL) return;
     356             : 
     357          22 :     free(info->rule_name);
     358          22 :     free(info);
     359             : }
     360             : 
     361          10 : const char *hbac_error_string(enum hbac_error_code code)
     362             : {
     363          10 :     switch(code) {
     364             :     case HBAC_SUCCESS:
     365           2 :         return "Success";
     366             :     case HBAC_ERROR_NOT_IMPLEMENTED:
     367           2 :         return "Function is not yet implemented";
     368             :     case HBAC_ERROR_OUT_OF_MEMORY:
     369           2 :         return "Out of memory";
     370             :     case HBAC_ERROR_UNPARSEABLE_RULE:
     371           2 :         return "Rule could not be evaluated";
     372             :     case HBAC_ERROR_UNKNOWN:
     373             :     default:
     374           2 :         return "Unknown error code";
     375             :     }
     376             : }
     377             : 
     378          88 : static void hbac_request_element_debug_print(struct hbac_request_element *el,
     379             :                                              const char *label)
     380             : {
     381          88 :     if (el) {
     382          72 :         if (el->name) {
     383          72 :             HBAC_DEBUG(HBAC_DBG_TRACE, "\t\t%s [%s]\n", label, el->name);
     384             :         }
     385             : 
     386          72 :         if (el->groups) {
     387          72 :             if (el->groups[0]) {
     388          48 :                 HBAC_DEBUG(HBAC_DBG_TRACE, "\t\t%s_group:\n", label);
     389         144 :                 for (int i = 0; el->groups[i]; i++) {
     390          96 :                     HBAC_DEBUG(HBAC_DBG_TRACE, "\t\t\t[%s]\n", el->groups[i]);
     391             :                 }
     392             :             } else {
     393          24 :                 HBAC_DEBUG(HBAC_DBG_TRACE, "\t\t%s_group (none)\n", label);
     394             :             }
     395             :         }
     396             :     } else {
     397          16 :         HBAC_DEBUG(HBAC_DBG_TRACE, "\t%s (none)\n", label);
     398             :     }
     399          88 : }
     400             : 
     401          22 : static void hbac_req_debug_print(struct hbac_eval_req *req)
     402             : {
     403          22 :     HBAC_DEBUG(HBAC_DBG_TRACE, "\tREQUEST:\n");
     404          22 :     if (req) {
     405          22 :         struct tm *local_time = NULL;
     406             :         size_t ret;
     407          22 :         const size_t buff_size = 100;
     408          22 :         char time_buff[buff_size];
     409             : 
     410          22 :         hbac_request_element_debug_print(req->service, "service");
     411          22 :         hbac_request_element_debug_print(req->user, "user");
     412          22 :         hbac_request_element_debug_print(req->targethost, "targethost");
     413          22 :         hbac_request_element_debug_print(req->srchost, "srchost");
     414             : 
     415          22 :         local_time = localtime(&req->request_time);
     416          22 :         if (local_time == NULL) {
     417           6 :             return;
     418             :         }
     419             : 
     420          16 :         ret = strftime(time_buff, buff_size, "%Y-%m-%d %H:%M:%S", local_time);
     421          16 :         if (ret <= 0) {
     422           0 :             return;
     423             :         }
     424             : 
     425          16 :         HBAC_DEBUG(HBAC_DBG_TRACE, "\t\trequest time %s\n", time_buff);
     426             :     } else {
     427           0 :         HBAC_DEBUG(HBAC_DBG_TRACE, "\tRequest is EMPTY.\n");
     428             :     }
     429             : }
     430             : 
     431          88 : static void hbac_rule_element_debug_print(struct hbac_rule_element *el,
     432             :                                           const char *label)
     433             : {
     434          88 :     if (el) {
     435          88 :         HBAC_DEBUG(HBAC_DBG_TRACE, "\t\tcategory [%#x] [%s]\n", el->category,
     436             :                    (el->category == HBAC_CATEGORY_ALL) ? "ALL" : "NONE");
     437             : 
     438          88 :         if (el->names) {
     439          39 :             if (el->names[0]) {
     440          39 :                 HBAC_DEBUG(HBAC_DBG_TRACE, "\t\t%s_names:\n", label);
     441          78 :                 for (int i = 0; el->names[i]; i++) {
     442          39 :                     HBAC_DEBUG(HBAC_DBG_TRACE, "\t\t\t[%s]\n", el->names[i]);
     443             :                 }
     444             :             } else {
     445           0 :                 HBAC_DEBUG(HBAC_DBG_TRACE, "\t\t%s_names (none)\n", label);
     446             :             }
     447             :         }
     448             : 
     449          88 :         if (el->groups) {
     450          30 :             if (el->groups[0]) {
     451           6 :                 HBAC_DEBUG(HBAC_DBG_TRACE, "\t\t%s_groups:\n", label);
     452          12 :                 for (int i = 0; el->groups[i]; i++) {
     453           6 :                     HBAC_DEBUG(HBAC_DBG_TRACE, "\t\t\t[%s]\n", el->groups[i]);
     454             :                 }
     455             :             } else {
     456          24 :                 HBAC_DEBUG(HBAC_DBG_TRACE, "\t\t%s_groups (none)\n", label);
     457             :             }
     458             :         }
     459             :     }
     460          88 : }
     461             : 
     462          22 : static void hbac_rule_debug_print(struct hbac_rule *rule)
     463             : {
     464          22 :     if (rule) {
     465          22 :         HBAC_DEBUG(HBAC_DBG_TRACE, "\tRULE [%s] [%s]:\n",
     466             :                    rule->name, (rule->enabled) ? "ENABLED" : "DISABLED");
     467          22 :         if (rule->services) {
     468          22 :             HBAC_DEBUG(HBAC_DBG_TRACE, "\tservices:\n");
     469          22 :             hbac_rule_element_debug_print(rule->services, "services");
     470             :         } else {
     471           0 :             HBAC_DEBUG(HBAC_DBG_TRACE, "\tservices (none)\n");
     472             :         }
     473             : 
     474          22 :         if (rule->users) {
     475          22 :             HBAC_DEBUG(HBAC_DBG_TRACE, "\tusers:\n");
     476          22 :             hbac_rule_element_debug_print(rule->users, "users");
     477             :         } else {
     478           0 :             HBAC_DEBUG(HBAC_DBG_TRACE, "\tusers (none)\n");
     479             :         }
     480             : 
     481          22 :         if (rule->targethosts) {
     482          22 :             HBAC_DEBUG(HBAC_DBG_TRACE, "\ttargethosts:\n");
     483          22 :             hbac_rule_element_debug_print(rule->targethosts, "targethosts");
     484             :         } else {
     485           0 :             HBAC_DEBUG(HBAC_DBG_TRACE, "\ttargethosts (none)\n");
     486             :         }
     487             : 
     488          22 :         if (rule->srchosts) {
     489          22 :             HBAC_DEBUG(HBAC_DBG_TRACE, "\tsrchosts:\n");
     490          22 :             hbac_rule_element_debug_print(rule->srchosts, "srchosts");
     491             :         } else {
     492           0 :             HBAC_DEBUG(HBAC_DBG_TRACE, "\tsrchosts (none)\n");
     493             :         }
     494             :     }
     495          22 : }

Generated by: LCOV version 1.10