Example #1
0
static int collect_aliasmem(struct db_record *rec, void *priv)
{
	struct aliasmem_state *state = (struct aliasmem_state *)priv;
	const char *p;
	char *alias_string;
	TALLOC_CTX *frame;

	if (strncmp((const char *)rec->key.dptr, MEMBEROF_PREFIX,
		    MEMBEROF_PREFIX_LEN) != 0)
		return 0;

	p = (const char *)rec->value.dptr;

	frame = talloc_stackframe();

	while (next_token_talloc(frame, &p, &alias_string, " ")) {
		struct dom_sid alias, member;
		const char *member_string;
		uint32_t num_sids;

		if (!string_to_sid(&alias, alias_string))
			continue;

		if (dom_sid_compare(state->alias, &alias) != 0)
			continue;

		/* Ok, we found the alias we're looking for in the membership
		 * list currently scanned. The key represents the alias
		 * member. Add that. */

		member_string = strchr((const char *)rec->key.dptr, '/');

		/* Above we tested for MEMBEROF_PREFIX which includes the
		 * slash. */

		SMB_ASSERT(member_string != NULL);
		member_string += 1;

		if (!string_to_sid(&member, member_string))
			continue;

		num_sids = *state->num;
		if (!NT_STATUS_IS_OK(add_sid_to_array(state->mem_ctx, &member,
						      state->sids,
						      &num_sids)))
		{
			/* talloc fail. */
			break;
		}
		*state->num = num_sids;
	}

	TALLOC_FREE(frame);
	return 0;
}
Example #2
0
void add_sid_to_array_unique(const DOM_SID *sid, DOM_SID **sids, int *num_sids)
{
	int i;

	for (i=0; i<(*num_sids); i++) {
		if (sid_compare(sid, &(*sids)[i]) == 0)
			return;
	}

	add_sid_to_array(sid, sids, num_sids);
}
Example #3
0
static int priv_traverse_fn(struct db_record *rec, void *state)
{
	PRIV_SID_LIST *priv = (PRIV_SID_LIST *)state;
	int  prefixlen = strlen(PRIVPREFIX);
	DOM_SID sid;
	fstring sid_string;

	/* easy check first */

	if (rec->value.dsize != sizeof(SE_PRIV) )
		return 0;

	/* check we have a PRIV_+SID entry */

	if ( strncmp((char *)rec->key.dptr, PRIVPREFIX, prefixlen) != 0)
		return 0;

	/* check to see if we are looking for a particular privilege */

	if ( !se_priv_equal(&priv->privilege, &se_priv_none) ) {
		SE_PRIV mask;

		se_priv_copy( &mask, (SE_PRIV*)rec->value.dptr );

		/* if the SID does not have the specified privilege
		   then just return */

		if ( !is_privilege_assigned( &mask, &priv->privilege) )
			return 0;
	}

	fstrcpy( sid_string, (char *)&(rec->key.dptr[strlen(PRIVPREFIX)]) );

	/* this is a last ditch safety check to preventing returning
	   and invalid SID (i've somehow run into this on development branches) */

	if ( strcmp( "S-0-0", sid_string ) == 0 )
		return 0;

	if ( !string_to_sid(&sid, sid_string) ) {
		DEBUG(0,("travsersal_fn_enum__acct: Could not convert SID [%s]\n",
			sid_string));
		return 0;
	}

	if (!NT_STATUS_IS_OK(add_sid_to_array(priv->mem_ctx, &sid,
					      &priv->sids.list,
					      &priv->sids.count)))
	{
		return 0;
	}

	return 0;
}
Example #4
0
NTSTATUS add_sid_to_array_unique(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
				 DOM_SID **sids, size_t *num_sids)
{
	size_t i;

	for (i=0; i<(*num_sids); i++) {
		if (sid_compare(sid, &(*sids)[i]) == 0)
			return NT_STATUS_OK;
	}

	return add_sid_to_array(mem_ctx, sid, sids, num_sids);
}
Example #5
0
static int priv_traverse_fn(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
{
	PRIV_SID_LIST *priv = state;
	int  prefixlen = strlen(PRIVPREFIX);
	DOM_SID sid;
	fstring sid_string;
	
	/* easy check first */
	
	if ( data.dsize != sizeof(SE_PRIV) )
		return 0;

	/* check we have a PRIV_+SID entry */

	if ( strncmp(key.dptr, PRIVPREFIX, prefixlen) != 0)
		return 0;
		
	/* check to see if we are looking for a particular privilege */

	if ( !se_priv_equal(&priv->privilege, &se_priv_none) ) {
		SE_PRIV mask;
		
		se_priv_copy( &mask, (SE_PRIV*)data.dptr );
		
		/* if the SID does not have the specified privilege 
		   then just return */
		   
		if ( !is_privilege_assigned( &mask, &priv->privilege) )
			return 0;
	}
		
	fstrcpy( sid_string, &key.dptr[strlen(PRIVPREFIX)] );

	/* this is a last ditch safety check to preventing returning
	   and invalid SID (i've somehow run into this on development branches) */

	if ( strcmp( "S-0-0", sid_string ) == 0 )
		return 0;

	if ( !string_to_sid(&sid, sid_string) ) {
		DEBUG(0,("travsersal_fn_enum__acct: Could not convert SID [%s]\n",
			sid_string));
		return 0;
	}

	add_sid_to_array( NULL, &sid, &priv->sids.list, &priv->sids.count );
	
	return 0;
}
Example #6
0
struct security_token *registry_create_system_token(TALLOC_CTX *mem_ctx)
{
	struct security_token *token = NULL;

	token = talloc_zero(mem_ctx, struct security_token);
	if (!token) {
		DEBUG(1,("talloc failed\n"));
		return NULL;
	}

	token->privilege_mask = SE_ALL_PRIVS;

	if (!NT_STATUS_IS_OK(add_sid_to_array(token, &global_sid_System,
			 &token->sids, &token->num_sids))) {
		DEBUG(1,("Error adding nt-authority system sid to token\n"));
		return NULL;
	}

	return token;
}
struct nt_user_token *registry_create_system_token(TALLOC_CTX *mem_ctx)
{
	struct nt_user_token *token = NULL;

	token = TALLOC_ZERO_P(mem_ctx, struct nt_user_token);
	if (!token) {
		DEBUG(1,("talloc failed\n"));
		return NULL;
	}

	token->privileges = se_priv_all;

	if (!NT_STATUS_IS_OK(add_sid_to_array(token, &global_sid_System,
			 &token->user_sids, &token->num_sids))) {
		DEBUG(1,("Error adding nt-authority system sid to token\n"));
		return NULL;
	}

	return token;
}
Example #8
0
bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
		   DOM_SID **sids, size_t *num_sids)
{
	const char *p, *q;

	p = sidstr;
	if (p == NULL)
		return False;

	while (p[0] != '\0') {
		fstring tmp;
		size_t sidlen;
		DOM_SID sid;
		q = strchr(p, '\n');
		if (q == NULL) {
			DEBUG(0, ("Got invalid sidstr: %s\n", p));
			return False;
		}
		sidlen = PTR_DIFF(q, p);
		if (sidlen >= sizeof(tmp)-1) {
			return false;
		}
		memcpy(tmp, p, sidlen);
		tmp[sidlen] = '\0';
		q += 1;
		if (!string_to_sid(&sid, tmp)) {
			DEBUG(0, ("Could not parse sid %s\n", p));
			return False;
		}
		if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
						      num_sids)))
		{
			return False;
		}
		p = q;
	}
	return True;
}
Example #9
0
/* Lookup groups a user is a member of. */
static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
				  TALLOC_CTX *mem_ctx,
				  const struct dom_sid *sid,
				  uint32 *p_num_groups, struct dom_sid **user_sids)
{
	ADS_STRUCT *ads = NULL;
	const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
	ADS_STATUS rc;
	int count;
	LDAPMessage *msg = NULL;
	char *user_dn = NULL;
	struct dom_sid *sids;
	int i;
	struct dom_sid primary_group;
	uint32 primary_group_rid;
	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
	uint32_t num_groups = 0;

	DEBUG(3,("ads: lookup_usergroups\n"));
	*p_num_groups = 0;

	status = lookup_usergroups_cached(domain, mem_ctx, sid, 
					  p_num_groups, user_sids);
	if (NT_STATUS_IS_OK(status)) {
		return NT_STATUS_OK;
	}

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

		/* Tell the cache manager not to remember this one */

		return NT_STATUS_SYNCHRONIZATION_REQUIRED;
	}

	ads = ads_cached_connection(domain);

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

	rc = ads_search_retry_sid(ads, &msg, sid, attrs);

	if (!ADS_ERR_OK(rc)) {
		status = ads_ntstatus(rc);
		DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
			  "%s\n", sid_string_dbg(sid), ads_errstr(rc)));
		goto done;
	}

	count = ads_count_replies(ads, msg);
	if (count != 1) {
		status = NT_STATUS_UNSUCCESSFUL;
		DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
			 "invalid number of results (count=%d)\n", 
			 sid_string_dbg(sid), count));
		goto done;
	}

	if (!msg) {
		DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n", 
			 sid_string_dbg(sid)));
		status = NT_STATUS_UNSUCCESSFUL;
		goto done;
	}

	user_dn = ads_get_dn(ads, mem_ctx, msg);
	if (user_dn == NULL) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}

	if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
		DEBUG(1,("%s: No primary group for sid=%s !?\n", 
			 domain->name, sid_string_dbg(sid)));
		goto done;
	}

	sid_compose(&primary_group, &domain->sid, primary_group_rid);

	count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);

	/* there must always be at least one group in the token, 
	   unless we are talking to a buggy Win2k server */

	/* actually this only happens when the machine account has no read
	 * permissions on the tokenGroup attribute - gd */

	if (count == 0) {

		/* no tokenGroups */

		/* lookup what groups this user is a member of by DN search on
		 * "memberOf" */

		status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
						    &primary_group,
						    &num_groups, user_sids);
		*p_num_groups = num_groups;
		if (NT_STATUS_IS_OK(status)) {
			goto done;
		}

		/* lookup what groups this user is a member of by DN search on
		 * "member" */

		status = lookup_usergroups_member(domain, mem_ctx, user_dn, 
						  &primary_group,
						  &num_groups, user_sids);
		*p_num_groups = num_groups;
		goto done;
	}

	*user_sids = NULL;
	num_groups = 0;

	status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
				  &num_groups);
	if (!NT_STATUS_IS_OK(status)) {
		goto done;
	}

	for (i=0;i<count;i++) {

		/* ignore Builtin groups from ADS - Guenther */
		if (sid_check_is_in_builtin(&sids[i])) {
			continue;
		}

		status = add_sid_to_array_unique(mem_ctx, &sids[i],
						 user_sids, &num_groups);
		if (!NT_STATUS_IS_OK(status)) {
			goto done;
		}
	}

	*p_num_groups = (uint32)num_groups;
	status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;

	DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
		 sid_string_dbg(sid)));
