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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }