Ejemplo n.º 1
0
/* Lookup user information from a rid */
static NTSTATUS query_user(struct winbindd_domain *domain, 
			   TALLOC_CTX *mem_ctx, 
			   const struct dom_sid *sid,
			   struct wbint_userinfo *info)
{
	ADS_STRUCT *ads = NULL;
	const char *attrs[] = { "*", NULL };
	ADS_STATUS rc;
	int count;
	LDAPMessage *msg = NULL;
	char *ldap_exp;
	char *sidstr;
	uint32 group_rid;
	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
	struct netr_SamInfo3 *user = NULL;
	gid_t gid = -1;
	int ret;
	char *ads_name;

	DEBUG(3,("ads: query_user\n"));

	info->homedir = NULL;
	info->shell = NULL;

	/* try netsamlogon cache first */

	if (winbindd_use_cache() && (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL )
	{
		DEBUG(5,("query_user: Cache lookup succeeded for %s\n", 
			 sid_string_dbg(sid)));

		sid_compose(&info->user_sid, &domain->sid, user->base.rid);
		sid_compose(&info->group_sid, &domain->sid, user->base.primary_gid);

		info->acct_name = talloc_strdup(mem_ctx, user->base.account_name.string);
		info->full_name = talloc_strdup(mem_ctx, user->base.full_name.string);

		nss_get_info_cached( domain, sid, mem_ctx,
			      &info->homedir, &info->shell, &info->full_name, 
			      &gid );
		info->primary_gid = gid;

		TALLOC_FREE(user);

		return NT_STATUS_OK;
	}

	if ( !winbindd_can_contact_domain(domain)) {
		DEBUG(8,("query_user: No incoming trust from domain %s\n",
			 domain->name));

		/* We still need to generate some basic information
		   about the user even if we cannot contact the 
		   domain.  Most of this stuff we can deduce. */

		sid_copy( &info->user_sid, sid );

		/* Assume "Domain Users" for the primary group */

		sid_compose(&info->group_sid, &domain->sid, DOMAIN_RID_USERS );

		/* Try to fill in what the nss_info backend can do */

		nss_get_info_cached( domain, sid, mem_ctx,
			      &info->homedir, &info->shell, &info->full_name, 
			      &gid);
		info->primary_gid = gid;

		return NT_STATUS_OK;
	}

	/* no cache...do the query */

	if ( (ads = ads_cached_connection(domain)) == NULL ) {
		domain->last_status = NT_STATUS_SERVER_DISABLED;
		return NT_STATUS_SERVER_DISABLED;
	}

	sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), sid);

	ret = asprintf(&ldap_exp, "(objectSid=%s)", sidstr);
	TALLOC_FREE(sidstr);
	if (ret == -1) {
		return NT_STATUS_NO_MEMORY;
	}
	rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
	SAFE_FREE(ldap_exp);
	if (!ADS_ERR_OK(rc) || !msg) {
		DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
			 sid_string_dbg(sid), ads_errstr(rc)));
		return ads_ntstatus(rc);
	}

	count = ads_count_replies(ads, msg);
	if (count != 1) {
		DEBUG(1,("query_user(sid=%s): Not found\n",
			 sid_string_dbg(sid)));
		ads_msgfree(ads, msg);
		return NT_STATUS_NO_SUCH_USER;
	}

	info->acct_name = ads_pull_username(ads, mem_ctx, msg);

	if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
		DEBUG(1,("No primary group for %s !?\n",
			 sid_string_dbg(sid)));
		ads_msgfree(ads, msg);
		return NT_STATUS_NO_SUCH_USER;
	}
	sid_copy(&info->user_sid, sid);
	sid_compose(&info->group_sid, &domain->sid, group_rid);

	/*
	 * We have to fetch the "name" attribute before doing the
	 * nss_get_info_cached call. nss_get_info_cached might destroy
	 * the ads struct, potentially invalidating the ldap message.
	 */
	ads_name = ads_pull_string(ads, mem_ctx, msg, "name");

	ads_msgfree(ads, msg);
	msg = NULL;

	status = nss_get_info_cached( domain, sid, mem_ctx,
		      &info->homedir, &info->shell, &info->full_name, 
		      &gid);
	info->primary_gid = gid;
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("nss_get_info_cached failed: %s\n",
			  nt_errstr(status)));
		return status;
	}

	if (info->full_name == NULL) {
		info->full_name = ads_name;
	} else {
		TALLOC_FREE(ads_name);
	}

	status = NT_STATUS_OK;

	DEBUG(3,("ads query_user gave %s\n", info->acct_name));
	return NT_STATUS_OK;
}
Ejemplo n.º 2
0
/* list all domain groups */
static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
				TALLOC_CTX *mem_ctx,
				uint32 *num_entries, 
				struct wb_acct_info **info)
{
	ADS_STRUCT *ads = NULL;
	const char *attrs[] = {"userPrincipalName", "sAMAccountName",
			       "name", "objectSid", NULL};
	int i, count;
	ADS_STATUS rc;
	LDAPMessage *res = NULL;
	LDAPMessage *msg = NULL;
	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
	const char *filter;
	bool enum_dom_local_groups = False;

