From bfd099e148ed97394bc858e746a1a998a71ac43c Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 17 Jan 2007 18:25:35 +0000 Subject: r20857: Silence gives assent :-). Checking in the fix for site support in a network where many DC's are down. I heard via Volker there is still a bug w.r.t the wrong site being chosen with trusted domains but we'll have to layer that fix on top of this. Gd - complain if this doesn't work for you. Jeremy. (This used to be commit 97e248f89ac6548274f03f2ae7583a255da5ddb3) --- source3/libads/dns.c | 10 +++----- source3/libads/kerberos.c | 65 +++++++++++++++++++++++++++++++++++++---------- source3/libads/ldap.c | 19 ++++++++++++-- 3 files changed, 72 insertions(+), 22 deletions(-) (limited to 'source3/libads') diff --git a/source3/libads/dns.c b/source3/libads/dns.c index c8b3f29507..b67d802bdc 100644 --- a/source3/libads/dns.c +++ b/source3/libads/dns.c @@ -673,16 +673,16 @@ NTSTATUS ads_dns_query_internal(TALLOC_CTX *ctx, } /******************************************************************** - Query for AD DC's. Transparently use sitename. + Query for AD DC's. ********************************************************************/ NTSTATUS ads_dns_query_dcs(TALLOC_CTX *ctx, const char *realm, + const char *sitename, struct dns_rr_srv **dclist, int *numdcs ) { NTSTATUS status; - char *sitename = sitename_fetch(); status = ads_dns_query_internal(ctx, "_ldap", realm, sitename, dclist, numdcs); @@ -691,23 +691,22 @@ NTSTATUS ads_dns_query_dcs(TALLOC_CTX *ctx, status = ads_dns_query_internal(ctx, "_ldap", realm, NULL, dclist, numdcs); } - SAFE_FREE(sitename); return status; } /******************************************************************** - Query for AD KDC's. Transparently use sitename. + Query for AD KDC's. Even if our underlying kerberos libraries are UDP only, this is pretty safe as it's unlikely that a KDC supports TCP and not UDP. ********************************************************************/ NTSTATUS ads_dns_query_kdcs(TALLOC_CTX *ctx, const char *realm, + const char *sitename, struct dns_rr_srv **dclist, int *numdcs ) { NTSTATUS status; - char *sitename = sitename_fetch(); status = ads_dns_query_internal(ctx, "_kerberos", realm, sitename, dclist, numdcs); @@ -716,6 +715,5 @@ NTSTATUS ads_dns_query_kdcs(TALLOC_CTX *ctx, status = ads_dns_query_internal(ctx, "_kerberos", realm, NULL, dclist, numdcs); } - SAFE_FREE(sitename); return status; } diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c index 76866a8093..95eed6fe27 100644 --- a/source3/libads/kerberos.c +++ b/source3/libads/kerberos.c @@ -470,10 +470,11 @@ int kerberos_kinit_password(const char *principal, Does DNS queries. ************************************************************************/ -static char *get_kdc_ip_string(char *mem_ctx, const char *realm, struct in_addr primary_ip) +static char *get_kdc_ip_string(char *mem_ctx, const char *realm, const char *sitename, struct in_addr primary_ip) { - struct ip_service *ip_srv; - int count, i; + struct ip_service *ip_srv_site; + struct ip_service *ip_srv_nonsite; + int count_site, count_nonsite, i; char *kdc_str = talloc_asprintf(mem_ctx, "\tkdc = %s\n", inet_ntoa(primary_ip)); @@ -481,26 +482,61 @@ static char *get_kdc_ip_string(char *mem_ctx, const char *realm, struct in_addr return NULL; } - if (!NT_STATUS_IS_OK(get_kdc_list(realm, &ip_srv, &count))) { - DEBUG(10,("get_kdc_ip_string: get_kdc_list failed. Returning %s\n", - kdc_str )); - return kdc_str; + /* Get the KDC's only in this site. */ + + get_kdc_list(realm, sitename, &ip_srv_site, &count_site); + + for (i = 0; i < count_site; i++) { + if (ip_equal(ip_srv_site[i].ip, primary_ip)) { + continue; + } + /* Append to the string - inefficient but not done often. */ + kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n", + kdc_str, inet_ntoa(ip_srv_site[i].ip)); + if (!kdc_str) { + SAFE_FREE(ip_srv_site); + return NULL; + } } - for (i = 0; i < count; i++) { - if (ip_equal(ip_srv[i].ip, primary_ip)) { + /* Get all KDC's. */ + + get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite); + + for (i = 0; i < count_nonsite; i++) { + int j; + + if (ip_equal(ip_srv_nonsite[i].ip, primary_ip)) { + continue; + } + + /* Ensure this isn't an IP already seen (YUK! this is n*n....) */ + for (j = 0; j < count_site; j++) { + if (ip_equal(ip_srv_nonsite[i].ip, ip_srv_site[j].ip)) { + break; + } + /* As the lists are sorted we can break early if nonsite > site. */ + if (ip_service_compare(&ip_srv_nonsite[i], &ip_srv_site[j]) > 0) { + break; + } + } + if (j != i) { continue; } + /* Append to the string - inefficient but not done often. */ kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n", - kdc_str, inet_ntoa(ip_srv[i].ip)); + kdc_str, inet_ntoa(ip_srv_nonsite[i].ip)); if (!kdc_str) { - SAFE_FREE(ip_srv); + SAFE_FREE(ip_srv_site); + SAFE_FREE(ip_srv_nonsite); return NULL; } } - SAFE_FREE(ip_srv); + + SAFE_FREE(ip_srv_site); + SAFE_FREE(ip_srv_nonsite); DEBUG(10,("get_kdc_ip_string: Returning %s\n", kdc_str )); @@ -515,7 +551,8 @@ static char *get_kdc_ip_string(char *mem_ctx, const char *realm, struct in_addr run as root or will fail (which is a good thing :-). ************************************************************************/ -BOOL create_local_private_krb5_conf_for_domain(const char *realm, const char *domain, struct in_addr ip) +BOOL create_local_private_krb5_conf_for_domain(const char *realm, const char *domain, + const char *sitename, struct in_addr ip) { char *dname = talloc_asprintf(NULL, "%s/smb_krb5", lp_lockdir()); char *tmpname = NULL; @@ -556,7 +593,7 @@ BOOL create_local_private_krb5_conf_for_domain(const char *realm, const char *do realm_upper = talloc_strdup(fname, realm); strupper_m(realm_upper); - kdc_ip_string = get_kdc_ip_string(dname, realm, ip); + kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, ip); if (!kdc_ip_string) { TALLOC_FREE(dname); return False; diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index c263e8e133..2ceae4d957 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -249,6 +249,7 @@ static NTSTATUS ads_find_dc(ADS_STRUCT *ads) pstring realm; BOOL got_realm = False; BOOL use_own_domain = False; + char *sitename = sitename_fetch(); NTSTATUS status = NT_STATUS_UNSUCCESSFUL; /* if the realm and workgroup are both empty, assume they are ours */ @@ -279,6 +280,7 @@ again: } if ( !c_realm || !*c_realm ) { + SAFE_FREE(sitename); DEBUG(0,("ads_find_dc: no realm or workgroup! Don't know what to do\n")); return NT_STATUS_INVALID_PARAMETER; /* rather need MISSING_PARAMETER ... */ } @@ -289,7 +291,7 @@ again: DEBUG(6,("ads_find_dc: looking for %s '%s'\n", (got_realm ? "realm" : "domain"), realm)); - status = get_sorted_dc_list(realm, &ip_list, &count, got_realm); + status = get_sorted_dc_list(realm, sitename, &ip_list, &count, got_realm); if (!NT_STATUS_IS_OK(status)) { /* fall back to netbios if we can */ if ( got_realm && !lp_disable_netbios() ) { @@ -331,6 +333,7 @@ again: if ( ads_try_connect(ads, server) ) { SAFE_FREE(ip_list); + SAFE_FREE(sitename); return NT_STATUS_OK; } @@ -339,7 +342,19 @@ again: } SAFE_FREE(ip_list); - + + /* In case we failed to contact one of our closest DC on our site we + * need to try to find another DC, retry with a site-less SRV DNS query + * - Guenther */ + + if (sitename) { + DEBUG(1,("ads_find_dc: failed to find a valid DC on our site (%s), " + "trying to find another DC\n", sitename)); + SAFE_FREE(sitename); + namecache_delete(realm, 0x1C); + goto again; + } + return NT_STATUS_NO_LOGON_SERVERS; } -- cgit