Hi,

the attached two patches are a proof-of-concept how we can eliminate the
need to have [capaths] defined in krb5.conf for member domains in
trusted forests together with Alexander's patch 0123.

capaths are used in the core KDC code at two places. One is to validate
transited field in the TGT, this is handled by Alexander's patch.

The other is to find out where to redirect a client asking for a cross
realm TGT for a realm we do not shared credential with but know and
trust a realm which can handle this. This is typically the case for
member domains(realms) in a trusted forest. We share credentials with
the forest root but not with the members but we know that the forest
root can handle requests for its member domains.

The patches are just proof-of-concept because I'm currently not sure if
this is kerberos-wise the right way to handle it. Additionally we might
want to enhance the patches to handle to more broader use case of
transitive-trusts.

Please note that for the time being there is a workaround implemented in
SSSD to add a suitable [capaths] section to the krb5.conf include file
managed by SSSD.

bye,
Sumit
From 73893a102c300627f7977afaf482ee83afc2a161 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@redhat.com>
Date: Wed, 2 Oct 2013 11:44:32 +0200
Subject: [PATCH 1/2] ipa-kdb: add transit_realm member to trusted domains

To be able to handle requests for member domains in a trusted forest we
must know which forest the domain belongs to. Because we only share
credentials with the forest root all request for member domains must go
through (transit) the KDC of the forest root. This will also be true for
other forests which are trusted by the forest we trust. But the patch
does not handle this case because it is currently not clear how
transitively trusted forests will be stored in the directory tree.
---
 daemons/ipa-kdb/ipa_kdb_mspac.c | 86 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)

diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
index 27d50ac..ce9b06a 100644
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
@@ -32,6 +32,7 @@ struct ipadb_adtrusts {
     char *domain_name;
     char *flat_name;
     char *domain_sid;
+    char *transit_realm;
     struct dom_sid domsid;
     struct dom_sid *sid_blacklist_incoming;
     int len_sid_blacklist_incoming;
@@ -2119,6 +2120,7 @@ void ipadb_mspac_struct_free(struct ipadb_mspac **mspac)
             free((*mspac)->trusts[i].domain_name);
             free((*mspac)->trusts[i].flat_name);
             free((*mspac)->trusts[i].domain_sid);
+            free((*mspac)->trusts[i].transit_realm);
             free((*mspac)->trusts[i].sid_blacklist_incoming);
             free((*mspac)->trusts[i].sid_blacklist_outgoing);
         }
@@ -2209,6 +2211,84 @@ done:
     return ret;
 }
 
