Exemplo n.º 1
0
void idmap_cache_set_sid2gid(const struct dom_sid *sid, gid_t gid)
{
	time_t now = time(NULL);
	time_t timeout;
	fstring sidstr, key, value;

	if (!is_null_sid(sid)) {
		fstr_sprintf(key, "IDMAP/SID2GID/%s",
			     sid_to_fstring(sidstr, sid));
		fstr_sprintf(value, "%d", (int)gid);
		timeout = (gid == -1)
			? lp_idmap_negative_cache_time()
			: lp_idmap_cache_time();
		gencache_set(key, value, now + timeout);
	}
	if (gid != -1) {
		fstr_sprintf(key, "IDMAP/GID2SID/%d", (int)gid);
		if (is_null_sid(sid)) {
			/* negative gid mapping */
			fstrcpy(value, "-");
			timeout = lp_idmap_negative_cache_time();
		}
		else {
			sid_to_fstring(value, sid);
			timeout = lp_idmap_cache_time();
		}
		gencache_set(key, value, now + timeout);
	}
}
Exemplo n.º 2
0
NTSTATUS idmap_gid_to_sid(struct dom_sid *sid, gid_t gid)
{
	NTSTATUS ret;
	struct id_map map;
	bool expired;

	DEBUG(10, ("idmap_gid_to_sid: gid = [%lu]\n", (unsigned long)gid));

	if (winbindd_use_idmap_cache()
	    && idmap_cache_find_gid2sid(gid, sid, &expired)) {
		DEBUG(10, ("idmap_cache_find_gid2sid found %u%s\n",
			(unsigned int)gid,
			   expired ? " (expired)": ""));
		if (expired && idmap_is_online()) {
			DEBUG(10, ("revalidating expired entry\n"));
			goto backend;
		}
		if (is_null_sid(sid)) {
			DEBUG(10, ("Returning negative cache entry\n"));
			return NT_STATUS_NONE_MAPPED;
		}
		DEBUG(10, ("Returning positive cache entry\n"));
		return NT_STATUS_OK;
	}

backend:
	ZERO_STRUCT(map);
	map.sid = sid;
	map.xid.type = ID_TYPE_GID;
	map.xid.id = gid;

	ret = idmap_backends_unixid_to_sid(&map);
	if ( ! NT_STATUS_IS_OK(ret)) {
		DEBUG(10, ("error mapping gid [%lu]: %s\n", (unsigned long)gid,
			   nt_errstr(ret)));
		map.status = ID_UNMAPPED;
	}

	if (map.status != ID_MAPPED) {
		if (winbindd_use_idmap_cache()) {
			struct dom_sid null_sid;
			struct unixid id;
			id.type = ID_TYPE_GID;
			id.id = gid;
			ZERO_STRUCT(null_sid);
			idmap_cache_set_sid2unixid(&null_sid, &id);
		}
		DEBUG(10, ("gid [%lu] not mapped\n", (unsigned long)gid));
		return NT_STATUS_NONE_MAPPED;
	}

	if (winbindd_use_idmap_cache()) {
		idmap_cache_set_sid2unixid(sid, &map.xid);
	}

	return NT_STATUS_OK;
}
Exemplo n.º 3
0
NTSTATUS idmap_gid_to_sid(const char *domname, DOM_SID *sid, gid_t gid)
{
	NTSTATUS ret;
	struct id_map map;
	bool expired;

	DEBUG(10,("idmap_gid_to_si: gid = [%lu], domain = '%s'\n",
		  (unsigned long)gid, domname?domname:"NULL"));

	if (winbindd_use_idmap_cache()
	    && idmap_cache_find_gid2sid(gid, sid, &expired)) {
		DEBUG(10, ("idmap_cache_find_gid2sid found %d%s\n", gid,
			   expired ? " (expired)": ""));
		if (expired && idmap_is_online()) {
			DEBUG(10, ("revalidating expired entry\n"));
			goto backend;
		}
		if (is_null_sid(sid)) {
			DEBUG(10, ("Returning negative cache entry\n"));
			return NT_STATUS_NONE_MAPPED;
		}
		DEBUG(10, ("Returning positive cache entry\n"));
		return NT_STATUS_OK;
	}

backend:
	map.sid = sid;
	map.xid.type = ID_TYPE_GID;
	map.xid.id = gid;

	ret = idmap_backends_unixid_to_sid(domname, &map);
	if ( ! NT_STATUS_IS_OK(ret)) {
		DEBUG(10, ("error mapping gid [%lu]\n", (unsigned long)gid));
		return ret;
	}

	if (map.status != ID_MAPPED) {
		if (winbindd_use_idmap_cache()) {
			struct dom_sid null_sid;
			ZERO_STRUCT(null_sid);
			idmap_cache_set_sid2uid(&null_sid, gid);
		}
		DEBUG(10, ("gid [%lu] not mapped\n", (unsigned long)gid));
		return NT_STATUS_NONE_MAPPED;
	}

	if (winbindd_use_idmap_cache()) {
		idmap_cache_set_sid2gid(sid, gid);
	}

	return NT_STATUS_OK;
}
Exemplo n.º 4
0
NTSTATUS samu_to_SamInfo3(TALLOC_CTX *mem_ctx,
			  struct samu *samu,
			  const char *login_server,
			  struct netr_SamInfo3 **_info3,
			  struct extra_auth_info *extra)
{
	struct netr_SamInfo3 *info3;
	const struct dom_sid *user_sid;
	const struct dom_sid *group_sid;
	struct dom_sid domain_sid;
	struct dom_sid *group_sids;
	uint32_t num_group_sids = 0;
	const char *tmp;
	gid_t *gids;
	NTSTATUS status;
	bool ok;