done:
	TALLOC_FREE(user_dn);
	ads_msgfree(ads, msg);
	return status;
}
Example #10
0
/* Lookup groups a user is a member of - alternate method, for when
   tokenGroups are not available. */
static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
					   TALLOC_CTX *mem_ctx,
					   const char *user_dn,
					   struct dom_sid *primary_group,
					   uint32_t *p_num_groups,
					   struct dom_sid **user_sids)
{
	ADS_STATUS rc;
	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
	ADS_STRUCT *ads;
	const char *attrs[] = {"memberOf", NULL};
	uint32_t num_groups = 0;
	struct dom_sid *group_sids = NULL;
	int i;
	char **strings = NULL;
	size_t num_strings = 0, num_sids = 0;


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

	if ( !winbindd_can_contact_domain( domain ) ) {
		DEBUG(10,("lookup_usergroups_memberof: 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;
		return NT_STATUS_UNSUCCESSFUL;
	}

	rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
						 ADS_EXTENDED_DN_HEX_STRING,
						 &strings, &num_strings);

	if (!ADS_ERR_OK(rc)) {
		DEBUG(1,("lookup_usergroups_memberof ads_search "
			"member=%s: %s\n", user_dn, ads_errstr(rc)));
		return ads_ntstatus(rc);
	}

	*user_sids = NULL;
	num_groups = 0;

	/* always add the primary group to the sid array */
	status = add_sid_to_array(mem_ctx, primary_group, user_sids,
				  &num_groups);
	if (!NT_STATUS_IS_OK(status)) {
		goto done;
	}

	group_sids = talloc_zero_array(mem_ctx, struct dom_sid, num_strings + 1);
	if (!group_sids) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}

