Пример #1
0
/*
 * smbrdr_hdr_process
 *
 * Assuming 'srh->srh_mbuf' contains a response from a Windows client,
 * decodes the 32 bytes SMB header.
 *
 * Buffer overflow typically means that the server has more data than
 * it could fit in the response buffer.  The client can use subsequent
 * SmbReadX requests to obtain the remaining data (KB 193839).
 *
 * Returns:
 *
 *  NT_STATUS_INVALID_NETWORK_RESPONSE	error decoding the header
 *  NT_STATUS_REPLY_MESSAGE_MISMATCH	response doesn't match the request
 *  NT_STATUS_SUCCESS			successful
 *  smb_hdr->status.ntstatus		error returned by server
 */
static DWORD
smbrdr_hdr_process(smbrdr_handle_t *srh, smb_hdr_t *smb_hdr)
{
	int rc;

	rc = smb_decode_nt_hdr(&srh->srh_mbuf, smb_hdr);
	if (rc < SMB_HEADER_LEN) {
		smb_log(smbrdr_log_hdl, LOG_DEBUG,
		    "smbrdr_hdr_process[%d]: invalid header (%d)",
		    srh->srh_cmd, rc);
		return (NT_STATUS_INVALID_NETWORK_RESPONSE);
	}

	switch (NT_SC_VALUE(smb_hdr->status.ntstatus)) {
	case NT_STATUS_SUCCESS:
	case NT_STATUS_BUFFER_OVERFLOW:
		break;

	default:
		smb_log(smbrdr_log_hdl, LOG_DEBUG,
		    "smbrdr_hdr_process[%d]: request failed (%s)",
		    srh->srh_cmd, xlate_nt_status(smb_hdr->status.ntstatus));
		return (smb_hdr->status.ntstatus);
	}

	if (smb_hdr->command != srh->srh_cmd) {
		smb_log(smbrdr_log_hdl, LOG_DEBUG,
		    "smbrdr_hdr_process[%d]: reply mismatch (%d)",
		    srh->srh_cmd, smb_hdr->command);
		return (NT_STATUS_REPLY_MESSAGE_MISMATCH);
	}

	return (NT_STATUS_SUCCESS);
}
Пример #2
0
/*ARGSUSED*/
static DWORD
samr_connect4(char *server, char *domain, char *username, DWORD access_mask,
    mlsvc_handle_t *samr_handle)
{
	struct samr_Connect4 arg;
	int opnum;
	DWORD status;
	int len;

	bzero(&arg, sizeof (struct samr_Connect4));
	opnum = SAMR_OPNUM_Connect4;
	status = NT_STATUS_SUCCESS;

	len = strlen(server) + 4;
	arg.servername = ndr_rpc_malloc(samr_handle, len);
	(void) snprintf((char *)arg.servername, len, "\\\\%s", server);
	arg.revision = SAMR_REVISION_2;
	arg.access_mask = access_mask;

	if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) {
		status = NT_STATUS_UNSUCCESSFUL;
	} else if (arg.status != 0) {
		status = NT_SC_VALUE(arg.status);
	} else {
		(void) memcpy(&samr_handle->handle, &arg.handle,
		    sizeof (ndr_hdid_t));

		if (ndr_is_null_handle(samr_handle))
			status = NT_STATUS_INVALID_HANDLE;
	}

	ndr_rpc_release(samr_handle);
	return (status);
}
Пример #3
0
/*
 * samr_enum_local_domains
 *
 * Get the list of local domains supported by a server.
 *
 * Returns NT status codes.
 */
