diff options
| -rw-r--r-- | source3/auth/auth_domain.c | 2 | ||||
| -rw-r--r-- | source3/libsmb/namecache.c | 83 | ||||
| -rw-r--r-- | source3/libsmb/namequery.c | 39 | ||||
| -rw-r--r-- | source3/libsmb/namequery_dc.c | 95 | ||||
| -rw-r--r-- | source3/nsswitch/winbindd_cm.c | 7 | 
5 files changed, 188 insertions, 38 deletions
diff --git a/source3/auth/auth_domain.c b/source3/auth/auth_domain.c index 2991684280..f1575e43b0 100644 --- a/source3/auth/auth_domain.c +++ b/source3/auth/auth_domain.c @@ -276,7 +276,7 @@ static NTSTATUS find_connect_dc(struct cli_state **cli,  	struct in_addr dc_ip;  	fstring srv_name; -	if (!rpc_find_dc(domain, srv_name, &dc_ip)) { +	if (!get_dc_name(domain, srv_name, &dc_ip)) {  		DEBUG(0,("find_connect_dc: Failed to find an DCs for %s\n", lp_workgroup()));  		return NT_STATUS_NO_LOGON_SERVERS;  	} diff --git a/source3/libsmb/namecache.c b/source3/libsmb/namecache.c index d3541b7719..7a0eb5212a 100644 --- a/source3/libsmb/namecache.c +++ b/source3/libsmb/namecache.c @@ -143,10 +143,19 @@ BOOL namecache_store(const char *name, int name_type,  	 * out of action for the entire cache timeout time!  	 */ +#if 0 +	        /* +		 * I don't think we need to do this. We are +		 * checking at a higher level for failed DC +		 * connections. JRA. +		 */ +  	if (name_type == 0x1b || name_type == 0x1c)  		expiry = time(NULL) + 10;  	else  		expiry = time(NULL) + lp_name_cache_timeout(); +#endif +	expiry = time(NULL) + lp_name_cache_timeout();  	/*  	 * Generate string representation of ip addresses list @@ -201,7 +210,9 @@ BOOL namecache_fetch(const char *name, int name_type, struct in_addr **ip_list,  	if (!gencache_get(key, &value, &timeout)) {  		DEBUG(5, ("no entry for %s#%02X found.\n", name, name_type)); +		gencache_del(key);  		SAFE_FREE(key); +		SAFE_FREE(value);		   		return False;  	} else {  		DEBUG(5, ("name %s#%02X found.\n", name, name_type)); @@ -252,3 +263,75 @@ void namecache_flush(void)  	DEBUG(5, ("Namecache flushed\n"));  } +/* Construct a name status record key. */ + +static char *namecache_status_record_key(const char *name, int name_type1, +				int name_type2, struct in_addr keyip) +{ +	char *keystr; + +	asprintf(&keystr, "NBT/%s#%02X.%02X.%s", +			strupper_static(name), name_type1, name_type2, inet_ntoa(keyip)); +	return keystr; +} + +/* Store a name status record. */ + +BOOL namecache_status_store(const char *keyname, int keyname_type, +		int name_type, struct in_addr keyip, +		const char *srvname) +{ +	char *key; +	time_t expiry; +	BOOL ret; + +	if (!gencache_init()) +		return False; + +	key = namecache_status_record_key(keyname, keyname_type, name_type, keyip); +	if (!key) +		return False; + +	expiry = time(NULL) + lp_name_cache_timeout(); +	ret = gencache_set(key, srvname, expiry); + +	if (ret) +		DEBUG(5, ("namecache_status_store: entry %s -> %s\n", key, srvname )); +	else +		DEBUG(5, ("namecache_status_store: entry %s store failed.\n", key )); + +	SAFE_FREE(key); +	return ret; +} + +/* Fetch a name status record. */ + +BOOL namecache_status_fetch(const char *keyname, int keyname_type, +			int name_type, struct in_addr keyip, char *srvname_out) +{ +	char *key = NULL; +	char *value = NULL; +	time_t timeout; + +	if (!gencache_init()) +		return False; + +	key = namecache_status_record_key(keyname, keyname_type, name_type, keyip); +	if (!key) +		return False; + +	if (!gencache_get(key, &value, &timeout)) { +		DEBUG(5, ("namecache_status_fetch: no entry for %s found.\n", key)); +		gencache_del(key); +		SAFE_FREE(key); +		SAFE_FREE(value); +		return False; +	} else { +		DEBUG(5, ("namecache_status_fetch: key %s -> %s\n", key, value )); +	} + +	strlcpy(srvname_out, value, 16); +	SAFE_FREE(key); +	SAFE_FREE(value); +	return True; +} diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c index 18ce5e4bd9..7f343033d6 100644 --- a/source3/libsmb/namequery.c +++ b/source3/libsmb/namequery.c @@ -25,8 +25,9 @@  BOOL global_in_nmbd = False;  /**************************************************************************** -generate a random trn_id + Generate a random trn_id.  ****************************************************************************/ +  static int generate_trn_id(void)  {  	static int trn_id; @@ -40,10 +41,10 @@ static int generate_trn_id(void)  	return trn_id % (unsigned)0x7FFF;  } -  /**************************************************************************** - parse a node status response into an array of structures + Parse a node status response into an array of structures.  ****************************************************************************/ +  static struct node_status *parse_node_status(char *p, int *num_names)  {  	struct node_status *ret; @@ -51,7 +52,8 @@ static struct node_status *parse_node_status(char *p, int *num_names)  	*num_names = CVAL(p,0); -	if (*num_names == 0) return NULL; +	if (*num_names == 0) +		return NULL;  	ret = (struct node_status *)malloc(sizeof(struct node_status)* (*num_names));  	if (!ret) return NULL; @@ -71,9 +73,10 @@ static struct node_status *parse_node_status(char *p, int *num_names)  /**************************************************************************** -do a NBT node status query on an open socket and return an array of -structures holding the returned names or NULL if the query failed + Do a NBT node status query on an open socket and return an array of + structures holding the returned names or NULL if the query failed.  **************************************************************************/ +  struct node_status *node_status_query(int fd,struct nmb_name *name,  				      struct in_addr to_ip, int *num_names)  { @@ -155,11 +158,9 @@ struct node_status *node_status_query(int fd,struct nmb_name *name,  	return NULL;  } -  /**************************************************************************** -find the first type XX name in a node status reply - used for finding -a servers name given its IP -return the matched name in *name + Find the first type XX name in a node status reply - used for finding + a servers name given its IP. Return the matched name in *name.  **************************************************************************/  BOOL name_status_find(const char *q_name, int q_type, int type, struct in_addr to_ip, char *name) @@ -178,6 +179,11 @@ BOOL name_status_find(const char *q_name, int q_type, int type, struct in_addr t  	DEBUG(10, ("name_status_find: looking up %s#%02x at %s\n", q_name,   		   q_type, inet_ntoa(to_ip))); +	/* Check the cache first. */ + +	if (namecache_status_fetch(q_name, q_type, type, to_ip, name)) +		return True; +  	sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True);  	if (sock == -1)  		goto done; @@ -197,6 +203,10 @@ BOOL name_status_find(const char *q_name, int q_type, int type, struct in_addr t  		goto done;  	pull_ascii(name, status[i].name, 16, 15, STR_TERMINATE); + +	/* Store the result in the cache. */ +	namecache_status_store(q_name, q_type, type, to_ip, name); +  	result = True;   done: @@ -205,17 +215,17 @@ BOOL name_status_find(const char *q_name, int q_type, int type, struct in_addr t  	DEBUG(10, ("name_status_find: name %sfound", result ? "" : "not "));  	if (result) -		DEBUGADD(10, (", ip address is %s", inet_ntoa(to_ip))); +		DEBUGADD(10, (", name %s ip address is %s", name, inet_ntoa(to_ip)));  	DEBUG(10, ("\n"));	  	return result;  } -  /*    comparison function used by sort_ip_list  */ +  int ip_compare(struct in_addr *ip1, struct in_addr *ip2)  {  	int max_bits1=0, max_bits2=0; @@ -248,6 +258,7 @@ int ip_compare(struct in_addr *ip1, struct in_addr *ip2)    are at the top. This prevents the problem where a WINS server returns an IP that    is not reachable from our subnet as the first match  */ +  static void sort_ip_list(struct in_addr *iplist, int count)  {  	if (count <= 1) { @@ -257,13 +268,13 @@ static void sort_ip_list(struct in_addr *iplist, int count)  	qsort(iplist, count, sizeof(struct in_addr), QSORT_CAST ip_compare);	  } -  /****************************************************************************   Do a netbios name query to find someones IP.   Returns an array of IP addresses or NULL if none.   *count will be set to the number of addresses returned.   *timed_out is set if we failed by timing out  ****************************************************************************/ +  struct in_addr *name_query(int fd,const char *name,int name_type,   			   BOOL bcast,BOOL recurse,  			   struct in_addr to_ip, int *count, int *flags, @@ -611,6 +622,7 @@ BOOL name_resolve_bcast(const char *name, int name_type,  /********************************************************   Resolve via "wins" method.  *********************************************************/ +  BOOL resolve_wins(const char *name, int name_type,  		  struct in_addr **return_iplist, int *return_count)  { @@ -1377,4 +1389,3 @@ BOOL get_dc_list(const char *domain, struct in_addr **ip_list, int *count, int *  	return internal_resolve_name(domain, 0x1C, ip_list, count);  } - diff --git a/source3/libsmb/namequery_dc.c b/source3/libsmb/namequery_dc.c index e98b728963..c162e34027 100644 --- a/source3/libsmb/namequery_dc.c +++ b/source3/libsmb/namequery_dc.c @@ -156,12 +156,11 @@ void flush_negative_conn_cache( void )  }  /**************************************************************************** - Utility function to return the name of a DC using RPC. The name is  - guaranteed to be valid since we have already done a name_status_find on it  - and we have checked our negative connection cache + Utility function to return the name of a DC. The name is guaranteed to be  + valid since we have already done a name_status_find on it    ***************************************************************************/ -  -BOOL rpc_find_dc(const char *domain, fstring srv_name, struct in_addr *ip_out) + +BOOL get_dc_name(const char *domain, fstring srv_name, struct in_addr *ip_out)  {  	struct in_addr *ip_list = NULL, dc_ip, exclude_ip;  	int count, i; @@ -177,10 +176,12 @@ BOOL rpc_find_dc(const char *domain, fstring srv_name, struct in_addr *ip_out)  	if ( use_pdc_only && get_pdc_ip(domain, &dc_ip) )   	{ -		DEBUG(10,("rpc_find_dc: Atempting to lookup PDC to avoid sam sync delays\n")); +		DEBUG(10,("get_dc_name: Atempting to lookup PDC to avoid sam sync delays\n")); -		if (name_status_find(domain, 0x1c, 0x20, dc_ip, srv_name)) { -			/* makre we we haven't tried this on previously and failed */ +		/* check the connection cache and perform the node status  +		   lookup only if the IP is not found to be bad */ + +		if (name_status_find(domain, 0x1c, 0x20, dc_ip, srv_name) ) {  			result = check_negative_conn_cache( domain, srv_name );  			if ( NT_STATUS_IS_OK(result) )  				goto done; @@ -205,11 +206,71 @@ BOOL rpc_find_dc(const char *domain, fstring srv_name, struct in_addr *ip_out)  		}  	} -	/* Pick a nice close server, but only if the list was not ordered */ -	if (!list_ordered && (count > 1) ) { -		qsort(ip_list, count, sizeof(struct in_addr), QSORT_CAST ip_compare); +	if ( !list_ordered )  +	{ +		/*  +		 * Pick a nice close server. Look for DC on local net  +		 * (assuming we don't have a list of preferred DC's) +		 */ +		  +		for (i = 0; i < count; i++) { +			if (is_zero_ip(ip_list[i])) +				continue; + +			if ( !is_local_net(ip_list[i]) ) +				continue; +		 +			if (name_status_find(domain, 0x1c, 0x20, ip_list[i], srv_name)) { +				result = check_negative_conn_cache( domain, srv_name ); +				if ( NT_STATUS_IS_OK(result) ) { +					dc_ip = ip_list[i]; +					goto done; +				} +			} +		 +			zero_ip(&ip_list[i]); +		} + +		/* +		 * Try looking in the name status cache for an +		 * entry we already have. We know that already +		 * resolved ok. +		 */ + +		for (i = 0; i < count; i++) { +			if (is_zero_ip(ip_list[i])) +				continue; + +			if (namecache_status_fetch(domain, 0x1c, 0x20, +						ip_list[i], srv_name)) { +				result = check_negative_conn_cache( domain, srv_name ); +				if ( NT_STATUS_IS_OK(result) ) { +					dc_ip = ip_list[i]; +					goto done; +				} +			} +		} +		 +		/* +		 * Secondly try and contact a random PDC/BDC. +		 */ + +		i = (sys_random() % count); + +		if ( !is_zero_ip(ip_list[i]) ) { +			if ( name_status_find(domain, 0x1c, 0x20, ip_list[i], srv_name)) { +				result = check_negative_conn_cache( domain, srv_name ); +				if ( NT_STATUS_IS_OK(result) ) { +					dc_ip = ip_list[i]; +					goto done; +				} +			} +			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; @@ -220,20 +281,21 @@ BOOL rpc_find_dc(const char *domain, fstring srv_name, struct in_addr *ip_out)  				dc_ip = ip_list[i];  				goto done;  			} -		} +		}		  	} -  	SAFE_FREE(ip_list); -	return False; -done: +	/* 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. */ -	DEBUG(3, ("rpc_find_dc: Returning DC %s (%s) for domain %s\n", srv_name, +	DEBUG(3, ("get_dc_name: Returning DC %s (%s) for domain %s\n", srv_name,  		  inet_ntoa(dc_ip), domain));  	*ip_out = dc_ip; @@ -242,4 +304,3 @@ done:  	return True;  } - diff --git a/source3/nsswitch/winbindd_cm.c b/source3/nsswitch/winbindd_cm.c index 381cdaaa20..0ba9ab8266 100644 --- a/source3/nsswitch/winbindd_cm.c +++ b/source3/nsswitch/winbindd_cm.c @@ -51,9 +51,6 @@       - I'm pretty annoyed by all the make_nmb_name() stuff.  It should be         moved down into another function. -     - There needs to be a utility function in libsmb/namequery.c that does -       cm_get_dc_name()  -       - Take care when destroying cli_structs as they can be shared between         various sam handles. @@ -132,8 +129,6 @@ static BOOL cm_ads_find_dc(const char *domain, struct in_addr *dc_ip, fstring sr  	return True;  } - -  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; @@ -196,7 +191,7 @@ static BOOL cm_get_dc_name(const char *domain, fstring srv_name, struct in_addr  	if (!ret) {  		/* fall back on rpc methods if the ADS methods fail */ -		ret = rpc_find_dc(domain, srv_name, &dc_ip); +		ret = get_dc_name(domain, srv_name, &dc_ip);  	}  	if (!ret)  | 