	for (i=0; i<num_strings; i++) {
		rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
						  ADS_EXTENDED_DN_HEX_STRING,
						  &(group_sids)[i]);
		if (!ADS_ERR_OK(rc)) {
			/* ignore members without SIDs */
			if (NT_STATUS_EQUAL(ads_ntstatus(rc),
			    NT_STATUS_NOT_FOUND)) {
				continue;
			}
			else {
				status = ads_ntstatus(rc);
				goto done;
			}
		}
		num_sids++;
	}

	if (i == 0) {
		DEBUG(1,("No memberOf for this user?!?\n"));
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}

	for (i=0; i<num_sids; i++) {

		/* ignore Builtin groups from ADS - Guenther */
		if (sid_check_is_in_builtin(&group_sids[i])) {
			continue;
		}

		status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
					  &num_groups);
		if (!NT_STATUS_IS_OK(status)) {
			goto done;
		}

	}

	*p_num_groups = num_groups;
	status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;

	DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
		user_dn));

done:
	TALLOC_FREE(strings);
	TALLOC_FREE(group_sids);

	return status;
}
Example #11
0
/* Lookup groups a user is a member of - alternate method, for when
   tokenGroups are not available. */
static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
					 TALLOC_CTX *mem_ctx,
					 const char *user_dn, 
					 struct dom_sid *primary_group,
					 uint32_t *p_num_groups, struct dom_sid **user_sids)
{
	ADS_STATUS rc;
	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
	int count;
	LDAPMessage *res = NULL;
	LDAPMessage *msg = NULL;
	char *ldap_exp;
	ADS_STRUCT *ads;
	const char *group_attrs[] = {"objectSid", NULL};
	char *escaped_dn;
	uint32_t num_groups = 0;

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

	if ( !winbindd_can_contact_domain( domain ) ) {
		DEBUG(10,("lookup_usergroups_members: 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;
	}

	if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}

	ldap_exp = talloc_asprintf(mem_ctx,
		"(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
		escaped_dn,
		ADS_LDAP_MATCHING_RULE_BIT_AND,
		GROUP_TYPE_SECURITY_ENABLED);
	if (!ldap_exp) {
		DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
		TALLOC_FREE(escaped_dn);
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}

	TALLOC_FREE(escaped_dn);

	rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);

	if (!ADS_ERR_OK(rc) || !res) {
		DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
		return ads_ntstatus(rc);
	}

	count = ads_count_replies(ads, res);

	*user_sids = NULL;
	num_groups = 0;

	/* always add the primary group to the sid array */
	status = add_sid_to_array(mem_ctx, primary_group, user_sids,
				  &num_groups);
	if (!NT_STATUS_IS_OK(status)) {
		goto done;
	}

	if (count > 0) {
		for (msg = ads_first_entry(ads, res); msg;
		     msg = ads_next_entry(ads, msg)) {
			struct dom_sid group_sid;

			if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
				DEBUG(1,("No sid for this group ?!?\n"));
				continue;
			}

			/* ignore Builtin groups from ADS - Guenther */
			if (sid_check_is_in_builtin(&group_sid)) {
				continue;
			}

			status = add_sid_to_array(mem_ctx, &group_sid,
						  user_sids, &num_groups);
			if (!NT_STATUS_IS_OK(status)) {
				goto done;
			}
		}

	}

	*p_num_groups = num_groups;
	status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;

	DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
