diff options
Diffstat (limited to 'source3')
-rw-r--r-- | source3/nsswitch/winbindd_cm.c | 168 |
1 files changed, 110 insertions, 58 deletions
diff --git a/source3/nsswitch/winbindd_cm.c b/source3/nsswitch/winbindd_cm.c index 02162bbd23..3175860a79 100644 --- a/source3/nsswitch/winbindd_cm.c +++ b/source3/nsswitch/winbindd_cm.c @@ -90,12 +90,113 @@ struct get_dc_name_cache { struct get_dc_name_cache *prev, *next; }; + +/* + find the DC for a domain using methods appropriate for a ADS domain +*/ +static BOOL cm_ads_find_dc(const char *domain, struct in_addr *dc_ip, fstring srv_name) +{ + ADS_STRUCT *ads; + ads = ads_init_simple(); + if (!ads) { + return False; + } + + DEBUG(4,("cm_ads_find_dc: realm=%s\n", ads->realm)); + +#ifdef HAVE_ADS + /* a full ads_connect() is actually overkill, as we don't srictly need + to do the SASL auth in order to get the info we need, but libads + doesn't offer a better way right now */ + ads_connect(ads); +#endif + + fstrcpy(srv_name, ads->ldap_server_name); + strupper(srv_name); + *dc_ip = ads->ldap_ip; + ads_destroy(&ads); + + if (!*srv_name || is_zero_ip(*dc_ip)) { + return False; + } + + DEBUG(4,("cm_ads_find_dc: using server='%s' IP=%s\n", + srv_name, inet_ntoa(*dc_ip))); + + return True; +} + +/* + find the DC for a domain using methods appropriate for a RPC domain +*/ +static BOOL cm_rpc_find_dc(const char *domain, struct in_addr *dc_ip, fstring srv_name) +{ + struct in_addr *ip_list = NULL; + int count, i; + + /* Lookup domain controller name. Try the real PDC first to avoid + SAM sync delays */ + if (!get_dc_list(True, domain, &ip_list, &count)) { + if (!get_dc_list(False, domain, &ip_list, &count)) { + DEBUG(3, ("Could not look up dc's for domain %s\n", domain)); + return False; + } + } + + /* Pick a nice close server */ + /* Look for DC on local net */ + for (i = 0; i < count; i++) { + if (!is_local_net(ip_list[i])) + continue; + + if (name_status_find(domain, 0x1c, 0x20, ip_list[i], srv_name)) { + *dc_ip = ip_list[i]; + SAFE_FREE(ip_list); + return True; + } + zero_ip(&ip_list[i]); + } + + /* + * Secondly try and contact a random PDC/BDC. + */ + + i = (sys_random() % count); + + if (!is_zero_ip(ip_list[i]) && + name_status_find(domain, 0x1c, 0x20, + ip_list[i], srv_name)) { + *dc_ip = ip_list[i]; + SAFE_FREE(ip_list); + return True; + } + zero_ip(&ip_list[i]); /* Tried and failed. */ + + /* Finally return first DC that we can contact using a node + status */ + for (i = 0; i < count; i++) { + if (is_zero_ip(ip_list[i])) + continue; + + if (name_status_find(domain, 0x1c, 0x20, ip_list[i], srv_name)) { + *dc_ip = ip_list[i]; + SAFE_FREE(ip_list); + return True; + } + } + + SAFE_FREE(ip_list); + + return False; +} + + static BOOL cm_get_dc_name(const char *domain, fstring srv_name, struct in_addr *ip_out) { static struct get_dc_name_cache *get_dc_name_cache; struct get_dc_name_cache *dcc; - struct in_addr *ip_list, dc_ip; - int count, i; + struct in_addr dc_ip; + BOOL ret; /* Check the cache for previous lookups */ @@ -144,66 +245,19 @@ static BOOL cm_get_dc_name(const char *domain, fstring srv_name, struct in_addr DLIST_ADD(get_dc_name_cache, dcc); - /* Lookup domain controller name. Try the real PDC first to avoid - SAM sync delays */ - if (!get_dc_list(True, domain, &ip_list, &count)) { - if (!get_dc_list(False, domain, &ip_list, &count)) { - DEBUG(3, ("Could not look up dc's for domain %s\n", domain)); - return False; - } - } - - /* Pick a nice close server */ - /* Look for DC on local net */ - - for (i = 0; i < count; i++) { - if (!is_local_net(ip_list[i])) - continue; - - if (name_status_find(domain, 0x1c, 0x20, ip_list[i], srv_name)) { - dc_ip = ip_list[i]; - goto done; - } - zero_ip(&ip_list[i]); - } - - /* - * Secondly try and contact a random PDC/BDC. - */ - - i = (sys_random() % count); + zero_ip(&dc_ip); - if (!is_zero_ip(ip_list[i]) && - name_status_find(domain, 0x1c, 0x20, - ip_list[i], srv_name)) { - dc_ip = ip_list[i]; - goto done; + if (lp_security() == SEC_ADS) { + ret = cm_ads_find_dc(domain, &dc_ip, srv_name); + } else { + ret = cm_rpc_find_dc(domain, &dc_ip, srv_name); } - zero_ip(&ip_list[i]); /* Tried and failed. */ - - /* Finally return first DC that we can contact */ - for (i = 0; i < count; i++) { - if (is_zero_ip(ip_list[i])) - continue; - - if (name_status_find(domain, 0x1c, 0x20, ip_list[i], srv_name)) { - dc_ip = ip_list[i]; - goto done; - } + if (!ret) { + return False; } - /* No-one to talk to )-: */ - return False; /* Boo-hoo */ - - done: - /* We have the netbios name and IP address of a domain controller. - Ideally we should sent a SAMLOGON request to determine whether - the DC is alive and kicking. If we can catch a dead DC before - performing a cli_connect() we can avoid a 30-second timeout. */ - /* We have a name so make the cache entry positive now */ - fstrcpy(dcc->srv_name, srv_name); DEBUG(3, ("cm_get_dc_name: Returning DC %s (%s) for domain %s\n", srv_name, @@ -211,8 +265,6 @@ static BOOL cm_get_dc_name(const char *domain, fstring srv_name, struct in_addr *ip_out = dc_ip; - SAFE_FREE(ip_list); - return True; } |