	*num_entries = 0;

	DEBUG(3,("ads: enum_dom_groups\n"));

	if ( !winbindd_can_contact_domain( domain ) ) {
		DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
			  domain->name));		
		return NT_STATUS_OK;
	}

	/* only grab domain local groups for our domain */
	if ( domain->active_directory && strequal(lp_realm(), domain->alt_name)  ) {
		enum_dom_local_groups = True;
	}

	/* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
	 * rollup-fixes:
	 *
	 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
	 * default value, it MUST be absent. In case of extensible matching the
	 * "dnattr" boolean defaults to FALSE and so it must be only be present
	 * when set to TRUE. 
	 *
	 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
	 * filter using bitwise matching rule then the buggy AD fails to decode
	 * the extensible match. As a workaround set it to TRUE and thereby add
	 * the dnAttributes "dn" field to cope with those older AD versions.
	 * It should not harm and won't put any additional load on the AD since
	 * none of the dn components have a bitmask-attribute.
	 *
	 * Thanks to Ralf Haferkamp for input and testing - Guenther */

	filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))", 
				 ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
				 ADS_LDAP_MATCHING_RULE_BIT_AND, 
				 enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);

	if (filter == NULL) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}

	ads = ads_cached_connection(domain);

	if (!ads) {
		domain->last_status = NT_STATUS_SERVER_DISABLED;
		goto done;
	}

	rc = ads_search_retry(ads, &res, filter, attrs);
	if (!ADS_ERR_OK(rc) || !res) {
		DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
		goto done;
	}

	count = ads_count_replies(ads, res);
	if (count == 0) {
		DEBUG(1,("enum_dom_groups: No groups found\n"));
		goto done;
	}

	(*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
	if (!*info) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}

	i = 0;

	for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
		char *name, *gecos;
		struct dom_sid sid;
		uint32 rid;

		name = ads_pull_username(ads, mem_ctx, msg);
		gecos = ads_pull_string(ads, mem_ctx, msg, "name");
		if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
			DEBUG(1,("No sid for %s !?\n", name));
			continue;
		}

		if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
			DEBUG(1,("No rid for %s !?\n", name));
			continue;
		}

		fstrcpy((*info)[i].acct_name, name);
		fstrcpy((*info)[i].acct_desc, gecos);
		(*info)[i].rid = rid;
		i++;
	}

	(*num_entries) = i;

	status = NT_STATUS_OK;

	DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));

done:
	if (res) 
		ads_msgfree(ads, res);

	return status;
}
Ejemplo n.º 3
0
/* Lookup user information from a rid */
static NTSTATUS query_user(struct winbindd_domain *domain, 
			   TALLOC_CTX *mem_ctx, 
			   const DOM_SID *sid, 
			   struct wbint_userinfo *info)
{
	ADS_STRUCT *ads = NULL;
	const char *attrs[] = { "*", NULL };
	ADS_STATUS rc;
	int count;
	LDAPMessage *msg = NULL;
	char *ldap_exp;
	char *sidstr;
	uint32 group_rid;
	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
	struct netr_SamInfo3 *user = NULL;
	gid_t gid;

	DEBUG(3,("ads: query_user\n"));

	info->homedir = NULL;
	info->shell = NULL;
	info->primary_gid = (gid_t)-1;

	/* try netsamlogon cache first */