done:
	if (res) 
		ads_msgfree(ads, res);

	return status;
}
Example #12
0
NTSTATUS sid_array_from_info3(TALLOC_CTX *mem_ctx,
			      const struct netr_SamInfo3 *info3,
			      struct dom_sid **user_sids,
			      uint32_t *num_user_sids,
			      bool include_user_group_rid)
{
	NTSTATUS status;
	struct dom_sid sid;
	struct dom_sid *sid_array = NULL;
	uint32_t num_sids = 0;
	int i;

	if (include_user_group_rid) {
		if (!sid_compose(&sid, info3->base.domain_sid, info3->base.rid)) {
			DEBUG(3, ("could not compose user SID from rid 0x%x\n",
				  info3->base.rid));
			return NT_STATUS_INVALID_PARAMETER;
		}
		status = add_sid_to_array(mem_ctx, &sid, &sid_array, &num_sids);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(3, ("could not append user SID from rid 0x%x\n",
				  info3->base.rid));
			return status;
		}
	}

	if (!sid_compose(&sid, info3->base.domain_sid, info3->base.primary_gid)) {
		DEBUG(3, ("could not compose group SID from rid 0x%x\n",
			  info3->base.primary_gid));
		return NT_STATUS_INVALID_PARAMETER;
	}
	status = add_sid_to_array(mem_ctx, &sid, &sid_array, &num_sids);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(3, ("could not append group SID from rid 0x%x\n",
			  info3->base.rid));
		return status;
	}

	for (i = 0; i < info3->base.groups.count; i++) {
		/* Don't add the primary group sid twice. */
		if (info3->base.primary_gid == info3->base.groups.rids[i].rid) {
			continue;
		}
		if (!sid_compose(&sid, info3->base.domain_sid,
				 info3->base.groups.rids[i].rid)) {
			DEBUG(3, ("could not compose SID from additional group "
				  "rid 0x%x\n", info3->base.groups.rids[i].rid));
			return NT_STATUS_INVALID_PARAMETER;
		}
		status = add_sid_to_array(mem_ctx, &sid, &sid_array, &num_sids);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(3, ("could not append SID from additional group "
				  "rid 0x%x\n", info3->base.groups.rids[i].rid));
			return status;
		}
	}

	/* Copy 'other' sids.  We need to do sid filtering here to
 	   prevent possible elevation of privileges.  See:

           http://www.microsoft.com/windows2000/techinfo/administration/security/sidfilter.asp
         */

	for (i = 0; i < info3->sidcount; i++) {
		status = add_sid_to_array(mem_ctx, info3->sids[i].sid,
				      &sid_array, &num_sids);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(3, ("could not add SID to array: %s\n",
				  sid_string_dbg(info3->sids[i].sid)));
			return status;
		}
	}

	*user_sids = sid_array;
	*num_user_sids = num_sids;

	return NT_STATUS_OK;
}
Example #13
0
enum winbindd_result winbindd_dual_getsidaliases(struct winbindd_domain *domain,
						 struct winbindd_cli_state *state)
{
	DOM_SID *sids = NULL;
	size_t num_sids = 0;
	char *sidstr = NULL;
	ssize_t len;
	size_t i;
	uint32 num_aliases;
	uint32 *alias_rids;
	NTSTATUS result;

