Beispiel #1
0
/*
 * lsar_lookup_sids3
 *
 * This function is only valid if the remote RPC server is a domain
 * controller and requires the security extensions defined in MS-RPCE.
 *
 * Domain controllers will return RPC_NT_PROTSEQ_NOT_SUPPORTED here
 * because we don't support the RPC_C_AUTHN_NETLOGON security provider.
 * Non-domain controllers will return NT_STATUS_INVALID_SERVER_STATE.
 */
static uint32_t /*LINTED E_STATIC_UNUSED*/
lsar_lookup_sids3(mlsvc_handle_t *lsa_handle, lsa_sid_t *sid,
    smb_account_t *account)
{
	struct lsar_lookup_sids3	arg;
	lsar_translated_name_ex_t	*name_entry;
	struct mslsa_lup_sid_entry	sid_entry;
	struct mslsa_domain_entry	*domain_entry;
	uint32_t			status = NT_STATUS_SUCCESS;
	char				*name;
	int				opnum = LSARPC_OPNUM_LookupSids3;

	bzero(&arg, sizeof (struct lsar_lookup_sids3));

	sid_entry.psid = sid;
	arg.lup_sid_table.n_entry = 1;
	arg.lup_sid_table.entries = &sid_entry;
	arg.lookup_level = LSA_LOOKUP_WKSTA;
	arg.client_revision = LSA_CLIENT_REVISION_AD;

	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
		ndr_rpc_release(lsa_handle);
		return (NT_STATUS_INVALID_PARAMETER);
	}

	if (arg.status != NT_STATUS_SUCCESS) {
		ndr_rpc_status(lsa_handle, opnum, arg.status);
		ndr_rpc_release(lsa_handle);
		if (arg.status == RPC_NT_PROTSEQ_NOT_SUPPORTED ||
		    arg.status == NT_STATUS_INVALID_SERVER_STATE)
			return (NT_STATUS_INVALID_PARAMETER);
		return (NT_SC_VALUE(arg.status));
	}

	if (arg.mapped_count == 0) {
		ndr_rpc_release(lsa_handle);
		return (NT_STATUS_NONE_MAPPED);
	}

	name_entry = &arg.name_table.entries[0];
	if (name_entry->domain_ix != 0) {
		ndr_rpc_release(lsa_handle);
		return (NT_STATUS_NONE_MAPPED);
	}

	name = (char *)name_entry->name.str;
	account->a_name = (name) ? strdup(name) : strdup("");
	account->a_type = name_entry->sid_name_use;
	account->a_sid = smb_sid_dup((smb_sid_t *)sid);
	(void) smb_sid_getrid(account->a_sid, &account->a_rid);

	domain_entry = &arg.domain_table->entries[0];
	if ((name = (char *)domain_entry->domain_name.str) != NULL)
		account->a_domain = strdup(name);
	account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);

	ndr_rpc_release(lsa_handle);
	return (status);
}
Beispiel #2
0
/*
 * lsar_lookup_sids1
 */
static uint32_t
lsar_lookup_sids1(mlsvc_handle_t *lsa_handle, lsa_sid_t *sid,
    smb_account_t *account)
{
	struct mslsa_LookupSids		arg;
	struct mslsa_lup_sid_entry	sid_entry;
	struct mslsa_name_entry		*name_entry;
	struct mslsa_domain_entry	*domain_entry;
	uint32_t			status = NT_STATUS_SUCCESS;
	char				*name;
	int				opnum = LSARPC_OPNUM_LookupSids;

	bzero(&arg, sizeof (struct mslsa_LookupSids));
	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
	arg.lookup_level = LSA_LOOKUP_WKSTA;

	sid_entry.psid = sid;
	arg.lup_sid_table.n_entry = 1;
	arg.lup_sid_table.entries = &sid_entry;

	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
		ndr_rpc_release(lsa_handle);
		return (NT_STATUS_INVALID_PARAMETER);
	}

	if (arg.status != NT_STATUS_SUCCESS) {
		ndr_rpc_status(lsa_handle, opnum, arg.status);
		ndr_rpc_release(lsa_handle);
		return (NT_SC_VALUE(arg.status));
	}

	if (arg.mapped_count == 0) {
		ndr_rpc_release(lsa_handle);
		return (NT_STATUS_NONE_MAPPED);
	}

	name_entry = &arg.name_table.entries[0];
	if (name_entry->domain_ix != 0) {
		ndr_rpc_release(lsa_handle);
		return (NT_STATUS_NONE_MAPPED);
	}

	name = (char *)name_entry->name.str;
	account->a_name = (name) ? strdup(name) : strdup("");
	account->a_type = name_entry->sid_name_use;
	account->a_sid = smb_sid_dup((smb_sid_t *)sid);
	(void) smb_sid_getrid(account->a_sid, &account->a_rid);

	domain_entry = &arg.domain_table->entries[0];
	if ((name = (char *)domain_entry->domain_name.str) != NULL)
		account->a_domain = strdup(name);
	account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);

	ndr_rpc_release(lsa_handle);
	return (status);
}
Beispiel #3
0
/*
 * lsar_lookup_names4
 *
 * This function is only valid if the remote RPC server is a domain
 * controller and requires the security extensions defined in MS-RPCE.
 *
 * Domain controllers will return RPC_NT_PROTSEQ_NOT_SUPPORTED here
 * because we don't support the RPC_C_AUTHN_NETLOGON security provider.
 * Non-domain controllers will return NT_STATUS_INVALID_SERVER_STATE.
 */