DWORD
samr_enum_local_domains(mlsvc_handle_t *samr_handle)
{
	struct samr_EnumLocalDomain	arg;
	int	opnum;
	DWORD	status;

	if (ndr_is_null_handle(samr_handle))
		return (NT_STATUS_INVALID_PARAMETER);

	opnum = SAMR_OPNUM_EnumLocalDomains;
	bzero(&arg, sizeof (struct samr_EnumLocalDomain));

	(void) memcpy(&arg.handle, &samr_handle->handle,
	    sizeof (samr_handle_t));
	arg.enum_context = 0;
	arg.max_length = 0x00002000;	/* Value used by NT */

	if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) {
		status = NT_STATUS_INVALID_PARAMETER;
	} else {
		status = NT_SC_VALUE(arg.status);

		/*
		 * Handle none-mapped status quietly.
		 */
		if (status != NT_STATUS_NONE_MAPPED)
			ndr_rpc_status(samr_handle, opnum, arg.status);
	}

	ndr_rpc_release(samr_handle);
	return (status);
}
Пример #4
0
/*ARGSUSED*/
static DWORD
samr_connect1(char *server, char *domain, char *username, DWORD access_mask,
    mlsvc_handle_t *samr_handle)
{
	struct samr_Connect arg;
	int opnum;
	DWORD status;

	bzero(&arg, sizeof (struct samr_Connect));
	opnum = SAMR_OPNUM_Connect;
	status = NT_STATUS_SUCCESS;

	arg.servername = ndr_rpc_malloc(samr_handle, sizeof (DWORD));
	*(arg.servername) = 0x0001005c;
	arg.access_mask = access_mask;

	if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) {
		status = NT_STATUS_UNSUCCESSFUL;
	} else if (arg.status != 0) {
		status = NT_SC_VALUE(arg.status);
	} else {
		(void) memcpy(&samr_handle->handle, &arg.handle,
		    sizeof (ndr_hdid_t));

		if (ndr_is_null_handle(samr_handle))
			status = NT_STATUS_INVALID_HANDLE;
	}

	ndr_rpc_release(samr_handle);
	return (status);
}
Пример #5
0
/*
 * samr_get_user_pwinfo
 *
 * Get some user password info. I'm not sure what this is yet but it is
 * part of the create user sequence. The handle must be a valid user
 * handle. Since I don't know what this is returning, I haven't provided
 * any return data yet.
 *
 * Returns 0 on success. Otherwise returns an NT status code.
 */
DWORD
samr_get_user_pwinfo(mlsvc_handle_t *user_handle)
{
	struct samr_GetUserPwInfo arg;
	int	opnum;
	DWORD	status;

	if (ndr_is_null_handle(user_handle))
		return (NT_STATUS_INVALID_PARAMETER);

	opnum = SAMR_OPNUM_GetUserPwInfo;
	bzero(&arg, sizeof (struct samr_GetUserPwInfo));
	(void) memcpy(&arg.user_handle, &user_handle->handle,
	    sizeof (samr_handle_t));

	if (ndr_rpc_call(user_handle, opnum, &arg) != 0) {
		status = NT_STATUS_INVALID_PARAMETER;
	} else if (arg.status != 0) {
		ndr_rpc_status(user_handle, opnum, arg.status);
		status = NT_SC_VALUE(arg.status);
	} else {
		status = 0;
	}

	ndr_rpc_release(user_handle);
	return (status);
}
Пример #6
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);
}
Пример #7
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);
}
Пример #8
0
/*
 * samr_create_user
 *
 * Create a user in the domain specified by the domain handle. If this
 * call is successful, the server will return the RID for the user and
 * a user handle, which may be used to set or query the SAM.
 *
 * Observed status codes:
 *	NT_STATUS_INVALID_PARAMETER
 *	NT_STATUS_INVALID_ACCOUNT_NAME
 *	NT_STATUS_ACCESS_DENIED
 *	NT_STATUS_USER_EXISTS
 *
 * Returns 0 on success. Otherwise returns an NT status code.
 */
