From af2ce7db9c51b7b058c5077801416f2757eb4896 Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy Date: Thu, 20 Aug 2015 15:06:12 +0300 Subject: client referral support for trusted domain principals https://fedorahosted.org/freeipa/ticket/3559 --- daemons/ipa-kdb/ipa_kdb.h | 8 +++++ daemons/ipa-kdb/ipa_kdb_mspac.c | 60 ++++++++++++++++++++++++++++++++++++ daemons/ipa-kdb/ipa_kdb_principals.c | 55 +++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+) diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h index 4abb7335d..a6f448150 100644 --- a/daemons/ipa-kdb/ipa_kdb.h +++ b/daemons/ipa-kdb/ipa_kdb.h @@ -274,6 +274,14 @@ krb5_error_code ipadb_check_transited_realms(krb5_context kcontext, const krb5_data *tr_contents, const krb5_data *client_realm, const krb5_data *server_realm); +/* Checks whether a principal's realm is one of trusted domains' realm or NetBIOS name + * and returns the realm of the matched trusted domain in 'trusted_domain' + * Returns 0 in case of success and KRB5_KDB_NOENTRY otherwise + * If DAL driver is not initialized, returns KRB5_KDB_DBNOTINITED */ +krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext, + const char *test_realm, size_t size, + char **trusted_realm); + /* DELEGATION CHECKS */ krb5_error_code ipadb_check_allowed_to_delegate(krb5_context kcontext, diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c index 3c0dca839..8594309db 100644 --- a/daemons/ipa-kdb/ipa_kdb_mspac.c +++ b/daemons/ipa-kdb/ipa_kdb_mspac.c @@ -2790,3 +2790,63 @@ krb5_error_code ipadb_check_transited_realms(krb5_context kcontext, } return ret; } + +/* Checks whether a principal's realm is one of trusted domains' realm or NetBIOS name + * and returns the realm of the matched trusted domain in 'trusted_domain' + * Returns 0 in case of success and KRB5_KDB_NOENTRY otherwise + * If DAL driver is not initialized, returns KRB5_KDB_DBNOTINITED */ +krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext, + const char *test_realm, size_t size, + char **trusted_realm) +{ + struct ipadb_context *ipactx; + int i, j, length; + const char *name; + + if (test_realm == NULL || test_realm[0] == '\0') { + return KRB5_KDB_NOENTRY; + } + + ipactx = ipadb_get_context(kcontext); + if (!ipactx || !ipactx->mspac) { + return KRB5_KDB_DBNOTINITED; + } + + /* First, compare realm with ours, it would not be from a trusted realm then */ + if (strncasecmp(test_realm, ipactx->realm, size) == 0) { + return KRB5_KDB_NOENTRY; + } + + if (!ipactx->mspac || !ipactx->mspac->trusts) { + return KRB5_KDB_NOENTRY; + } + + /* Iterate through list of trusts and check if input realm belongs to any of the trust */ + for(i = 0 ; i < ipactx->mspac->num_trusts ; i++) { + if ((strncasecmp(test_realm, + ipactx->mspac->trusts[i].domain_name, + size) == 0) || + (strncasecmp(test_realm, + ipactx->mspac->trusts[i].flat_name, + size) == 0)) { + /* return the realm if caller supplied a place for it */ + if (trusted_realm != NULL) { + name = (ipactx->mspac->trusts[i].parent_name != NULL) ? + ipactx->mspac->trusts[i].parent_name : + ipactx->mspac->trusts[i].domain_name; + length = strlen(name) + 1; + *trusted_realm = calloc(1, length); + if (*trusted_realm != NULL) { + for (j = 0; j < length; j++) { + (*trusted_realm)[j] = toupper(name[j]); + } + } else { + return KRB5_KDB_NOENTRY; + } + } + return 0; + } + } + + return KRB5_KDB_NOENTRY; +} diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c index b3f8b1ad7..f2a5a417e 100644 --- a/daemons/ipa-kdb/ipa_kdb_principals.c +++ b/daemons/ipa-kdb/ipa_kdb_principals.c @@ -1023,8 +1023,10 @@ krb5_error_code ipadb_get_principal(krb5_context kcontext, struct ipadb_context *ipactx; krb5_error_code kerr; char *principal = NULL; + char *trusted_realm = NULL; LDAPMessage *res = NULL; LDAPMessage *lentry; + krb5_db_entry *kentry = NULL; uint32_t pol; ipactx = ipadb_get_context(kcontext); @@ -1044,6 +1046,55 @@ krb5_error_code ipadb_get_principal(krb5_context kcontext, kerr = ipadb_find_principal(kcontext, flags, res, &principal, &lentry); if (kerr != 0) { + if ((kerr == KRB5_KDB_NOENTRY) && + ((flags & (KRB5_KDB_FLAG_CANONICALIZE | + KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY)) != 0)) { + + /* First check if we got enterprise principal which looks like + * username\@enterprise_realm@REALM */ + char *realm; + krb5_data *upn; + + upn = krb5_princ_component(kcontext, search_for, + krb5_princ_size(kcontext, search_for) - 1); + + if (upn == NULL) { + kerr = KRB5_KDB_NOENTRY; + goto done; + } + + realm = memrchr(upn->data, '@', upn->length); + if (realm == NULL) { + kerr = KRB5_KDB_NOENTRY; + goto done; + } + + /* skip '@' and use part after '@' as an enterprise realm for comparison */ + realm++; + + kerr = ipadb_is_princ_from_trusted_realm(kcontext, + realm, + upn->length - (realm - upn->data), + &trusted_realm); + if (kerr == 0) { + kentry = calloc(1, sizeof(krb5_db_entry)); + if (!kentry) { + kerr = ENOMEM; + goto done; + } + kerr = krb5_parse_name(kcontext, principal, + &kentry->princ); + if (kerr != 0) { + goto done; + } + + kerr = krb5_set_principal_realm(kcontext, kentry->princ, trusted_realm); + if (kerr != 0) { + goto done; + } + *entry = kentry; + } + } goto done; } @@ -1060,6 +1111,10 @@ krb5_error_code ipadb_get_principal(krb5_context kcontext, } done: + free(trusted_realm); + if ((kerr != 0) && (kentry != NULL)) { + ipadb_free_principal(kcontext, kentry); + } ldap_msgfree(res); krb5_free_unparsed_name(kcontext, principal); return kerr; -- cgit