static uint32_t /*LINTED E_STATIC_UNUSED*/
lsar_lookup_names4(mlsvc_handle_t *lsa_handle, lsa_names_t *names,
    smb_account_t *info)
{
	struct lsar_LookupNames4	arg;
	lsar_translated_sid_ex2_t	*sid_entry;
	struct mslsa_domain_entry	*domain_entry;
	uint32_t			status = NT_STATUS_SUCCESS;
	char				*domname;
	int				opnum = LSARPC_OPNUM_LookupNames4;

	bzero(&arg, sizeof (struct lsar_LookupNames4));
	arg.lookup_level = LSA_LOOKUP_WKSTA;
	arg.client_revision = LSA_CLIENT_REVISION_AD;
	arg.name_table = (struct mslsa_lup_name_table *)names;

	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
		ndr_rpc_release(lsa_handle);
		return (NT_STATUS_INVALID_PARAMETER);
	}

	if (arg.status != NT_STATUS_SUCCESS) {
		ndr_rpc_status(lsa_handle, opnum, arg.status);
		ndr_rpc_release(lsa_handle);
		if (arg.status == RPC_NT_PROTSEQ_NOT_SUPPORTED ||
		    arg.status == NT_STATUS_INVALID_SERVER_STATE)
			return (NT_STATUS_INVALID_PARAMETER);
		return (NT_SC_VALUE(arg.status));
	}

	if (arg.mapped_count == 0) {
		ndr_rpc_release(lsa_handle);
		return (NT_STATUS_NONE_MAPPED);
	}

	sid_entry = &arg.translated_sids.sids[0];
	if (sid_entry->domain_index != 0) {
		ndr_rpc_release(lsa_handle);
		return (NT_STATUS_NONE_MAPPED);
	}

	domain_entry = &arg.domain_table->entries[0];

	info->a_type = sid_entry->sid_name_use;
	info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
	if ((domname = (char *)domain_entry->domain_name.str) != NULL)
		info->a_domain = strdup(domname);
	info->a_sid = smb_sid_dup((smb_sid_t *)sid_entry->sid);
	(void) smb_sid_getrid(info->a_sid, &info->a_rid);

	ndr_rpc_release(lsa_handle);
	return (status);
}
Beispiel #4
0
/*
 * Lookup well known accounts table
 *
 * Return status:
 *
 *   NT_STATUS_SUCCESS		Account is translated successfully
 *   NT_STATUS_NOT_FOUND	This is not a well known account
 *   NT_STATUS_NONE_MAPPED	Account is found but domains don't match
 *   NT_STATUS_NO_MEMORY	Memory shortage
 *   NT_STATUS_INTERNAL_ERROR	Internal error/unexpected failure
 */
