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.


--
/ Alexander Bokovoy
From 22cdeeb87e82b13d518c1514a5a4feb84c5a6e16 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <aboko...@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 | 47 ++++++++++++++++++++++++++++
 3 files changed, 115 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..d4aa2dd 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,47 @@ 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, *enterprise_realm;
+
+            realm = strrchr(principal, '@');
+            enterprise_realm = strchr(principal, '@');
+            if ((realm == NULL) || (*realm == '\0') || (realm == 
enterprise_realm)) {
+                kerr = KRB5_KDB_NOENTRY;
+                goto done;
+            }
+
+            /* skip '@' and use part between '@' and '@' as enterprise realm 
for comparison */
+            enterprise_realm++;
+
+            kerr = ipadb_is_princ_from_trusted_realm(kcontext,
+                                                     enterprise_realm,
+                                                     (realm - 
enterprise_realm),
+                                                     &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 +1103,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

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to