	user_sid = pdb_get_user_sid(samu);
	group_sid = pdb_get_group_sid(samu);

	if (!user_sid || !group_sid) {
		DEBUG(1, ("Sam account is missing sids!\n"));
		return NT_STATUS_UNSUCCESSFUL;
	}

	info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
	if (!info3) {
		return NT_STATUS_NO_MEMORY;
	}

	ZERO_STRUCT(domain_sid);

	/* check if this is a "Unix Users" domain user,
	 * we need to handle it in a special way if that's the case */
	if (sid_check_is_in_unix_users(user_sid)) {
		/* in info3 you can only set rids for the user and the
		 * primary group, and the domain sid must be that of
		 * the sam domain.
		 *
		 * Store a completely bogus value here.
		 * The real SID is stored in the extra sids.
		 * Other code will know to look there if (-1) is found
		 */
		info3->base.rid = (uint32_t)(-1);
		sid_copy(&extra->user_sid, user_sid);

		DEBUG(10, ("Unix User found in struct samu. Rid marked as "
			   "special and sid (%s) saved as extra sid\n",
			   sid_string_dbg(user_sid)));
	} else {
		sid_copy(&domain_sid, user_sid);
		sid_split_rid(&domain_sid, &info3->base.rid);
	}

	if (is_null_sid(&domain_sid)) {
		sid_copy(&domain_sid, get_global_sam_sid());
	}

	/* check if this is a "Unix Groups" domain group,
	 * if so we need special handling */
	if (sid_check_is_in_unix_groups(group_sid)) {
		/* in info3 you can only set rids for the user and the
		 * primary group, and the domain sid must be that of
		 * the sam domain.
		 *
		 * Store a completely bogus value here.
		 * The real SID is stored in the extra sids.
		 * Other code will know to look there if (-1) is found
		 */
		info3->base.primary_gid = (uint32_t)(-1);
		sid_copy(&extra->pgid_sid, group_sid);

		DEBUG(10, ("Unix Group found in struct samu. Rid marked as "
			   "special and sid (%s) saved as extra sid\n",
			   sid_string_dbg(group_sid)));

	} else {
		ok = sid_peek_check_rid(&domain_sid, group_sid,
					&info3->base.primary_gid);
		if (!ok) {
			DEBUG(1, ("The primary group domain sid(%s) does not "
				  "match the domain sid(%s) for %s(%s)\n",
				  sid_string_dbg(group_sid),
				  sid_string_dbg(&domain_sid),
				  pdb_get_username(samu),
				  sid_string_dbg(user_sid)));
			TALLOC_FREE(info3);
			return NT_STATUS_UNSUCCESSFUL;
		}
	}

	unix_to_nt_time(&info3->base.last_logon, pdb_get_logon_time(samu));
	unix_to_nt_time(&info3->base.last_logoff, get_time_t_max());
	unix_to_nt_time(&info3->base.acct_expiry, get_time_t_max());
	unix_to_nt_time(&info3->base.last_password_change,
			pdb_get_pass_last_set_time(samu));
	unix_to_nt_time(&info3->base.allow_password_change,
			pdb_get_pass_can_change_time(samu));
	unix_to_nt_time(&info3->base.force_password_change,
			pdb_get_pass_must_change_time(samu));