static uint32_t
lsa_lookup_name_builtin(char *domain, char *name, smb_account_t *info)
{
	smb_wka_t *wka;
	char *wkadom;

	bzero(info, sizeof (smb_account_t));

	if ((wka = smb_wka_lookup_name(name)) == NULL)
		return (NT_STATUS_NOT_FOUND);

	if ((wkadom = smb_wka_get_domain(wka->wka_domidx)) == NULL)
		return (NT_STATUS_INTERNAL_ERROR);

	if ((domain != NULL) && (smb_strcasecmp(domain, wkadom, 0) != 0))
		return (NT_STATUS_NONE_MAPPED);

	info->a_name = strdup(name);
	info->a_sid = smb_sid_dup(wka->wka_binsid);
	info->a_domain = strdup(wkadom);
	info->a_domsid = smb_sid_split(wka->wka_binsid, &info->a_rid);
	info->a_type = wka->wka_type;

	if (!smb_account_validate(info)) {
		smb_account_free(info);
		return (NT_STATUS_NO_MEMORY);
	}

	return (NT_STATUS_SUCCESS);
}
Beispiel #5
0
/*
 * Lookup well known accounts table for the given SID
 *
 * Return status:
 *
 *   NT_STATUS_SUCCESS		Account is translated successfully
 *   NT_STATUS_NOT_FOUND	This is not a well known account
 *   NT_STATUS_NO_MEMORY	Memory shortage
 *   NT_STATUS_INTERNAL_ERROR	Internal error/unexpected failure
 */
static uint32_t
lsa_lookup_sid_builtin(smb_sid_t *sid, smb_account_t *ainfo)
{
	smb_wka_t *wka;
	char *wkadom;

	bzero(ainfo, sizeof (smb_account_t));

	if ((wka = smb_wka_lookup_sid(sid)) == NULL)
		return (NT_STATUS_NOT_FOUND);

	if ((wkadom = smb_wka_get_domain(wka->wka_domidx)) == NULL)
		return (NT_STATUS_INTERNAL_ERROR);

	ainfo->a_name = strdup(wka->wka_name);
	ainfo->a_sid = smb_sid_dup(wka->wka_binsid);
	ainfo->a_domain = strdup(wkadom);
	ainfo->a_domsid = smb_sid_split(ainfo->a_sid, &ainfo->a_rid);
	ainfo->a_type = wka->wka_type;

	if (!smb_account_validate(ainfo)) {
		smb_account_free(ainfo);
		return (NT_STATUS_NO_MEMORY);
	}

	return (NT_STATUS_SUCCESS);
}
Beispiel #6
0
/*
 * samr_lookup_domain
 *
 * Lookup up the domain SID for the specified domain name. The handle
 * should be one returned from samr_connect. The allocated memory for
 * the returned SID must be freed by caller.
 */
smb_sid_t *
samr_lookup_domain(mlsvc_handle_t *samr_handle, char *domain_name)
{
	struct samr_LookupDomain	arg;
	smb_sid_t	*domsid = NULL;
	int		opnum;
	size_t		length;

	if (ndr_is_null_handle(samr_handle) || domain_name == NULL)
		return (NULL);

	opnum = SAMR_OPNUM_LookupDomain;
	bzero(&arg, sizeof (struct samr_LookupDomain));

	(void) memcpy(&arg.handle, &samr_handle->handle,
	    sizeof (samr_handle_t));

	length = smb_wcequiv_strlen(domain_name);
	if (ndr_rpc_server_os(samr_handle) == NATIVE_OS_WIN2000)
		length += sizeof (smb_wchar_t);

	arg.domain_name.length = length;
	arg.domain_name.allosize = length;
	arg.domain_name.str = (unsigned char *)domain_name;

	if (ndr_rpc_call(samr_handle, opnum, &arg) == 0)
		domsid = smb_sid_dup((smb_sid_t *)arg.sid);

	ndr_rpc_release(samr_handle);
	return (domsid);
}
Beispiel #7
0
/*
 * lsar_enum_accounts
 *
 * Enumerate the list of accounts (i.e. SIDs). Use the handle returned
 * from lsa_open_policy2. The enum_context is used to support multiple
 * calls to this enumeration function. It should be set to 0 on the
 * first call. It will be updated by the domain controller and should
 * simply be passed unchanged to subsequent calls until there are no
 * more accounts. A warning status of 0x1A indicates that no more data
 * is available. The list of accounts will be returned in accounts.
 * This list is dynamically allocated using malloc, it should be freed
 * by the caller when it is no longer required.
 */
int
lsar_enum_accounts(mlsvc_handle_t *lsa_handle, DWORD *enum_context,
    struct mslsa_EnumAccountBuf *accounts)
{
	struct mslsa_EnumerateAccounts	arg;
	struct mslsa_AccountInfo	*info;
	int	opnum;
	int	rc;
	DWORD	n_entries;
	DWORD	i;
	int	nbytes;

	if (lsa_handle == NULL || enum_context == NULL || accounts == NULL)
		return (-1);

	accounts->entries_read = 0;
	accounts->info = 0;

	opnum = LSARPC_OPNUM_EnumerateAccounts;

