diff options
| -rw-r--r-- | source3/auth/auth_domain.c | 6 | ||||
| -rw-r--r-- | source3/include/ads.h | 41 | ||||
| -rw-r--r-- | source3/libads/ads_struct.c | 119 | ||||
| -rw-r--r-- | source3/libads/kerberos.c | 12 | ||||
| -rw-r--r-- | source3/libads/kerberos_verify.c | 2 | ||||
| -rw-r--r-- | source3/libads/ldap.c | 355 | ||||
| -rw-r--r-- | source3/libads/ldap_user.c | 6 | ||||
| -rw-r--r-- | source3/libads/sasl.c | 9 | ||||
| -rw-r--r-- | source3/libads/util.c | 2 | ||||
| -rw-r--r-- | source3/libsmb/namequery.c | 2 | ||||
| -rw-r--r-- | source3/nsswitch/winbindd.h | 8 | ||||
| -rw-r--r-- | source3/nsswitch/winbindd_ads.c | 119 | ||||
| -rw-r--r-- | source3/nsswitch/winbindd_cache.c | 15 | ||||
| -rw-r--r-- | source3/nsswitch/winbindd_cm.c | 22 | ||||
| -rw-r--r-- | source3/nsswitch/winbindd_rpc.c | 15 | ||||
| -rw-r--r-- | source3/nsswitch/winbindd_util.c | 118 | ||||
| -rw-r--r-- | source3/rpc_client/cli_lsarpc.c | 5 | ||||
| -rw-r--r-- | source3/rpcclient/cmd_lsarpc.c | 18 | ||||
| -rw-r--r-- | source3/smbd/negprot.c | 5 | ||||
| -rw-r--r-- | source3/smbd/server.c | 4 | ||||
| -rw-r--r-- | source3/smbd/sesssetup.c | 14 | ||||
| -rw-r--r-- | source3/utils/net_ads.c | 88 | ||||
| -rw-r--r-- | source3/utils/net_lookup.c | 2 | ||||
| -rw-r--r-- | source3/utils/net_rpc.c | 4 | 
24 files changed, 629 insertions, 362 deletions
diff --git a/source3/auth/auth_domain.c b/source3/auth/auth_domain.c index b37ce2cc91..d48cec5b29 100644 --- a/source3/auth/auth_domain.c +++ b/source3/auth/auth_domain.c @@ -46,7 +46,9 @@ static NTSTATUS ads_resolve_dc(fstring remote_machine,  		return NT_STATUS_NO_LOGON_SERVERS;		  	} -	DEBUG(4,("ads_resolve_dc: realm=%s\n", ads->realm)); +	DEBUG(4,("ads_resolve_dc: realm=%s\n", ads->config.realm)); + +	ads->auth.no_bind = 1;  #ifdef HAVE_ADS  	/* a full ads_connect() is actually overkill, as we don't srictly need @@ -55,7 +57,7 @@ static NTSTATUS ads_resolve_dc(fstring remote_machine,  	ads_connect(ads);  #endif -	fstrcpy(remote_machine, ads->ldap_server_name); +	fstrcpy(remote_machine, ads->config.ldap_server_name);  	strupper(remote_machine);  	*dest_ip = ads->ldap_ip;  	ads_destroy(&ads); diff --git a/source3/include/ads.h b/source3/include/ads.h index 78d2fcf4b5..9305b71671 100644 --- a/source3/include/ads.h +++ b/source3/include/ads.h @@ -5,19 +5,34 @@  */  typedef struct { -	void *ld; -	char *realm; -	char *workgroup; -	char *ldap_server; -	char *ldap_server_name; -	char *kdc_server; +	void *ld; /* the active ldap structure */ +	struct in_addr ldap_ip; /* the ip of the active connection, if any */ +	time_t last_attempt; /* last attempt to reconnect */  	int ldap_port; -	char *bind_path; -	time_t last_attempt; -	char *password; -	char *user_name; -	char *server_realm; -	struct in_addr ldap_ip; +	 +	/* info needed to find the server */ +	struct { +		char *realm; +		char *workgroup; +		char *ldap_server; +		int foreign; /* set to 1 if connecting to a foreign realm */ +	} server; + +	/* info needed to authenticate */ +	struct { +		char *realm; +		char *password; +		char *user_name; +		char *kdc_server; +		int no_bind; +	} auth; + +	/* info derived from the servers config */ +	struct { +		char *realm; +		char *bind_path; +		char *ldap_server_name; +	} config;  } ADS_STRUCT;  typedef struct { @@ -95,7 +110,7 @@ typedef void **ADS_MODLIST;  /* macros to simplify error returning */  #define ADS_ERROR(rc) ads_build_error(ADS_ERROR_LDAP, rc, 0) -#define ADS_ERROR_SYSTEM(rc) ads_build_error(ADS_ERROR_SYSTEM, rc, 0) +#define ADS_ERROR_SYSTEM(rc) ads_build_error(ADS_ERROR_SYSTEM, rc?rc:EINVAL, 0)  #define ADS_ERROR_KRB5(rc) ads_build_error(ADS_ERROR_KRB5, rc, 0)  #define ADS_ERROR_GSS(rc, minor) ads_build_error(ADS_ERROR_GSS, rc, minor) diff --git a/source3/libads/ads_struct.c b/source3/libads/ads_struct.c index af0b5d4143..b68c822ce3 100644 --- a/source3/libads/ads_struct.c +++ b/source3/libads/ads_struct.c @@ -72,47 +72,6 @@ char *ads_build_dn(const char *realm)  } -#ifdef HAVE_LDAP -/* -  find the ldap server from DNS -*/ -static char *find_ldap_server(ADS_STRUCT *ads) -{ -	char *list = NULL; -	struct in_addr ip; - -	if (ads->realm && -	    strcasecmp(ads->workgroup, lp_workgroup()) == 0 && -	    ldap_domain2hostlist(ads->realm, &list) == LDAP_SUCCESS) { -		char *p; -		p = strchr(list, ':'); -		if (p) *p = 0; -		return list; -	} - -	/* get desperate, find the domain controller IP */ -	if (resolve_name(ads->workgroup, &ip, 0x1B)) { -		return strdup(inet_ntoa(ip)); -	} -	 -	/* or a BDC ... */ -	if (resolve_name(ads->workgroup, &ip, 0x1C)) { -		return strdup(inet_ntoa(ip)); -	} - -	return NULL; -} - -#else  - -static char *find_ldap_server(ADS_STRUCT *ads) -{ -	/* Without LDAP this doesn't make much sense */ -	return NULL; -} - -#endif  -  #ifndef LDAP_PORT  #define LDAP_PORT 389  #endif @@ -122,58 +81,24 @@ static char *find_ldap_server(ADS_STRUCT *ads)  */  ADS_STRUCT *ads_init(const char *realm,   		     const char *workgroup, -		     const char *ldap_server, -		     const char *bind_path, -		     const char *password) +		     const char *ldap_server)  {  	ADS_STRUCT *ads;  	ads = (ADS_STRUCT *)smb_xmalloc(sizeof(*ads));  	ZERO_STRUCTP(ads); -	if (!workgroup) { -		workgroup = lp_workgroup(); +	ads->server.realm = realm? strdup(realm) : NULL; +	ads->server.workgroup = workgroup ? strdup(workgroup) : NULL; +	ads->server.ldap_server = ldap_server? strdup(ldap_server) : NULL; + +	/* we need to know if this is a foreign realm to know if we can +	   use lp_ads_server() */ +	if (realm && strcasecmp(lp_realm(), realm) != 0) { +		ads->server.foreign = 1;  	} - -	ads->realm = realm? strdup(realm) : NULL; -	ads->workgroup = strdup(workgroup); -	ads->ldap_server = ldap_server? strdup(ldap_server) : NULL; -	ads->bind_path = bind_path? strdup(bind_path) : NULL; -	ads->ldap_port = LDAP_PORT; -	if (password) ads->password = strdup(password); - -	if (!ads->realm) { -		ads->realm = strdup(lp_realm()); -		if (!ads->realm[0]) { -			SAFE_FREE(ads->realm); -		} -	} - -	if (!ads->realm && strchr_m(ads->workgroup, '.')) { -		/* the smb.conf has specified the realm in 'workgroup =' */ -		ads->realm = strdup(ads->workgroup); -	} - -	if (!ads->bind_path && ads->realm) { -		ads->bind_path = ads_build_dn(ads->realm); -	} -	if (!ads->ldap_server) { -		if (strcasecmp(ads->workgroup, lp_workgroup()) == 0) { -			ads->ldap_server = strdup(lp_ads_server()); -		} -		if (!ads->ldap_server || !ads->ldap_server[0]) { -			SAFE_FREE(ads->ldap_server); -			ads->ldap_server = find_ldap_server(ads); -		} -	} -	if (!ads->kdc_server) { -		/* assume its the same as LDAP */ -		ads->kdc_server = ads->ldap_server? strdup(ads->ldap_server) : NULL; -	} - -	if (ads->ldap_server) { -		/* its very useful knowing the IP of the ldap server */ -		ads->ldap_ip = *interpret_addr2(ads->ldap_server); +	if (workgroup && strcasecmp(lp_workgroup(), workgroup) != 0) { +		ads->server.foreign = 1;  	}  	return ads; @@ -182,7 +107,7 @@ ADS_STRUCT *ads_init(const char *realm,  /* a simpler ads_init() interface using all defaults */  ADS_STRUCT *ads_init_simple(void)  { -	return ads_init(NULL, NULL, NULL, NULL, NULL); +	return ads_init(NULL, NULL, NULL);  }  /* @@ -194,13 +119,19 @@ void ads_destroy(ADS_STRUCT **ads)  #if HAVE_LDAP  		if ((*ads)->ld) ldap_unbind((*ads)->ld);  #endif -		SAFE_FREE((*ads)->realm); -		SAFE_FREE((*ads)->ldap_server); -		SAFE_FREE((*ads)->ldap_server_name); -		SAFE_FREE((*ads)->kdc_server); -		SAFE_FREE((*ads)->bind_path); -		SAFE_FREE((*ads)->password); -		SAFE_FREE((*ads)->user_name); +		SAFE_FREE((*ads)->server.realm); +		SAFE_FREE((*ads)->server.workgroup); +		SAFE_FREE((*ads)->server.ldap_server); + +		SAFE_FREE((*ads)->auth.realm); +		SAFE_FREE((*ads)->auth.password); +		SAFE_FREE((*ads)->auth.user_name); +		SAFE_FREE((*ads)->auth.kdc_server); + +		SAFE_FREE((*ads)->config.realm); +		SAFE_FREE((*ads)->config.bind_path); +		SAFE_FREE((*ads)->config.ldap_server_name); +  		ZERO_STRUCTP(*ads);  		SAFE_FREE(*ads);  	} diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c index 1ba5d978e8..9a486237c9 100644 --- a/source3/libads/kerberos.c +++ b/source3/libads/kerberos.c @@ -110,16 +110,8 @@ int ads_kinit_password(ADS_STRUCT *ads)  	char *s;  	int ret; -	if (!ads->user_name) { -		/* by default use the machine account */ -		extern pstring global_myname; -		fstring myname; -		fstrcpy(myname, global_myname); -		strlower(myname); -		asprintf(&ads->user_name, "HOST/%s", global_myname); -	} -	asprintf(&s, "%s@%s", ads->user_name, ads->realm); -	ret = kerberos_kinit_password(s, ads->password); +	asprintf(&s, "%s@%s", ads->auth.user_name, ads->auth.realm); +	ret = kerberos_kinit_password(s, ads->auth.password);  	if (ret) {  		DEBUG(0,("kerberos_kinit_password %s failed: %s\n",  diff --git a/source3/libads/kerberos_verify.c b/source3/libads/kerberos_verify.c index dac90908c4..22b58f47dd 100644 --- a/source3/libads/kerberos_verify.c +++ b/source3/libads/kerberos_verify.c @@ -67,7 +67,7 @@ NTSTATUS ads_verify_ticket(ADS_STRUCT *ads, const DATA_BLOB *ticket,  		return NT_STATUS_LOGON_FAILURE;  	} -	ret = krb5_set_default_realm(context, ads->realm); +	ret = krb5_set_default_realm(context, ads->auth.realm);  	if (ret) {  		DEBUG(1,("krb5_set_default_realm failed (%s)\n", error_message(ret)));  		ads_destroy(&ads); diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index 1753d7d3ad..a8126faffe 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -37,6 +37,153 @@   * codepoints in UTF-8).  This may have to change at some point   **/ + +/* +  try a connection to a given ldap server, returning True and setting the servers IP +  in the ads struct if successful + */ +static BOOL ads_try_connect(ADS_STRUCT *ads, const char *server, unsigned port) +{ +	char *srv; + +	if (!server || !*server) { +		return False; +	} + +	DEBUG(5,("ads_try_connect: trying ldap server '%s' port %u\n", server, port)); + +	/* this copes with inet_ntoa brokenness */ +	srv = strdup(server); + +	ads->ld = ldap_open(srv, port); +	if (!ads->ld) { +		free(srv); +		return False; +	} +	ads->ldap_port = port; +	ads->ldap_ip = *interpret_addr2(srv); +	free(srv); +	return True; +} + +/* used by the IP comparison function */ +struct ldap_ip { +	struct in_addr ip; +	unsigned port; +}; + +/* compare 2 ldap IPs by nearness to our interfaces - used in qsort */ +static int ldap_ip_compare(struct ldap_ip *ip1, struct ldap_ip *ip2) +{ +	return ip_compare(&ip1->ip, &ip2->ip); +} + +/* try connecting to a ldap server via DNS */ +static BOOL ads_try_dns(ADS_STRUCT *ads) +{ +	char *realm, *ptr; +	char *list = NULL; +	pstring tok; +	struct ldap_ip *ip_list; +	int count, i=0; + +	realm = ads->server.realm; +	if (!realm || !*realm) { +		SAFE_FREE(realm); +		realm = lp_realm(); +	} +	if (!realm || !*realm) { +		SAFE_FREE(realm); +		realm = ads->server.workgroup; +	} +	if (!realm || !*realm) { +		SAFE_FREE(realm); +		realm = lp_workgroup(); +	} +	if (!realm) { +		return False; +	} + +	DEBUG(6,("ads_try_dns: looking for realm '%s'\n", realm)); +	if (ldap_domain2hostlist(realm, &list) != LDAP_SUCCESS) { +		return False; +	} + +	DEBUG(6,("ads_try_dns: ldap realm '%s' host list '%s'\n", realm, list)); + +	count = count_chars(list, ' ') + 1; +	ip_list = malloc(count * sizeof(struct ldap_ip)); +	if (!ip_list) { +		return False; +	} + +	ptr = list; +	while (next_token(&ptr, tok, " ", sizeof(tok))) { +		unsigned port = LDAP_PORT; +		char *p = strchr(tok, ':'); +		if (p) { +			*p = 0; +			port = atoi(p+1); +		} +		ip_list[i].ip = *interpret_addr2(tok); +		ip_list[i].port = port; +		if (!is_zero_ip(ip_list[i].ip)) { +			i++; +		} +	} +	free(list); + +	count = i; + +	/* we sort the list of addresses by closeness to our interfaces. This +	   tries to prevent us using a DC on the other side of the country */ +	if (count > 1) { +		qsort(ip_list, count, sizeof(struct ldap_ip),  +		      QSORT_CAST ldap_ip_compare);	 +	} + +	for (i=0;i<count;i++) { +		if (ads_try_connect(ads, inet_ntoa(ip_list[i].ip), ip_list[i].port)) { +			free(ip_list); +			return True; +		} +	} + +	SAFE_FREE(ip_list); +	return False; +} + +/* try connecting to a ldap server via netbios */ +static BOOL ads_try_netbios(ADS_STRUCT *ads) +{ +	struct in_addr *ip_list; +	int count; +	int i; +	char *workgroup = ads->server.workgroup; + +	if (!workgroup) { +		workgroup = lp_workgroup(); +	} + +	DEBUG(6,("ads_try_netbios: looking for workgroup '%s'\n", workgroup)); + +	if (!get_dc_list(True, workgroup, &ip_list, &count) && +	    !get_dc_list(False, workgroup, &ip_list, &count)) { +		return False; +	} + +	for (i=0;i<count;i++) { +		DEBUG(6,("ads_try_netbios: trying server '%s'\n", inet_ntoa(ip_list[i]))); +		if (ads_try_connect(ads, inet_ntoa(ip_list[i]), LDAP_PORT)) { +			free(ip_list); +			return True; +		} +	} + +	free(ip_list); +	return False; +} +  /**   * Connect to the LDAP server   * @param ads Pointer to an existing ADS_STRUCT @@ -49,38 +196,35 @@ ADS_STATUS ads_connect(ADS_STRUCT *ads)  	ADS_STATUS status;  	ads->last_attempt = time(NULL); -  	ads->ld = NULL; -	if (ads->ldap_server) { -		ads->ld = ldap_open(ads->ldap_server, ads->ldap_port); +	/* try with a user specified server */ +	if (ads->server.ldap_server &&  +	    ads_try_connect(ads, ads->server.ldap_server, LDAP_PORT)) { +		goto got_connection;  	} -	/* if that failed then try each of the BDC's in turn */ -	if (!ads->ld) { -		struct in_addr *ip_list; -		int count; - -		if (get_dc_list(False, ads->workgroup, &ip_list, &count)) { -			int i; -			for (i=0;i<count;i++) { -				ads->ld = ldap_open(inet_ntoa(ip_list[i]), -						    ads->ldap_port); -				if (ads->ld) break; -			} -			if (ads->ld) { -				SAFE_FREE(ads->ldap_server); -				ads->ldap_server = strdup(inet_ntoa(ip_list[i])); -			} -			free(ip_list); -		} +	/* try with a smb.conf ads server setting if we are connecting +           to the primary workgroup or realm */ +	if (!ads->server.foreign && +	    ads_try_connect(ads, lp_ads_server(), LDAP_PORT)) { +		goto got_connection;  	} -	if (!ads->ld) { -		return ADS_ERROR_SYSTEM(errno); +	/* try via DNS */ +	if (ads_try_dns(ads)) { +		goto got_connection; +		} + +	/* try via netbios lookups */ +	if (!lp_disable_netbios() && ads_try_netbios(ads)) { +		goto got_connection;  	} -	DEBUG(3,("Connected to LDAP server %s\n", ads->ldap_server)); +	return ADS_ERROR_SYSTEM(errno?errno:ENOENT); + +got_connection: +	DEBUG(3,("Connected to LDAP server %s\n", inet_ntoa(ads->ldap_ip)));  	status = ads_server_info(ads);  	if (!ADS_ERR_OK(status)) { @@ -90,22 +234,43 @@ ADS_STATUS ads_connect(ADS_STRUCT *ads)  	ldap_set_option(ads->ld, LDAP_OPT_PROTOCOL_VERSION, &version); +	if (!ads->auth.user_name) { +		/* by default use the machine account */ +		extern pstring global_myname; +		fstring myname; +		fstrcpy(myname, global_myname); +		strlower(myname); +		asprintf(&ads->auth.user_name, "HOST/%s", myname); +	} + +	if (!ads->auth.realm) { +		ads->auth.realm = strdup(ads->config.realm); +	} + +	if (!ads->auth.kdc_server) { +		ads->auth.kdc_server = strdup(inet_ntoa(ads->ldap_ip)); +	} +  #if KRB5_DNS_HACK  	/* this is a really nasty hack to avoid ADS DNS problems. It needs a patch  	   to MIT kerberos to work (tridge) */  	{  		char *env; -		asprintf(&env, "KRB5_KDC_ADDRESS_%s", ads->server_realm); -		setenv(env, inet_ntoa(*interpret_addr2(ads->ldap_server)), 1); +		asprintf(&env, "KRB5_KDC_ADDRESS_%s", ads->config.realm); +		setenv(env, ads->auth.kdc_server, 1);  		free(env);  	}  #endif -	if (ads->password) { +	if (ads->auth.password) {  		if ((code = ads_kinit_password(ads)))  			return ADS_ERROR_KRB5(code);  	} +	if (ads->auth.no_bind) { +		return ADS_SUCCESS; +	} +  	return ads_sasl_bind(ads);  } @@ -494,7 +659,7 @@ ADS_STATUS ads_search(ADS_STRUCT *ads, void **res,  		      const char *exp,   		      const char **attrs)  { -	return ads_do_search(ads, ads->bind_path, LDAP_SCOPE_SUBTREE,  +	return ads_do_search(ads, ads->config.bind_path, LDAP_SCOPE_SUBTREE,   			     exp, attrs, res);  } @@ -805,11 +970,11 @@ static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname,  	if (!(host_spn = talloc_asprintf(ctx, "HOST/%s", hostname)))  		goto done; -	if (!(host_upn = talloc_asprintf(ctx, "%s@%s", host_spn, ads->realm))) +	if (!(host_upn = talloc_asprintf(ctx, "%s@%s", host_spn, ads->config.realm)))  		goto done;  	ou_str = ads_ou_string(org_unit);  	new_dn = talloc_asprintf(ctx, "cn=%s,%s,%s", hostname, ou_str,  -				 ads->bind_path); +				 ads->config.bind_path);  	free(ou_str);  	if (!new_dn)  		goto done; @@ -925,6 +1090,7 @@ static BOOL ads_dump_field(char *field, void **values, void *data_area)  	} handlers[] = {  		{"objectGUID", False, dump_binary},  		{"nTSecurityDescriptor", False, dump_sd}, +		{"dnsRecord", False, dump_binary},  		{"objectSid", False, dump_sid},  		{NULL, True, NULL}  	}; @@ -1061,7 +1227,7 @@ ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *hostname, const char *org  		status = ads_leave_realm(ads, host);  		if (!ADS_ERR_OK(status)) {  			DEBUG(0, ("Failed to delete host '%s' from the '%s' realm.\n",  -				  host, ads->realm)); +				  host, ads->config.realm));  			return status;  		}  	} @@ -1224,20 +1390,15 @@ ADS_STATUS ads_set_machine_password(ADS_STRUCT *ads,  	char *host = strdup(hostname);  	char *principal;  -        if (!ads->kdc_server) { -		DEBUG(0, ("Unable to find KDC server\n")); -		return ADS_ERROR(LDAP_SERVER_DOWN); -	} -  	strlower(host);  	/*  	  we need to use the '$' form of the name here, as otherwise the  	  server might end up setting the password for a user instead  	 */ -	asprintf(&principal, "%s$@%s", host, ads->realm); +	asprintf(&principal, "%s$@%s", host, ads->auth.realm); -	status = krb5_set_password(ads->kdc_server, principal, password); +	status = krb5_set_password(ads->auth.kdc_server, principal, password);  	free(host);  	free(principal); @@ -1472,33 +1633,27 @@ ADS_STATUS ads_server_info(ADS_STRUCT *ads)  		return ADS_ERROR(LDAP_DECODING_ERROR);  	} -	SAFE_FREE(ads->ldap_server_name); +	SAFE_FREE(ads->config.ldap_server_name); -	ads->ldap_server_name = strdup(p+1); -	p = strchr(ads->ldap_server_name, '$'); +	ads->config.ldap_server_name = strdup(p+1); +	p = strchr(ads->config.ldap_server_name, '$');  	if (!p || p[1] != '@') {  		ldap_value_free(values);  		ldap_msgfree(res); -		SAFE_FREE(ads->ldap_server_name); +		SAFE_FREE(ads->config.ldap_server_name);  		return ADS_ERROR(LDAP_DECODING_ERROR);  	}  	*p = 0; -	SAFE_FREE(ads->server_realm); -	SAFE_FREE(ads->bind_path); +	SAFE_FREE(ads->config.realm); +	SAFE_FREE(ads->config.bind_path); -	ads->server_realm = strdup(p+2); -	ads->bind_path = ads_build_dn(ads->server_realm); - -	/* in case the realm isn't configured in smb.conf */ -	if (!ads->realm || !ads->realm[0]) { -		SAFE_FREE(ads->realm); -		ads->realm = strdup(ads->server_realm); -	} +	ads->config.realm = strdup(p+2); +	ads->config.bind_path = ads_build_dn(ads->config.realm);  	DEBUG(3,("got ldap server name %s@%s\n",  -		 ads->ldap_server_name, ads->realm)); +		 ads->config.ldap_server_name, ads->config.realm));  	return ADS_SUCCESS;  } @@ -1514,9 +1669,13 @@ ADS_STATUS ads_server_info(ADS_STRUCT *ads)   * @return the count of SIDs pulled   **/  ADS_STATUS ads_trusted_domains(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,  -			       int *num_trusts, char ***names, DOM_SID **sids) +			       int *num_trusts,  +			       char ***names,  +			       char ***alt_names, +			       DOM_SID **sids)  { -	const char *attrs[] = {"flatName", "securityIdentifier", NULL}; +	const char *attrs[] = {"name", "flatname", "securityIdentifier",  +			       "trustDirection", NULL};  	ADS_STATUS status;  	void *res, *msg;  	int count, i; @@ -1533,11 +1692,31 @@ ADS_STATUS ads_trusted_domains(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,  	}  	(*names) = talloc(mem_ctx, sizeof(char *) * count); +	(*alt_names) = talloc(mem_ctx, sizeof(char *) * count);  	(*sids) = talloc(mem_ctx, sizeof(DOM_SID) * count);  	if (! *names || ! *sids) return ADS_ERROR(LDAP_NO_MEMORY);  	for (i=0, msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) { -		(*names)[i] = ads_pull_string(ads, mem_ctx, msg, "flatName"); +		uint32 direction; + +		/* direction is a 2 bit bitfield, 1 means they trust us  +		   but we don't trust them, so we should not list them +		   as users from that domain can't login */ +		if (ads_pull_uint32(ads, msg, "trustDirection", &direction) && +		    direction == 1) { +			continue; +		} +		 +		(*names)[i] = ads_pull_string(ads, mem_ctx, msg, "name"); +		(*alt_names)[i] = ads_pull_string(ads, mem_ctx, msg, "flatname"); + +		if ((*alt_names)[i] && (*alt_names)[i][0]) { +			/* we prefer the flatname as the primary name +			   for consistency with RPC */ +			char *name = (*alt_names)[i]; +			(*alt_names)[i] = (*names)[i]; +			(*names)[i] = name; +		}  		if (ads_pull_sid(ads, msg, "securityIdentifier", &(*sids)[i])) {  			i++;  		} @@ -1562,7 +1741,7 @@ ADS_STATUS ads_domain_sid(ADS_STRUCT *ads, DOM_SID *sid)  	void *res;  	ADS_STATUS rc; -	rc = ads_do_search(ads, ads->bind_path, LDAP_SCOPE_BASE, "(objectclass=*)",  +	rc = ads_do_search(ads, ads->config.bind_path, LDAP_SCOPE_BASE, "(objectclass=*)",   			   attrs, &res);  	if (!ADS_ERR_OK(rc)) return rc;  	if (!ads_pull_sid(ads, res, "objectSid", sid)) { @@ -1573,4 +1752,66 @@ ADS_STATUS ads_domain_sid(ADS_STRUCT *ads, DOM_SID *sid)  	return ADS_SUCCESS;  } +/* this is rather complex - we need to find the allternate (netbios) name +   for the domain, but there isn't a simple query to do this. Instead +   we look for the principle names on the DCs account and find one that has  +   the right form, then extract the netbios name of the domain from that +*/ +ADS_STATUS ads_workgroup_name(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, char **workgroup) +{ +	char *exp; +	ADS_STATUS rc; +	char **principles; +	char *prefix; +	int prefix_length; +	int i; +	void *res; +	const char *attrs[] = {"servicePrincipalName", NULL}; + +	(*workgroup) = NULL; + +	asprintf(&exp, "(&(objectclass=computer)(dnshostname=%s.%s))",  +		 ads->config.ldap_server_name, ads->config.realm); +	rc = ads_search(ads, &res, exp, attrs); +	free(exp); + +	if (!ADS_ERR_OK(rc)) { +		return rc; +	} + +	principles = ads_pull_strings(ads, mem_ctx, res, "servicePrincipalName"); + +	ads_msgfree(ads, res); + +	if (!principles) { +		return ADS_ERROR(LDAP_NO_RESULTS_RETURNED); +	} + +	asprintf(&prefix, "HOST/%s.%s/",  +		 ads->config.ldap_server_name,  +		 ads->config.realm); + +	prefix_length = strlen(prefix); + +	for (i=0;principles[i]; i++) { +		if (strncasecmp(principles[i], prefix, prefix_length) == 0 && +		    strcasecmp(ads->config.realm, principles[i]+prefix_length) != 0 && +		    !strchr(principles[i]+prefix_length, '.')) { +			/* found an alternate (short) name for the domain. */ +			DEBUG(3,("Found alternate name '%s' for realm '%s'\n", +				 principles[i]+prefix_length,  +				 ads->config.realm)); +			(*workgroup) = talloc_strdup(mem_ctx, principles[i]+prefix_length); +			break; +		} +	} +	free(prefix); + +	if (!*workgroup) { +		return ADS_ERROR(LDAP_NO_RESULTS_RETURNED); +	} +	 +	return ADS_SUCCESS; +} +  #endif diff --git a/source3/libads/ldap_user.c b/source3/libads/ldap_user.c index b6e3d189c5..b6fef24b5c 100644 --- a/source3/libads/ldap_user.c +++ b/source3/libads/ldap_user.c @@ -55,10 +55,10 @@ ADS_STATUS ads_add_user_acct(ADS_STRUCT *ads, const char *user,  	status = ADS_ERROR(LDAP_NO_MEMORY); -	if (!(upn = talloc_asprintf(ctx, "%s@%s", user, ads->realm))) +	if (!(upn = talloc_asprintf(ctx, "%s@%s", user, ads->config.realm)))  		goto done;  	if (!(new_dn = talloc_asprintf(ctx, "cn=%s,cn=Users,%s", name,  -				       ads->bind_path))) +				       ads->config.bind_path)))  		goto done;  	if (!(controlstr = talloc_asprintf(ctx, "%u", UF_NORMAL_ACCOUNT)))  		goto done; @@ -94,7 +94,7 @@ ADS_STATUS ads_add_group_acct(ADS_STRUCT *ads, const char *group,  	status = ADS_ERROR(LDAP_NO_MEMORY);  	if (!(new_dn = talloc_asprintf(ctx, "cn=%s,cn=Users,%s", group,  -				       ads->bind_path))) +				       ads->config.bind_path)))  		goto done;  	if (!(mods = ads_init_mods(ctx)))  		goto done; diff --git a/source3/libads/sasl.c b/source3/libads/sasl.c index 1b55453cac..81dedb0a81 100644 --- a/source3/libads/sasl.c +++ b/source3/libads/sasl.c @@ -77,7 +77,7 @@ ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)  	/* we need to fetch a service ticket as the ldap user in the  	   servers realm, regardless of our realm */ -	asprintf(&sname, "ldap/%s@%s", ads->ldap_server_name, ads->server_realm); +	asprintf(&sname, "ldap/%s@%s", ads->config.ldap_server_name, ads->config.realm);  	krb5_init_context(&ctx);  	krb5_set_default_tgs_ktypes(ctx, enc_types);  	krb5_parse_name(ctx, sname, &principal); @@ -163,7 +163,7 @@ ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)  	gss_release_buffer(&minor_status, &output_token); -	output_token.value = malloc(strlen(ads->bind_path) + 8); +	output_token.value = malloc(strlen(ads->config.bind_path) + 8);  	p = output_token.value;  	*p++ = 1; /* no sign or seal */ @@ -171,9 +171,10 @@ ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)  	*p++ = max_msg_size>>16;  	*p++ = max_msg_size>>8;  	*p++ = max_msg_size; -	snprintf(p, strlen(ads->bind_path)+4, "dn:%s", ads->bind_path); +	snprintf(p, strlen(ads->config.bind_path)+4, "dn:%s", ads->config.bind_path); +	p += strlen(ads->config.bind_path); -	output_token.length = strlen(ads->bind_path) + 8; +	output_token.length = strlen(ads->config.bind_path) + 8;  	gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,  			  &output_token, &conf_state, diff --git a/source3/libads/util.c b/source3/libads/util.c index d48eb10b71..b10b130a31 100644 --- a/source3/libads/util.c +++ b/source3/libads/util.c @@ -39,7 +39,7 @@ ADS_STATUS ads_change_trust_account_password(ADS_STRUCT *ads, char *host_princip      new_password = strdup(tmp_password);      asprintf(&service_principal, "HOST/%s", host_principal); -    ret = kerberos_set_password(ads->kdc_server, host_principal, password,  +    ret = kerberos_set_password(ads->auth.kdc_server, host_principal, password,   				service_principal, new_password);      if (!secrets_store_machine_password(new_password)) { diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c index 141581e261..3382ce4f4a 100644 --- a/source3/libsmb/namequery.c +++ b/source3/libsmb/namequery.c @@ -216,7 +216,7 @@ BOOL name_status_find(const char *q_name, int q_type, int type, struct in_addr t  /*    comparison function used by sort_ip_list  */ -static int ip_compare(struct in_addr *ip1, struct in_addr *ip2) +int ip_compare(struct in_addr *ip1, struct in_addr *ip2)  {  	int max_bits1=0, max_bits2=0;  	int num_interfaces = iface_count(); diff --git a/source3/nsswitch/winbindd.h b/source3/nsswitch/winbindd.h index 11d399be49..dd92ecefe6 100644 --- a/source3/nsswitch/winbindd.h +++ b/source3/nsswitch/winbindd.h @@ -88,7 +88,7 @@ typedef struct {  struct winbindd_domain {  	fstring name;                          /* Domain name */	 -	fstring full_name;                     /* full Domain name (realm) */	 +	fstring alt_name;                      /* alt Domain name (if any) */  	DOM_SID sid;                           /* SID for this domain */  	/* Lookup methods for this domain (LDAP or RPC) */ @@ -170,11 +170,15 @@ struct winbindd_methods {  				    TALLOC_CTX *mem_ctx,  				    uint32 *num_domains,  				    char ***names, +				    char ***alt_names,  				    DOM_SID **dom_sids);  	/* find the domain sid */  	NTSTATUS (*domain_sid)(struct winbindd_domain *domain,  			       DOM_SID *sid); + +	/* setup the list of alternate names for the domain, if any */ +	NTSTATUS (*alternate_name)(struct winbindd_domain *domain);  };  /* Used to glue a policy handle and cli_state together */ @@ -190,6 +194,8 @@ typedef struct {  #include "rpc_client.h"  #define WINBINDD_ESTABLISH_LOOP 30 +#define WINBINDD_RESCAN_FREQ 300 +  #define DOM_SEQUENCE_NONE ((uint32)-1)  /* SETENV */ diff --git a/source3/nsswitch/winbindd_ads.c b/source3/nsswitch/winbindd_ads.c index b61348adfe..b0b70178a4 100644 --- a/source3/nsswitch/winbindd_ads.c +++ b/source3/nsswitch/winbindd_ads.c @@ -61,8 +61,8 @@ ADS_STATUS ads_do_search_retry(ADS_STRUCT *ads, const char *bind_path, int scope  		if (*res) ads_msgfree(ads, *res);  		*res = NULL; -		DEBUG(3,("Reopening ads connection to %s after error %s\n",  -			 ads->ldap_server, ads_errstr(status))); +		DEBUG(3,("Reopening ads connection to realm '%s' after error %s\n",  +			 ads->config.realm, ads_errstr(status)));  		if (ads->ld) {  			ldap_unbind(ads->ld);   		} @@ -87,7 +87,7 @@ ADS_STATUS ads_search_retry(ADS_STRUCT *ads, void **res,  			    const char *exp,   			    const char **attrs)  { -	return ads_do_search_retry(ads, ads->bind_path, LDAP_SCOPE_SUBTREE, +	return ads_do_search_retry(ads, ads->config.bind_path, LDAP_SCOPE_SUBTREE,  				   exp, attrs, res);  } @@ -108,8 +108,6 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)  	ADS_STRUCT *ads;  	ADS_STATUS status;  	char *ccache; -	struct in_addr server_ip; -	char *sname;  	if (domain->private) {  		return (ADS_STRUCT *)domain->private; @@ -120,30 +118,23 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)  	SETENV("KRB5CCNAME", ccache, 1);  	unlink(ccache); -	if (resolve_name(domain->name, &server_ip, 0x1b)) { -		sname = inet_ntoa(server_ip); -	} else if (resolve_name(domain->name, &server_ip, 0x1c)) { -		sname = inet_ntoa(server_ip); -	} else { -		if (strcasecmp(domain->name, lp_workgroup()) != 0) { -			DEBUG(1,("can't find domain controller for %s\n", domain->name)); -			return NULL; -		} -		sname = NULL; -	} - -	ads = ads_init(primary_realm, domain->name, NULL, NULL, NULL); +	ads = ads_init(domain->alt_name, domain->name, NULL);  	if (!ads) {  		DEBUG(1,("ads_init for domain %s failed\n", domain->name));  		return NULL;  	}  	/* the machine acct password might have change - fetch it every time */ -	SAFE_FREE(ads->password); -	ads->password = secrets_fetch_machine_password(); +	SAFE_FREE(ads->auth.password); +	ads->auth.password = secrets_fetch_machine_password(); + +	if (primary_realm) { +		SAFE_FREE(ads->auth.realm); +		ads->auth.realm = strdup(primary_realm); +	}  	status = ads_connect(ads); -	if (!ADS_ERR_OK(status) || !ads->realm) { +	if (!ADS_ERR_OK(status) || !ads->config.realm) {  		extern struct winbindd_methods msrpc_methods;  		DEBUG(1,("ads_connect for domain %s failed: %s\n",   			 domain->name, ads_errstr(status))); @@ -161,11 +152,9 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)  	/* remember our primary realm for trusted domain support */  	if (!primary_realm) { -		primary_realm = strdup(ads->realm); +		primary_realm = strdup(ads->config.realm);  	} -	fstrcpy(domain->full_name, ads->server_realm); -  	domain->private = (void *)ads;  	return ads;  } @@ -405,7 +394,7 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain,  	/* accept either the win2000 or the pre-win2000 username */  	asprintf(&exp, "(|(sAMAccountName=%s)(userPrincipalName=%s@%s))",  -		 name, name, ads->realm); +		 name, name, ads->config.realm);  	rc = ads_search_retry(ads, &res, exp, attrs);  	free(exp);  	if (!ADS_ERR_OK(rc)) { @@ -535,49 +524,6 @@ failed:  	return False;  } - -/* convert a sid to a distnguished name */ -static NTSTATUS sid_to_distinguished_name(struct winbindd_domain *domain, -					  TALLOC_CTX *mem_ctx, -					  DOM_SID *sid, -					  char **dn) -{ -	ADS_STRUCT *ads = NULL; -	const char *attrs[] = {"distinguishedName", NULL}; -	ADS_STATUS rc; -	void *msg = NULL; -	char *exp; -	char *sidstr; -	NTSTATUS status = NT_STATUS_UNSUCCESSFUL; - -	DEBUG(3,("ads: sid_to_distinguished_name\n")); - -	ads = ads_cached_connection(domain); -	if (!ads) goto done; - -	sidstr = sid_binstring(sid); -	asprintf(&exp, "(objectSid=%s)", sidstr); -	rc = ads_search_retry(ads, &msg, exp, attrs); -	free(exp); -	free(sidstr); -	if (!ADS_ERR_OK(rc)) { -		DEBUG(1,("sid_to_distinguished_name ads_search: %s\n", ads_errstr(rc))); -		goto done; -	} - -	*dn = ads_pull_string(ads, mem_ctx, msg, "distinguishedName"); - -	status = NT_STATUS_OK; - -	DEBUG(3,("ads sid_to_distinguished_name mapped %s\n", *dn)); - -done: -	if (msg) ads_msgfree(ads, msg); - -	return status; -} - -  /* Lookup user information from a rid */  static NTSTATUS query_user(struct winbindd_domain *domain,   			   TALLOC_CTX *mem_ctx,  @@ -831,6 +777,7 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,  				TALLOC_CTX *mem_ctx,  				uint32 *num_domains,  				char ***names, +				char ***alt_names,  				DOM_SID **dom_sids)  {  	ADS_STRUCT *ads; @@ -842,7 +789,7 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,  	ads = ads_cached_connection(domain);  	if (!ads) return NT_STATUS_UNSUCCESSFUL; -	rc = ads_trusted_domains(ads, mem_ctx, num_domains, names, dom_sids); +	rc = ads_trusted_domains(ads, mem_ctx, num_domains, names, alt_names, dom_sids);  	return ads_ntstatus(rc);  } @@ -867,6 +814,37 @@ static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)  	return ads_ntstatus(rc);  } + +/* find alternate names list for the domain - for ADS this is the +   netbios name */ +static NTSTATUS alternate_name(struct winbindd_domain *domain) +{ +	ADS_STRUCT *ads; +	ADS_STATUS rc; +	TALLOC_CTX *ctx; +	char *workgroup; + +	ads = ads_cached_connection(domain); +	if (!ads) return NT_STATUS_UNSUCCESSFUL; + +	if (!(ctx = talloc_init_named("alternate_name"))) { +		return NT_STATUS_NO_MEMORY; +	} + +	rc = ads_workgroup_name(ads, ctx, &workgroup); + +	if (ADS_ERR_OK(rc)) { +		fstrcpy(domain->name, workgroup); +		fstrcpy(domain->alt_name, ads->config.realm); +		strupper(domain->alt_name); +		strupper(domain->name); +	} + +	talloc_destroy(ctx); + +	return ads_ntstatus(rc);	 +} +  /* the ADS backend methods are exposed via this structure */  struct winbindd_methods ads_methods = {  	True, @@ -879,7 +857,8 @@ struct winbindd_methods ads_methods = {  	lookup_groupmem,  	sequence_number,  	trusted_domains, -	domain_sid +	domain_sid, +	alternate_name  };  #endif diff --git a/source3/nsswitch/winbindd_cache.c b/source3/nsswitch/winbindd_cache.c index a607727867..060139af3e 100644 --- a/source3/nsswitch/winbindd_cache.c +++ b/source3/nsswitch/winbindd_cache.c @@ -873,13 +873,14 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,  				TALLOC_CTX *mem_ctx,  				uint32 *num_domains,  				char ***names, +				char ***alt_names,  				DOM_SID **dom_sids)  {  	struct winbind_cache *cache = get_cache(domain);  	/* we don't cache this call */  	return cache->backend->trusted_domains(domain, mem_ctx, num_domains,  -					       names, dom_sids); +					       names, alt_names, dom_sids);  }  /* find the domain sid */ @@ -891,6 +892,15 @@ static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)  	return cache->backend->domain_sid(domain, sid);  } +/* find the alternate names for the domain, if any */ +static NTSTATUS alternate_name(struct winbindd_domain *domain) +{ +	struct winbind_cache *cache = get_cache(domain); + +	/* we don't cache this call */ +	return cache->backend->alternate_name(domain); +} +  /* the ADS backend methods are exposed via this structure */  struct winbindd_methods cache_methods = {  	True, @@ -903,5 +913,6 @@ struct winbindd_methods cache_methods = {  	lookup_groupmem,  	sequence_number,  	trusted_domains, -	domain_sid +	domain_sid, +	alternate_name  }; diff --git a/source3/nsswitch/winbindd_cm.c b/source3/nsswitch/winbindd_cm.c index 3175860a79..be28984791 100644 --- a/source3/nsswitch/winbindd_cm.c +++ b/source3/nsswitch/winbindd_cm.c @@ -97,12 +97,15 @@ struct get_dc_name_cache {  static BOOL cm_ads_find_dc(const char *domain, struct in_addr *dc_ip, fstring srv_name)  {  	ADS_STRUCT *ads; -	ads = ads_init_simple(); +	ads = ads_init(domain, domain, NULL);  	if (!ads) {  		return False;  	} -	DEBUG(4,("cm_ads_find_dc: realm=%s\n", ads->realm)); +	/* we don't need to bind, just connect */ +	ads->auth.no_bind = 1; + +	DEBUG(4,("cm_ads_find_dc: domain=%s\n", domain));  #ifdef HAVE_ADS  	/* a full ads_connect() is actually overkill, as we don't srictly need @@ -111,15 +114,15 @@ static BOOL cm_ads_find_dc(const char *domain, struct in_addr *dc_ip, fstring sr  	ads_connect(ads);  #endif -	fstrcpy(srv_name, ads->ldap_server_name); +	if (!ads->config.realm) { +		return False; +	} + +	fstrcpy(srv_name, ads->config.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))); @@ -247,9 +250,12 @@ static BOOL cm_get_dc_name(const char *domain, fstring srv_name, struct in_addr  	zero_ip(&dc_ip); +	ret = False;  	if (lp_security() == SEC_ADS) {  		ret = cm_ads_find_dc(domain, &dc_ip, srv_name); -	} else { +	} +	if (!ret) { +		/* fall back on rpc methods if the ADS methods fail */  		ret = cm_rpc_find_dc(domain, &dc_ip, srv_name);  	} diff --git a/source3/nsswitch/winbindd_rpc.c b/source3/nsswitch/winbindd_rpc.c index 2bb0e8c49f..5ec34f663d 100644 --- a/source3/nsswitch/winbindd_rpc.c +++ b/source3/nsswitch/winbindd_rpc.c @@ -575,22 +575,23 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,  				TALLOC_CTX *mem_ctx,  				uint32 *num_domains,  				char ***names, +				char ***alt_names,  				DOM_SID **dom_sids)  {  	CLI_POLICY_HND *hnd;  	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;  	uint32 enum_ctx = 0; -	uint32 pref_num_domains = 5;  	DEBUG(3,("rpc: trusted_domains\n"));  	*num_domains = 0; +	*alt_names = NULL;  	if (!(hnd = cm_get_lsa_handle(lp_workgroup())))  		goto done;  	result = cli_lsa_enum_trust_dom(hnd->cli, mem_ctx, -					&hnd->pol, &enum_ctx, &pref_num_domains, +					&hnd->pol, &enum_ctx,  					num_domains, names, dom_sids);  done:  	return result; @@ -621,6 +622,13 @@ done:  	return status;  } +/* find alternate names list for the domain - none for rpc */ +static NTSTATUS alternate_name(struct winbindd_domain *domain) +{ +	return NT_STATUS_OK; +} + +  /* the rpc backend methods are exposed via this structure */  struct winbindd_methods msrpc_methods = {  	False, @@ -633,5 +641,6 @@ struct winbindd_methods msrpc_methods = {  	lookup_groupmem,  	sequence_number,  	trusted_domains, -	domain_sid +	domain_sid, +	alternate_name  }; diff --git a/source3/nsswitch/winbindd_util.c b/source3/nsswitch/winbindd_util.c index b927380af8..daa3abb340 100644 --- a/source3/nsswitch/winbindd_util.c +++ b/source3/nsswitch/winbindd_util.c @@ -74,19 +74,17 @@ void free_domain_list(void)  }  /* Add a trusted domain to our list of domains */ - -static struct winbindd_domain *add_trusted_domain(char *domain_name, -						  struct winbindd_methods *methods) +static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name, +						  struct winbindd_methods *methods, +						  DOM_SID *sid)  {  	struct winbindd_domain *domain;  	/* We can't call domain_list() as this function is called from  	   init_domain_list() and we'll get stuck in a loop. */ -  	for (domain = _domain_list; domain; domain = domain->next) { -		if (strcmp(domain_name, domain->name) == 0) { -			DEBUG(3, ("domain %s already in domain list\n",  -				  domain_name)); +		if (strcmp(domain_name, domain->name) == 0 || +		    strcmp(domain_name, domain->alt_name) == 0) {  			return domain;  		}  	} @@ -101,40 +99,95 @@ static struct winbindd_domain *add_trusted_domain(char *domain_name,  	ZERO_STRUCTP(domain); +	/* prioritise the short name */ +	if (strchr_m(domain_name, '.') && alt_name && *alt_name) { +		fstrcpy(domain->name, alt_name); +		fstrcpy(domain->alt_name, domain_name); +	} else {  	fstrcpy(domain->name, domain_name); +		if (alt_name) { +			fstrcpy(domain->alt_name, alt_name); +		} +	} +          domain->methods = methods;  	domain->sequence_number = DOM_SEQUENCE_NONE;  	domain->last_seq_check = 0; +	if (sid) { +		sid_copy(&domain->sid, sid); +	}  	/* Link to domain list */ -          	DLIST_ADD(_domain_list, domain); +	DEBUG(1,("Added domain %s %s %s\n",  +		 domain->name, domain->alt_name, +		 sid?sid_string_static(&domain->sid):"")); +          	return domain;  } -/* Look up global info for the winbind daemon */ +/* +  rescan our domains looking for new trusted domains + */ +void rescan_trusted_domains(void) +{ +	struct winbindd_domain *domain; +	TALLOC_CTX *mem_ctx; +	static time_t last_scan; +	time_t t = time(NULL); + +	/* ony rescan every few minutes */ +	if ((unsigned)(t - last_scan) < WINBINDD_RESCAN_FREQ) { +		return; +	} +	last_scan = time(NULL); +	 +	DEBUG(1, ("scanning trusted domain list\n")); + +	if (!(mem_ctx = talloc_init_named("init_domain_list"))) +		return; + +	for (domain = _domain_list; domain; domain = domain->next) { +		NTSTATUS result; +		char **names; +		char **alt_names; +		int num_domains = 0; +		DOM_SID *dom_sids; +		int i; + +		result = domain->methods->trusted_domains(domain, mem_ctx, &num_domains, +							  &names, &alt_names, &dom_sids); +		if (!NT_STATUS_IS_OK(result)) { +			continue; +		} + +		/* Add each domain to the trusted domain list. Each domain inherits +		   the access methods of its parent */ +		for(i = 0; i < num_domains; i++) { +			DEBUG(10,("Found domain %s\n", names[i])); +			add_trusted_domain(names[i],  +					   alt_names?alt_names[i]:NULL,  +					   domain->methods, &dom_sids[i]); +		} +	} + +	talloc_destroy(mem_ctx); +} + +/* Look up global info for the winbind daemon */  BOOL init_domain_list(void)  {  	NTSTATUS result; -	TALLOC_CTX *mem_ctx;  	extern struct winbindd_methods cache_methods;  	struct winbindd_domain *domain; -	DOM_SID *dom_sids; -	char **names; -	uint32 num_domains = 0; - -	if (!(mem_ctx = talloc_init_named("init_domain_list"))) -		return False;  	/* Free existing list */ -  	free_domain_list();  	/* Add ourselves as the first entry */ - -	domain = add_trusted_domain(lp_workgroup(), &cache_methods); +	domain = add_trusted_domain(lp_workgroup(), NULL, &cache_methods, NULL);  	/* Now we *must* get the domain sid for our primary domain. Go into  	   a holding pattern until that is available */ @@ -147,29 +200,12 @@ BOOL init_domain_list(void)  		result = cache_methods.domain_sid(domain, &domain->sid);  	} -	DEBUG(1,("Added domain %s (%s)\n",  -		 domain->name,  -		 sid_string_static(&domain->sid))); - -	DEBUG(1, ("getting trusted domain list\n")); +	/* get any alternate name for the primary domain */ +	cache_methods.alternate_name(domain); -	result = cache_methods.trusted_domains(domain, mem_ctx, &num_domains, -					       &names, &dom_sids); +	/* do an initial scan for trusted domains */ +	rescan_trusted_domains(); -	/* Add each domain to the trusted domain list */ -	if (NT_STATUS_IS_OK(result)) { -		int i; -		for(i = 0; i < num_domains; i++) { -			domain = add_trusted_domain(names[i], &cache_methods); -			if (!domain) continue; -			sid_copy(&domain->sid, &dom_sids[i]); -			DEBUG(1,("Added domain %s (%s)\n",  -				 domain->name,  -				 sid_string_static(&domain->sid))); -		} -	} - -	talloc_destroy(mem_ctx);  	return True;  } @@ -184,7 +220,7 @@ struct winbindd_domain *find_domain_from_name(const char *domain_name)  	for (domain = domain_list(); domain != NULL; domain = domain->next) {  		if (strequal(domain_name, domain->name) || -		    strequal(domain_name, domain->full_name)) +		    (domain->alt_name[0] && strequal(domain_name, domain->alt_name)))  			return domain;  	} diff --git a/source3/rpc_client/cli_lsarpc.c b/source3/rpc_client/cli_lsarpc.c index 542fad311c..14227a349a 100644 --- a/source3/rpc_client/cli_lsarpc.c +++ b/source3/rpc_client/cli_lsarpc.c @@ -542,7 +542,7 @@ NTSTATUS cli_lsa_query_info_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,  NTSTATUS cli_lsa_enum_trust_dom(struct cli_state *cli, TALLOC_CTX *mem_ctx,                                  POLICY_HND *pol, uint32 *enum_ctx,  -                                uint32 *pref_num_domains, uint32 *num_domains, +                                uint32 *num_domains,                                  char ***domain_names, DOM_SID **domain_sids)  {  	prs_struct qbuf, rbuf; @@ -561,7 +561,8 @@ NTSTATUS cli_lsa_enum_trust_dom(struct cli_state *cli, TALLOC_CTX *mem_ctx,  	/* Marshall data and send request */ -        init_q_enum_trust_dom(&q, pol, *enum_ctx, *pref_num_domains); +	/* 64k is enough for about 2000 trusted domains */ +        init_q_enum_trust_dom(&q, pol, *enum_ctx, 0x10000);  	if (!lsa_io_q_enum_trust_dom("", &q, &qbuf, 0) ||  	    !rpc_api_pipe_req(cli, LSA_ENUMTRUSTDOM, &qbuf, &rbuf)) { diff --git a/source3/rpcclient/cmd_lsarpc.c b/source3/rpcclient/cmd_lsarpc.c index 067325c06e..51b260cceb 100644 --- a/source3/rpcclient/cmd_lsarpc.c +++ b/source3/rpcclient/cmd_lsarpc.c @@ -191,23 +191,15 @@ static NTSTATUS cmd_lsa_enum_trust_dom(struct cli_state *cli,  	/* defaults, but may be changed using params */  	uint32 enum_ctx = 0; -	uint32 preferred_maxnum = 5;  	uint32 num_domains = 0;  	int i; -	if (argc > 3) { -		printf("Usage: %s [preferred max number (%d)] [enum context (0)]\n", -			argv[0], preferred_maxnum); +	if (argc > 2) { +		printf("Usage: %s [enum context (0)]\n", argv[0]);  		return NT_STATUS_OK;  	} -	/* enumeration context */ -	if (argc >= 2 && argv[1]) { -		preferred_maxnum = atoi(argv[1]); -	}	 - -	/* preferred maximum number */ -	if (argc == 3 && argv[2]) { +	if (argc == 2 && argv[1]) {  		enum_ctx = atoi(argv[2]);  	}	 @@ -221,8 +213,8 @@ static NTSTATUS cmd_lsa_enum_trust_dom(struct cli_state *cli,  	/* Lookup list of trusted domains */  	result = cli_lsa_enum_trust_dom(cli, mem_ctx, &pol, &enum_ctx, -						&preferred_maxnum, &num_domains, -						&domain_names, &domain_sids); +					&num_domains, +					&domain_names, &domain_sids);  	if (!NT_STATUS_IS_OK(result) &&  	    !NT_STATUS_EQUAL(result, NT_STATUS_NO_MORE_ENTRIES) &&  	    !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c index d8aea624be..1d79cbd5d0 100644 --- a/source3/smbd/negprot.c +++ b/source3/smbd/negprot.c @@ -200,14 +200,11 @@ static int negprot_spnego(char *p)  	if (lp_security() != SEC_ADS) {  		blob = spnego_gen_negTokenInit(guid, OIDs_plain, "NONE");  	} else { -		ADS_STRUCT *ads; -		ads = ads_init_simple();  		/* win2000 uses host$@REALM, which we will probably use eventually,  		   but for now this works */ -		asprintf(&principal, "HOST/%s@%s", guid, ads->realm); +		asprintf(&principal, "HOST/%s@%s", guid, lp_realm());  		blob = spnego_gen_negTokenInit(guid, OIDs_krb5, principal);  		free(principal); -		ads_destroy(&ads);  	}  	memcpy(p, blob.data, blob.length);  	len = blob.length; diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 1eef3d98e8..d173fec00e 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -364,6 +364,10 @@ static BOOL open_sockets_smbd(BOOL is_daemon,const char *smb_ports)  				set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");  				set_socket_options(smbd_server_fd(),user_socket_options); +				/* this is needed so that we get decent entries +				   in smbstatus for port 445 connects */ +				fstrcpy(remote_machine, get_socket_addr(smbd_server_fd())); +				  				/* Reset global variables in util.c so  				   that client substitutions will be  				   done correctly in the process.  */ diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index a00554e638..2e9e54b8d9 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -122,6 +122,12 @@ static int reply_spnego_kerberos(connection_struct *conn,  	ads = ads_init_simple(); +	if (!ads) { +		return ERROR_NT(NT_STATUS_LOGON_FAILURE); +	} + +	ads->auth.realm = strdup(lp_realm()); +  	ret = ads_verify_ticket(ads, &ticket, &client, &auth_data);  	if (!NT_STATUS_IS_OK(ret)) {  		DEBUG(1,("Failed to verify incoming ticket!\n"));	 @@ -139,7 +145,7 @@ static int reply_spnego_kerberos(connection_struct *conn,  	}  	*p = 0; -	if (strcasecmp(p+1, ads->realm) != 0) { +	if (strcasecmp(p+1, ads->auth.realm) != 0) {  		DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));  		if (!lp_allow_trusted_domains()) {  			return ERROR_NT(NT_STATUS_LOGON_FAILURE); @@ -379,6 +385,7 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,  	uint32 auth_flags = AUTH_FLAG_NONE;  	auth_usersupplied_info *user_info = NULL;  	auth_serversupplied_info *server_info = NULL; +	extern fstring remote_machine;  	/* we must have setup the auth context by now */  	if (!ntlmssp_auth_context) { @@ -413,6 +420,11 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,  	DEBUG(3,("Got user=[%s] workgroup=[%s] machine=[%s] len1=%d len2=%d\n",  		 user, workgroup, machine, lmhash.length, nthash.length)); +	/* the client has given us its machine name (which we otherwise would not get on port 445). +	   we need to possibly reload smb.conf if smb.conf includes depend on the machine name */ +	fstrcpy(remote_machine, machine); +	reload_services(True); +  #if 0  	file_save("nthash1.dat", nthash.data, nthash.length);  	file_save("lmhash1.dat", lmhash.data, lmhash.length); diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c index ef4de3d76f..f74f633cf9 100644 --- a/source3/utils/net_ads.c +++ b/source3/utils/net_ads.c @@ -58,23 +58,23 @@ static int net_ads_info(int argc, const char **argv)  {  	ADS_STRUCT *ads; -	ads = ads_init(NULL, NULL, opt_host, NULL, NULL); +	ads = ads_init(NULL, NULL, opt_host); -	/* we want this servers realm, not our realm */ -	SAFE_FREE(ads->realm); +	if (ads) { +		ads->auth.no_bind = 1; +	}  	ads_connect(ads); -	if (!ads) { +	if (!ads || !ads->config.realm) {  		d_printf("Didn't find the ldap server!\n");  		return -1;  	} -	d_printf("LDAP server: %s\n", ads->ldap_server); -	d_printf("LDAP server IP: %s\n", inet_ntoa(ads->ldap_ip)); -	d_printf("LDAP server name: %s\n", ads->ldap_server_name); -	d_printf("Realm: %s\n", ads->realm); -	d_printf("Bind Path: %s\n", ads->bind_path); +	d_printf("LDAP server: %s\n", inet_ntoa(ads->ldap_ip)); +	d_printf("LDAP server name: %s\n", ads->config.ldap_server_name); +	d_printf("Realm: %s\n", ads->config.realm); +	d_printf("Bind Path: %s\n", ads->config.bind_path);  	d_printf("LDAP port: %d\n", ads->ldap_port);  	return 0; @@ -88,7 +88,7 @@ static ADS_STRUCT *ads_startup(void)  	BOOL need_password = False;  	BOOL second_time = False; -	ads = ads_init(NULL, NULL, opt_host, NULL, NULL); +	ads = ads_init(NULL, NULL, opt_host);  	if (!opt_user_name) {  		opt_user_name = "administrator"; @@ -106,9 +106,9 @@ retry:  	}  	if (opt_password) -		ads->password = strdup(opt_password); +		ads->auth.password = strdup(opt_password); -	ads->user_name = strdup(opt_user_name); +	ads->auth.user_name = strdup(opt_user_name);  	status = ads_connect(ads);  	if (!ADS_ERR_OK(status)) { @@ -141,8 +141,38 @@ int net_ads_check(void)  	return 0;  } +/*  +   determine the netbios workgroup name for a domain + */ +static int net_ads_workgroup(int argc, const char **argv) +{ +	ADS_STRUCT *ads; +	TALLOC_CTX *ctx; +	char *workgroup; + +	if (!(ads = ads_startup())) return -1; + +	if (!(ctx = talloc_init_named("net_ads_workgroup"))) { +		return -1; +	} + +	if (!ADS_ERR_OK(ads_workgroup_name(ads, ctx, &workgroup))) { +		d_printf("Failed to find workgroup for realm '%s'\n",  +			 ads->config.realm); +		talloc_destroy(ctx); +		return -1; +	} + +	d_printf("Workgroup: %s\n", workgroup); + +	talloc_destroy(ctx); + +	return 0; +} + + -static BOOL usergrp_display(char *field, void **values, void *data_area) +static void usergrp_display(char *field, void **values, void *data_area)  {  	char **disp_fields = (char **) data_area; @@ -156,16 +186,15 @@ static BOOL usergrp_display(char *field, void **values, void *data_area)  		}  		SAFE_FREE(disp_fields[0]);  		SAFE_FREE(disp_fields[1]); -		return True; +		return;  	}  	if (!values) /* must be new field, indicate string field */ -		return True; +		return;  	if (StrCaseCmp(field, "sAMAccountName") == 0) {  		disp_fields[0] = strdup((char *) values[0]);  	}  	if (StrCaseCmp(field, "description") == 0)  		disp_fields[1] = strdup((char *) values[0]); -	return True; /* always strings here */  }  static int net_ads_user_usage(int argc, const char **argv) @@ -213,8 +242,8 @@ static int ads_user_add(int argc, const char **argv)  	}  	/* try setting the password */ -	asprintf(&upn, "%s@%s", argv[0], ads->realm); -	status = krb5_set_password(ads->kdc_server, upn, argv[1]); +	asprintf(&upn, "%s@%s", argv[0], ads->config.realm); +	status = krb5_set_password(ads->auth.kdc_server, upn, argv[1]);  	safe_free(upn);  	if (ADS_ERR_OK(status)) {  		d_printf("User %s added\n", argv[0]); @@ -331,7 +360,7 @@ int net_ads_user(int argc, const char **argv)  			d_printf("\nUser name             Comment"\  				 "\n-----------------------------\n"); -		rc = ads_do_search_all_fn(ads, ads->bind_path,  +		rc = ads_do_search_all_fn(ads, ads->config.bind_path,   					  LDAP_SCOPE_SUBTREE,  					  "(objectclass=user)",   					  opt_long_list_entries ? longattrs : @@ -438,7 +467,7 @@ int net_ads_group(int argc, const char **argv)  		if (opt_long_list_entries)  			d_printf("\nGroup name            Comment"\  				 "\n-----------------------------\n"); -		rc = ads_do_search_all_fn(ads, ads->bind_path,  +		rc = ads_do_search_all_fn(ads, ads->config.bind_path,   					  LDAP_SCOPE_SUBTREE,   					  "(objectclass=group)",   					  opt_long_list_entries ? longattrs :  @@ -499,11 +528,11 @@ static int net_ads_leave(int argc, const char **argv)  	rc = ads_leave_realm(ads, global_myname);  	if (!ADS_ERR_OK(rc)) {  	    d_printf("Failed to delete host '%s' from the '%s' realm.\n",  -		     global_myname, ads->realm); +		     global_myname, ads->config.realm);  	    return -1;  	} -	d_printf("Removed '%s' from realm '%s'\n", global_myname, ads->realm); +	d_printf("Removed '%s' from realm '%s'\n", global_myname, ads->config.realm);  	return 0;  } @@ -534,7 +563,7 @@ int net_ads_join(int argc, const char **argv)  	if (!(ads = ads_startup())) return -1;  	ou_str = ads_ou_string(org_unit); -	asprintf(&dn, "%s,%s", ou_str, ads->bind_path); +	asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path);  	free(ou_str);  	rc = ads_search_dn(ads, &res, dn, NULL); @@ -580,7 +609,7 @@ int net_ads_join(int argc, const char **argv)  		return -1;  	} -	d_printf("Joined '%s' to realm '%s'\n", global_myname, ads->realm); +	d_printf("Joined '%s' to realm '%s'\n", global_myname, ads->config.realm);  	free(password); @@ -675,7 +704,7 @@ static int net_ads_printer_publish(int argc, const char **argv)  	   get_a_printer, because the server name might be  	   localhost or an ip address */  	prt.printerName = argv[0]; -	asprintf(&servername, "%s.%s", global_myname, ads->realm); +	asprintf(&servername, "%s.%s", global_myname, ads->config.realm);  	prt.serverName = servername;  	prt.shortServerName = global_myname;  	prt.versionNumber = "4"; @@ -779,13 +808,13 @@ static int net_ads_password(int argc, const char **argv)      /* use the realm so we can eventually change passwords for users       in realms other than default */ -    if (!(ads = ads_init(realm, NULL, NULL, NULL, NULL))) return -1; +    if (!(ads = ads_init(realm, NULL, NULL))) return -1;      asprintf(&prompt, "Enter new password for %s:", argv[0]);      new_password = getpass(prompt); -    ret = kerberos_set_password(ads->kdc_server, auth_principal,  +    ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,   				auth_password, argv[0], new_password);      if (!ADS_ERR_OK(ret)) {  	d_printf("Password change failed :-( ...\n"); @@ -814,7 +843,7 @@ static int net_ads_change_localhost_pass(int argc, const char **argv)      hostname = strdup(global_myname);      strlower(hostname); -    asprintf(&host_principal, "%s@%s", hostname, ads->realm); +    asprintf(&host_principal, "%s@%s", hostname, ads->config.realm);      SAFE_FREE(hostname);      d_printf("Changing password for principal: HOST/%s\n", host_principal); @@ -873,7 +902,7 @@ static int net_ads_search(int argc, const char **argv)  	exp = argv[0];  	attrs = (argv + 1); -	rc = ads_do_search_all(ads, ads->bind_path,  +	rc = ads_do_search_all(ads, ads->config.bind_path,   			       LDAP_SCOPE_SUBTREE,  			       exp, attrs, &res);  	if (!ADS_ERR_OK(rc)) { @@ -927,6 +956,7 @@ int net_ads(int argc, const char **argv)  		{"CHOSTPASS", net_ads_change_localhost_pass},  		{"PRINTER", net_ads_printer},  		{"SEARCH", net_ads_search}, +		{"WORKGROUP", net_ads_workgroup},  		{"HELP", net_ads_help},  		{NULL, NULL}  	}; diff --git a/source3/utils/net_lookup.c b/source3/utils/net_lookup.c index a9aa080054..f76b186251 100644 --- a/source3/utils/net_lookup.c +++ b/source3/utils/net_lookup.c @@ -215,6 +215,8 @@ static int net_lookup_kdc(int argc, const char **argv)  	DEBUG(1, ("No kerberos support\n"));  	return -1;  } + +  /* lookup hosts or IP addresses using internal samba lookup fns */  int net_lookup(int argc, const char **argv)  { diff --git a/source3/utils/net_rpc.c b/source3/utils/net_rpc.c index 9b3248cf63..ae956076d5 100644 --- a/source3/utils/net_rpc.c +++ b/source3/utils/net_rpc.c @@ -1824,7 +1824,7 @@ static int rpc_trustdom_list(int argc, const char **argv)  	POLICY_HND connect_hnd;  	/* trusted domains listing variables */ -	int enum_ctx = 0, pref_num_domains = 5; +	int enum_ctx = 0;  	int num_domains, i, pad_len, col_len = 20;  	DOM_SID *domain_sids;  	char **trusted_dom_names; @@ -1894,7 +1894,7 @@ static int rpc_trustdom_list(int argc, const char **argv)  	do {  		nt_status = cli_lsa_enum_trust_dom(cli, mem_ctx, &connect_hnd, &enum_ctx, -						   &pref_num_domains, &num_domains, +						   &num_domains,  						   &trusted_dom_names, &domain_sids);  		if (NT_STATUS_IS_ERR(nt_status)) {  | 