	tmp = pdb_get_username(samu);
	if (tmp) {
		info3->base.account_name.string	= talloc_strdup(info3, tmp);
		RET_NOMEM(info3->base.account_name.string);
	}
	tmp = pdb_get_fullname(samu);
	if (tmp) {
		info3->base.full_name.string = talloc_strdup(info3, tmp);
		RET_NOMEM(info3->base.full_name.string);
	}
	tmp = pdb_get_logon_script(samu);
	if (tmp) {
		info3->base.logon_script.string = talloc_strdup(info3, tmp);
		RET_NOMEM(info3->base.logon_script.string);
	}
	tmp = pdb_get_profile_path(samu);
	if (tmp) {
		info3->base.profile_path.string	= talloc_strdup(info3, tmp);
		RET_NOMEM(info3->base.profile_path.string);
	}
	tmp = pdb_get_homedir(samu);
	if (tmp) {
		info3->base.home_directory.string = talloc_strdup(info3, tmp);
		RET_NOMEM(info3->base.home_directory.string);
	}
	tmp = pdb_get_dir_drive(samu);
	if (tmp) {
		info3->base.home_drive.string = talloc_strdup(info3, tmp);
		RET_NOMEM(info3->base.home_drive.string);
	}

	info3->base.logon_count	= pdb_get_logon_count(samu);
	info3->base.bad_password_count = pdb_get_bad_password_count(samu);

	info3->base.domain.string = talloc_strdup(info3,
						  pdb_get_domain(samu));
	RET_NOMEM(info3->base.domain.string);

	info3->base.domain_sid = dom_sid_dup(info3, &domain_sid);
	RET_NOMEM(info3->base.domain_sid);

	status = pdb_enum_group_memberships(mem_ctx, samu,
					    &group_sids, &gids,
					    &num_group_sids);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Failed to get groups from sam account.\n"));
		TALLOC_FREE(info3);
		return status;
	}

	if (num_group_sids) {
		status = group_sids_to_info3(info3, group_sids, num_group_sids);
		if (!NT_STATUS_IS_OK(status)) {
			TALLOC_FREE(info3);
			return status;
		}
	}

	/* We don't need sids and gids after the conversion */
	TALLOC_FREE(group_sids);
	TALLOC_FREE(gids);
	num_group_sids = 0;

	/* FIXME: should we add other flags ? */
	info3->base.user_flags = NETLOGON_EXTRA_SIDS;

	if (login_server) {
		info3->base.logon_server.string = talloc_strdup(info3, login_server);
		RET_NOMEM(info3->base.logon_server.string);
	}

	info3->base.acct_flags = pdb_get_acct_ctrl(samu);

	*_info3 = info3;
	return NT_STATUS_OK;
}
/* Add a trusted domain to our list of domains */
static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
						  struct winbindd_methods *methods,
						  const struct dom_sid *sid)
{
	struct winbindd_domain *domain;
	const char *alternative_name = NULL;
	char *idmap_config_option;
	const char *param;
	const char **ignored_domains, **dom;

	ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
	for (dom=ignored_domains; dom && *dom; dom++) {
		if (gen_fnmatch(*dom, domain_name) == 0) {
			DEBUG(2,("Ignoring domain '%s'\n", domain_name));
			return NULL;
		}
	}

	/* use alt_name if available to allow DNS lookups */

	if (alt_name && *alt_name) {
		alternative_name = alt_name;
	}

	/* 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 (strequal(domain_name, domain->name) ||
		    strequal(domain_name, domain->alt_name))
		{
			break;
		}

		if (alternative_name && *alternative_name)
		{
			if (strequal(alternative_name, domain->name) ||
			    strequal(alternative_name, domain->alt_name))
			{
				break;
			}
		}

		if (sid)
		{
			if (is_null_sid(sid)) {
				continue;
			}

			if (dom_sid_equal(sid, &domain->sid)) {
				break;
			}
		}
	}

	if (domain != NULL) {
		/*
		 * We found a match. Possibly update the SID
		 */
		if ((sid != NULL)
		    && dom_sid_equal(&domain->sid, &global_sid_NULL)) {
			sid_copy( &domain->sid, sid );
		}
		return domain;
	}

	/* Create new domain entry */
	domain = talloc_zero(NULL, struct winbindd_domain);
	if (domain == NULL) {
		return NULL;
	}

	domain->children = talloc_zero_array(domain,
					     struct winbindd_child,
					     lp_winbind_max_domain_connections());
	if (domain->children == NULL) {
		TALLOC_FREE(domain);
		return NULL;
	}

	domain->name = talloc_strdup(domain, domain_name);
	if (domain->name == NULL) {
		TALLOC_FREE(domain);
		return NULL;
	}

	if (alternative_name) {
		domain->alt_name = talloc_strdup(domain, alternative_name);
		if (domain->alt_name == NULL) {
			TALLOC_FREE(domain);
			return NULL;
		}
	}

	domain->methods = methods;
	domain->backend = NULL;
	domain->internal = is_internal_domain(sid);
	domain->sequence_number = DOM_SEQUENCE_NONE;
	domain->last_seq_check = 0;
	domain->initialized = False;
	domain->online = is_internal_domain(sid);
	domain->check_online_timeout = 0;
	domain->dc_probe_pid = (pid_t)-1;
	if (sid) {
		sid_copy(&domain->sid, sid);
	}

	/* Link to domain list */
	DLIST_ADD_END(_domain_list, domain, struct winbindd_domain *);

	wcache_tdc_add_domain( domain );

	idmap_config_option = talloc_asprintf(talloc_tos(), "idmap config %s",
					      domain->name);
	if (idmap_config_option == NULL) {
		DEBUG(0, ("talloc failed, not looking for idmap config\n"));
		goto done;
	}

	param = lp_parm_const_string(-1, idmap_config_option, "range", NULL);

	DEBUG(10, ("%s : range = %s\n", idmap_config_option,
		   param ? param : "not defined"));

	if (param != NULL) {
		unsigned low_id, high_id;
		if (sscanf(param, "%u - %u", &low_id, &high_id) != 2) {
			DEBUG(1, ("invalid range syntax in %s: %s\n",
				  idmap_config_option, param));
			goto done;
		}
		if (low_id > high_id) {
			DEBUG(1, ("invalid range in %s: %s\n",
				  idmap_config_option, param));
			goto done;
		}
		domain->have_idmap_config = true;
		domain->id_range_low = low_id;
		domain->id_range_high = high_id;
	}

