From 08d7d90ab0934ecefaaccf7866c73dca8ccf636f Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy Date: Mon, 18 Jan 2021 17:51:20 +0200 Subject: [PATCH] ipasam: derive parent domain for subdomains automatically [MS-ADTS] 6.1.6.7.13 defines 'trustPartner' attribute as containing a FQDN of the trusted domain. In practice, for a subdomain of a forest, it would be FQDN of the subdomain itself in the trusted domain entry in the parent domain. This is reflected as ipaNTTrustPartner attribute in FreeIPA. Remove ipaNTTrustPartner from the searches that use NetBIOS name. We match cn of that entry already. Use RDN value of the entry to derive DNS domain name in case ipaNTTrustPartner is missing. For subdomains, set trust attributes to 0 and trust flags to mark them as being within the forest. This will trigger winbindd to not ask for credentials to reach those domain controllers directly. Fixes: https://pagure.io/freeipa/issue/8576 Signed-off-by: Alexander Bokovoy Reviewed-By: Christian Heimes Reviewed-By: Rob Crittenden --- daemons/ipa-sam/ipa_sam.c | 82 +++++++++++++++++++++++++++++++++------ 1 file changed, 70 insertions(+), 12 deletions(-) diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c index c11e99177..06b1b7af4 100644 --- a/daemons/ipa-sam/ipa_sam.c +++ b/daemons/ipa-sam/ipa_sam.c @@ -2358,10 +2358,10 @@ static bool get_trusted_domain_by_name_int(struct ipasam_private *ipasam_state, bool ok; filter = talloc_asprintf(mem_ctx, - "(&(objectClass=%s)(|(%s=%s)(%s=%s)(cn=%s)))", + "(&(objectClass=%s)(|(%s=%s)(cn=%s)))", LDAP_OBJ_TRUSTED_DOMAIN, LDAP_ATTRIBUTE_FLAT_NAME, domain, - LDAP_ATTRIBUTE_TRUST_PARTNER, domain, domain); + domain); if (filter == NULL) { return false; } @@ -2431,16 +2431,74 @@ static bool fill_pdb_trusted_domain(TALLOC_CTX *mem_ctx, struct pdb_trusted_domain *td; struct dom_sid *sid = NULL; enum idmap_error_code err; + char *strdn = NULL; + char *dnl = NULL; + int rc = 0; + int count = 0; + char *dns_domain = NULL; + LDAPDN dn = NULL; if (entry == NULL) { return false; } - td = talloc_zero(mem_ctx, struct pdb_trusted_domain); - if (td == NULL) { + strdn = ldap_get_dn(priv2ld(ipasam_state), entry); + if (strdn == NULL) { + DEBUG(1, ("Couldn't retrieve DN of the trusted domain entry\n")); return false; } + dnl = strcasestr(strdn, ipasam_state->trust_dn); + if (dnl == NULL) { + DEBUG(1, ("DN %s of trusted domain entry is not under %s\n", + strdn, + ipasam_state->trust_dn)); + free(strdn); + return false; + } + + td = talloc_zero(mem_ctx, struct pdb_trusted_domain); + if (td == NULL) { + free(strdn); + return false; + } + + /* dnl points to the begining of cn=ad,cn=trusts,... and we need + * to go one character back and turn ',' into end of string. */ + dnl--; + dnl[0] = '\0'; + + /* Now strdn has at most two RDNs: + * - there is one RDN for the directly trusted one + * - there are two RDNs for a subdomain + */ + rc = ldap_str2dn(strdn, &dn, LDAP_DN_FORMAT_LDAPV3); + if (rc) { + free(strdn); + return false; + } + + for (count = 0; dn[count] != NULL; count++); + + /* For subdomains, we must set parent domain */ + if (count < 1 || count > 2) { + DEBUG(1, ("LDAP object with DN %s,%s " + "cannot be used as a trusted domain\n", + strdn, ipasam_state->trust_dn)); + ldap_dnfree(dn); + free(strdn); + TALLOC_FREE(td); + return false; + + } + + dns_domain = talloc_asprintf(td, "%*s", + (int)dn[0][0]->la_value.bv_len, + dn[0][0]->la_value.bv_val); + + ldap_dnfree(dn); + free(strdn); + /* All attributes are MAY */ dummy = get_single_attribute(NULL, priv2ld(ipasam_state), entry, @@ -2479,13 +2537,16 @@ static bool fill_pdb_trusted_domain(TALLOC_CTX *mem_ctx, LDAP_ATTRIBUTE_FLAT_NAME)); } + /* If ipaNTTrustPartner is missing, it should be the same as the domain + * itself. */ td->domain_name = get_single_attribute(td, priv2ld(ipasam_state), entry, LDAP_ATTRIBUTE_TRUST_PARTNER); if (td->domain_name == NULL) { - DEBUG(9, ("Attribute %s not present.\n", - LDAP_ATTRIBUTE_TRUST_PARTNER)); + td->domain_name = dns_domain; } + /* For subdomains ipaNTTrustDirection is missing which is OK, we + * default to 0 */ res = get_uint32_t_from_ldap_msg(ipasam_state, entry, LDAP_ATTRIBUTE_TRUST_DIRECTION, &td->trust_direction); @@ -2493,10 +2554,6 @@ static bool fill_pdb_trusted_domain(TALLOC_CTX *mem_ctx, TALLOC_FREE(td); return false; } - if (td->trust_direction == 0) { - /* attribute wasn't present, set default value */ - td->trust_direction = LSA_TRUST_DIRECTION_INBOUND | LSA_TRUST_DIRECTION_OUTBOUND; - } res = get_uint32_t_from_ldap_msg(ipasam_state, entry, LDAP_ATTRIBUTE_TRUST_ATTRIBUTES, @@ -2506,8 +2563,9 @@ static bool fill_pdb_trusted_domain(TALLOC_CTX *mem_ctx, return false; } if (td->trust_attributes == 0) { - /* attribute wasn't present, set default value */ - td->trust_attributes = LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE; + /* attribute wasn't present, this is a subdomain within the + * parent forest */ + td->trust_attributes = LSA_TRUST_ATTRIBUTE_WITHIN_FOREST; } res = get_uint32_t_from_ldap_msg(ipasam_state, entry,