DWORD
samr_create_user(mlsvc_handle_t *domain_handle, char *username,
    DWORD account_flags, DWORD *rid, mlsvc_handle_t *user_handle)
{
	struct samr_CreateUser arg;
	ndr_heap_t *heap;
	int opnum;
	int rc;
	DWORD status = 0;

	if (ndr_is_null_handle(domain_handle) ||
	    username == NULL || rid == NULL) {
		return (NT_STATUS_INVALID_PARAMETER);
	}

	opnum = SAMR_OPNUM_CreateUser;

	bzero(&arg, sizeof (struct samr_CreateUser));
	(void) memcpy(&arg.handle, &domain_handle->handle,
	    sizeof (ndr_hdid_t));

	heap = ndr_rpc_get_heap(domain_handle);
	ndr_heap_mkvcs(heap, username, (ndr_vcstr_t *)&arg.username);

	arg.account_flags = account_flags;
	arg.desired_access = 0xE00500B0;

	rc = ndr_rpc_call(domain_handle, opnum, &arg);
	if (rc != 0) {
		status = NT_STATUS_INVALID_PARAMETER;
	} else if (arg.status != 0) {
		status = NT_SC_VALUE(arg.status);

		if (status != NT_STATUS_USER_EXISTS) {
			smb_tracef("SamrCreateUser[%s]: %s", username,
			    xlate_nt_status(status));
		}
	} else {
		ndr_inherit_handle(user_handle, domain_handle);

		(void) memcpy(&user_handle->handle, &arg.user_handle,
		    sizeof (ndr_hdid_t));

		*rid = arg.rid;

		if (ndr_is_null_handle(user_handle))
			status = NT_STATUS_INVALID_HANDLE;
		else
			status = 0;
	}

	ndr_rpc_release(domain_handle);
	return (status);
}
Пример #9
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);
}
Пример #10
0
/*
 * samr_lookup_domain_names
 *
 * Lookup up the given name in the domain specified by domain_handle.
 * Upon a successful lookup the information is returned in the account
 * arg and caller must free allocated memories by calling smb_account_free().
 *
 * Returns NT status codes.
 */