	DEBUG(3, ("[%5lu]: getsidaliases\n", (unsigned long)state->pid));

	sidstr = state->request->extra_data.data;
	if (sidstr == NULL) {
		sidstr = talloc_strdup(state->mem_ctx, "\n"); /* No SID */
		if (!sidstr) {
			DEBUG(0, ("Out of memory\n"));
			return WINBINDD_ERROR;
		}
	}

	DEBUG(10, ("Sidlist: %s\n", sidstr));

	if (!parse_sidlist(state->mem_ctx, sidstr, &sids, &num_sids)) {
		DEBUG(0, ("Could not parse SID list: %s\n", sidstr));
		return WINBINDD_ERROR;
	}

	num_aliases = 0;
	alias_rids = NULL;

	result = domain->methods->lookup_useraliases(domain,
						     state->mem_ctx,
						     num_sids, sids,
						     &num_aliases,
						     &alias_rids);

	if (!NT_STATUS_IS_OK(result)) {
		DEBUG(3, ("Could not lookup_useraliases: %s\n",
			  nt_errstr(result)));
		return WINBINDD_ERROR;
	}

	num_sids = 0;
	sids = NULL;
	sidstr = NULL;

	DEBUG(10, ("Got %d aliases\n", num_aliases));

	for (i=0; i<num_aliases; i++) {
		DOM_SID sid;
		DEBUGADD(10, (" rid %d\n", alias_rids[i]));
		sid_copy(&sid, &domain->sid);
		sid_append_rid(&sid, alias_rids[i]);
		result = add_sid_to_array(state->mem_ctx, &sid, &sids,
					  &num_sids);
		if (!NT_STATUS_IS_OK(result)) {
			return WINBINDD_ERROR;
		}
	}


	if (!print_sidlist(state->mem_ctx, sids, num_sids, &sidstr, &len)) {
		DEBUG(0, ("Could not print_sidlist\n"));
		state->response->extra_data.data = NULL;
		return WINBINDD_ERROR;
	}

	state->response->extra_data.data = NULL;

	if (sidstr) {
		state->response->extra_data.data = sidstr;
		DEBUG(10, ("aliases_list: %s\n",
			   (char *)state->response->extra_data.data));
		state->response->length += len+1;
		state->response->data.num_entries = num_sids;
	}

	return WINBINDD_OK;
}