From ba772c91f17035bbaf8e26770ccc208857605e3c Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Oct 26 2012 16:10:23 +0000 Subject: krb5_auth: check if principal belongs to a different realm Add a flag if the principal used for authentication does not belong to our realm. This can be used to act differently for users from other realms. --- diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index c98535b..72f0711 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -427,6 +427,13 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx, DEBUG(1, ("krb5_get_simple_upn failed.\n")); goto done; } + } else { + ret = compare_principal_realm(kr->upn, realm, + &kr->upn_from_different_realm); + if (ret != 0) { + DEBUG(SSSDBG_OP_FAILURE, ("compare_principal_realm failed.\n")); + goto done; + } } kr->homedir = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_HOMEDIR, diff --git a/src/providers/krb5/krb5_auth.h b/src/providers/krb5/krb5_auth.h index cc079ba..a23b8b4 100644 --- a/src/providers/krb5/krb5_auth.h +++ b/src/providers/krb5/krb5_auth.h @@ -54,6 +54,7 @@ struct krb5child_req { bool active_ccache_present; bool valid_tgt_present; bool run_as_user; + bool upn_from_different_realm; }; errno_t krb5_setup(TALLOC_CTX *mem_ctx, struct pam_data *pd, diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c index 006dac1..45f126f 100644 --- a/src/providers/krb5/krb5_common.c +++ b/src/providers/krb5/krb5_common.c @@ -881,3 +881,34 @@ errno_t krb5_get_simple_upn(TALLOC_CTX *mem_ctx, struct krb5_ctx *krb5_ctx, *_upn = upn; return EOK; } + +errno_t compare_principal_realm(const char *upn, const char *realm, + bool *different_realm) +{ + size_t upn_len; + size_t realm_len; + char *at_sign; + + if (upn == NULL || realm == NULL || different_realm == NULL) { + return EINVAL; + } + + upn_len = strlen(upn); + realm_len = strlen(realm); + at_sign = strchr(upn, '@'); + + /* if coming from the same realm the upn must be at least the size of the + * realm plus 1 for the '@' char. */ + if (upn_len == 0 || realm_len == 0 || upn_len <= realm_len + 1 || + at_sign == NULL) { + return EINVAL; + } + + if (strcmp(realm, at_sign + 1) == 0) { + *different_realm = false; + } else { + *different_realm = true; + } + + return EOK; +} diff --git a/src/providers/krb5/krb5_common.h b/src/providers/krb5/krb5_common.h index 51bd267..bc63bf9 100644 --- a/src/providers/krb5/krb5_common.h +++ b/src/providers/krb5/krb5_common.h @@ -177,6 +177,10 @@ errno_t remove_krb5_info_files(TALLOC_CTX *mem_ctx, const char *realm); errno_t krb5_get_simple_upn(TALLOC_CTX *mem_ctx, struct krb5_ctx *krb5_ctx, const char *username, const char **_upn); +errno_t compare_principal_realm(const char *upn, const char *realm, + bool *different_realm); + + int sssm_krb5_auth_init(struct be_ctx *bectx, struct bet_ops **ops, void **pvt_auth_data); diff --git a/src/tests/krb5_utils-tests.c b/src/tests/krb5_utils-tests.c index 5fee454..636bcd4 100644 --- a/src/tests/krb5_utils-tests.c +++ b/src/tests/krb5_utils-tests.c @@ -673,6 +673,47 @@ START_TEST(test_no_substitution) } END_TEST +START_TEST(test_compare_principal_realm) +{ + int ret; + bool different_realm; + + ret = compare_principal_realm(NULL, "a", &different_realm); + fail_unless(ret == EINVAL, "NULL upn does not cause EINVAL."); + + ret = compare_principal_realm("a", NULL, &different_realm); + fail_unless(ret == EINVAL, "NULL realm does not cause EINVAL."); + + ret = compare_principal_realm("a", "b", NULL); + fail_unless(ret == EINVAL, "NULL different_realmbool " \ + "does not cause EINVAL."); + + ret = compare_principal_realm("", "a", &different_realm); + fail_unless(ret == EINVAL, "Empty upn does not cause EINVAL."); + + ret = compare_principal_realm("a", "", &different_realm); + fail_unless(ret == EINVAL, "Empty realm does not cause EINVAL."); + + ret = compare_principal_realm("ABC", "ABC", &different_realm); + fail_unless(ret == EINVAL, "Short UPN does not cause EINVAL."); + + ret = compare_principal_realm("userABC", "ABC", &different_realm); + fail_unless(ret == EINVAL, "Missing '@' does not cause EINVAL."); + + fail_unless(different_realm == false, "Same realm but " \ + "different_realm is not false."); + ret = compare_principal_realm("user@ABC", "ABC", &different_realm); + fail_unless(ret == EOK, "Failure with same realm"); + fail_unless(different_realm == false, "Same realm but " \ + "different_realm is not false."); + + ret = compare_principal_realm("user@ABC", "DEF", &different_realm); + fail_unless(ret == EOK, "Failure with different realm"); + fail_unless(different_realm == true, "Different realm but " \ + "different_realm is not true."); +} +END_TEST + Suite *krb5_utils_suite (void) { Suite *s = suite_create ("krb5_utils"); @@ -713,6 +754,10 @@ Suite *krb5_utils_suite (void) } suite_add_tcase (s, tc_create_dir); + TCase *tc_krb5_helpers = tcase_create("Helper functions"); + tcase_add_test(tc_krb5_helpers, test_compare_principal_realm); + suite_add_tcase(s, tc_krb5_helpers); + return s; }