uint32_t
samr_lookup_domain_names(mlsvc_handle_t *domain_handle, char *name,
    smb_account_t *account)
{
	struct samr_LookupNames	arg;
	int			opnum;
	uint32_t		status;
	size_t			length;

	if (ndr_is_null_handle(domain_handle) ||
	    name == NULL || account == NULL) {
		return (NT_STATUS_INVALID_PARAMETER);
	}

	bzero(account, sizeof (smb_account_t));
	opnum = SAMR_OPNUM_LookupNames;
	bzero(&arg, sizeof (struct samr_LookupNames));

	(void) memcpy(&arg.handle, &domain_handle->handle,
	    sizeof (samr_handle_t));
	arg.n_entry = 1;
	arg.max_n_entry = 1000;
	arg.index = 0;
	arg.total = 1;

	length = smb_wcequiv_strlen(name);
	if (ndr_rpc_server_os(domain_handle) == NATIVE_OS_WIN2000)
		length += sizeof (smb_wchar_t);

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

	if (ndr_rpc_call(domain_handle, opnum, &arg) != 0) {
		status = NT_STATUS_INVALID_PARAMETER;
	} else if (arg.status != NT_STATUS_SUCCESS) {
		status = NT_SC_VALUE(arg.status);

		/*
		 * Handle none-mapped status quietly.
		 */
		if (status != NT_STATUS_NONE_MAPPED)
			ndr_rpc_status(domain_handle, opnum, arg.status);
	} else {
		account->a_type = arg.rid_types.rid_type[0];
		account->a_rid = arg.rids.rid[0];
		status = NT_STATUS_SUCCESS;
	}

	ndr_rpc_release(domain_handle);
	return (status);
}
Пример #11
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);
}
Пример #12
0
/*ARGSUSED*/
static DWORD
samr_connect5(char *server, char *domain, char *username, DWORD access_mask,
    mlsvc_handle_t *samr_handle)
{
	struct samr_Connect5 arg;
	int len;
	int opnum;
	DWORD status;
	smb_domainex_t dinfo;

	bzero(&arg, sizeof (struct samr_Connect5));
	opnum = SAMR_OPNUM_Connect5;
	status = NT_STATUS_SUCCESS;

	if (!smb_domain_getinfo(&dinfo))
		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);

	len = strlen(server) + strlen(dinfo.d_primary.di_fqname) + 4;
	arg.servername = ndr_rpc_malloc(samr_handle, len);

	if (*dinfo.d_primary.di_fqname != '\0')
		(void) snprintf((char *)arg.servername, len, "\\\\%s.%s",
		    server, dinfo.d_primary.di_fqname);
	else
		(void) snprintf((char *)arg.servername, len, "\\\\%s", server);

	arg.access_mask = SAM_ENUM_LOCAL_DOMAIN;
	arg.unknown2_00000001 = 0x00000001;
	arg.unknown3_00000001 = 0x00000001;
	arg.unknown4_00000003 = 0x00000003;
	arg.unknown5_00000000 = 0x00000000;

	if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) {
		status = NT_STATUS_UNSUCCESSFUL;
	} else if (arg.status != 0) {
		status = NT_SC_VALUE(arg.status);
	} else {

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

		if (ndr_is_null_handle(samr_handle))
			status = NT_STATUS_INVALID_HANDLE;
	}

	ndr_rpc_release(samr_handle);
	return (status);
}
Пример #13
0
DWORD
lsar_enum_trusted_domains_ex(mlsvc_handle_t *lsa_handle, DWORD *enum_context,
    smb_trusted_domains_t *list)
{
	struct mslsa_EnumTrustedDomainEx	arg;
	int	opnum;
	DWORD	status;

	if (list == NULL)
		return (NT_STATUS_INVALID_PARAMETER);

	opnum = LSARPC_OPNUM_EnumTrustedDomainsEx;

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

	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
		status = NT_STATUS_INVALID_PARAMETER;
	} else if (arg.status != 0) {
		*enum_context = arg.enum_context;
		status = NT_SC_VALUE(arg.status);

		/*
		 * STATUS_NO_MORE_ENTRIES provides call
		 * status but does not indicate an error.
		 */
		if (status != NT_STATUS_NO_MORE_ENTRIES)
			ndr_rpc_status(lsa_handle, opnum, arg.status);
	} else if (arg.enum_buf->entries_read == 0) {
		*enum_context = arg.enum_context;
		status = 0;
	} else {
		lsar_set_trusted_domains_ex(arg.enum_buf, list);
		*enum_context = arg.enum_context;
		status = 0;
	}

	ndr_rpc_release(lsa_handle);
	return (status);
}
Пример #14
0
/*
 * lsar_lookup_priv_display_name
 *
 * Map a privilege name to a privilege display name. The input handle
 * should be an LSA policy handle and the name would normally be one
 * of the privileges defined in smb_privilege.h
 *
 * There's something peculiar about the return status from NT servers,
 * it's not always present. So for now, I'm ignoring the status in the
 * RPC response.
 *
 * Returns NT status codes.
 */
DWORD
lsar_lookup_priv_display_name(mlsvc_handle_t *lsa_handle, char *name,
    char *display_name, int display_len)
{
	struct mslsa_LookupPrivDisplayName	arg;
	int	opnum;
	size_t	length;
	DWORD	status;

	if (lsa_handle == NULL || name == NULL || display_name == NULL)
		return (NT_STATUS_INVALID_PARAMETER);

	opnum = LSARPC_OPNUM_LookupPrivDisplayName;

	bzero(&arg, sizeof (struct mslsa_LookupPrivDisplayName));
	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));

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

	arg.client_language = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
	arg.default_language = MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL);

	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0)
		status = NT_STATUS_INVALID_PARAMETER;
#if 0
	else if (arg.status != 0)
		status = NT_SC_VALUE(arg.status);