	bzero(&arg, sizeof (struct mslsa_EnumerateAccounts));
	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
	arg.enum_context = *enum_context;
	arg.max_length = MLSVC_MAX_RESPONSE_LEN;

	rc = ndr_rpc_call(lsa_handle, opnum, &arg);
	if (rc == 0) {
		if (arg.status != 0) {
			if (arg.status == NT_STATUS_NO_MORE_ENTRIES) {
				*enum_context = arg.enum_context;
			} else {
				ndr_rpc_status(lsa_handle, opnum, arg.status);
				rc = -1;
			}
		} else if (arg.enum_buf->entries_read != 0) {
			n_entries = arg.enum_buf->entries_read;
			nbytes = n_entries * sizeof (struct mslsa_AccountInfo);

			if ((info = malloc(nbytes)) == NULL) {
				ndr_rpc_release(lsa_handle);
				return (-1);
			}

			for (i = 0; i < n_entries; ++i)
				info[i].sid = (lsa_sid_t *)smb_sid_dup(
				    (smb_sid_t *)arg.enum_buf->info[i].sid);

			accounts->entries_read = n_entries;
			accounts->info = info;
			*enum_context = arg.enum_context;
		}
	}

	ndr_rpc_release(lsa_handle);
	return (rc);
}
Beispiel #8
0
/*
 * Converts groups information in the returned structure by domain controller
 * (info3) to an internal representation (gids)
 */
static uint32_t
netr_setup_domain_groups(struct netr_validation_info3 *info3, smb_ids_t *gids)
{
	smb_sid_t *domain_sid;
	smb_id_t *ids;
	int i, total_cnt;

	if ((i = info3->GroupCount) == 0)
		i++;
	i += info3->SidCount;

	total_cnt = gids->i_cnt + i;

	gids->i_ids = realloc(gids->i_ids, total_cnt * sizeof (smb_id_t));
	if (gids->i_ids == NULL)
		return (NT_STATUS_NO_MEMORY);

	domain_sid = (smb_sid_t *)info3->LogonDomainId;

	ids = gids->i_ids + gids->i_cnt;
	for (i = 0; i < info3->GroupCount; i++, gids->i_cnt++, ids++) {
		ids->i_sid = smb_sid_splice(domain_sid, info3->GroupIds[i].rid);
		if (ids->i_sid == NULL)
			return (NT_STATUS_NO_MEMORY);

		ids->i_attrs = info3->GroupIds[i].attributes;
	}

	if (info3->GroupCount == 0) {
		/*
		 * if there's no global group should add the primary group.
		 */
		ids->i_sid = smb_sid_splice(domain_sid, info3->PrimaryGroupId);
		if (ids->i_sid == NULL)
			return (NT_STATUS_NO_MEMORY);

		ids->i_attrs = 0x7;
		gids->i_cnt++;
		ids++;
	}

	/* Add the extra SIDs */
	for (i = 0; i < info3->SidCount; i++, gids->i_cnt++, ids++) {
		ids->i_sid = smb_sid_dup((smb_sid_t *)info3->ExtraSids[i].sid);
		if (ids->i_sid == NULL)
			return (NT_STATUS_NO_MEMORY);

		ids->i_attrs = info3->ExtraSids[i].attributes;
	}

	return (NT_STATUS_SUCCESS);
}
Beispiel #9
0
/*
 * Lookup local SMB group account database (/var/smb/smbgroup.db)
 * The memory for the returned SID must be freed by the caller.
 */
static uint32_t
smb_sam_lookup_group(char *name, smb_sid_t **sid)
{
	smb_group_t grp;

	if (smb_lgrp_getbyname(name, &grp) != SMB_LGRP_SUCCESS)
		return (NT_STATUS_NO_SUCH_ALIAS);

	*sid = smb_sid_dup(grp.sg_id.gs_sid);
	smb_lgrp_free(&grp);

	return ((*sid == NULL) ? NT_STATUS_NO_MEMORY : NT_STATUS_SUCCESS);
}
Beispiel #10
0
/*
 * lsar_lookup_names2
 */