	if ( (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL ) 
	{
		DEBUG(5,("query_user: Cache lookup succeeded for %s\n", 
			 sid_string_dbg(sid)));

		sid_compose(&info->user_sid, &domain->sid, user->base.rid);
		sid_compose(&info->group_sid, &domain->sid, user->base.primary_gid);

		info->acct_name = talloc_strdup(mem_ctx, user->base.account_name.string);
		info->full_name = talloc_strdup(mem_ctx, user->base.full_name.string);

		nss_get_info_cached( domain, sid, mem_ctx, NULL, NULL, 
			      &info->homedir, &info->shell, &info->full_name, 
			      &gid );
		info->primary_gid = gid;

		TALLOC_FREE(user);

		return NT_STATUS_OK;
	}

	if ( !winbindd_can_contact_domain(domain)) {
		DEBUG(8,("query_user: No incoming trust from domain %s\n",
			 domain->name));

		/* We still need to generate some basic information
		   about the user even if we cannot contact the 
		   domain.  Most of this stuff we can deduce. */

		sid_copy( &info->user_sid, sid );

		/* Assume "Domain Users" for the primary group */

		sid_compose(&info->group_sid, &domain->sid, DOMAIN_GROUP_RID_USERS );

		/* Try to fill in what the nss_info backend can do */

		nss_get_info_cached( domain, sid, mem_ctx, NULL, NULL, 
			      &info->homedir, &info->shell, &info->full_name, 
			      &gid);
		info->primary_gid = gid;

		status = NT_STATUS_OK;
		goto done;
	}

	/* no cache...do the query */

	if ( (ads = ads_cached_connection(domain)) == NULL ) {
		domain->last_status = NT_STATUS_SERVER_DISABLED;
		goto done;
	}

	sidstr = sid_binstring(talloc_tos(), sid);
	if (asprintf(&ldap_exp, "(objectSid=%s)", sidstr) == -1) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}
	rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
	free(ldap_exp);
	TALLOC_FREE(sidstr);
	if (!ADS_ERR_OK(rc) || !msg) {
		DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
			 sid_string_dbg(sid), ads_errstr(rc)));
		goto done;
	}

	count = ads_count_replies(ads, msg);
	if (count != 1) {
		DEBUG(1,("query_user(sid=%s): Not found\n",
			 sid_string_dbg(sid)));
		goto done;
	}

	info->acct_name = ads_pull_username(ads, mem_ctx, msg);

	nss_get_info_cached( domain, sid, mem_ctx, ads, msg, 
		      &info->homedir, &info->shell, &info->full_name, 
		      &gid);
	info->primary_gid = gid;

	if (info->full_name == NULL) {
		info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
	}

	if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
		DEBUG(1,("No primary group for %s !?\n",
			 sid_string_dbg(sid)));
		goto done;
	}

	sid_copy(&info->user_sid, sid);
	sid_compose(&info->group_sid, &domain->sid, group_rid);

	status = NT_STATUS_OK;

	DEBUG(3,("ads query_user gave %s\n", info->acct_name));
done:
	if (msg) 
		ads_msgfree(ads, msg);

	return status;
}
Ejemplo n.º 4
0
/* Query display info for a realm. This is the basic user list fn */
static NTSTATUS query_user_list(struct winbindd_domain *domain,
			       TALLOC_CTX *mem_ctx,
			       uint32 *num_entries, 
			       struct wbint_userinfo **pinfo)
{
	ADS_STRUCT *ads = NULL;
	const char *attrs[] = { "*", NULL };
	int i, count;
	ADS_STATUS rc;
	LDAPMessage *res = NULL;
	LDAPMessage *msg = NULL;
	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;

	*num_entries = 0;

	DEBUG(3,("ads: query_user_list\n"));

