[Freeipa-devel] [PATCH] 0197 client referral support for trusted domain principal
Alexander Bokovoy
abokovoy at redhat.com
Thu Sep 3 15:22:05 UTC 2015
On Thu, 03 Sep 2015, Alexander Bokovoy wrote:
> Hi,
>
> attached patch adds support for issuing client referrals when FreeIPA
> KDC is asked to give a TGT for a principal from a trusted forest.
>
> We return a matching forest name as a realm and KDC then returns an
> error pointing a client to a direction of that realm. You can see how it
> looks with http://fpaste.org/263064/14412849/ -- it shows behavior for
> both 'kinit -E -C' and 'kinit -E'.
>
> Note that current MIT Kerberos KDC has a bug that prevents us from
> responding with a correct client referral. A patched version for Fedora
> 22 is available in COPR abbra/krb5-test, a fix to upstream krb5 is
> https://github.com/krb5/krb5/pull/323/ and I'm working on filing bugs to
> Fedora and RHEL versions.
>
> With the version in my abbra/krb5-test COPR you can test the patch with
> the help of kinit like fpaste URL above shows.
After discussing with Simo and Sumit, here is updated patch that
operates directly on 'search_for' krb5_principal and avoids
strchr()/strrchr() and additional memory allocations -- it uses
memrchr() to find '@' in the last component of the search_for principal
and considers the part of the component after '@' as an enterprise realm
to check.
--
/ Alexander Bokovoy
-------------- next part --------------
From af2ce7db9c51b7b058c5077801416f2757eb4896 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy at redhat.com>
Date: Thu, 20 Aug 2015 15:06:12 +0300
Subject: [PATCH] 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 4abb733..a6f4481 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 3c0dca8..8594309 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 b3f8b1a..f2a5a41 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 at 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;
--
2.4.3
More information about the Freeipa-devel
mailing list