static uint32_t
lsar_lookup_names2(mlsvc_handle_t *lsa_handle, lsa_names_t *names,
    smb_account_t *info)
{
	struct lsar_LookupNames2	arg;
	struct lsar_rid_entry2		*rid_entry;
	struct mslsa_domain_entry	*domain_entry;
	uint32_t			status = NT_STATUS_SUCCESS;
	char				*domname;
	int				opnum = LSARPC_OPNUM_LookupNames2;

	bzero(&arg, sizeof (struct lsar_LookupNames2));
	(void) memcpy(&arg.policy_handle, lsa_handle, sizeof (mslsa_handle_t));
	arg.lookup_level = LSA_LOOKUP_WKSTA;
	arg.client_revision = LSA_CLIENT_REVISION_AD;
	arg.name_table = (struct mslsa_lup_name_table *)names;

	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
		ndr_rpc_release(lsa_handle);
		return (NT_STATUS_INVALID_PARAMETER);
	}

	if (arg.status != NT_STATUS_SUCCESS) {
		ndr_rpc_status(lsa_handle, opnum, arg.status);
		ndr_rpc_release(lsa_handle);
		return (NT_SC_VALUE(arg.status));
	}

	if (arg.mapped_count == 0) {
		ndr_rpc_release(lsa_handle);
		return (NT_STATUS_NONE_MAPPED);
	}

	rid_entry = &arg.translated_sids.rids[0];
	if (rid_entry->domain_index != 0) {
		ndr_rpc_release(lsa_handle);
		return (NT_STATUS_NONE_MAPPED);
	}

	domain_entry = &arg.domain_table->entries[0];

	info->a_type = rid_entry->sid_name_use;
	info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
	if ((domname = (char *)domain_entry->domain_name.str) != NULL)
		info->a_domain = strdup(domname);
	info->a_rid = rid_entry->rid;
	info->a_sid = smb_sid_splice(info->a_domsid, info->a_rid);

	ndr_rpc_release(lsa_handle);
	return (status);
}
Beispiel #11
0
/*
 * smb_acl_from_zfs
 *
 * Converts given ZFS ACL to a Windows ACL.
 *
 * A pointer to allocated memory for the Win ACL will be
 * returned upon successful conversion.
 */
smb_acl_t *
smb_acl_from_zfs(acl_t *zacl)
{
	ace_t *zace;
	int numaces;
	smb_acl_t *acl;
	smb_ace_t *ace;
	smb_idmap_batch_t sib;
	smb_idmap_t *sim;
	idmap_stat idm_stat;

	idm_stat = smb_idmap_batch_create(&sib, zacl->acl_cnt,
	    SMB_IDMAP_ID2SID);
	if (idm_stat != IDMAP_SUCCESS)
		return (NULL);

	if (smb_fsacl_getsids(&sib, zacl) != IDMAP_SUCCESS) {
		smb_idmap_batch_destroy(&sib);
		return (NULL);
	}

	acl = smb_acl_alloc(ACL_REVISION, SMB_ACL_HDRSIZE, zacl->acl_cnt);

	sim = sib.sib_maps;
	for (numaces = 0, zace = zacl->acl_aclp;
	    numaces < zacl->acl_cnt;
	    zace++, numaces++, sim++) {
		ASSERT(sim->sim_sid);
		if (sim->sim_sid == NULL) {
			smb_acl_free(acl);
			acl = NULL;
			break;
		}

		ace = &acl->sl_aces[numaces];
		ace->se_hdr.se_type = zace->a_type;
		ace->se_hdr.se_flags = smb_ace_flags_fromzfs(zace->a_flags);
		ace->se_mask = zace->a_access_mask;
		ace->se_sid = smb_sid_dup(sim->sim_sid);
		ace->se_hdr.se_bsize = smb_ace_len(ace);

		acl->sl_bsize += ace->se_hdr.se_bsize;
	}

	smb_idmap_batch_destroy(&sib);
	return (acl);
}
Beispiel #12
0
smb_sid_t *
smb_sid_fromstr(const char *sidstr)
{
	smb_sid_t *sid;
	smb_sid_t *retsid;
	const char *p;
	int size;
	uint8_t i;
	unsigned long sua;

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

	if (strncmp(sidstr, "S-1-", 4) != 0)
		return (NULL);

	size = sizeof (smb_sid_t) + (NT_SID_SUBAUTH_MAX * sizeof (uint32_t));
	sid = kmem_zalloc(size, KM_SLEEP);

	sid->sid_revision = NT_SID_REVISION;
	sua = 0;
	(void) ddi_strtoul(&sidstr[4], 0, 10, &sua);
	sid->sid_authority[5] = (uint8_t)sua;

	for (i = 0, p = &sidstr[5]; i < NT_SID_SUBAUTH_MAX && *p; ++i) {
		while (*p && *p == '-')
			++p;

		if (*p < '0' || *p > '9') {
			kmem_free(sid, size);
			return (NULL);
		}

		sua = 0;
		(void) ddi_strtoul(p, 0, 10, &sua);
		sid->sid_subauth[i] = (uint32_t)sua;

		while (*p && *p != '-')
			++p;
	}

	sid->sid_subauthcnt = i;
	retsid = smb_sid_dup(sid);
	kmem_free(sid, size);

	return (retsid);
}
Beispiel #13
0
/*
 * smb_sid_split
 *
 * Take a full sid and split it into a domain sid and a relative id (rid).
 * The domain SID is allocated and a pointer to it will be returned. The
 * RID value is passed back in 'rid' arg if it's not NULL. The allocated
 * memory for the domain SID must be freed by caller.
 */