done:

	DEBUG(2,("Added domain %s %s %s\n",
		 domain->name, domain->alt_name,
		 &domain->sid?sid_string_dbg(&domain->sid):""));

	return domain;
}
Exemplo n.º 6
0
/* Add a trusted domain out of a trusted domain cache
   entry
*/
static struct winbindd_domain *
add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
{
	struct winbindd_domain *domain;
	const char *alternative_name = NULL;
	const char **ignored_domains, **dom;
	int role = lp_server_role();
	const char *domain_name = tdc->domain_name;
	const struct dom_sid *sid = &tdc->sid;

	if (is_null_sid(sid)) {
		sid = NULL;
	}

	ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
	for (dom=ignored_domains; dom && *dom; dom++) {
		if (gen_fnmatch(*dom, domain_name) == 0) {
			DEBUG(2,("Ignoring domain '%s'\n", domain_name));
			return NULL;
		}
	}

	/* use alt_name if available to allow DNS lookups */

	if (tdc->dns_name && *tdc->dns_name) {
		alternative_name = tdc->dns_name;
	}

	/* 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 (strequal(domain_name, domain->name) ||
		    strequal(domain_name, domain->alt_name))
		{
			break;
		}

		if (alternative_name) {
			if (strequal(alternative_name, domain->name) ||
			    strequal(alternative_name, domain->alt_name))
			{
				break;
			}
		}

		if (sid != NULL) {
			if (dom_sid_equal(sid, &domain->sid)) {
				break;
			}
		}
	}

	if (domain != NULL) {
		/*
		 * We found a match on domain->name or
		 * domain->alt_name. Possibly update the SID
		 * if the stored SID was the NULL SID
		 * and return the matching entry.
		 */
		if ((sid != NULL)
		    && dom_sid_equal(&domain->sid, &global_sid_NULL)) {
			sid_copy( &domain->sid, sid );
		}
		return domain;
	}

	/* Create new domain entry */
	domain = talloc_zero(NULL, struct winbindd_domain);
	if (domain == NULL) {
		return NULL;
	}

	domain->children = talloc_zero_array(domain,
					     struct winbindd_child,
					     lp_winbind_max_domain_connections());
	if (domain->children == NULL) {
		TALLOC_FREE(domain);
		return NULL;
	}

	domain->name = talloc_strdup(domain, domain_name);
	if (domain->name == NULL) {
		TALLOC_FREE(domain);
		return NULL;
	}

	if (alternative_name) {
		domain->alt_name = talloc_strdup(domain, alternative_name);
		if (domain->alt_name == NULL) {
			TALLOC_FREE(domain);
			return NULL;
		}
	}

	domain->backend = NULL;
	domain->internal = is_internal_domain(sid);
	domain->sequence_number = DOM_SEQUENCE_NONE;
	domain->last_seq_check = 0;
	domain->initialized = false;
	domain->online = is_internal_domain(sid);
	domain->check_online_timeout = 0;
	domain->dc_probe_pid = (pid_t)-1;
	if (sid != NULL) {
		sid_copy(&domain->sid, sid);
	}
	domain->domain_flags = tdc->trust_flags;
	domain->domain_type = tdc->trust_type;
	domain->domain_trust_attribs = tdc->trust_attribs;

	/* Is this our primary domain ? */
	if (strequal(domain_name, get_global_sam_name()) &&
			(role != ROLE_DOMAIN_MEMBER)) {
		domain->primary = true;
	} else if (strequal(domain_name, lp_workgroup()) &&
			(role == ROLE_DOMAIN_MEMBER)) {
		domain->primary = true;
	}

	if (domain->primary) {
		if (role == ROLE_ACTIVE_DIRECTORY_DC) {
			domain->active_directory = true;
		}
		if (lp_security() == SEC_ADS) {
			domain->active_directory = true;
		}
	} else if (!domain->internal) {
		if (domain->domain_type == LSA_TRUST_TYPE_UPLEVEL) {
			domain->active_directory = true;
		}
	}

	/* Link to domain list */
	DLIST_ADD_END(_domain_list, domain);

	wcache_tdc_add_domain( domain );

	setup_domain_child(domain);

	DEBUG(2,
	      ("Added domain %s %s %s\n", domain->name, domain->alt_name,
	       !is_null_sid(&domain->sid) ? sid_string_dbg(&domain->sid) : ""));

	return domain;
}
Exemplo n.º 7
0
NTSTATUS passwd_to_SamInfo3(TALLOC_CTX *mem_ctx,
			    const char *unix_username,
			    const struct passwd *pwd,
			    struct netr_SamInfo3 **pinfo3,
			    struct extra_auth_info *extra)
{
	struct netr_SamInfo3 *info3;
	NTSTATUS status;
	TALLOC_CTX *tmp_ctx;
	const char *domain_name = NULL;
	const char *user_name = NULL;
	struct dom_sid domain_sid;
	struct dom_sid user_sid;
	struct dom_sid group_sid;
	enum lsa_SidType type;
	uint32_t num_sids = 0;
	struct dom_sid *user_sids = NULL;
	bool is_null;
	bool ok;

