Exemple #1
0
NTSTATUS smbd_smb2_request_process_ioctl(struct smbd_smb2_request *req)
{
	const uint8_t *inhdr;
	const uint8_t *inbody;
	int i = req->current_idx;
	size_t expected_body_size = 0x39;
	size_t body_size;
	uint32_t in_ctl_code;
	uint64_t in_file_id_persistent;
	uint64_t in_file_id_volatile;
	uint32_t in_input_offset;
	uint32_t in_input_length;
	DATA_BLOB in_input_buffer;
	uint32_t in_max_output_length;
	uint32_t in_flags;
	struct tevent_req *subreq;

	inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
	if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	inbody = (const uint8_t *)req->in.vector[i+1].iov_base;

	body_size = SVAL(inbody, 0x00);
	if (body_size != expected_body_size) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	in_ctl_code		= IVAL(inbody, 0x04);
	in_file_id_persistent	= BVAL(inbody, 0x08);
	in_file_id_volatile	= BVAL(inbody, 0x10);
	in_input_offset		= IVAL(inbody, 0x18);
	in_input_length		= IVAL(inbody, 0x1C);
	in_max_output_length	= IVAL(inbody, 0x2C);
	in_flags		= IVAL(inbody, 0x30);

	if (in_input_offset != (SMB2_HDR_BODY + (body_size & 0xFFFFFFFE))) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	if (in_input_length > req->in.vector[i+2].iov_len) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	in_input_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base;
	in_input_buffer.length = in_input_length;

	if (req->compat_chain_fsp) {
		/* skip check */
	} else if (in_file_id_persistent == UINT64_MAX &&
		   in_file_id_volatile == UINT64_MAX) {
		/* without a handle */
	} else if (in_file_id_persistent != in_file_id_volatile) {
		return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
	}

	subreq = smbd_smb2_ioctl_send(req,
				      req->sconn->smb2.event_ctx,
				      req,
				      in_ctl_code,
				      in_file_id_volatile,
				      in_input_buffer,
				      in_max_output_length,
				      in_flags);
	if (subreq == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
	}
	tevent_req_set_callback(subreq, smbd_smb2_request_ioctl_done, req);

	return smbd_smb2_request_pending_queue(req, subreq);
}
Exemple #2
0
NTSTATUS smbd_smb2_request_process_find(struct smbd_smb2_request *req)
{
	NTSTATUS status;
	const uint8_t *inbody;
	int i = req->current_idx;
	uint8_t in_file_info_class;
	uint8_t in_flags;
	uint32_t in_file_index;
	uint64_t in_file_id_persistent;
	uint64_t in_file_id_volatile;
	struct files_struct *in_fsp;
	uint16_t in_file_name_offset;
	uint16_t in_file_name_length;
	DATA_BLOB in_file_name_buffer;
	char *in_file_name_string;
	size_t in_file_name_string_size;
	uint32_t in_output_buffer_length;
	struct tevent_req *subreq;
	bool ok;

	status = smbd_smb2_request_verify_sizes(req, 0x21);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(req, status);
	}
	inbody = (const uint8_t *)req->in.vector[i+1].iov_base;

	in_file_info_class		= CVAL(inbody, 0x02);
	in_flags			= CVAL(inbody, 0x03);
	in_file_index			= IVAL(inbody, 0x04);
	in_file_id_persistent		= BVAL(inbody, 0x08);
	in_file_id_volatile		= BVAL(inbody, 0x10);
	in_file_name_offset		= SVAL(inbody, 0x18);
	in_file_name_length		= SVAL(inbody, 0x1A);
	in_output_buffer_length		= IVAL(inbody, 0x1C);

	if (in_file_name_offset == 0 && in_file_name_length == 0) {
		/* This is ok */
	} else if (in_file_name_offset !=
		   (SMB2_HDR_BODY + req->in.vector[i+1].iov_len)) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	if (in_file_name_length > req->in.vector[i+2].iov_len) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	/* The output header is 8 bytes. */
	if (in_output_buffer_length <= 8) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	DEBUG(10,("smbd_smb2_request_find_done: in_output_buffer_length = %u\n",
		(unsigned int)in_output_buffer_length ));

	/* Take into account the output header. */
	in_output_buffer_length -= 8;

	in_file_name_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base;
	in_file_name_buffer.length = in_file_name_length;

	ok = convert_string_talloc(req, CH_UTF16, CH_UNIX,
				   in_file_name_buffer.data,
				   in_file_name_buffer.length,
				   &in_file_name_string,
				   &in_file_name_string_size, false);
	if (!ok) {
		return smbd_smb2_request_error(req, NT_STATUS_ILLEGAL_CHARACTER);
	}

	if (in_file_name_buffer.length == 0) {
		in_file_name_string_size = 0;
	}

	if (strlen(in_file_name_string) != in_file_name_string_size) {
		return smbd_smb2_request_error(req, NT_STATUS_OBJECT_NAME_INVALID);
	}

	in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
	if (in_fsp == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
	}

	subreq = smbd_smb2_find_send(req, req->sconn->smb2.event_ctx,
				     req, in_fsp,
				     in_file_info_class,
				     in_flags,
				     in_file_index,
				     in_output_buffer_length,
				     in_file_name_string);
	if (subreq == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
	}
	tevent_req_set_callback(subreq, smbd_smb2_request_find_done, req);

	return smbd_smb2_request_pending_queue(req, subreq);
}
Exemple #3
0
NTSTATUS smbd_smb2_request_process_getinfo(struct smbd_smb2_request *req)
{
	const uint8_t *inhdr;
	const uint8_t *inbody;
	int i = req->current_idx;
	size_t expected_body_size = 0x29;
	size_t body_size;
	uint8_t in_info_type;
	uint8_t in_file_info_class;
	uint32_t in_output_buffer_length;
	uint16_t in_input_buffer_offset;
	uint32_t in_input_buffer_length;
	DATA_BLOB in_input_buffer;
	uint32_t in_additional_information;
	uint32_t in_flags;
	uint64_t in_file_id_persistent;
	uint64_t in_file_id_volatile;
	struct tevent_req *subreq;

	inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
	if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	inbody = (const uint8_t *)req->in.vector[i+1].iov_base;

	body_size = SVAL(inbody, 0x00);
	if (body_size != expected_body_size) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	in_info_type			= CVAL(inbody, 0x02);
	in_file_info_class		= CVAL(inbody, 0x03);
	in_output_buffer_length		= IVAL(inbody, 0x04);
	in_input_buffer_offset		= SVAL(inbody, 0x08);
	/* 0x0A 2 bytes reserved */
	in_input_buffer_length		= IVAL(inbody, 0x0C);
	in_additional_information	= IVAL(inbody, 0x10);
	in_flags			= IVAL(inbody, 0x14);
	in_file_id_persistent		= BVAL(inbody, 0x18);
	in_file_id_volatile		= BVAL(inbody, 0x20);

	if (in_input_buffer_offset == 0 && in_input_buffer_length == 0) {
		/* This is ok */
	} else if (in_input_buffer_offset !=
		   (SMB2_HDR_BODY + (body_size & 0xFFFFFFFE))) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	if (in_input_buffer_length > req->in.vector[i+2].iov_len) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	in_input_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base;
	in_input_buffer.length = in_input_buffer_length;

	if (req->compat_chain_fsp) {
		/* skip check */
	} else if (in_file_id_persistent != 0) {
		return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
	}

	subreq = smbd_smb2_getinfo_send(req,
					req->sconn->smb2.event_ctx,
					req,
					in_info_type,
					in_file_info_class,
					in_output_buffer_length,
					in_input_buffer,
					in_additional_information,
					in_flags,
					in_file_id_volatile);
	if (subreq == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
	}
	tevent_req_set_callback(subreq, smbd_smb2_request_getinfo_done, req);

	return smbd_smb2_request_pending_queue(req, subreq);
}
Exemple #4
0
NTSTATUS smbd_smb2_request_process_getinfo(struct smbd_smb2_request *req)
{
	NTSTATUS status;
	const uint8_t *inbody;
	uint8_t in_info_type;
	uint8_t in_file_info_class;
	uint32_t in_output_buffer_length;
	uint16_t in_input_buffer_offset;
	uint32_t in_input_buffer_length;
	DATA_BLOB in_input_buffer;
	uint32_t in_additional_information;
	uint32_t in_flags;
	uint64_t in_file_id_persistent;
	uint64_t in_file_id_volatile;
	struct files_struct *in_fsp;
	struct tevent_req *subreq;

	status = smbd_smb2_request_verify_sizes(req, 0x29);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(req, status);
	}
	inbody = SMBD_SMB2_IN_BODY_PTR(req);

	in_info_type			= CVAL(inbody, 0x02);
	in_file_info_class		= CVAL(inbody, 0x03);
	in_output_buffer_length		= IVAL(inbody, 0x04);
	in_input_buffer_offset		= SVAL(inbody, 0x08);
	/* 0x0A 2 bytes reserved */
	in_input_buffer_length		= IVAL(inbody, 0x0C);
	in_additional_information	= IVAL(inbody, 0x10);
	in_flags			= IVAL(inbody, 0x14);
	in_file_id_persistent		= BVAL(inbody, 0x18);
	in_file_id_volatile		= BVAL(inbody, 0x20);

	if (in_input_buffer_offset == 0 && in_input_buffer_length == 0) {
		/* This is ok */
	} else if (in_input_buffer_offset !=
		   (SMB2_HDR_BODY + SMBD_SMB2_IN_BODY_LEN(req))) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	if (in_input_buffer_length > SMBD_SMB2_IN_DYN_LEN(req)) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	in_input_buffer.data = SMBD_SMB2_IN_DYN_PTR(req);
	in_input_buffer.length = in_input_buffer_length;

	if (in_input_buffer.length > req->sconn->smb2.max_trans) {
		DEBUG(2,("smbd_smb2_request_process_getinfo: "
			 "client ignored max trans: %s: 0x%08X: 0x%08X\n",
			 __location__, (unsigned)in_input_buffer.length,
			 (unsigned)req->sconn->smb2.max_trans));
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}
	if (in_output_buffer_length > req->sconn->smb2.max_trans) {
		DEBUG(2,("smbd_smb2_request_process_getinfo: "
			 "client ignored max trans: %s: 0x%08X: 0x%08X\n",
			 __location__, in_output_buffer_length,
			 req->sconn->smb2.max_trans));
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	status = smbd_smb2_request_verify_creditcharge(req,
			MAX(in_input_buffer.length,in_output_buffer_length));
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(req, status);
	}

	in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
	if (in_fsp == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
	}

	subreq = smbd_smb2_getinfo_send(req, req->sconn->ev_ctx,
					req, in_fsp,
					in_info_type,
					in_file_info_class,
					in_output_buffer_length,
					in_input_buffer,
					in_additional_information,
					in_flags);
	if (subreq == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
	}
	tevent_req_set_callback(subreq, smbd_smb2_request_getinfo_done, req);

	return smbd_smb2_request_pending_queue(req, subreq, 500);
}
Exemple #5
0
NTSTATUS smbd_smb2_request_process_getinfo(struct smbd_smb2_request *req)
{
	NTSTATUS status;
	const uint8_t *inbody;
	int i = req->current_idx;
	uint8_t in_info_type;
	uint8_t in_file_info_class;
	uint32_t in_output_buffer_length;
	uint16_t in_input_buffer_offset;
	uint32_t in_input_buffer_length;
	DATA_BLOB in_input_buffer;
	uint32_t in_additional_information;
	uint32_t in_flags;
	uint64_t in_file_id_persistent;
	uint64_t in_file_id_volatile;
	struct files_struct *in_fsp;
	struct tevent_req *subreq;

	status = smbd_smb2_request_verify_sizes(req, 0x29);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(req, status);
	}
	inbody = (const uint8_t *)req->in.vector[i+1].iov_base;

	in_info_type			= CVAL(inbody, 0x02);
	in_file_info_class		= CVAL(inbody, 0x03);
	in_output_buffer_length		= IVAL(inbody, 0x04);
	in_input_buffer_offset		= SVAL(inbody, 0x08);
	/* 0x0A 2 bytes reserved */
	in_input_buffer_length		= IVAL(inbody, 0x0C);
	in_additional_information	= IVAL(inbody, 0x10);
	in_flags			= IVAL(inbody, 0x14);
	in_file_id_persistent		= BVAL(inbody, 0x18);
	in_file_id_volatile		= BVAL(inbody, 0x20);

	if (in_input_buffer_offset == 0 && in_input_buffer_length == 0) {
		/* This is ok */
	} else if (in_input_buffer_offset !=
		   (SMB2_HDR_BODY + req->in.vector[i+1].iov_len)) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	if (in_input_buffer_length > req->in.vector[i+2].iov_len) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	in_input_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base;
	in_input_buffer.length = in_input_buffer_length;

	if (in_input_buffer.length > req->sconn->smb2.max_trans) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}
	if (in_output_buffer_length > req->sconn->smb2.max_trans) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
	if (in_fsp == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
	}

	subreq = smbd_smb2_getinfo_send(req, req->sconn->smb2.event_ctx,
					req, in_fsp,
					in_info_type,
					in_file_info_class,
					in_output_buffer_length,
					in_input_buffer,
					in_additional_information,
					in_flags);
	if (subreq == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
	}
	tevent_req_set_callback(subreq, smbd_smb2_request_getinfo_done, req);

	return smbd_smb2_request_pending_queue(req, subreq);
}
Exemple #6
0
NTSTATUS smbd_smb2_request_process_create(struct smbd_smb2_request *smb2req)
{
	const uint8_t *inbody;
	const struct iovec *indyniov;
	uint8_t in_oplock_level;
	uint32_t in_impersonation_level;
	uint32_t in_desired_access;
	uint32_t in_file_attributes;
	uint32_t in_share_access;
	uint32_t in_create_disposition;
	uint32_t in_create_options;
	uint16_t in_name_offset;
	uint16_t in_name_length;
	DATA_BLOB in_name_buffer;
	char *in_name_string;
	size_t in_name_string_size;
	uint32_t name_offset = 0;
	uint32_t name_available_length = 0;
	uint32_t in_context_offset;
	uint32_t in_context_length;
	DATA_BLOB in_context_buffer;
	struct smb2_create_blobs in_context_blobs;
	uint32_t context_offset = 0;
	uint32_t context_available_length = 0;
	uint32_t dyn_offset;
	NTSTATUS status;
	bool ok;
	struct tevent_req *tsubreq;

	status = smbd_smb2_request_verify_sizes(smb2req, 0x39);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(smb2req, status);
	}
	inbody = SMBD_SMB2_IN_BODY_PTR(smb2req);

	in_oplock_level		= CVAL(inbody, 0x03);
	in_impersonation_level	= IVAL(inbody, 0x04);
	in_desired_access	= IVAL(inbody, 0x18);
	in_file_attributes	= IVAL(inbody, 0x1C);
	in_share_access		= IVAL(inbody, 0x20);
	in_create_disposition	= IVAL(inbody, 0x24);
	in_create_options	= IVAL(inbody, 0x28);
	in_name_offset		= SVAL(inbody, 0x2C);
	in_name_length		= SVAL(inbody, 0x2E);
	in_context_offset	= IVAL(inbody, 0x30);
	in_context_length	= IVAL(inbody, 0x34);

	/*
	 * First check if the dynamic name and context buffers
	 * are correctly specified.
	 *
	 * Note: That we don't check if the name and context buffers
	 *       overlap
	 */

	dyn_offset = SMB2_HDR_BODY + SMBD_SMB2_IN_BODY_LEN(smb2req);

	if (in_name_offset == 0 && in_name_length == 0) {
		/* This is ok */
		name_offset = 0;
	} else if (in_name_offset < dyn_offset) {
		return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
	} else {
		name_offset = in_name_offset - dyn_offset;
	}

	indyniov = SMBD_SMB2_IN_DYN_IOV(smb2req);

	if (name_offset > indyniov->iov_len) {
		return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
	}

	name_available_length = indyniov->iov_len - name_offset;

	if (in_name_length > name_available_length) {
		return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
	}

	in_name_buffer.data = (uint8_t *)indyniov->iov_base + name_offset;
	in_name_buffer.length = in_name_length;

	if (in_context_offset == 0 && in_context_length == 0) {
		/* This is ok */
		context_offset = 0;
	} else if (in_context_offset < dyn_offset) {
		return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
	} else {
		context_offset = in_context_offset - dyn_offset;
	}

	if (context_offset > indyniov->iov_len) {
		return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
	}

	context_available_length = indyniov->iov_len - context_offset;

	if (in_context_length > context_available_length) {
		return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
	}

	in_context_buffer.data = (uint8_t *)indyniov->iov_base +
		context_offset;
	in_context_buffer.length = in_context_length;

	/*
	 * Now interpret the name and context buffers
	 */

	ok = convert_string_talloc(smb2req, CH_UTF16, CH_UNIX,
				   in_name_buffer.data,
				   in_name_buffer.length,
				   &in_name_string,
				   &in_name_string_size);
	if (!ok) {
		return smbd_smb2_request_error(smb2req, NT_STATUS_ILLEGAL_CHARACTER);
	}

	if (in_name_buffer.length == 0) {
		in_name_string_size = 0;
	}

	if (strlen(in_name_string) != in_name_string_size) {
		return smbd_smb2_request_error(smb2req, NT_STATUS_OBJECT_NAME_INVALID);
	}

	ZERO_STRUCT(in_context_blobs);
	status = smb2_create_blob_parse(smb2req, in_context_buffer, &in_context_blobs);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(smb2req, status);
	}

	tsubreq = smbd_smb2_create_send(smb2req,
				       smb2req->sconn->ev_ctx,
				       smb2req,
				       in_oplock_level,
				       in_impersonation_level,
				       in_desired_access,
				       in_file_attributes,
				       in_share_access,
				       in_create_disposition,
				       in_create_options,
				       in_name_string,
				       in_context_blobs);
	if (tsubreq == NULL) {
		smb2req->subreq = NULL;
		return smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY);
	}
	tevent_req_set_callback(tsubreq, smbd_smb2_request_create_done, smb2req);

	/*
	 * For now we keep the logic that we do not send STATUS_PENDING
	 * for sharing violations, so we just wait 2 seconds.
	 *
	 * TODO: we need more tests for this.
	 */
	return smbd_smb2_request_pending_queue(smb2req, tsubreq, 2000000);
}
Exemple #7
0
NTSTATUS smbd_smb2_request_process_write(struct smbd_smb2_request *req)
{
	NTSTATUS status;
	const uint8_t *inbody;
	uint16_t in_data_offset;
	uint32_t in_data_length;
	DATA_BLOB in_data_buffer;
	uint64_t in_offset;
	uint64_t in_file_id_persistent;
	uint64_t in_file_id_volatile;
	struct files_struct *in_fsp;
	uint32_t in_flags;
	struct tevent_req *subreq;

	status = smbd_smb2_request_verify_sizes(req, 0x31);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(req, status);
	}
	inbody = SMBD_SMB2_IN_BODY_PTR(req);

	in_data_offset		= SVAL(inbody, 0x02);
	in_data_length		= IVAL(inbody, 0x04);
	in_offset		= BVAL(inbody, 0x08);
	in_file_id_persistent	= BVAL(inbody, 0x10);
	in_file_id_volatile	= BVAL(inbody, 0x18);
	in_flags		= IVAL(inbody, 0x2C);

	if (in_data_offset != (SMB2_HDR_BODY + SMBD_SMB2_IN_BODY_LEN(req))) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	if (in_data_length > SMBD_SMB2_IN_DYN_LEN(req)) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	/* check the max write size */
	if (in_data_length > req->sconn->smb2.max_write) {
		DEBUG(2,("smbd_smb2_request_process_write : "
			"client ignored max write :%s: 0x%08X: 0x%08X\n",
			__location__, in_data_length, req->sconn->smb2.max_write));
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	in_data_buffer.data = SMBD_SMB2_IN_DYN_PTR(req);
	in_data_buffer.length = in_data_length;

	status = smbd_smb2_request_verify_creditcharge(req, in_data_length);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(req, status);
	}

	in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
	if (in_fsp == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
	}

	subreq = smbd_smb2_write_send(req, req->sconn->ev_ctx,
				      req, in_fsp,
				      in_data_buffer,
				      in_offset,
				      in_flags);
	if (subreq == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
	}
	tevent_req_set_callback(subreq, smbd_smb2_request_write_done, req);

	return smbd_smb2_request_pending_queue(req, subreq, 500);
}
Exemple #8
0
NTSTATUS smbd_smb2_request_process_write(struct smbd_smb2_request *req)
{
	NTSTATUS status;
	const uint8_t *inhdr;
	const uint8_t *inbody;
	int i = req->current_idx;
	uint32_t in_smbpid;
	uint16_t in_data_offset;
	uint32_t in_data_length;
	DATA_BLOB in_data_buffer;
	uint64_t in_offset;
	uint64_t in_file_id_persistent;
	uint64_t in_file_id_volatile;
	uint32_t in_flags;
	struct tevent_req *subreq;

	status = smbd_smb2_request_verify_sizes(req, 0x31);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(req, status);
	}
	inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
	inbody = (const uint8_t *)req->in.vector[i+1].iov_base;

	in_smbpid = IVAL(inhdr, SMB2_HDR_PID);

	in_data_offset		= SVAL(inbody, 0x02);
	in_data_length		= IVAL(inbody, 0x04);
	in_offset		= BVAL(inbody, 0x08);
	in_file_id_persistent	= BVAL(inbody, 0x10);
	in_file_id_volatile	= BVAL(inbody, 0x18);
	in_flags		= IVAL(inbody, 0x2C);

	if (in_data_offset != (SMB2_HDR_BODY + req->in.vector[i+1].iov_len)) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	if (in_data_length > req->in.vector[i+2].iov_len) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	/* check the max write size */
	if (in_data_length > lp_smb2_max_write()) {
		/* This is a warning. */
		DEBUG(2,("smbd_smb2_request_process_write : "
			"client ignored max write :%s: 0x%08X: 0x%08X\n",
			__location__, in_data_length, lp_smb2_max_write()));
#if 0
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
#endif
	}

	in_data_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base;
	in_data_buffer.length = in_data_length;

	if (req->compat_chain_fsp) {
		/* skip check */
	} else if (in_file_id_persistent != in_file_id_volatile) {
		return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
	}

	subreq = smbd_smb2_write_send(req,
				      req->sconn->smb2.event_ctx,
				      req,
				      in_smbpid,
				      in_file_id_volatile,
				      in_data_buffer,
				      in_offset,
				      in_flags);
	if (subreq == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
	}
	tevent_req_set_callback(subreq, smbd_smb2_request_write_done, req);

	return smbd_smb2_request_pending_queue(req, subreq);
}
Exemple #9
0
NTSTATUS smbd_smb2_request_process_read(struct smbd_smb2_request *req)
{
	struct smbXsrv_connection *xconn = req->xconn;
	NTSTATUS status;
	const uint8_t *inbody;
	uint8_t in_flags;
	uint32_t in_length;
	uint64_t in_offset;
	uint64_t in_file_id_persistent;
	uint64_t in_file_id_volatile;
	struct files_struct *in_fsp;
	uint32_t in_minimum_count;
	uint32_t in_remaining_bytes;
	struct tevent_req *subreq;

	status = smbd_smb2_request_verify_sizes(req, 0x31);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(req, status);
	}
	inbody = SMBD_SMB2_IN_BODY_PTR(req);

	if (xconn->protocol >= PROTOCOL_SMB3_02) {
		in_flags		= CVAL(inbody, 0x03);
	} else {
		in_flags		= 0;
	}
	in_length		= IVAL(inbody, 0x04);
	in_offset		= BVAL(inbody, 0x08);
	in_file_id_persistent	= BVAL(inbody, 0x10);
	in_file_id_volatile	= BVAL(inbody, 0x18);
	in_minimum_count	= IVAL(inbody, 0x20);
	in_remaining_bytes	= IVAL(inbody, 0x28);

	/* check the max read size */
	if (in_length > xconn->smb2.server.max_read) {
		DEBUG(2,("smbd_smb2_request_process_read: "
			 "client ignored max read: %s: 0x%08X: 0x%08X\n",
			__location__, in_length, xconn->smb2.server.max_read));
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	status = smbd_smb2_request_verify_creditcharge(req, in_length);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(req, status);
	}

	in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
	if (in_fsp == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
	}

	subreq = smbd_smb2_read_send(req, req->sconn->ev_ctx,
				     req, in_fsp,
				     in_flags,
				     in_length,
				     in_offset,
				     in_minimum_count,
				     in_remaining_bytes);
	if (subreq == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
	}
	tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);

	return smbd_smb2_request_pending_queue(req, subreq, 500);
}
Exemple #10
0
NTSTATUS smbd_smb2_request_process_ioctl(struct smbd_smb2_request *req)
{
	NTSTATUS status;
	const uint8_t *inbody;
	uint32_t min_buffer_offset;
	uint32_t max_buffer_offset;
	uint32_t min_output_offset;
	uint32_t allowed_length_in;
	uint32_t allowed_length_out;
	uint32_t in_ctl_code;
	uint64_t in_file_id_persistent;
	uint64_t in_file_id_volatile;
	struct files_struct *in_fsp = NULL;
	uint32_t in_input_offset;
	uint32_t in_input_length;
	DATA_BLOB in_input_buffer = data_blob_null;
	uint32_t in_max_input_length;
	uint32_t in_output_offset;
	uint32_t in_output_length;
	DATA_BLOB in_output_buffer = data_blob_null;
	uint32_t in_max_output_length;
	uint32_t in_flags;
	uint32_t data_length_in;
	uint32_t data_length_out;
	uint32_t data_length_tmp;
	uint32_t data_length_max;
	struct tevent_req *subreq;

	status = smbd_smb2_request_verify_sizes(req, 0x39);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(req, status);
	}
	inbody = SMBD_SMB2_IN_BODY_PTR(req);

	in_ctl_code		= IVAL(inbody, 0x04);
	in_file_id_persistent	= BVAL(inbody, 0x08);
	in_file_id_volatile	= BVAL(inbody, 0x10);
	in_input_offset		= IVAL(inbody, 0x18);
	in_input_length		= IVAL(inbody, 0x1C);
	in_max_input_length	= IVAL(inbody, 0x20);
	in_output_offset	= IVAL(inbody, 0x24);
	in_output_length	= IVAL(inbody, 0x28);
	in_max_output_length	= IVAL(inbody, 0x2C);
	in_flags		= IVAL(inbody, 0x30);

	min_buffer_offset = SMB2_HDR_BODY + SMBD_SMB2_IN_BODY_LEN(req);
	max_buffer_offset = min_buffer_offset + SMBD_SMB2_IN_DYN_LEN(req);
	min_output_offset = min_buffer_offset;

	/*
	 * InputOffset (4 bytes): The offset, in bytes, from the beginning of
	 * the SMB2 header to the input data buffer. If no input data is
	 * required for the FSCTL/IOCTL command being issued, the client SHOULD
	 * set this value to 0.<49>
	 * <49> If no input data is required for the FSCTL/IOCTL command being
	 * issued, Windows-based clients set this field to any value.
	 */
	allowed_length_in = 0;
	if ((in_input_offset > 0) && (in_input_length > 0)) {
		uint32_t tmp_ofs;

		if (in_input_offset < min_buffer_offset) {
			return smbd_smb2_request_error(req,
					NT_STATUS_INVALID_PARAMETER);
		}
		if (in_input_offset > max_buffer_offset) {
			return smbd_smb2_request_error(req,
					NT_STATUS_INVALID_PARAMETER);
		}
		allowed_length_in = max_buffer_offset - in_input_offset;

		tmp_ofs = in_input_offset - min_buffer_offset;
		in_input_buffer.data = SMBD_SMB2_IN_DYN_PTR(req);
		in_input_buffer.data += tmp_ofs;
		in_input_buffer.length = in_input_length;
		min_output_offset += tmp_ofs;
		min_output_offset += in_input_length;
	}

	if (in_input_length > allowed_length_in) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	allowed_length_out = 0;
	if (in_output_offset > 0) {
		if (in_output_offset < min_buffer_offset) {
			return smbd_smb2_request_error(req,
					NT_STATUS_INVALID_PARAMETER);
		}
		if (in_output_offset > max_buffer_offset) {
			return smbd_smb2_request_error(req,
					NT_STATUS_INVALID_PARAMETER);
		}
		allowed_length_out = max_buffer_offset - in_output_offset;
	}

	if (in_output_length > allowed_length_out) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	if (in_output_length > 0) {
		uint32_t tmp_ofs;

		if (in_output_offset < min_output_offset) {
			return smbd_smb2_request_error(req,
					NT_STATUS_INVALID_PARAMETER);
		}

		tmp_ofs = in_output_offset - min_buffer_offset;
		in_output_buffer.data = SMBD_SMB2_IN_DYN_PTR(req);
		in_output_buffer.data += tmp_ofs;
		in_output_buffer.length = in_output_length;
	}

	/*
	 * verify the credits and avoid overflows
	 * in_input_buffer.length and in_output_buffer.length
	 * are already verified.
	 */
	data_length_in = in_input_buffer.length + in_output_buffer.length;

	data_length_out = in_max_input_length;
	data_length_tmp = UINT32_MAX - data_length_out;
	if (data_length_tmp < in_max_output_length) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}
	data_length_out += in_max_output_length;

	data_length_max = MAX(data_length_in, data_length_out);

	status = smbd_smb2_request_verify_creditcharge(req, data_length_max);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(req, status);
	}

	/*
	 * If the Flags field of the request is not SMB2_0_IOCTL_IS_FSCTL the
	 * server MUST fail the request with STATUS_NOT_SUPPORTED.
	 */
	if (in_flags != SMB2_IOCTL_FLAG_IS_FSCTL) {
		return smbd_smb2_request_error(req, NT_STATUS_NOT_SUPPORTED);
	}

	switch (in_ctl_code) {
	case FSCTL_DFS_GET_REFERRALS:
	case FSCTL_DFS_GET_REFERRALS_EX:
	case FSCTL_PIPE_WAIT:
	case FSCTL_VALIDATE_NEGOTIATE_INFO_224:
	case FSCTL_VALIDATE_NEGOTIATE_INFO:
	case FSCTL_QUERY_NETWORK_INTERFACE_INFO:
		/*
		 * Some SMB2 specific CtlCodes like FSCTL_DFS_GET_REFERRALS or
		 * FSCTL_PIPE_WAIT does not take a file handle.
		 *
		 * If FileId in the SMB2 Header of the request is not
		 * 0xFFFFFFFFFFFFFFFF, then the server MUST fail the request
		 * with STATUS_INVALID_PARAMETER.
		 */
		if (in_file_id_persistent != UINT64_MAX ||
		    in_file_id_volatile != UINT64_MAX) {
			return smbd_smb2_request_error(req,
				NT_STATUS_INVALID_PARAMETER);
		}
		break;
	default:
		in_fsp = file_fsp_smb2(req, in_file_id_persistent,
				       in_file_id_volatile);
		if (in_fsp == NULL) {
			return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
		}
		break;
	}

	subreq = smbd_smb2_ioctl_send(req, req->sconn->ev_ctx,
				      req, in_fsp,
				      in_ctl_code,
				      in_input_buffer,
				      in_max_output_length,
				      in_flags);
	if (subreq == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
	}
	tevent_req_set_callback(subreq, smbd_smb2_request_ioctl_done, req);

	return smbd_smb2_request_pending_queue(req, subreq, 1000);
}
Exemple #11
0
NTSTATUS smbd_smb2_request_process_read(struct smbd_smb2_request *req)
{
	const uint8_t *inhdr;
	const uint8_t *inbody;
	int i = req->current_idx;
	size_t expected_body_size = 0x31;
	size_t body_size;
	uint32_t in_smbpid;
	uint32_t in_length;
	uint64_t in_offset;
	uint64_t in_file_id_persistent;
	uint64_t in_file_id_volatile;
	uint32_t in_minimum_count;
	uint32_t in_remaining_bytes;
	struct tevent_req *subreq;

	inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
	if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	inbody = (const uint8_t *)req->in.vector[i+1].iov_base;

	body_size = SVAL(inbody, 0x00);
	if (body_size != expected_body_size) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	in_smbpid = IVAL(inhdr, SMB2_HDR_PID);

	in_length		= IVAL(inbody, 0x04);
	in_offset		= BVAL(inbody, 0x08);
	in_file_id_persistent	= BVAL(inbody, 0x10);
	in_file_id_volatile	= BVAL(inbody, 0x18);
	in_minimum_count	= IVAL(inbody, 0x20);
	in_remaining_bytes	= IVAL(inbody, 0x28);

	/* check the max read size */
	if (in_length > 0x00010000) {
		DEBUG(0,("here:%s: 0x%08X: 0x%08X\n",
			__location__, in_length, 0x00010000));
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	if (req->compat_chain_fsp) {
		/* skip check */
	} else if (in_file_id_persistent != 0) {
		return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
	}

	subreq = smbd_smb2_read_send(req,
				     req->sconn->smb2.event_ctx,
				     req,
				     in_smbpid,
				     in_file_id_volatile,
				     in_length,
				     in_offset,
				     in_minimum_count,
				     in_remaining_bytes);
	if (subreq == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
	}
	tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);

	return smbd_smb2_request_pending_queue(req, subreq);
}