	if ( !winbindd_can_contact_domain( domain ) ) {
		DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
			  domain->name));		
		return NT_STATUS_OK;
	}

	ads = ads_cached_connection(domain);

	if (!ads) {
		domain->last_status = NT_STATUS_SERVER_DISABLED;
		goto done;
	}

	rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
	if (!ADS_ERR_OK(rc) || !res) {
		DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
		goto done;
	}

	count = ads_count_replies(ads, res);
	if (count == 0) {
		DEBUG(1,("query_user_list: No users found\n"));
		goto done;
	}

	(*pinfo) = talloc_zero_array(mem_ctx, struct wbint_userinfo, count);
	if (!*pinfo) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}

	count = 0;

	for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
		struct wbint_userinfo *info = &((*pinfo)[count]);
		uint32 group;
		uint32 atype;

		if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) ||
		    ds_atype_map(atype) != SID_NAME_USER) {
			DEBUG(1,("Not a user account? atype=0x%x\n", atype));
			continue;
		}

		info->acct_name = ads_pull_username(ads, mem_ctx, msg);
		info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
		info->homedir = NULL;
		info->shell = NULL;
		info->primary_gid = (gid_t)-1;

		if (!ads_pull_sid(ads, msg, "objectSid",
				  &info->user_sid)) {
			DEBUG(1, ("No sid for %s !?\n", info->acct_name));
			continue;
		}

		if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
			DEBUG(1, ("No primary group for %s !?\n",
				  info->acct_name));
			continue;
		}
		sid_compose(&info->group_sid, &domain->sid, group);

		count += 1;
	}

	(*num_entries) = count;
	ads_msgfree(ads, res);

	for (i=0; i<count; i++) {
		struct wbint_userinfo *info = &((*pinfo)[i]);
		const char *gecos = NULL;
		gid_t primary_gid = (gid_t)-1;

		status = nss_get_info_cached(domain, &info->user_sid, mem_ctx,
					     &info->homedir, &info->shell,
					     &gecos, &primary_gid);
		if (!NT_STATUS_IS_OK(status)) {
			/*
			 * Deliberately ignore this error, there might be more
			 * users to fill
			 */
			continue;
		}

		if (gecos != NULL) {
			info->full_name = gecos;
		}
		info->primary_gid = primary_gid;
	}

	status = NT_STATUS_OK;

	DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));

done:
	return status;
}
Ejemplo n.º 5
0
/* Query display info for a realm. This is the basic user list fn */
static NTSTATUS query_user_list(struct winbindd_domain *domain,
			       TALLOC_CTX *mem_ctx,
			       uint32 *num_entries, 
			       struct wbint_userinfo **info)
{
	ADS_STRUCT *ads = NULL;
	const char *attrs[] = { "*", NULL };
	int i, count;
	ADS_STATUS rc;
	LDAPMessage *res = NULL;
	LDAPMessage *msg = NULL;
	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;

	*num_entries = 0;

	DEBUG(3,("ads: query_user_list\n"));

	if ( !winbindd_can_contact_domain( domain ) ) {
		DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
			  domain->name));		
		return NT_STATUS_OK;
	}

	ads = ads_cached_connection(domain);

	if (!ads) {
		domain->last_status = NT_STATUS_SERVER_DISABLED;
		goto done;
	}

	rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
	if (!ADS_ERR_OK(rc) || !res) {
		DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
		goto done;
	}

	count = ads_count_replies(ads, res);
	if (count == 0) {
		DEBUG(1,("query_user_list: No users found\n"));
		goto done;
	}

	(*info) = TALLOC_ZERO_ARRAY(mem_ctx, struct wbint_userinfo, count);
	if (!*info) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}

	i = 0;

	for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
		const char *name;
		const char *gecos = NULL;
		const char *homedir = NULL;
		const char *shell = NULL;
		uint32 group;
		uint32 atype;
		DOM_SID user_sid;
		gid_t primary_gid = (gid_t)-1;

		if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) ||
		    ds_atype_map(atype) != SID_NAME_USER) {
			DEBUG(1,("Not a user account? atype=0x%x\n", atype));
			continue;
		}

		name = ads_pull_username(ads, mem_ctx, msg);

		if ( ads_pull_sid( ads, msg, "objectSid", &user_sid ) ) {
			status = nss_get_info_cached( domain, &user_sid, mem_ctx, 
					       ads, msg, &homedir, &shell, &gecos,
					       &primary_gid );
		}

		if (gecos == NULL) {
			gecos = ads_pull_string(ads, mem_ctx, msg, "name");
		}

		if (!ads_pull_sid(ads, msg, "objectSid",
				  &(*info)[i].user_sid)) {
			DEBUG(1,("No sid for %s !?\n", name));
			continue;
		}
		if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
			DEBUG(1,("No primary group for %s !?\n", name));
			continue;
		}

		(*info)[i].acct_name = name;
		(*info)[i].full_name = gecos;
		(*info)[i].homedir = homedir;
		(*info)[i].shell = shell;
		(*info)[i].primary_gid = primary_gid;
		sid_compose(&(*info)[i].group_sid, &domain->sid, group);
		i++;
	}

	(*num_entries) = i;
	status = NT_STATUS_OK;

	DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));

done:
	if (res) 
		ads_msgfree(ads, res);

	return status;
}