	tmp_ctx = talloc_stackframe();

	ok = lookup_name_smbconf(tmp_ctx,
				 unix_username,
				 LOOKUP_NAME_ALL,
				 &domain_name,
				 &user_name,
				 &user_sid,
				 &type);
	if (!ok) {
		status = NT_STATUS_NO_SUCH_USER;
		goto done;
	}

	if (type != SID_NAME_USER) {
		status = NT_STATUS_NO_SUCH_USER;
		goto done;
	}

	ok = winbind_lookup_usersids(tmp_ctx,
				     &user_sid,
				     &num_sids,
				     &user_sids);
	/* Check if winbind is running */
	if (ok) {
		/*
		 * Winbind is running and the first element of the user_sids
		 * is the primary group.
		 */
		if (num_sids > 0) {
			group_sid = user_sids[0];
		}
	} else {
		/*
		 * Winbind is not running, try to create the group_sid from the
		 * passwd group id.
		 */

		/*
		 * This can lead to a primary group of S-1-22-2-XX which
		 * will be rejected by other Samba code.
		 */
		gid_to_sid(&group_sid, pwd->pw_gid);
	}

	/*
	 * If we are a unix group, or a wellknown/builtin alias,
	 * set the group_sid to the
	 * 'Domain Users' RID of 513 which will always resolve to a
	 * name.
	 */
	if (sid_check_is_in_unix_groups(&group_sid) ||
	    sid_check_is_in_builtin(&group_sid) ||
	    sid_check_is_in_wellknown_domain(&group_sid)) {
		if (sid_check_is_in_unix_users(&user_sid)) {
			sid_compose(&group_sid,
				    get_global_sam_sid(),
				    DOMAIN_RID_USERS);
		} else {
			sid_copy(&domain_sid, &user_sid);
			sid_split_rid(&domain_sid, NULL);
			sid_compose(&group_sid,
				    &domain_sid,
				    DOMAIN_RID_USERS);
		}
	}

