From 43833ccbca01c8892409586b5e8381de2096ac1b Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Tue, 28 Jul 2015 11:00:41 +0200 Subject: IPA KDB: allow case in-sensitive realm in AS request If the canonicalization flag is set the realm of the client principal in an AS request (kinit) is transformed into upper-case to match the IPA convention for realm names. Resolves https://fedorahosted.org/freeipa/ticket/4844 --- daemons/ipa-kdb/ipa_kdb.h | 2 +- daemons/ipa-kdb/ipa_kdb_common.c | 43 ++++++++++++++++++++++++++- daemons/ipa-kdb/ipa_kdb_principals.c | 3 +- daemons/ipa-kdb/ipa_kdb_pwdpolicy.c | 2 +- daemons/ipa-kdb/tests/ipa_kdb_tests.c | 55 +++++++++++++++++++++++++++++++++++ 5 files changed, 101 insertions(+), 4 deletions(-) diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h index 4abb7335d..a9d36fe25 100644 --- a/daemons/ipa-kdb/ipa_kdb.h +++ b/daemons/ipa-kdb/ipa_kdb.h @@ -133,7 +133,7 @@ struct ipadb_context *ipadb_get_context(krb5_context kcontext); int ipadb_get_connection(struct ipadb_context *ipactx); /* COMMON LDAP FUNCTIONS */ -char *ipadb_filter_escape(const char *input, bool star); +char *ipadb_filter_escape(const char *input, bool star, bool unify); krb5_error_code ipadb_simple_search(struct ipadb_context *ipactx, char *basedn, int scope, char *filter, char **attrs, diff --git a/daemons/ipa-kdb/ipa_kdb_common.c b/daemons/ipa-kdb/ipa_kdb_common.c index 112086b57..80afa23f0 100644 --- a/daemons/ipa-kdb/ipa_kdb_common.c +++ b/daemons/ipa-kdb/ipa_kdb_common.c @@ -25,9 +25,41 @@ static struct timeval std_timeout = {300, 0}; -char *ipadb_filter_escape(const char *input, bool star) +#define PRINC_BUF_SIZE 512 + +static char *canon_princ(const char *princ) +{ + int ret; + char *p; + uint8_t *uc_realm; + char *canon_princ; + uint8_t buf[PRINC_BUF_SIZE] = { 0 }; + size_t size = PRINC_BUF_SIZE; + + p = strrchr(princ, '@'); + if (p == NULL) { + return NULL; + } + + /* Assume the worst-case. */ + uc_realm = u8_toupper((const uint8_t *)( p + 1), size, NULL, NULL, buf, + &size); + if (uc_realm == NULL) { + return NULL; + } + + ret = asprintf(&canon_princ, "%.*s@%s", (p - princ), princ, uc_realm); + if (ret == -1) { + return NULL; + } + + return canon_princ; +} + +char *ipadb_filter_escape(const char *input, bool star, bool canon) { char *output; + char *canonicalized; size_t i = 0; size_t j = 0; @@ -75,6 +107,15 @@ char *ipadb_filter_escape(const char *input, bool star) } output[j] = '\0'; + if (canon) { + canonicalized = canon_princ(output); + /* return output in case of an error */ + if (canonicalized != NULL) { + free(output); + output = canonicalized; + } + } + return output; } diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c index b3f8b1ad7..5fb280d62 100644 --- a/daemons/ipa-kdb/ipa_kdb_principals.c +++ b/daemons/ipa-kdb/ipa_kdb_principals.c @@ -788,7 +788,8 @@ static krb5_error_code ipadb_fetch_principals(struct ipadb_context *ipactx, /* escape filter but do not touch '*' as this function accepts * wildcards in names */ - esc_original_princ = ipadb_filter_escape(principal, false); + esc_original_princ = ipadb_filter_escape(principal, false, + (flags & KRB5_KDB_FLAG_ALIAS_OK)); if (!esc_original_princ) { kerr = KRB5_KDB_INTERNAL_ERROR; goto done; diff --git a/daemons/ipa-kdb/ipa_kdb_pwdpolicy.c b/daemons/ipa-kdb/ipa_kdb_pwdpolicy.c index 076314a12..875960c5d 100644 --- a/daemons/ipa-kdb/ipa_kdb_pwdpolicy.c +++ b/daemons/ipa-kdb/ipa_kdb_pwdpolicy.c @@ -151,7 +151,7 @@ krb5_error_code ipadb_get_pwd_policy(krb5_context kcontext, char *name, return KRB5_KDB_DBNOTINITED; } - esc_name = ipadb_filter_escape(name, true); + esc_name = ipadb_filter_escape(name, true, false); if (!esc_name) { return ENOMEM; } diff --git a/daemons/ipa-kdb/tests/ipa_kdb_tests.c b/daemons/ipa-kdb/tests/ipa_kdb_tests.c index edd4ae097..ac541ad91 100644 --- a/daemons/ipa-kdb/tests/ipa_kdb_tests.c +++ b/daemons/ipa-kdb/tests/ipa_kdb_tests.c @@ -465,6 +465,60 @@ void test_dom_sid_string(void **state) str_sid = dom_sid_string(test_ctx, &test_sid); } +void test_ipadb_filter_escape(void **state) +{ + char *out; + size_t c; + + struct test_data { + const char *in; + bool star; + bool canon; + const char *exp_out; + } test_data[] = { + {"abc", false, false, "abc"}, + {"abc", false, true, "abc"}, + {"abc", true, true, "abc"}, + {"abc", true, false, "abc"}, + {"abc@def", false, false, "abc@def"}, + {"abc@def", false, true, "abc@DEF"}, + {"abc@def", true, true, "abc@DEF"}, + {"abc@def", true, false, "abc@def"}, + {"abc@DEF", false, false, "abc@DEF"}, + {"abc@DEF", false, true, "abc@DEF"}, + {"abc@DEF", true, true, "abc@DEF"}, + {"abc@DEF", true, false, "abc@DEF"}, + {"ab*c@def", false, false, "ab*c@def"}, + {"ab*c@def", false, true, "ab*c@DEF"}, + {"ab*c@def", true, true, "ab\\2ac@DEF"}, + {"ab*c@def", true, false, "ab\\2ac@def"}, + {"\\a(b)c@def", false, false, "\\5ca\\28b\\29c@def"}, + {"\\a(b)c@def", false, true, "\\5ca\\28b\\29c@DEF"}, + {"\\a(b)c@def", true, true, "\\5ca\\28b\\29c@DEF"}, + {"\\a(b)c@def", true, false, "\\5ca\\28b\\29c@def"}, + {"abc@de*f", false, false, "abc@de*f"}, + {"abc@de*f", false, true, "abc@DE*F"}, + {"abc@de*f", true, true, "abc@DE\\2AF"}, + {"abc@de*f", true, false, "abc@de\\2af"}, + /* Special characters must be UTF-8 encoded, don't change encoding */ + {"abc@öäü", false, false, "abc@öäü"}, + {"abc@öäü", false, true, "abc@ÖÄÜ"}, + {"abc@öäü", true, true, "abc@ÖÄÜ"}, + {"abc@öäü", true, false, "abc@öäü"}, + {NULL, false, false, NULL} + }; + + out = ipadb_filter_escape(NULL, false, false); + assert_null(out); + + for (c = 0; test_data[c]. in != NULL; c++) { + out = ipadb_filter_escape(test_data[c].in, test_data[c].star, + test_data[c].canon); + assert_string_equal(out, test_data[c].exp_out); + free(out); + } +} + int main(int argc, const char *argv[]) { @@ -473,6 +527,7 @@ int main(int argc, const char *argv[]) unit_test_setup_teardown(test_filter_logon_info, setup, teardown), unit_test(test_string_to_sid), unit_test_setup_teardown(test_dom_sid_string, setup, teardown), + unit_test(test_ipadb_filter_escape), }; return run_tests(tests); -- cgit