smb_sid_t *
smb_sid_split(smb_sid_t *sid, uint32_t *rid)
{
	smb_sid_t *domsid;

	if (!smb_sid_isvalid(sid) || (sid->sid_subauthcnt == 0))
		return (NULL);

	if ((domsid = smb_sid_dup(sid)) == NULL)
		return (NULL);

	--domsid->sid_subauthcnt;
	if (rid)
		*rid = domsid->sid_subauth[domsid->sid_subauthcnt];

	return (domsid);
}
Beispiel #14
0
/*
 * Looks up the given name in local account databases:
 *
 * SMB Local users are looked up in /var/smb/smbpasswd
 * SMB Local groups are looked up in /var/smb/smbgroup.db
 *
 * If the account is found, its information is populated
 * in the passed smb_account_t structure. Caller must free
 * allocated memories by calling smb_account_free() upon
 * successful return.
 *
 * The type of account is specified by 'type', which can be user,
 * alias (local group) or unknown. If the caller doesn't know
 * whether the name is a user or group name then SidTypeUnknown
 * should be passed.
 *
 * If a local user and group have the same name, the user will
 * always be picked. Note that this situation cannot happen on
 * Windows systems.
 *
 * If a SMB local user/group is found but it turns out that
 * it'll be mapped to a domain user/group the lookup is considered
 * failed and NT_STATUS_NONE_MAPPED is returned.
 *
 * Return status:
 *
 *   NT_STATUS_NOT_FOUND	This is not a local account
 *   NT_STATUS_NONE_MAPPED	It's a local account but cannot be
 *   				translated.
 *   other error status codes.
 */
uint32_t
smb_sam_lookup_name(char *domain, char *name, uint16_t type,
    smb_account_t *account)
{
	smb_domain_t di;
	smb_sid_t *sid;
	uint32_t status;
	smb_lwka_t *lwka;

	bzero(account, sizeof (smb_account_t));

	if (domain != NULL) {
		if (!smb_domain_lookup_name(domain, &di) ||
		    (di.di_type != SMB_DOMAIN_LOCAL))
			return (NT_STATUS_NOT_FOUND);

		/* Only Netbios hostname is accepted */
		if (smb_strcasecmp(domain, di.di_nbname, 0) != 0)
			return (NT_STATUS_NONE_MAPPED);
	} else {
		if (!smb_domain_lookup_type(SMB_DOMAIN_LOCAL, &di))
			return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
	}

	if (smb_strcasecmp(name, di.di_nbname, 0) == 0) {
		/* This is the local domain name */
		account->a_type = SidTypeDomain;
		account->a_name = strdup("");
		account->a_domain = strdup(di.di_nbname);
		account->a_sid = smb_sid_dup(di.di_binsid);
		account->a_domsid = smb_sid_dup(di.di_binsid);
		account->a_rid = (uint32_t)-1;

		if (!smb_account_validate(account)) {
			smb_account_free(account);
			return (NT_STATUS_NO_MEMORY);
		}

		return (NT_STATUS_SUCCESS);
	}

	if ((lwka = smb_lwka_lookup_name(name)) != NULL) {
		sid = smb_sid_splice(di.di_binsid, lwka->lwka_rid);
		type = lwka->lwka_type;
	} else {
		switch (type) {
		case SidTypeUser:
			status = smb_sam_lookup_user(name, &sid);
			if (status != NT_STATUS_SUCCESS)
				return (status);
			break;

		case SidTypeAlias:
			status = smb_sam_lookup_group(name, &sid);
			if (status != NT_STATUS_SUCCESS)
				return (status);
			break;

		case SidTypeUnknown:
			type = SidTypeUser;
			status = smb_sam_lookup_user(name, &sid);
			if (status == NT_STATUS_SUCCESS)
				break;

			if (status == NT_STATUS_NONE_MAPPED)
				return (status);

			type = SidTypeAlias;
			status = smb_sam_lookup_group(name, &sid);
			if (status != NT_STATUS_SUCCESS)
				return (status);
			break;

		default:
			return (NT_STATUS_INVALID_PARAMETER);
		}
	}

	account->a_name = strdup(name);
	account->a_sid = sid;
	account->a_domain = strdup(di.di_nbname);
	account->a_domsid = smb_sid_split(sid, &account->a_rid);
	account->a_type = type;

	if (!smb_account_validate(account)) {
		smb_account_free(account);
		return (NT_STATUS_NO_MEMORY);
	}

	return (NT_STATUS_SUCCESS);
}
Beispiel #15
0
/*
 * Updates a list of groups in which the given user is a member
 * by adding any local (SAM) groups.
 *
 * We are a member of local groups where the local group
 * contains either the user's primary SID, or any of their
 * other SIDs such as from domain groups, SID history, etc.
 * We can have indirect membership via domain groups.
 */
