From 600f24749008caaf03adbfa6bc5cf65a806f0b92 Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Wed, 18 May 2011 16:38:38 -0400 Subject: Add HBAC evaluator and tests --- src/providers/ipa/hbac_evaluator.c | 221 +++++++++++++++++++++++++++++++++++++ src/providers/ipa/ipa_hbac.h | 154 ++++++++++++++++++++++++++ src/providers/ipa/ipa_hbac.pc.in | 11 ++ 3 files changed, 386 insertions(+) create mode 100644 src/providers/ipa/hbac_evaluator.c create mode 100644 src/providers/ipa/ipa_hbac.h create mode 100644 src/providers/ipa/ipa_hbac.pc.in (limited to 'src/providers/ipa') diff --git a/src/providers/ipa/hbac_evaluator.c b/src/providers/ipa/hbac_evaluator.c new file mode 100644 index 000000000..949f0aefd --- /dev/null +++ b/src/providers/ipa/hbac_evaluator.c @@ -0,0 +1,221 @@ +/* + SSSD + + IPA Backend Module -- Access control + + Authors: + Sumit Bose + Stephen Gallagher + + Copyright (C) 2011 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include "providers/ipa/ipa_hbac.h" + +/* Placeholder structure for future HBAC time-based + * evaluation rules + */ +struct hbac_time_rules { + int not_yet_implemented; +}; + +enum hbac_eval_result_int { + HBAC_EVAL_MATCH_ERROR = -1, + HBAC_EVAL_MATCHED, + HBAC_EVAL_UNMATCHED +}; + +enum hbac_eval_result_int hbac_evaluate_rule(struct hbac_rule *rule, + struct hbac_eval_req *hbac_req, + enum hbac_error_code *error); + +enum hbac_eval_result hbac_evaluate(struct hbac_rule **rules, + struct hbac_eval_req *hbac_req, + struct hbac_info **info) +{ + enum hbac_error_code ret; + enum hbac_eval_result result = HBAC_EVAL_DENY; + enum hbac_eval_result_int intermediate_result; + + if (info) { + *info = malloc(sizeof(struct hbac_info)); + if (!*info) { + return HBAC_EVAL_OOM; + } + (*info)->code = HBAC_ERROR_UNKNOWN; + (*info)->rule_name = NULL; + } + uint32_t i; + + for (i = 0; rules[i]; i++) { + intermediate_result = hbac_evaluate_rule(rules[i], hbac_req, &ret); + if (intermediate_result == HBAC_EVAL_UNMATCHED) { + /* This rule did not match at all. Skip it */ + continue; + } else if (intermediate_result == HBAC_EVAL_MATCHED) { + /* This request matched an ALLOW rule + * Set the result to ALLOW but continue checking + * the other rules in case a DENY rule trumps it. + */ + result = HBAC_EVAL_ALLOW; + if (info) { + (*info)->code = HBAC_SUCCESS; + (*info)->rule_name = strdup(rules[i]->name); + if (!(*info)->rule_name) { + result = HBAC_EVAL_ERROR; + (*info)->code = HBAC_ERROR_OUT_OF_MEMORY; + } + } + break; + } else { + /* An error occurred processing this rule */ + result = HBAC_EVAL_ERROR; + (*info)->code = ret; + (*info)->rule_name = strdup(rules[i]->name); + /* Explicitly not checking the result of strdup(), since if + * it's NULL, we can't do anything anyway. + */ + goto done; + } + } + + /* If we've reached the end of the loop, we have either set the + * result to ALLOW explicitly or we'll stick with the default DENY. + */ +done: + + return result; +} + +static bool hbac_evaluate_element(struct hbac_rule_element *rule_el, + struct hbac_request_element *req_el); + +enum hbac_eval_result_int hbac_evaluate_rule(struct hbac_rule *rule, + struct hbac_eval_req *hbac_req, + enum hbac_error_code *error) +{ + if (!rule->enabled) return HBAC_EVAL_UNMATCHED; + + /* Make sure we have all elements */ + if (!rule->users + || !rule->services + || !rule->targethosts + || !rule->srchosts) { + *error = HBAC_ERROR_UNPARSEABLE_RULE; + return HBAC_EVAL_MATCH_ERROR; + } + + /* Check users */ + if (!hbac_evaluate_element(rule->users, hbac_req->user)) { + return HBAC_EVAL_UNMATCHED; + } + + /* Check services */ + if (!hbac_evaluate_element(rule->services, hbac_req->service)) { + return HBAC_EVAL_UNMATCHED; + } + + /* Check target hosts */ + if (!hbac_evaluate_element(rule->targethosts, hbac_req->targethost)) { + return HBAC_EVAL_UNMATCHED; + } + + /* Check source hosts */ + if (!hbac_evaluate_element(rule->srchosts, hbac_req->srchost)) { + return HBAC_EVAL_UNMATCHED; + } + + return HBAC_EVAL_MATCHED; +} + +static bool hbac_evaluate_element(struct hbac_rule_element *rule_el, + struct hbac_request_element *req_el) +{ + size_t i, j; + + if (rule_el->category & HBAC_CATEGORY_ALL) { + return true; + } + + /* First check the name list */ + if (rule_el->names) { + for (i = 0; rule_el->names[i]; i++) { + if (strcmp(rule_el->names[i], req_el->name) == 0) { + return true; + } + } + } + + if (rule_el->groups) { + /* Not found in the name list + * Check for group membership + */ + for (i = 0; rule_el->groups[i]; i++) { + for (j = 0; req_el->groups[j]; j++) { + if (strcmp(rule_el->groups[i], + req_el->groups[j]) == 0) { + return true; + } + } + } + } + + /* Not found in groups either */ + return false; +} + +const char *hbac_result_string(enum hbac_eval_result result) +{ + switch(result) { + case HBAC_EVAL_ALLOW: + return "HBAC_EVAL_ALLOW"; + case HBAC_EVAL_DENY: + return "HBAC_EVAL_DENY"; + case HBAC_EVAL_ERROR: + return "HBAC_EVAL_ERROR"; + case HBAC_EVAL_OOM: + return "Could not allocate memory for hbac_info object"; + } + return "HBAC_EVAL_ERROR"; +} + +void hbac_free_info(struct hbac_info *info) +{ + if (info == NULL) return; + + free(info->rule_name); + free(info); + info = NULL; +} + +const char *hbac_error_string(enum hbac_error_code code) +{ + switch(code) { + case HBAC_SUCCESS: + return "Success"; + case HBAC_ERROR_NOT_IMPLEMENTED: + return "Function is not yet implemented"; + case HBAC_ERROR_OUT_OF_MEMORY: + return "Out of memory"; + case HBAC_ERROR_UNPARSEABLE_RULE: + return "Rule could not be evaluated"; + case HBAC_ERROR_UNKNOWN: + default: + return "Unknown error code"; + } +} diff --git a/src/providers/ipa/ipa_hbac.h b/src/providers/ipa/ipa_hbac.h new file mode 100644 index 000000000..a1d513785 --- /dev/null +++ b/src/providers/ipa/ipa_hbac.h @@ -0,0 +1,154 @@ +/* + SSSD + + IPA Backend Module -- Access control + + Authors: + Sumit Bose + Stephen Gallagher + + Copyright (C) 2009 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef IPA_HBAC_H_ +#define IPA_HBAC_H_ + +#include +#include + +enum hbac_eval_result { + HBAC_EVAL_ERROR = -1, + HBAC_EVAL_ALLOW, + HBAC_EVAL_DENY, + HBAC_EVAL_OOM +}; + +#define HBAC_CATEGORY_NULL 0x0000 /* No service category specified */ +#define HBAC_CATEGORY_ALL 0x0001 /* Rule should apply to all */ + +/* Opaque type contained in hbac_evaluator.c */ +struct hbac_time_rules; + +struct hbac_rule_element { + uint32_t category; + const char **names; + const char **groups; +}; + +struct hbac_rule { + const char *name; + bool enabled; + + /* Services and service groups + * for which this rule applies + */ + struct hbac_rule_element *services; + + /* Users and groups for which this + * rule applies + */ + struct hbac_rule_element *users; + + /* Target hosts for which this rule apples */ + struct hbac_rule_element *targethosts; + + /* Source hosts for which this rule applies */ + struct hbac_rule_element *srchosts; + + /* For future use */ + struct hbac_time_rules *timerules; +}; + +struct hbac_request_element { + const char *name; + const char **groups; +}; + +struct hbac_eval_req { + /* This is a list of service DNs to check, + * it must consist of the actual service + * requested, as well as all parent groups + * containing that service. + */ + struct hbac_request_element *service; + + /* This is a list of user DNs to check, + * it must consist of the actual user + * requested, as well as all parent groups + * containing that user. + */ + struct hbac_request_element *user; + + /* This is a list of target hosts to check, + * it must consist of the actual target host + * requested, as well as all parent groups + * containing that target host. + */ + struct hbac_request_element *targethost; + + /* This is a list of source hosts to check, + * it must consist of the actual source host + * requested, as well as all parent groups + * containing that source host. + */ + struct hbac_request_element *srchost; + + /* For future use */ + time_t request_time; +}; + +enum hbac_error_code { + HBAC_ERROR_UNKNOWN = -1, + HBAC_SUCCESS, + HBAC_ERROR_NOT_IMPLEMENTED, + HBAC_ERROR_OUT_OF_MEMORY, + HBAC_ERROR_UNPARSEABLE_RULE +}; + +/* Extended information */ +struct hbac_info { + /* If the hbac_eval_result was HBAC_EVAL_ERROR, + * this will be an error code. + * Otherwise it will be HBAC_SUCCESS + */ + enum hbac_error_code code; + + /* Specify the name of the rule that matched or + * threw an error + */ + char *rule_name; +}; + + +/** + * @brief Evaluate an authorization request against a set of HBAC rules + * + * @param[in] rules A NULL-terminated list of rules to evaluate against + * @param[in] hbac_req A user authorization request + * @param[out] info Extended information (including the name of the + * rule that allowed access (or caused a parse error) + * @return + */ +enum hbac_eval_result hbac_evaluate(struct hbac_rule **rules, + struct hbac_eval_req *hbac_req, + struct hbac_info **info); + +const char *hbac_result_string(enum hbac_eval_result result); +const char *hbac_error_string(enum hbac_error_code code); + +void hbac_free_info(struct hbac_info *info); + +#endif /* IPA_HBAC_H_ */ diff --git a/src/providers/ipa/ipa_hbac.pc.in b/src/providers/ipa/ipa_hbac.pc.in new file mode 100644 index 000000000..9d799e850 --- /dev/null +++ b/src/providers/ipa/ipa_hbac.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: ipa_hbac +Description: FreeIPA HBAC Evaluator library +Version: @VERSION@ +Libs: -L$(libdir) -lipa_hbac +Cflags: +URL: http://fedorahosted.org/sssd/ -- cgit