+static int get_transit_realm(LDAP *lc, LDAPMessage *le, char **transit_realm)
+{
+    char *dn_str = NULL;
+    char *val = NULL;
+    LDAPDN dn;
+    int ret;
+    size_t num_vals;
+    char *p;
+
+    dn_str = ldap_get_dn(lc, le);
+    if (dn_str == NULL) {
+        ret = EINVAL;
+        goto done;
+    }
+
+    ret = ldap_str2dn(dn_str, &dn, LDAP_DN_FORMAT_LDAPV3);
+    if (ret != LDAP_SUCCESS) {
+        ret = EINVAL;
+        goto done;
+    }
+
+    for (num_vals = 0; dn != NULL && dn[num_vals] != NULL; num_vals++);
+    if (num_vals < 5) {
+        /* we are only interested in the children of a forest root object */
+        ret = 0;
+        *transit_realm = NULL;
+        goto done;
+    }
+
+    ret = ldap_rdn2str(dn[2], &val, LDAP_DN_FORMAT_UFN);
+    if (ret != LDAP_SUCCESS) {
+        ret = EINVAL;
+        goto done;
+    }
+    if (strcmp(val, "ad") != 0) {
+        ret = 0;
+        *transit_realm = NULL;
+        goto done;
+    }
+
+    ldap_memfree(val);
+    ret = ldap_rdn2str(dn[3], &val, LDAP_DN_FORMAT_UFN);
+    if (ret != LDAP_SUCCESS) {
+        ret = EINVAL;
+        goto done;
+    }
+    if (strcmp(val, "trusts") != 0) {
+        ret = 0;
+        *transit_realm = NULL;
+        goto done;
+    }
+
+    ldap_memfree(val);
+    ret = ldap_rdn2str(dn[1], &val, LDAP_DN_FORMAT_UFN);
+    if (ret != LDAP_SUCCESS) {
+        ret = EINVAL;
+        goto done;
+    }
+    *transit_realm = strdup(val);
+    if (*transit_realm == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    for (p = *transit_realm; *p; p++) {
+        *p = toupper(*p);
+    }
+
+    ret = 0;
+
+done:
+    ldap_memfree(val);
+    ldap_dnfree(dn);
+    ldap_memfree(dn_str);
+
+    return ret;
+}
+
 krb5_error_code ipadb_mspac_get_trusted_domains(struct ipadb_context *ipactx)
 {
     struct ipadb_adtrusts *t;
@@ -2280,6 +2360,12 @@ krb5_error_code ipadb_mspac_get_trusted_domains(struct 
ipadb_context *ipactx)
             goto done;
         }
 
+        ret = get_transit_realm(lc, le, &t[n].transit_realm);
+        if (ret) {
+            ret = EINVAL;
+            goto done;
+        }
+
         ret = ipadb_ldap_attr_to_strlist(lc, le, "ipaNTSIDBlacklistIncoming",
                                          &sid_blacklist_incoming);
 
-- 
1.8.1.4

From 50c6e3b90981dfcb38c3b7f8889be6f050a599c7 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@redhat.com>
Date: Wed, 2 Oct 2013 11:45:27 +0200
Subject: [PATCH 2/2] ipa-kdb: check for alternatives if cross realm TGT cannot
 be found

If an IPA client wants to access a service from the member domain of a
trusted forest it will first try to get a cross realm TGT for this
domain, e.g. krbtgt/member.ad....@ipa.dom. But IPA will only share
credentials with the forest root and hence only have
krbtgt/ad....@ipa.dom. But the KDC of the forest root has credentials
for it's member domains.

With this patch for every cross realm ticket which cannot be found in
the directory tree we check if there is a transit realm which might be
able to handle this request further. If this is the case we send a cross
realm TGT for the transit realm back to the client. Although this is the
same behaviour as can be seen when using [capaths] in krb5.conf I'm
currently not sure if this is really the right behaviour. It needs
further discussion.
---
 daemons/ipa-kdb/ipa_kdb.h            |  9 +++++
 daemons/ipa-kdb/ipa_kdb_mspac.c      | 66 ++++++++++++++++++++++++++++++++++++
 daemons/ipa-kdb/ipa_kdb_principals.c | 13 ++++---
 3 files changed, 83 insertions(+), 5 deletions(-)

diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
index 1c2aefc..8eb9247 100644
--- a/daemons/ipa-kdb/ipa_kdb.h
+++ b/daemons/ipa-kdb/ipa_kdb.h
@@ -163,6 +163,11 @@ int ipadb_ldap_attr_has_value(LDAP *lcontext, LDAPMessage 
*le,
 int ipadb_ldap_deref_results(LDAP *lcontext, LDAPMessage *le,
                              LDAPDerefRes **results);
 
+krb5_error_code ipadb_check_for_alternative_tgs(struct ipadb_context *ipactx,
+                                                unsigned int flags,
+                                                char **principal,
+                                                LDAPMessage **result);
+
 /* PRINCIPALS FUNCTIONS */
 krb5_error_code ipadb_get_principal(krb5_context kcontext,
                                     krb5_const_principal search_for,
@@ -178,6 +183,10 @@ krb5_error_code ipadb_iterate(krb5_context kcontext,
                               char *match_entry,
                               int (*func)(krb5_pointer, krb5_db_entry *),
                               krb5_pointer func_arg);
+krb5_error_code ipadb_fetch_principals(struct ipadb_context *ipactx,
+                                       unsigned int flags,
+                                       char *principal,
+                                       LDAPMessage **result);
 
 /* POLICY FUNCTIONS */
 
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
index ce9b06a..39259dd 100644
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
@@ -2211,6 +2211,72 @@ done:
     return ret;
 }
 
+krb5_error_code ipadb_check_for_alternative_tgs(struct ipadb_context *ipactx,
+                                                unsigned int flags,
+                                                char **principal,
+                                                LDAPMessage **result)
+{
+    krb5_error_code kerr;
+    krb5_principal princ;
+    char *new_principal = NULL;
+    int ret;
+    size_t c;
+
+    if (!ipactx->kcontext) {
+        kerr = KRB5_KDB_SERVER_INTERNAL_ERR;
+        goto done;
+    }
+
+    kerr = krb5_parse_name(ipactx->kcontext, *principal, &princ);
+    if (!is_cross_realm_krbtgt(princ)) {
+        kerr = KRB5_KDB_NOENTRY;
+        goto done;
+    }
+
+    for (c = 0; c < ipactx->mspac->num_trusts; c++) {
+        if (strncasecmp(ipactx->mspac->trusts[c].domain_name,
+                        princ->data[1].data, princ->data[1].length) == 0) {
+            if (ipactx->mspac->trusts[c].transit_realm == NULL) {
+                kerr = KRB5_KDB_NOENTRY;
+                goto done;
+            }
+
+            ret = asprintf(&new_principal, "krbtgt/%s@%.*s",
+                           ipactx->mspac->trusts[c].transit_realm,
+                           princ->realm.length, princ->realm.data);
+            if (ret == -1) {
+                new_principal = NULL;
+                kerr = KRB5_KDB_INTERNAL_ERROR;
+                goto done;
+            }
+
+            break;
+        }
+    }
+
+    if (new_principal == NULL) {
+        kerr = KRB5_KDB_NOENTRY;
+        goto done;
+    }
+
+    kerr = ipadb_fetch_principals(ipactx, flags, new_principal, result);
+
+    if (kerr == 0) {
+        free(*principal);
+        *principal = strdup(new_principal);
+        if (*principal == NULL) {
+            kerr = KRB5_KDB_INTERNAL_ERROR;
+            goto done;
+        }
+    }
+
+done:
+    free(new_principal);
+    krb5_free_principal(ipactx->kcontext, princ);
+
+    return kerr;
+}
+
 static int get_transit_realm(LDAP *lc, LDAPMessage *le, char **transit_realm)
 {
     char *dn_str = NULL;
diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c 
b/daemons/ipa-kdb/ipa_kdb_principals.c
index 38059d2..e56e29d 100644
--- a/daemons/ipa-kdb/ipa_kdb_principals.c
+++ b/daemons/ipa-kdb/ipa_kdb_principals.c
@@ -557,10 +557,10 @@ done:
     return kerr;
 }
 
-static krb5_error_code ipadb_fetch_principals(struct ipadb_context *ipactx,
-                                              unsigned int flags,
-                                              char *principal,
-                                              LDAPMessage **result)
+krb5_error_code ipadb_fetch_principals(struct ipadb_context *ipactx,
+                                       unsigned int flags,
+                                       char *principal,
+                                       LDAPMessage **result)
 {
     krb5_error_code kerr;
     char *src_filter = NULL;
@@ -828,7 +828,10 @@ krb5_error_code ipadb_get_principal(krb5_context kcontext,
     }
 
     kerr = ipadb_fetch_principals(ipactx, flags, principal, &res);
-    if (kerr != 0) {
+    if (kerr == KRB5_KDB_NOENTRY
+            || ldap_count_entries(ipactx->lcontext, res) == 0) {
+        kerr = ipadb_check_for_alternative_tgs(ipactx, flags, &principal, 
&res);
+    } else if (kerr != 0) {
         goto done;
     }
 
-- 
1.8.1.4

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to