uint32_t
smb_sam_usr_groups(smb_sid_t *user_sid, smb_ids_t *gids)
{
	smb_ids_t new_gids;
	smb_id_t *ids, *new_ids;
	smb_giter_t gi;
	smb_group_t lgrp;
	int i, gcnt, total_cnt;
	uint32_t ret;
	boolean_t member;

	/*
	 * First pass: count groups to be added (gcnt)
	 */
	gcnt = 0;
	if (smb_lgrp_iteropen(&gi) != SMB_LGRP_SUCCESS)
		return (NT_STATUS_INTERNAL_ERROR);

	while (smb_lgrp_iterate(&gi, &lgrp) == SMB_LGRP_SUCCESS) {
		member = B_FALSE;
		if (smb_lgrp_is_member(&lgrp, user_sid))
			member = B_TRUE;
		else for (i = 0, ids = gids->i_ids;
		    i < gids->i_cnt; i++, ids++) {
			if (smb_lgrp_is_member(&lgrp, ids->i_sid)) {
				member = B_TRUE;
				break;
			}
		}
		/* Careful: only count lgrp once */
		if (member)
			gcnt++;
		smb_lgrp_free(&lgrp);
	}
	smb_lgrp_iterclose(&gi);

	if (gcnt == 0)
		return (NT_STATUS_SUCCESS);

	/*
	 * Second pass: add to groups list.
	 * Do not modify gcnt after here.
	 */
	if (smb_lgrp_iteropen(&gi) != SMB_LGRP_SUCCESS)
		return (NT_STATUS_INTERNAL_ERROR);

	/*
	 * Expand the list (copy to a new, larger one)
	 * Note: were're copying pointers from the old
	 * array to the new (larger) array, and then
	 * adding new pointers after what we copied.
	 */
	ret = 0;
	new_gids.i_cnt = gids->i_cnt;
	total_cnt = gids->i_cnt + gcnt;
	new_gids.i_ids = malloc(total_cnt * sizeof (smb_id_t));
	if (new_gids.i_ids == NULL) {
		ret = NT_STATUS_NO_MEMORY;
		goto out;
	}
	(void) memcpy(new_gids.i_ids, gids->i_ids,
	    gids->i_cnt * sizeof (smb_id_t));
	new_ids = new_gids.i_ids + gids->i_cnt;
	(void) memset(new_ids, 0, gcnt * sizeof (smb_id_t));

	/*
	 * Add group SIDs starting at the end of the
	 * previous list.  (new_ids)
	 */
	while (smb_lgrp_iterate(&gi, &lgrp) == SMB_LGRP_SUCCESS) {
		member = B_FALSE;
		if (smb_lgrp_is_member(&lgrp, user_sid))
			member = B_TRUE;
		else for (i = 0, ids = gids->i_ids;
		    i < gids->i_cnt; i++, ids++) {
			if (smb_lgrp_is_member(&lgrp, ids->i_sid)) {
				member = B_TRUE;
				break;
			}
		}
		if (member && (new_gids.i_cnt < (gids->i_cnt + gcnt))) {
			new_ids->i_sid = smb_sid_dup(lgrp.sg_id.gs_sid);
			if (new_ids->i_sid == NULL) {
				smb_lgrp_free(&lgrp);
				ret = NT_STATUS_NO_MEMORY;
				goto out;
			}
			new_ids->i_attrs = lgrp.sg_attr;
			new_ids++;
			new_gids.i_cnt++;
		}
		smb_lgrp_free(&lgrp);
	}

out:
	smb_lgrp_iterclose(&gi);

	if (ret != 0) {
		if (new_gids.i_ids != NULL) {
			/*
			 * Free only the new sids we added.
			 * The old ones were copied ptrs.
			 */
			ids = new_gids.i_ids + gids->i_cnt;
			for (i = 0; i < gcnt; i++, ids++) {
				smb_sid_free(ids->i_sid);
			}
			free(new_gids.i_ids);
		}
		return (ret);
	}

	/*
	 * Success! Update passed gids and
	 * free the old array.
	 */
	free(gids->i_ids);
	*gids = new_gids;

	return (NT_STATUS_SUCCESS);
}
Beispiel #16
0
/*
 * Looks up the given SID in local account databases:
 *
 * SMB Local users are looked up in /var/smb/smbpasswd
 * SMB Local groups are looked up in /var/smb/smbgroup.db
 *
 * If the account is found, its information is populated
 * in the passed smb_account_t structure. Caller must free
 * allocated memories by calling smb_account_free() upon
 * successful return.
 *
 * Return status:
 *
 *   NT_STATUS_NOT_FOUND	This is not a local account
 *   NT_STATUS_NONE_MAPPED	It's a local account but cannot be
 *   				translated.
 *   other error status codes.
 */
