From 4dd615c01357b8715711aad6820ba9595d3ad377 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 --- Makefile.am | 28 +- configure.ac | 3 +- contrib/sssd.spec.in | 29 ++ src/providers/ipa/hbac_evaluator.c | 221 +++++++++++++ src/providers/ipa/ipa_hbac.h | 154 +++++++++ src/providers/ipa/ipa_hbac.pc.in | 11 + src/tests/ipa_hbac-tests.c | 618 +++++++++++++++++++++++++++++++++++++ 7 files changed, 1062 insertions(+), 2 deletions(-) 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 create mode 100644 src/tests/ipa_hbac-tests.c diff --git a/Makefile.am b/Makefile.am index b8423bab..ee7c4685 100644 --- a/Makefile.am +++ b/Makefile.am @@ -33,6 +33,7 @@ initdir = @initdir@ systemdunitdir = @systemdunitdir@ logpath = @logpath@ pubconfpath = @pubconfpath@ +pkgconfigdir = $(libdir)/pkgconfig AM_CFLAGS = if WANT_AUX_INFO @@ -44,6 +45,8 @@ if HAVE_GCC -Werror-implicit-function-declaration endif +dist_pkgconfig_DATA = + ACLOCAL_AMFLAGS = -I m4 -I . sbin_PROGRAMS = \ @@ -80,7 +83,8 @@ if HAVE_CHECK ipa_ldap_opt-tests \ simple_access-tests \ crypto-tests \ - util-tests + util-tests \ + ipa_hbac-tests endif check_PROGRAMS = \ @@ -365,6 +369,16 @@ libsss_util_la_LIBADD = \ libsss_crypt.la \ libsss_debug.la +lib_LTLIBRARIES = libipa_hbac.la +dist_pkgconfig_DATA += src/providers/ipa/ipa_hbac.pc +libipa_hbac_la_SOURCES = \ + src/providers/ipa/hbac_evaluator.c +libipa_hbac_la_LDFLAGS = \ + -version 0:0:0 + +include_HEADERS = \ + src/providers/ipa/ipa_hbac.h + #################### # Program Binaries # #################### @@ -711,6 +725,18 @@ crypto_tests_LDADD = \ $(CHECK_LIBS) \ libsss_test_common.la +ipa_hbac_tests_SOURCES = \ + src/tests/ipa_hbac-tests.c +ipa_hbac_tests_CFLAGS = \ + $(AM_CFLAGS) \ + $(CHECK_CFLAGS) +ipa_hbac_tests_LDADD = \ + $(SSSD_LIBS) \ + $(CHECK_LIBS) \ + libsss_util.la \ + libsss_test_common.la \ + libipa_hbac.la + endif stress_tests_SOURCES = \ diff --git a/configure.ac b/configure.ac index 972c24c8..2cf3137f 100644 --- a/configure.ac +++ b/configure.ac @@ -192,6 +192,7 @@ AC_DEFINE_UNQUOTED([ABS_BUILD_DIR], ["$abs_build_dir"], [Absolute path to the bu AC_SUBST([abs_builddir], $abs_build_dir) AC_CONFIG_FILES([Makefile contrib/sssd.spec src/examples/rwtab src/doxy.config - src/sysv/systemd/sssd.service po/Makefile.in src/man/Makefile]) + src/sysv/systemd/sssd.service po/Makefile.in src/man/Makefile + src/providers/ipa/ipa_hbac.pc]) AC_OUTPUT diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in index b1481802..9c24fecb 100644 --- a/contrib/sssd.spec.in +++ b/contrib/sssd.spec.in @@ -116,6 +116,23 @@ SSSD when using id_provider = local in /etc/sssd/sssd.conf. Also provides a userspace tool for generating an obfuscated LDAP password for use with ldap_default_authtok_type = obfuscated_password. +%package -n libipa_hbac +Summary: FreeIPA HBAC Evaluator library +Group: Development/Libraries +License: LGPLv3+ + +%description -n libipa_hbac +Utility library to validate FreeIPA HBAC rules for authorization requests + +%package -n libipa_hbac-devel +Summary: FreeIPA HBAC Evaluator library +Group: Development/Libraries +License: LGPLv3+ +Requires: libipa_hbac = %{version}-%{release} + +%description -n libipa_hbac-devel +Utility library to validate FreeIPA HBAC rules for authorization requests + %prep %setup -q @@ -181,6 +198,7 @@ rm -f \ $RPM_BUILD_ROOT/%{_libdir}/sssd/libsss_ipa.la \ $RPM_BUILD_ROOT/%{_libdir}/sssd/libsss_simple.la \ $RPM_BUILD_ROOT/%{_libdir}/krb5/plugins/libkrb5/sssd_krb5_locator_plugin.la \ + $RPM_BUILD_ROOT/%{_libdir}/libipa_hbac.la \ $RPM_BUILD_ROOT/%{python_sitearch}/pysss.la # Older versions of rpmbuild can only handle one -f option @@ -268,6 +286,17 @@ rm -rf $RPM_BUILD_ROOT %{_mandir}/man8/sss_obfuscate.8* %{_mandir}/man8/sss_cache.8* +%files -n libipa_hbac +%defattr(-,root,root,-) +%doc src/sss_client/COPYING src/sss_client/COPYING.LESSER +%{_libdir}/libipa_hbac.so.* + +%files -n libipa_hbac-devel +%defattr(-,root,root,-) +%{_includedir}/ipa_hbac.h +%{_libdir}/libipa_hbac.so +%{_libdir}/pkgconfig/ipa_hbac.pc + %post /sbin/ldconfig /sbin/chkconfig --add %{servicename} diff --git a/src/providers/ipa/hbac_evaluator.c b/src/providers/ipa/hbac_evaluator.c new file mode 100644 index 00000000..949f0aef --- /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 00000000..a1d51378 --- /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 00000000..9d799e85 --- /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/ diff --git a/src/tests/ipa_hbac-tests.c b/src/tests/ipa_hbac-tests.c new file mode 100644 index 00000000..2038812d --- /dev/null +++ b/src/tests/ipa_hbac-tests.c @@ -0,0 +1,618 @@ +/* + SSSD + + Authors: + 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 +#include +#include +#include + +#include "tests/common.h" +#include "providers/ipa/ipa_hbac.h" + +#define HBAC_TEST_USER "testuser" +#define HBAC_TEST_INVALID_USER "nosuchuser" + +#define HBAC_TEST_GROUP1 "testgroup1" +#define HBAC_TEST_GROUP2 "testgroup2" +#define HBAC_TEST_INVALID_GROUP "nosuchgroup" + +#define HBAC_TEST_SERVICE "testservice" +#define HBAC_TEST_INVALID_SERVICE "nosuchservice" + +#define HBAC_TEST_SERVICEGROUP1 "login_services" +#define HBAC_TEST_SERVICEGROUP2 "all_services" +#define HBAC_TEST_INVALID_SERVICEGROUP "nosuchservicegroup" + +#define HBAC_TEST_SRCHOST "client.example.com" +#define HBAC_TEST_INVALID_SRCHOST "nosuchsrchost" + +#define HBAC_TEST_SRCHOSTGROUP1 "site_hosts" +#define HBAC_TEST_SRCHOSTGROUP2 "corp_hosts" +#define HBAC_TEST_INVALID_SRCHOSTGROUP "nosuchsrchostgroup" + +static void get_allow_all_rule(TALLOC_CTX *mem_ctx, + struct hbac_rule **allow_rule) +{ + struct hbac_rule *rule; + /* Create a rule that ALLOWs all services, users and + * remote hosts. + */ + rule = talloc_zero(mem_ctx, struct hbac_rule); + fail_if (rule == NULL); + + rule->enabled = true; + + rule->services = talloc_zero(rule, struct hbac_rule_element); + fail_if (rule->services == NULL); + rule->services->category = HBAC_CATEGORY_ALL; + rule->services->names = NULL; + rule->services->groups = NULL; + + rule->users = talloc_zero(rule, struct hbac_rule_element); + fail_if (rule->users == NULL); + rule->users->category = HBAC_CATEGORY_ALL; + rule->users->names = NULL; + rule->users->groups = NULL; + + rule->targethosts = talloc_zero(rule, struct hbac_rule_element); + fail_if (rule->targethosts == NULL); + rule->targethosts->category = HBAC_CATEGORY_ALL; + rule->targethosts->names = NULL; + rule->targethosts->groups = NULL; + + rule->srchosts = talloc_zero(rule, struct hbac_rule_element); + fail_if (rule->srchosts == NULL); + rule->srchosts->category = HBAC_CATEGORY_ALL; + rule->srchosts->names = NULL; + rule->srchosts->groups = NULL; + + *allow_rule = rule; +} + +static void get_test_user(TALLOC_CTX *mem_ctx, + struct hbac_request_element **user) +{ + struct hbac_request_element *new_user; + + new_user = talloc_zero(mem_ctx, struct hbac_request_element); + fail_if (new_user == NULL); + + new_user->name = talloc_strdup(new_user, HBAC_TEST_USER); + fail_if(new_user->name == NULL); + + new_user->groups = talloc_array(new_user, const char *, 3); + fail_if(new_user->groups == NULL); + + new_user->groups[0] = talloc_strdup(new_user->groups, HBAC_TEST_GROUP1); + fail_if(new_user->groups[0] == NULL); + + new_user->groups[1] = talloc_strdup(new_user->groups, HBAC_TEST_GROUP2); + fail_if(new_user->groups[1] == NULL); + + new_user->groups[2] = NULL; + + *user = new_user; +} + +static void get_test_service(TALLOC_CTX *mem_ctx, + struct hbac_request_element **service) +{ + struct hbac_request_element *new_service; + + new_service = talloc_zero(mem_ctx, struct hbac_request_element); + fail_if (new_service == NULL); + + new_service->name = talloc_strdup(new_service, HBAC_TEST_SERVICE); + fail_if(new_service->name == NULL); + + new_service->groups = talloc_array(new_service, const char *, 3); + fail_if(new_service->groups == NULL); + + new_service->groups[0] = talloc_strdup(new_service->groups, HBAC_TEST_SERVICEGROUP1); + fail_if(new_service->groups[0] == NULL); + + new_service->groups[1] = talloc_strdup(new_service->groups, HBAC_TEST_SERVICEGROUP2); + fail_if(new_service->groups[1] == NULL); + + new_service->groups[2] = NULL; + + *service = new_service; +} + +static void get_test_srchost(TALLOC_CTX *mem_ctx, + struct hbac_request_element **srchost) +{ + struct hbac_request_element *new_srchost; + + new_srchost = talloc_zero(mem_ctx, struct hbac_request_element); + fail_if (new_srchost == NULL); + + new_srchost->name = talloc_strdup(new_srchost, "client.example.com"); + fail_if(new_srchost->name == NULL); + + new_srchost->groups = talloc_array(new_srchost, const char *, 3); + fail_if(new_srchost->groups == NULL); + + new_srchost->groups[0] = talloc_strdup(new_srchost->groups, "site_hosts"); + fail_if(new_srchost->groups[0] == NULL); + + new_srchost->groups[1] = talloc_strdup(new_srchost->groups, "corp_hosts"); + fail_if(new_srchost->groups[1] == NULL); + + new_srchost->groups[2] = NULL; + + *srchost = new_srchost; +} + +START_TEST(ipa_hbac_test_allow_all) +{ + enum hbac_eval_result result; + TALLOC_CTX *test_ctx; + struct hbac_rule **rules; + struct hbac_eval_req *eval_req; + struct hbac_info *info; + + test_ctx = talloc_new(global_talloc_context); + + /* Create a request */ + eval_req = talloc_zero(test_ctx, struct hbac_eval_req); + fail_if (eval_req == NULL); + + get_test_user(eval_req, &eval_req->user); + get_test_service(eval_req, &eval_req->service); + get_test_srchost(eval_req, &eval_req->srchost); + + /* Create the rules to evaluate against */ + rules = talloc_array(test_ctx, struct hbac_rule *, 2); + fail_if (rules == NULL); + + get_allow_all_rule(rules, &rules[0]); + rules[0]->name = talloc_strdup(rules[0], "Allow All"); + fail_if(rules[0]->name == NULL); + rules[1] = NULL; + + /* Evaluate the rules */ + result = hbac_evaluate(rules, eval_req, &info); + fail_unless(result == HBAC_EVAL_ALLOW, + "Expected [%s], got [%s]; " + "Error: [%s]", + hbac_result_string(HBAC_EVAL_ALLOW), + hbac_result_string(result), + info ? hbac_error_string(info->code):"Unknown"); + + talloc_free(test_ctx); +} +END_TEST + +START_TEST(ipa_hbac_test_allow_user) +{ + enum hbac_eval_result result; + TALLOC_CTX *test_ctx; + struct hbac_rule **rules; + struct hbac_eval_req *eval_req; + struct hbac_info *info; + + test_ctx = talloc_new(global_talloc_context); + + /* Create a request */ + eval_req = talloc_zero(test_ctx, struct hbac_eval_req); + fail_if (eval_req == NULL); + + get_test_user(eval_req, &eval_req->user); + get_test_service(eval_req, &eval_req->service); + get_test_srchost(eval_req, &eval_req->srchost); + + /* Create the rules to evaluate against */ + rules = talloc_array(test_ctx, struct hbac_rule *, 2); + fail_if (rules == NULL); + + get_allow_all_rule(rules, &rules[0]); + + /* Modify the rule to allow only a specific user */ + rules[0]->name = talloc_strdup(rules[0], "Allow user"); + fail_if(rules[0]->name == NULL); + rules[0]->users->category = HBAC_CATEGORY_NULL; + + rules[0]->users->names = talloc_array(rules[0], const char *, 2); + fail_if(rules[0]->users->names == NULL); + + rules[0]->users->names[0] = HBAC_TEST_USER; + rules[0]->users->names[1] = NULL; + + rules[1] = NULL; + + /* Evaluate the rules */ + result = hbac_evaluate(rules, eval_req, &info); + fail_unless(result == HBAC_EVAL_ALLOW, + "Expected [%s], got [%s]; " + "Error: [%s]", + hbac_result_string(HBAC_EVAL_ALLOW), + hbac_result_string(result), + info ? hbac_error_string(info->code):"Unknown"); + + /* Negative test */ + rules[0]->users->names[0] = HBAC_TEST_INVALID_USER; + + /* Evaluate the rules */ + result = hbac_evaluate(rules, eval_req, &info); + fail_unless(result == HBAC_EVAL_DENY, + "Expected [%s], got [%s]; " + "Error: [%s]", + hbac_result_string(HBAC_EVAL_DENY), + hbac_result_string(result), + info ? hbac_error_string(info->code):"Unknown"); + + talloc_free(test_ctx); +} +END_TEST + +START_TEST(ipa_hbac_test_allow_group) +{ + enum hbac_eval_result result; + TALLOC_CTX *test_ctx; + struct hbac_rule **rules; + struct hbac_eval_req *eval_req; + struct hbac_info *info; + + test_ctx = talloc_new(global_talloc_context); + + /* Create a request */ + eval_req = talloc_zero(test_ctx, struct hbac_eval_req); + fail_if (eval_req == NULL); + + get_test_user(eval_req, &eval_req->user); + get_test_service(eval_req, &eval_req->service); + get_test_srchost(eval_req, &eval_req->srchost); + + /* Create the rules to evaluate against */ + rules = talloc_array(test_ctx, struct hbac_rule *, 2); + fail_if (rules == NULL); + + get_allow_all_rule(rules, &rules[0]); + + /* Modify the rule to allow only a group of users */ + rules[0]->name = talloc_strdup(rules[0], "Allow group"); + fail_if(rules[0]->name == NULL); + rules[0]->users->category = HBAC_CATEGORY_NULL; + + rules[0]->users->names = NULL; + rules[0]->users->groups = talloc_array(rules[0], const char *, 2); + fail_if(rules[0]->users->groups == NULL); + + rules[0]->users->groups[0] = HBAC_TEST_GROUP1; + rules[0]->users->groups[1] = NULL; + + rules[1] = NULL; + + /* Evaluate the rules */ + result = hbac_evaluate(rules, eval_req, &info); + fail_unless(result == HBAC_EVAL_ALLOW, + "Expected [%s], got [%s]; " + "Error: [%s]", + hbac_result_string(HBAC_EVAL_ALLOW), + hbac_result_string(result), + info ? hbac_error_string(info->code):"Unknown"); + + /* Negative test */ + rules[0]->users->groups[0] = HBAC_TEST_INVALID_GROUP; + + /* Evaluate the rules */ + result = hbac_evaluate(rules, eval_req, &info); + fail_unless(result == HBAC_EVAL_DENY, + "Expected [%s], got [%s]; " + "Error: [%s]", + hbac_result_string(HBAC_EVAL_DENY), + hbac_result_string(result), + info ? hbac_error_string(info->code):"Unknown"); + + talloc_free(test_ctx); +} +END_TEST + +START_TEST(ipa_hbac_test_allow_svc) +{ + enum hbac_eval_result result; + TALLOC_CTX *test_ctx; + struct hbac_rule **rules; + struct hbac_eval_req *eval_req; + struct hbac_info *info; + + test_ctx = talloc_new(global_talloc_context); + + /* Create a request */ + eval_req = talloc_zero(test_ctx, struct hbac_eval_req); + fail_if (eval_req == NULL); + + get_test_user(eval_req, &eval_req->user); + get_test_service(eval_req, &eval_req->service); + get_test_srchost(eval_req, &eval_req->srchost); + + /* Create the rules to evaluate against */ + rules = talloc_array(test_ctx, struct hbac_rule *, 2); + fail_if (rules == NULL); + + get_allow_all_rule(rules, &rules[0]); + + /* Modify the rule to allow only a specific service */ + rules[0]->name = talloc_strdup(rules[0], "Allow service"); + fail_if(rules[0]->name == NULL); + rules[0]->services->category = HBAC_CATEGORY_NULL; + + rules[0]->services->names = talloc_array(rules[0], const char *, 2); + fail_if(rules[0]->services->names == NULL); + + rules[0]->services->names[0] = HBAC_TEST_SERVICE; + rules[0]->services->names[1] = NULL; + + rules[1] = NULL; + + /* Evaluate the rules */ + result = hbac_evaluate(rules, eval_req, &info); + fail_unless(result == HBAC_EVAL_ALLOW, + "Expected [%s], got [%s]; " + "Error: [%s]", + hbac_result_string(HBAC_EVAL_ALLOW), + hbac_result_string(result), + info ? hbac_error_string(info->code):"Unknown"); + + /* Negative test */ + rules[0]->services->names[0] = HBAC_TEST_INVALID_SERVICE; + + /* Evaluate the rules */ + result = hbac_evaluate(rules, eval_req, &info); + fail_unless(result == HBAC_EVAL_DENY, + "Expected [%s], got [%s]; " + "Error: [%s]", + hbac_result_string(HBAC_EVAL_DENY), + hbac_result_string(result), + info ? hbac_error_string(info->code):"Unknown"); + + talloc_free(test_ctx); +} +END_TEST + +START_TEST(ipa_hbac_test_allow_svcgroup) +{ + enum hbac_eval_result result; + TALLOC_CTX *test_ctx; + struct hbac_rule **rules; + struct hbac_eval_req *eval_req; + struct hbac_info *info; + + test_ctx = talloc_new(global_talloc_context); + + /* Create a request */ + eval_req = talloc_zero(test_ctx, struct hbac_eval_req); + fail_if (eval_req == NULL); + + get_test_user(eval_req, &eval_req->user); + get_test_service(eval_req, &eval_req->service); + get_test_srchost(eval_req, &eval_req->srchost); + + /* Create the rules to evaluate against */ + rules = talloc_array(test_ctx, struct hbac_rule *, 2); + fail_if (rules == NULL); + + get_allow_all_rule(rules, &rules[0]); + + /* Modify the rule to allow only a group of users */ + rules[0]->name = talloc_strdup(rules[0], "Allow servicegroup"); + fail_if(rules[0]->name == NULL); + rules[0]->services->category = HBAC_CATEGORY_NULL; + + rules[0]->services->names = NULL; + rules[0]->services->groups = talloc_array(rules[0], const char *, 2); + fail_if(rules[0]->services->groups == NULL); + + rules[0]->services->groups[0] = HBAC_TEST_SERVICEGROUP1; + rules[0]->services->groups[1] = NULL; + + rules[1] = NULL; + + /* Evaluate the rules */ + result = hbac_evaluate(rules, eval_req, &info); + fail_unless(result == HBAC_EVAL_ALLOW, + "Expected [%s], got [%s]; " + "Error: [%s]", + hbac_result_string(HBAC_EVAL_ALLOW), + hbac_result_string(result), + info ? hbac_error_string(info->code):"Unknown"); + + /* Negative test */ + rules[0]->services->groups[0] = HBAC_TEST_INVALID_SERVICEGROUP; + + /* Evaluate the rules */ + result = hbac_evaluate(rules, eval_req, &info); + fail_unless(result == HBAC_EVAL_DENY, + "Expected [%s], got [%s]; " + "Error: [%s]", + hbac_result_string(HBAC_EVAL_DENY), + hbac_result_string(result), + info ? hbac_error_string(info->code):"Unknown"); + + talloc_free(test_ctx); +} +END_TEST + +START_TEST(ipa_hbac_test_allow_srchost) +{ + enum hbac_eval_result result; + TALLOC_CTX *test_ctx; + struct hbac_rule **rules; + struct hbac_eval_req *eval_req; + struct hbac_info *info; + + test_ctx = talloc_new(global_talloc_context); + + /* Create a request */ + eval_req = talloc_zero(test_ctx, struct hbac_eval_req); + fail_if (eval_req == NULL); + + get_test_user(eval_req, &eval_req->user); + get_test_service(eval_req, &eval_req->service); + get_test_srchost(eval_req, &eval_req->srchost); + + /* Create the rules to evaluate against */ + rules = talloc_array(test_ctx, struct hbac_rule *, 2); + fail_if (rules == NULL); + + get_allow_all_rule(rules, &rules[0]); + + /* Modify the rule to allow only a specific service */ + rules[0]->name = talloc_strdup(rules[0], "Allow srchost"); + fail_if(rules[0]->name == NULL); + rules[0]->srchosts->category = HBAC_CATEGORY_NULL; + + rules[0]->srchosts->names = talloc_array(rules[0], const char *, 2); + fail_if(rules[0]->srchosts->names == NULL); + + rules[0]->srchosts->names[0] = HBAC_TEST_SRCHOST; + rules[0]->srchosts->names[1] = NULL; + + rules[1] = NULL; + + /* Evaluate the rules */ + result = hbac_evaluate(rules, eval_req, &info); + fail_unless(result == HBAC_EVAL_ALLOW, + "Expected [%s], got [%s]; " + "Error: [%s]", + hbac_result_string(HBAC_EVAL_ALLOW), + hbac_result_string(result), + info ? hbac_error_string(info->code):"Unknown"); + + /* Negative test */ + rules[0]->srchosts->names[0] = HBAC_TEST_INVALID_SRCHOST; + + /* Evaluate the rules */ + result = hbac_evaluate(rules, eval_req, &info); + fail_unless(result == HBAC_EVAL_DENY, + "Expected [%s], got [%s]; " + "Error: [%s](%s)", + hbac_result_string(HBAC_EVAL_DENY), + hbac_result_string(result), + info ? hbac_error_string(info->code):"Unknown"); + + talloc_free(test_ctx); +} +END_TEST + +START_TEST(ipa_hbac_test_allow_srchostgroup) +{ + enum hbac_eval_result result; + TALLOC_CTX *test_ctx; + struct hbac_rule **rules; + struct hbac_eval_req *eval_req; + struct hbac_info *info; + + test_ctx = talloc_new(global_talloc_context); + + /* Create a request */ + eval_req = talloc_zero(test_ctx, struct hbac_eval_req); + fail_if (eval_req == NULL); + + get_test_user(eval_req, &eval_req->user); + get_test_service(eval_req, &eval_req->service); + get_test_srchost(eval_req, &eval_req->srchost); + + /* Create the rules to evaluate against */ + rules = talloc_array(test_ctx, struct hbac_rule *, 2); + fail_if (rules == NULL); + + get_allow_all_rule(rules, &rules[0]); + + /* Modify the rule to allow only a group of users */ + rules[0]->name = talloc_strdup(rules[0], "Allow srchostgroup"); + fail_if(rules[0]->name == NULL); + rules[0]->srchosts->category = HBAC_CATEGORY_NULL; + + rules[0]->srchosts->names = NULL; + rules[0]->srchosts->groups = talloc_array(rules[0], const char *, 2); + fail_if(rules[0]->srchosts->groups == NULL); + + rules[0]->srchosts->groups[0] = HBAC_TEST_SRCHOSTGROUP1; + rules[0]->srchosts->groups[1] = NULL; + + rules[1] = NULL; + + /* Evaluate the rules */ + result = hbac_evaluate(rules, eval_req, &info); + fail_unless(result == HBAC_EVAL_ALLOW, + "Expected [%s], got [%s]; " + "Error: [%s]", + hbac_result_string(HBAC_EVAL_ALLOW), + hbac_result_string(result), + info ? hbac_error_string(info->code):"Unknown"); + + /* Negative test */ + rules[0]->srchosts->groups[0] = HBAC_TEST_INVALID_SRCHOSTGROUP; + + /* Evaluate the rules */ + result = hbac_evaluate(rules, eval_req, &info); + fail_unless(result == HBAC_EVAL_DENY, + "Expected [%s], got [%s]; " + "Error: [%s]", + hbac_result_string(HBAC_EVAL_DENY), + hbac_result_string(result), + info ? hbac_error_string(info->code):"Unknown"); + + talloc_free(test_ctx); +} +END_TEST + +Suite *hbac_test_suite (void) +{ + Suite *s = suite_create ("HBAC"); + + TCase *tc_hbac = tcase_create("HBAC_rules"); + tcase_add_checked_fixture(tc_hbac, + leak_check_setup, + leak_check_teardown); + + tcase_add_test(tc_hbac, ipa_hbac_test_allow_all); + tcase_add_test(tc_hbac, ipa_hbac_test_allow_user); + tcase_add_test(tc_hbac, ipa_hbac_test_allow_group); + tcase_add_test(tc_hbac, ipa_hbac_test_allow_svc); + tcase_add_test(tc_hbac, ipa_hbac_test_allow_svcgroup); + tcase_add_test(tc_hbac, ipa_hbac_test_allow_srchost); + tcase_add_test(tc_hbac, ipa_hbac_test_allow_srchostgroup); + + suite_add_tcase(s, tc_hbac); + return s; +} + +int main(int argc, const char *argv[]) +{ + int number_failed; + + tests_set_cwd(); + + Suite *s = hbac_test_suite(); + SRunner *sr = srunner_create(s); + + /* If CK_VERBOSITY is set, use that, otherwise it defaults to CK_NORMAL */ + srunner_run_all(sr, CK_ENV); + number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} -- cgit