#endif
	else {
		(void) strlcpy(display_name,
		    (char const *)arg.display_name->str, display_len);
		status = NT_STATUS_SUCCESS;
	}

	ndr_rpc_release(lsa_handle);
	return (status);
}
Пример #15
0
/*ARGSUSED*/
DWORD
samr_set_user_info(mlsvc_handle_t *user_handle)
{
	unsigned char ssn_key[SMBAUTH_SESSION_KEY_SZ];
	struct samr_SetUserInfo arg;
	int opnum;
	DWORD status = 0;

	if (ndr_is_null_handle(user_handle))
		return (NT_STATUS_INVALID_PARAMETER);

	if (ndr_rpc_get_ssnkey(user_handle, ssn_key, sizeof (ssn_key)))
		return (NT_STATUS_INVALID_PARAMETER);

	opnum = SAMR_OPNUM_SetUserInfo;
	bzero(&arg, sizeof (struct samr_SetUserInfo));
	(void) memcpy(&arg.user_handle, &user_handle->handle,
	    sizeof (samr_handle_t));

	arg.info.index = SAMR_SET_USER_INFO_23;
	arg.info.switch_value = SAMR_SET_USER_INFO_23;

	samr_set_user_unknowns(&arg.info.ru.info23);
	samr_set_user_logon_hours(&arg);

	if (samr_set_user_password(ssn_key, arg.info.ru.info23.password) < 0)
		status = NT_STATUS_INTERNAL_ERROR;

	if (ndr_rpc_call(user_handle, opnum, &arg) != 0) {
		status = NT_STATUS_INVALID_PARAMETER;
	} else if (arg.status != 0) {
		ndr_rpc_status(user_handle, opnum, arg.status);
		status = NT_SC_VALUE(arg.status);
	}

	ndr_rpc_release(user_handle);
	return (status);
}
Пример #16
0
/*
 * samr_open_user
 *
 * Use a domain handle to obtain a handle for a user, specified by the
 * user RID. A user RID (effectively a uid) can be obtained via the
 * LSA interface. A handle for the user is returned in user_handle.
 * Once you have a user handle it should be possible to query the SAM
 * for information on that user.
 */
DWORD
samr_open_user(mlsvc_handle_t *domain_handle, DWORD access_mask, DWORD rid,
    mlsvc_handle_t *user_handle)
{
	struct samr_OpenUser arg;
	int opnum;
	DWORD status = NT_STATUS_SUCCESS;

	if (ndr_is_null_handle(domain_handle) || user_handle == NULL)
		return (NT_STATUS_INVALID_PARAMETER);

	opnum = SAMR_OPNUM_OpenUser;
	bzero(&arg, sizeof (struct samr_OpenUser));
	(void) memcpy(&arg.handle, &domain_handle->handle,
	    sizeof (ndr_hdid_t));
	arg.access_mask = access_mask;
	arg.rid = rid;

	if (ndr_rpc_call(domain_handle, opnum, &arg) != 0) {
		status = NT_STATUS_UNSUCCESSFUL;
	} else if (arg.status != 0) {
		ndr_rpc_status(domain_handle, opnum, arg.status);
		status = NT_SC_VALUE(arg.status);
	} else {
		ndr_inherit_handle(user_handle, domain_handle);

		(void) memcpy(&user_handle->handle, &arg.user_handle,
		    sizeof (ndr_hdid_t));

		if (ndr_is_null_handle(user_handle))
			status = NT_STATUS_INVALID_HANDLE;
	}

	ndr_rpc_release(domain_handle);
	return (status);
}
Пример #17
0
/*
 * netr_server_samlogon
 *
 * NetrServerSamLogon RPC: interactive or network. It is assumed that
 * we have already authenticated with the PDC. If everything works,
 * we build a user info structure and return it, where the caller will
 * probably build an access token.
 *
 * Returns an NT status. There are numerous possibilities here.
 * For example:
 *	NT_STATUS_INVALID_INFO_CLASS
 *	NT_STATUS_INVALID_PARAMETER
 *	NT_STATUS_ACCESS_DENIED
 *	NT_STATUS_PASSWORD_MUST_CHANGE
 *	NT_STATUS_NO_SUCH_USER
 *	NT_STATUS_WRONG_PASSWORD
 *	NT_STATUS_LOGON_FAILURE
 *	NT_STATUS_ACCOUNT_RESTRICTION
 *	NT_STATUS_INVALID_LOGON_HOURS
 *	NT_STATUS_INVALID_WORKSTATION
 *	NT_STATUS_INTERNAL_ERROR
 *	NT_STATUS_PASSWORD_EXPIRED
 *	NT_STATUS_ACCOUNT_DISABLED
 */
