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