	/* Make sure we have a valid group sid */
	is_null = is_null_sid(&group_sid);
	if (is_null) {
		status = NT_STATUS_NO_SUCH_USER;
		goto done;
	}

	/* Construct a netr_SamInfo3 from the information we have */
	info3 = talloc_zero(tmp_ctx, struct netr_SamInfo3);
	if (!info3) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}

	info3->base.account_name.string = talloc_strdup(info3, unix_username);
	if (info3->base.account_name.string == NULL) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}

	ZERO_STRUCT(domain_sid);

	status = SamInfo3_handle_sids(unix_username,
				&user_sid,
				&group_sid,
				info3,
				&domain_sid,
				extra);

	if (!NT_STATUS_IS_OK(status)) {
		goto done;
	}

	info3->base.domain_sid = dom_sid_dup(info3, &domain_sid);
	if (info3->base.domain_sid == NULL) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}

	ok = sid_peek_check_rid(&domain_sid, &group_sid,
				&info3->base.primary_gid);
	if (!ok) {
		DEBUG(1, ("The primary group domain sid(%s) does not "
			  "match the domain sid(%s) for %s(%s)\n",
			  sid_string_dbg(&group_sid),
			  sid_string_dbg(&domain_sid),
			  unix_username,
			  sid_string_dbg(&user_sid)));
		status = NT_STATUS_INVALID_SID;
		goto done;
	}

	info3->base.acct_flags = ACB_NORMAL;

	if (num_sids) {
		status = group_sids_to_info3(info3, user_sids, num_sids);
		if (!NT_STATUS_IS_OK(status)) {
			goto done;
		}
	}

	*pinfo3 = talloc_steal(mem_ctx, info3);

	status = NT_STATUS_OK;
done:
	talloc_free(tmp_ctx);

	return status;
}
Exemplo n.º 8
0
static NTSTATUS SamInfo3_handle_sids(const char *username,
			const struct dom_sid *user_sid,
			const struct dom_sid *group_sid,
			struct netr_SamInfo3 *info3,
			struct dom_sid *domain_sid,
			struct extra_auth_info *extra)
{
	if (sid_check_is_in_unix_users(user_sid)) {
		/* in info3 you can only set rids for the user and the
		 * primary group, and the domain sid must be that of
		 * the sam domain.
		 *
		 * Store a completely bogus value here.
		 * The real SID is stored in the extra sids.
		 * Other code will know to look there if (-1) is found
		 */
		info3->base.rid = (uint32_t)(-1);
		sid_copy(&extra->user_sid, user_sid);

		DEBUG(10, ("Unix User found. Rid marked as "
			"special and sid (%s) saved as extra sid\n",
			sid_string_dbg(user_sid)));
	} else {
		sid_copy(domain_sid, user_sid);
		sid_split_rid(domain_sid, &info3->base.rid);
	}

	if (is_null_sid(domain_sid)) {
		sid_copy(domain_sid, get_global_sam_sid());
	}

	/* check if this is a "Unix Groups" domain group,
	 * if so we need special handling */
	if (sid_check_is_in_unix_groups(group_sid)) {
		/* in info3 you can only set rids for the user and the
		 * primary group, and the domain sid must be that of
		 * the sam domain.
		 *
		 * Store a completely bogus value here.
		 * The real SID is stored in the extra sids.
		 * Other code will know to look there if (-1) is found
		 */
		info3->base.primary_gid = (uint32_t)(-1);
		sid_copy(&extra->pgid_sid, group_sid);

		DEBUG(10, ("Unix Group found. Rid marked as "
			"special and sid (%s) saved as extra sid\n",
			sid_string_dbg(group_sid)));
	} else {
		bool ok = sid_peek_check_rid(domain_sid, group_sid,
					&info3->base.primary_gid);
		if (!ok) {
			DEBUG(1, ("The primary group domain sid(%s) does not "
				"match the domain sid(%s) for %s(%s)\n",
				sid_string_dbg(group_sid),
				sid_string_dbg(domain_sid),
				username,
				sid_string_dbg(user_sid)));
			return NT_STATUS_INVALID_SID;
		}
	}
	return NT_STATUS_OK;
}