diff options
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | contrib/sssd.spec.in | 1 | ||||
-rw-r--r-- | src/external/libunistring.m4 | 9 | ||||
-rw-r--r-- | src/providers/ipa/hbac_evaluator.c | 114 |
5 files changed, 111 insertions, 17 deletions
diff --git a/Makefile.am b/Makefile.am index 6829788a..6647528c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -378,7 +378,8 @@ 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 + -version 0:1:0 \ + -lunistring include_HEADERS = \ src/providers/ipa/ipa_hbac.h diff --git a/configure.ac b/configure.ac index 0e2e6d44..248a9ae3 100644 --- a/configure.ac +++ b/configure.ac @@ -114,6 +114,7 @@ m4_include([src/external/libkeyutils.m4]) m4_include([src/external/libnl.m4]) m4_include([src/external/systemd.m4]) m4_include([src/util/signal.m4]) +m4_include([src/external/libunistring.m4]) WITH_INITSCRIPT if test x$initscript = xsystemd; then diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in index 6798b7ae..6f7c8bca 100644 --- a/contrib/sssd.spec.in +++ b/contrib/sssd.spec.in @@ -86,6 +86,7 @@ BuildRequires: libnl-devel BuildRequires: nscd BuildRequires: gettext-devel BuildRequires: pkgconfig +BuildRequires: libunistring-devel %description Provides a set of daemons to manage access to remote directories and diff --git a/src/external/libunistring.m4 b/src/external/libunistring.m4 new file mode 100644 index 00000000..69c54fe3 --- /dev/null +++ b/src/external/libunistring.m4 @@ -0,0 +1,9 @@ +AC_CHECK_HEADERS(unistr.h, + [AC_CHECK_LIB([unistring], [u8_strlen], [ UNISTRING_LIBS="-lunistring" ], [AC_MSG_ERROR([No usable libunistring library found])])], + [AC_MSG_ERROR([libunistring header files are not installed])] +) + +AC_CHECK_HEADERS(unicase.h, + [AC_CHECK_LIB([unistring], [u8_casecmp], [ UNISTRING_LIBS="-lunistring" ], [AC_MSG_ERROR([No usable libunistring library found])])], + [AC_MSG_ERROR([libunistring header files are not installed])] +)
\ No newline at end of file diff --git a/src/providers/ipa/hbac_evaluator.c b/src/providers/ipa/hbac_evaluator.c index e120d51e..ee39a09a 100644 --- a/src/providers/ipa/hbac_evaluator.c +++ b/src/providers/ipa/hbac_evaluator.c @@ -25,8 +25,20 @@ #include <stdlib.h> #include <string.h> +#include <unistr.h> +#include <unicase.h> +#include <errno.h> #include "providers/ipa/ipa_hbac.h" +#ifndef HAVE_ERRNO_T +#define HAVE_ERRNO_T +typedef int errno_t; +#endif + +#ifndef EOK +#define EOK 0 +#endif + /* Placeholder structure for future HBAC time-based * evaluation rules */ @@ -102,13 +114,17 @@ done: return result; } -static bool hbac_evaluate_element(struct hbac_rule_element *rule_el, - struct hbac_request_element *req_el); +static errno_t hbac_evaluate_element(struct hbac_rule_element *rule_el, + struct hbac_request_element *req_el, + bool *matched); enum hbac_eval_result_int hbac_evaluate_rule(struct hbac_rule *rule, struct hbac_eval_req *hbac_req, enum hbac_error_code *error) { + errno_t ret; + bool matched; + if (!rule->enabled) return HBAC_EVAL_UNMATCHED; /* Make sure we have all elements */ @@ -121,43 +137,90 @@ enum hbac_eval_result_int hbac_evaluate_rule(struct hbac_rule *rule, } /* Check users */ - if (!hbac_evaluate_element(rule->users, hbac_req->user)) { + ret = hbac_evaluate_element(rule->users, + hbac_req->user, + &matched); + if (ret != EOK) { + *error = HBAC_ERROR_UNPARSEABLE_RULE; + return HBAC_EVAL_MATCH_ERROR; + } else if (!matched) { return HBAC_EVAL_UNMATCHED; } /* Check services */ - if (!hbac_evaluate_element(rule->services, hbac_req->service)) { + ret = hbac_evaluate_element(rule->services, + hbac_req->service, + &matched); + if (ret != EOK) { + *error = HBAC_ERROR_UNPARSEABLE_RULE; + return HBAC_EVAL_MATCH_ERROR; + } else if (!matched) { return HBAC_EVAL_UNMATCHED; } /* Check target hosts */ - if (!hbac_evaluate_element(rule->targethosts, hbac_req->targethost)) { + ret = hbac_evaluate_element(rule->targethosts, + hbac_req->targethost, + &matched); + if (ret != EOK) { + *error = HBAC_ERROR_UNPARSEABLE_RULE; + return HBAC_EVAL_MATCH_ERROR; + } else if (!matched) { return HBAC_EVAL_UNMATCHED; } /* Check source hosts */ - if (!hbac_evaluate_element(rule->srchosts, hbac_req->srchost)) { + ret = hbac_evaluate_element(rule->srchosts, + hbac_req->srchost, + &matched); + if (ret != EOK) { + *error = HBAC_ERROR_UNPARSEABLE_RULE; + return HBAC_EVAL_MATCH_ERROR; + } else if (!matched) { 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) +static errno_t hbac_evaluate_element(struct hbac_rule_element *rule_el, + struct hbac_request_element *req_el, + bool *matched) { size_t i, j; + const uint8_t *rule_name; + const uint8_t *req_name; + int result; + int ret; if (rule_el->category & HBAC_CATEGORY_ALL) { - return true; + *matched = true; + return EOK; } /* First check the name list */ if (rule_el->names) { for (i = 0; rule_el->names[i]; i++) { if (req_el->name != NULL) { - if (strcmp(rule_el->names[i], req_el->name) == 0) { - return true; + rule_name = (const uint8_t *) rule_el->names[i]; + req_name = (const uint8_t *) req_el->name; + + /* Do a case-insensitive comparison. + * The input must be encoded in UTF8. + * We have no way of knowing the language, + * so we'll pass NULL for the language and + * hope for the best. + */ + errno = 0; + ret = u8_casecmp(rule_name, u8_strlen(rule_name), + req_name, u8_strlen(req_name), + NULL, NULL, &result); + if (ret < 0) { + return errno; + } + + if (result == 0) { + *matched = true; + return EOK; } } } @@ -168,17 +231,36 @@ static bool hbac_evaluate_element(struct hbac_rule_element *rule_el, * Check for group membership */ for (i = 0; rule_el->groups[i]; i++) { + rule_name = (const uint8_t *) rule_el->groups[i]; + for (j = 0; req_el->groups[j]; j++) { - if (strcmp(rule_el->groups[i], - req_el->groups[j]) == 0) { - return true; + req_name = (const uint8_t *) req_el->groups[j]; + + /* Do a case-insensitive comparison. + * The input must be encoded in UTF8. + * We have no way of knowing the language, + * so we'll pass NULL for the language and + * hope for the best. + */ + errno = 0; + ret = u8_casecmp(rule_name, u8_strlen(rule_name), + req_name, u8_strlen(req_name), + NULL, NULL, &result); + if (ret < 0) { + return errno; + } + + if (result == 0) { + *matched = true; + return EOK; } } } } /* Not found in groups either */ - return false; + *matched = false; + return EOK; } const char *hbac_result_string(enum hbac_eval_result result) |