uint32_t
smb_sam_lookup_sid(smb_sid_t *sid, smb_account_t *account)
{
	char hostname[MAXHOSTNAMELEN];
	smb_passwd_t smbpw;
	smb_group_t grp;
	smb_lwka_t *lwka;
	smb_domain_t di;
	uint32_t rid;
	uid_t id;
	int id_type;
	int rc;

	bzero(account, sizeof (smb_account_t));

	if (!smb_domain_lookup_type(SMB_DOMAIN_LOCAL, &di))
		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);

	if (smb_sid_cmp(sid, di.di_binsid)) {
		/* This is the local domain SID */
		account->a_type = SidTypeDomain;
		account->a_name = strdup("");
		account->a_domain = strdup(di.di_nbname);
		account->a_sid = smb_sid_dup(sid);
		account->a_domsid = smb_sid_dup(sid);
		account->a_rid = (uint32_t)-1;

		if (!smb_account_validate(account)) {
			smb_account_free(account);
			return (NT_STATUS_NO_MEMORY);
		}

		return (NT_STATUS_SUCCESS);
	}

	if (!smb_sid_indomain(di.di_binsid, sid)) {
		/* This is not a local SID */
		return (NT_STATUS_NOT_FOUND);
	}

	if ((lwka = smb_lwka_lookup_sid(sid)) != NULL) {
		account->a_type = lwka->lwka_type;
		account->a_name = strdup(lwka->lwka_name);
	} else {
		id_type = SMB_IDMAP_UNKNOWN;
		if (smb_idmap_getid(sid, &id, &id_type) != IDMAP_SUCCESS)
			return (NT_STATUS_NONE_MAPPED);

		switch (id_type) {
		case SMB_IDMAP_USER:
			account->a_type = SidTypeUser;
			if (smb_pwd_getpwuid(id, &smbpw) == NULL)
				return (NT_STATUS_NO_SUCH_USER);

			account->a_name = strdup(smbpw.pw_name);
			break;

		case SMB_IDMAP_GROUP:
			account->a_type = SidTypeAlias;
			(void) smb_sid_getrid(sid, &rid);
			rc = smb_lgrp_getbyrid(rid, SMB_DOMAIN_LOCAL, &grp);
			if (rc != SMB_LGRP_SUCCESS)
				return (NT_STATUS_NO_SUCH_ALIAS);

			account->a_name = strdup(grp.sg_name);
			smb_lgrp_free(&grp);
			break;

		default:
			return (NT_STATUS_NONE_MAPPED);
		}
	}

	if (smb_getnetbiosname(hostname, MAXHOSTNAMELEN) == 0)
		account->a_domain = strdup(hostname);
	account->a_sid = smb_sid_dup(sid);
	account->a_domsid = smb_sid_split(sid, &account->a_rid);

	if (!smb_account_validate(account)) {
		smb_account_free(account);
		return (NT_STATUS_NO_MEMORY);
	}

	return (NT_STATUS_SUCCESS);
}