uint32_t
netr_server_samlogon(mlsvc_handle_t *netr_handle, netr_info_t *netr_info,
    char *server, smb_logon_t *user_info, smb_token_t *token)
{
	struct netr_SamLogon arg;
	struct netr_authenticator auth;
	struct netr_authenticator ret_auth;
	struct netr_logon_info1 info1;
	struct netr_logon_info2 info2;
	struct netr_validation_info3 *info3;
	ndr_heap_t *heap;
	int opnum;
	int rc, len;
	uint32_t status;

	bzero(&arg, sizeof (struct netr_SamLogon));
	opnum = NETR_OPNUM_SamLogon;

	/*
	 * Should we get the server and hostname from netr_info?
	 */

	len = strlen(server) + 4;
	arg.servername = ndr_rpc_malloc(netr_handle, len);
	arg.hostname = ndr_rpc_malloc(netr_handle, NETBIOS_NAME_SZ);
	if (arg.servername == NULL || arg.hostname == NULL) {
		ndr_rpc_release(netr_handle);
		return (NT_STATUS_INTERNAL_ERROR);
	}

	(void) snprintf((char *)arg.servername, len, "\\\\%s", server);
	if (smb_getnetbiosname((char *)arg.hostname, NETBIOS_NAME_SZ) != 0) {
		ndr_rpc_release(netr_handle);
		return (NT_STATUS_INTERNAL_ERROR);
	}

	rc = netr_setup_authenticator(netr_info, &auth, &ret_auth);
	if (rc != SMBAUTH_SUCCESS) {
		ndr_rpc_release(netr_handle);
		return (NT_STATUS_INTERNAL_ERROR);
	}

	arg.auth = &auth;
	arg.ret_auth = &ret_auth;
	arg.validation_level = NETR_VALIDATION_LEVEL3;
	arg.logon_info.logon_level = user_info->lg_level;
	arg.logon_info.switch_value = user_info->lg_level;

	heap = ndr_rpc_get_heap(netr_handle);

	switch (user_info->lg_level) {
	case NETR_INTERACTIVE_LOGON:
		netr_setup_identity(heap, user_info, &info1.identity);
		netr_interactive_samlogon(netr_info, user_info, &info1);
		arg.logon_info.ru.info1 = &info1;
		break;

	case NETR_NETWORK_LOGON:
		if (user_info->lg_challenge_key.len < 8 ||
		    user_info->lg_challenge_key.val == NULL) {
			ndr_rpc_release(netr_handle);
			return (NT_STATUS_INVALID_PARAMETER);
		}
		netr_setup_identity(heap, user_info, &info2.identity);
		netr_network_samlogon(heap, netr_info, user_info, &info2);
		arg.logon_info.ru.info2 = &info2;
		break;

	default:
		ndr_rpc_release(netr_handle);
		return (NT_STATUS_INVALID_PARAMETER);
	}

	rc = ndr_rpc_call(netr_handle, opnum, &arg);
	if (rc != 0) {
		bzero(netr_info, sizeof (netr_info_t));
		status = NT_STATUS_INVALID_PARAMETER;
	} else if (arg.status != 0) {
		status = NT_SC_VALUE(arg.status);

		/*
		 * We need to validate the chain even though we have
		 * a non-zero status. If the status is ACCESS_DENIED
		 * this will trigger a new credential chain. However,
		 * a valid credential is returned with some status
		 * codes; for example, WRONG_PASSWORD.
		 */
		(void) netr_validate_chain(netr_info, arg.ret_auth);
	} else {
		status = netr_validate_chain(netr_info, arg.ret_auth);
		if (status == NT_STATUS_INSUFFICIENT_LOGON_INFO) {
			ndr_rpc_release(netr_handle);
			return (status);
		}

		info3 = arg.ru.info3;
		status = netr_setup_token(info3, user_info, netr_info, token);
	}

	ndr_rpc_release(netr_handle);
	return (status);
}
Пример #18
0
/*
 * lsar_query_info_policy
 *
 * The general purpose of this function is to allow various pieces of
 * information to be queried on the domain controller. The only
 * information queries supported are MSLSA_POLICY_PRIMARY_DOMAIN_INFO
 * and MSLSA_POLICY_ACCOUNT_DOMAIN_INFO.
 *
 * On success, the return code will be 0 and the user_info structure
 * will be set up. The sid_name_use field will be set to SidTypeDomain
 * indicating that the domain name and domain sid fields are vaild. If
 * the infoClass returned from the server is not one of the supported
 * values, the sid_name_use willbe set to SidTypeUnknown. If the RPC
 * fails, a negative error code will be returned, in which case the
 * user_info will not have been updated.
 */
