NTSTATUS smbd_smb2_request_process_create(struct smbd_smb2_request *smb2req) { const uint8_t *inbody; int i = smb2req->current_idx; size_t expected_body_size = 0x39; size_t body_size; 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; if (smb2req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER); } inbody = (const uint8_t *)smb2req->in.vector[i+1].iov_base; body_size = SVAL(inbody, 0x00); if (body_size != expected_body_size) { return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER); } 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 + (body_size & 0xFFFFFFFE); 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; } if (name_offset > smb2req->in.vector[i+2].iov_len) { return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER); } name_available_length = smb2req->in.vector[i+2].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 *)smb2req->in.vector[i+2].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 > smb2req->in.vector[i+2].iov_len) { return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER); } context_available_length = smb2req->in.vector[i+2].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 *)smb2req->in.vector[i+2].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); } 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->smb2.event_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); return smbd_smb2_request_pending_queue(smb2req, tsubreq); }
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); }