diff options
| -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;  }  | 