DWORD
lsar_query_info_policy(mlsvc_handle_t *lsa_handle, WORD infoClass,
    smb_domain_t *info)
{
	struct mslsa_QueryInfoPolicy	arg;
	struct mslsa_PrimaryDomainInfo	*pd_info;
	struct mslsa_AccountDomainInfo	*ad_info;
	struct mslsa_DnsDomainInfo	*dns_info;
	char	guid_str[UUID_PRINTABLE_STRING_LENGTH];
	char	sidstr[SMB_SID_STRSZ];
	int	opnum;
	DWORD	status;

	if (lsa_handle == NULL || info == NULL)
		return (NT_STATUS_INVALID_PARAMETER);

	opnum = LSARPC_OPNUM_QueryInfoPolicy;

	bzero(info, sizeof (smb_domain_t));
	bzero(&arg, sizeof (struct mslsa_QueryInfoPolicy));
	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));

	arg.info_class = infoClass;

	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
		status = NT_STATUS_INVALID_PARAMETER;
	} else if (arg.status != 0) {
		ndr_rpc_status(lsa_handle, opnum, arg.status);
		status = NT_SC_VALUE(arg.status);
	} else {

		switch (infoClass) {
		case MSLSA_POLICY_PRIMARY_DOMAIN_INFO:
			pd_info = &arg.ru.pd_info;

			smb_sid_tostr((smb_sid_t *)pd_info->sid, sidstr);
			info->di_type = SMB_DOMAIN_PRIMARY;
			smb_domain_set_basic_info(sidstr,
			    (char *)pd_info->name.str, "", info);

			status = NT_STATUS_SUCCESS;
			break;

		case MSLSA_POLICY_ACCOUNT_DOMAIN_INFO:
			ad_info = &arg.ru.ad_info;

			smb_sid_tostr((smb_sid_t *)ad_info->sid, sidstr);
			info->di_type = SMB_DOMAIN_ACCOUNT;
			smb_domain_set_basic_info(sidstr,
			    (char *)ad_info->name.str, "", info);

			status = NT_STATUS_SUCCESS;
			break;

		case MSLSA_POLICY_DNS_DOMAIN_INFO:
			dns_info = &arg.ru.dns_info;
			ndr_uuid_unparse((ndr_uuid_t *)&dns_info->guid,
			    guid_str);
			smb_sid_tostr((smb_sid_t *)dns_info->sid, sidstr);

			info->di_type = SMB_DOMAIN_PRIMARY;
			smb_domain_set_dns_info(sidstr,
			    (char *)dns_info->nb_domain.str,
			    (char *)dns_info->dns_domain.str,
			    (char *)dns_info->forest.str,
			    guid_str, info);
			status = NT_STATUS_SUCCESS;
			break;

		default:
			status = NT_STATUS_INVALID_INFO_CLASS;
			break;
		}
	}

	ndr_rpc_release(lsa_handle);
	return (status);
}