void smb2srv_lock_recv(struct smb2srv_request *req) { union smb_lock *io; int i; SMB2SRV_CHECK_BODY_SIZE(req, 0x30, false); SMB2SRV_TALLOC_IO_PTR(io, union smb_lock); SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_lock_send, NTVFS_ASYNC_STATE_MAY_ASYNC); io->smb2.level = RAW_LOCK_SMB2; io->smb2.in.lock_count = SVAL(req->in.body, 0x02); io->smb2.in.reserved = IVAL(req->in.body, 0x04); io->smb2.in.file.ntvfs = smb2srv_pull_handle(req, req->in.body, 0x08); if (req->in.body_size < 24 + 24*(uint64_t)io->smb2.in.lock_count) { DEBUG(0,("%s: lock buffer too small\n", __location__)); smb2srv_send_error(req, NT_STATUS_FOOBAR); return; } io->smb2.in.locks = talloc_array(io, struct smb2_lock_element, io->smb2.in.lock_count); if (io->smb2.in.locks == NULL) { smb2srv_send_error(req, NT_STATUS_NO_MEMORY); return; } for (i=0;i<io->smb2.in.lock_count;i++) { io->smb2.in.locks[i].offset = BVAL(req->in.body, 24 + i*24); io->smb2.in.locks[i].length = BVAL(req->in.body, 32 + i*24); io->smb2.in.locks[i].flags = IVAL(req->in.body, 40 + i*24); io->smb2.in.locks[i].reserved = IVAL(req->in.body, 44 + i*24); } SMB2SRV_CHECK_FILE_HANDLE(io->smb2.in.file.ntvfs); SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_lock(req->ntvfs, io)); }
static void smb2srv_tcon_send(struct smb2srv_request *req, union smb_tcon *io) { uint16_t unknown1; if (!NT_STATUS_IS_OK(req->status)) { smb2srv_send_error(req, req->status); return; } if (io->smb2.out.unknown1 == 0x0002) { /* if it's an IPC share vista returns 0x0005 */ unknown1 = 0x0005; } else { unknown1 = 0x0001; } SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x10, False, 0)); SIVAL(req->out.hdr, SMB2_HDR_TID, io->smb2.out.tid); SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1,unknown1); SSVAL(req->out.body, 0x02, io->smb2.out.unknown1); SIVAL(req->out.body, 0x04, io->smb2.out.unknown2); SIVAL(req->out.body, 0x08, io->smb2.out.unknown3); SIVAL(req->out.body, 0x0C, io->smb2.out.access_mask); smb2srv_send_reply(req); }
void smb2srv_read_recv(struct smb2srv_request *req) { union smb_read *io; SMB2SRV_CHECK_BODY_SIZE(req, 0x30, true); /* MS-SMB2 2.2.19 read must have a single byte of zero */ if (req->in.body_size - req->in.body_fixed < 1) { smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER); return; } SMB2SRV_TALLOC_IO_PTR(io, union smb_read); SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_read_send, NTVFS_ASYNC_STATE_MAY_ASYNC); io->smb2.level = RAW_READ_SMB2; io->smb2.in._pad = SVAL(req->in.body, 0x02); io->smb2.in.length = IVAL(req->in.body, 0x04); io->smb2.in.offset = BVAL(req->in.body, 0x08); io->smb2.in.file.ntvfs = smb2srv_pull_handle(req, req->in.body, 0x10); io->smb2.in.min_count = IVAL(req->in.body, 0x20); io->smb2.in.channel = IVAL(req->in.body, 0x24); io->smb2.in.remaining = IVAL(req->in.body, 0x28); io->smb2.in.channel_offset = SVAL(req->in.body, 0x2C); io->smb2.in.channel_length = SVAL(req->in.body, 0x2E); SMB2SRV_CHECK_FILE_HANDLE(io->smb2.in.file.ntvfs); /* preallocate the buffer for the backends */ io->smb2.out.data = data_blob_talloc(io, NULL, io->smb2.in.length); if (io->smb2.out.data.length != io->smb2.in.length) { SMB2SRV_CHECK(NT_STATUS_NO_MEMORY); } SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_read(req->ntvfs, io)); }
void smb2srv_negprot_recv(struct smb2srv_request *req) { struct smb2_negprot *io; if (req->in.body_size < 0x26) { smb2srv_send_error(req, NT_STATUS_FOOBAR); return; } io = talloc(req, struct smb2_negprot); if (!io) { smbsrv_terminate_connection(req->smb_conn, nt_errstr(NT_STATUS_NO_MEMORY)); talloc_free(req); return; } io->in.unknown1 = SVAL(req->in.body, 0x02); memcpy(io->in.unknown2, req->in.body + 0x04, 0x20); io->in.unknown3 = SVAL(req->in.body, 0x24); req->status = smb2srv_negprot_backend(req, io); if (req->control_flags & SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY) { talloc_free(req); return; } smb2srv_negprot_send(req, io); }
void smb2srv_keepalive_recv(struct smb2srv_request *req) { uint16_t _pad; if (req->in.body_size != 0x04) { smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER); return; } if (SVAL(req->in.body, 0x00) != 0x04) { smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER); return; } _pad = SVAL(req->in.body, 0x02); req->status = smb2srv_keepalive_backend(req); if (req->control_flags & SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY) { talloc_free(req); return; } smb2srv_keepalive_send(req); }
static void smb2srv_keepalive_send(struct smb2srv_request *req) { NTSTATUS status; if (NT_STATUS_IS_ERR(req->status)) { smb2srv_send_error(req, req->status); return; } status = smb2srv_setup_reply(req, 0x04, false, 0); if (!NT_STATUS_IS_OK(status)) { smbsrv_terminate_connection(req->smb_conn, nt_errstr(status)); talloc_free(req); return; } SSVAL(req->out.body, 0x02, 0); smb2srv_send_reply(req); }
static void smb2srv_sesssetup_send(struct smb2srv_request *req, union smb_sesssetup *io) { if (NT_STATUS_IS_OK(req->status)) { /* nothing */ } else if (NT_STATUS_EQUAL(req->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { /* nothing */ } else { smb2srv_send_error(req, req->status); return; } SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x08, true, io->smb2.out.secblob.length)); SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID, io->smb2.out.uid); SSVAL(req->out.body, 0x02, io->smb2.out.session_flags); SMB2SRV_CHECK(smb2_push_o16s16_blob(&req->out, 0x04, io->smb2.out.secblob)); smb2srv_send_reply(req); }
static void smb2srv_negprot_send(struct smb2srv_request *req, struct smb2_negprot *io) { NTSTATUS status; if (NT_STATUS_IS_ERR(req->status)) { smb2srv_send_error(req, req->status); /* TODO: is this correct? */ return; } status = smb2srv_setup_reply(req, 0x40, true, io->out.secblob.length); if (!NT_STATUS_IS_OK(status)) { smbsrv_terminate_connection(req->smb_conn, nt_errstr(status)); talloc_free(req); return; } SSVAL(req->out.body, 0x02, io->out.security_mode); SIVAL(req->out.body, 0x04, io->out.dialect_revision); SIVAL(req->out.body, 0x06, io->out.reserved); status = smbcli_push_guid(req->out.body, 0x08, &io->out.server_guid); if (!NT_STATUS_IS_OK(status)) { smbsrv_terminate_connection(req->smb_conn, nt_errstr(status)); talloc_free(req); return; } SIVAL(req->out.body, 0x18, io->out.capabilities); SIVAL(req->out.body, 0x1C, io->out.max_transact_size); SIVAL(req->out.body, 0x20, io->out.max_read_size); SIVAL(req->out.body, 0x24, io->out.max_write_size); push_nttime(req->out.body, 0x28, io->out.system_time); push_nttime(req->out.body, 0x30, io->out.server_start_time); SIVAL(req->out.body, 0x3C, io->out.reserved2); status = smb2_push_o16s16_blob(&req->out, 0x38, io->out.secblob); if (!NT_STATUS_IS_OK(status)) { smbsrv_terminate_connection(req->smb_conn, nt_errstr(status)); talloc_free(req); return; } smb2srv_send_reply(req); }
static void smb2srv_sesssetup_send(struct smb2srv_request *req, union smb_sesssetup *io) { uint16_t unknown1; if (NT_STATUS_IS_OK(req->status)) { unknown1 = 0x0003; } else if (NT_STATUS_EQUAL(req->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { unknown1 = 0x0002; } else { smb2srv_send_error(req, req->status); return; } SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x08, True, io->smb2.out.secblob.length)); SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1, unknown1); SBVAL(req->out.hdr, SMB2_HDR_UID, io->smb2.out.uid); SSVAL(req->out.body, 0x02, io->smb2.out._pad); SMB2SRV_CHECK(smb2_push_o16s16_blob(&req->out, 0x04, io->smb2.out.secblob)); smb2srv_send_reply(req); }
static void smb2srv_negprot_send(struct smb2srv_request *req, struct smb2_negprot *io) { NTSTATUS status; if (NT_STATUS_IS_ERR(req->status)) { smb2srv_send_error(req, req->status); /* TODO: is this correct? */ return; } status = smb2srv_setup_reply(req, 0x40, True, io->out.secblob.length); if (!NT_STATUS_IS_OK(status)) { smbsrv_terminate_connection(req->smb_conn, nt_errstr(status)); talloc_free(req); return; } SSVAL(req->out.body, 0x02, io->out._pad); SIVAL(req->out.body, 0x04, io->out.unknown2); memcpy(req->out.body+0x08, io->out.sessid, 16); SIVAL(req->out.body, 0x18, io->out.unknown3); SSVAL(req->out.body, 0x1C, io->out.unknown4); SIVAL(req->out.body, 0x1E, io->out.unknown5); SIVAL(req->out.body, 0x22, io->out.unknown6); SSVAL(req->out.body, 0x26, io->out.unknown7); push_nttime(req->out.body, 0x28, io->out.current_time); push_nttime(req->out.body, 0x30, io->out.boot_time); status = smb2_push_o16s16_blob(&req->out, 0x38, io->out.secblob); if (!NT_STATUS_IS_OK(status)) { smbsrv_terminate_connection(req->smb_conn, nt_errstr(status)); talloc_free(req); return; } SIVAL(req->out.body, 0x3C, io->out.unknown9); smb2srv_send_reply(req); }
void smb2srv_break_recv(struct smb2srv_request *req) { smb2srv_send_error(req, NT_STATUS_NOT_IMPLEMENTED); }
void smb2srv_create_recv(struct smb2srv_request *req) { union smb_open *io; DATA_BLOB blob; int i; SMB2SRV_CHECK_BODY_SIZE(req, 0x38, true); SMB2SRV_TALLOC_IO_PTR(io, union smb_open); SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_create_send, NTVFS_ASYNC_STATE_MAY_ASYNC); ZERO_STRUCT(io->smb2.in); io->smb2.level = RAW_OPEN_SMB2; io->smb2.in.security_flags = CVAL(req->in.body, 0x02); io->smb2.in.oplock_level = CVAL(req->in.body, 0x03); io->smb2.in.impersonation_level = IVAL(req->in.body, 0x04); io->smb2.in.create_flags = BVAL(req->in.body, 0x08); io->smb2.in.reserved = BVAL(req->in.body, 0x10); io->smb2.in.desired_access = IVAL(req->in.body, 0x18); io->smb2.in.file_attributes = IVAL(req->in.body, 0x1C); io->smb2.in.share_access = IVAL(req->in.body, 0x20); io->smb2.in.create_disposition = IVAL(req->in.body, 0x24); io->smb2.in.create_options = IVAL(req->in.body, 0x28); SMB2SRV_CHECK(smb2_pull_o16s16_string(&req->in, io, req->in.body+0x2C, &io->smb2.in.fname)); SMB2SRV_CHECK(smb2_pull_o32s32_blob(&req->in, io, req->in.body+0x30, &blob)); SMB2SRV_CHECK(smb2_create_blob_parse(io, blob, &io->smb2.in.blobs)); /* interpret the parsed tags that a server needs to respond to */ for (i=0;i<io->smb2.in.blobs.num_blobs;i++) { if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_EXTA) == 0) { SMB2SRV_CHECK(ea_pull_list_chained(&io->smb2.in.blobs.blobs[i].data, io, &io->smb2.in.eas.num_eas, &io->smb2.in.eas.eas)); } if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_SECD) == 0) { enum ndr_err_code ndr_err; io->smb2.in.sec_desc = talloc(io, struct security_descriptor); if (io->smb2.in.sec_desc == NULL) { smb2srv_send_error(req, NT_STATUS_NO_MEMORY); return; } ndr_err = ndr_pull_struct_blob(&io->smb2.in.blobs.blobs[i].data, io, NULL, io->smb2.in.sec_desc, (ndr_pull_flags_fn_t)ndr_pull_security_descriptor); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { smb2srv_send_error(req, ndr_map_error2ntstatus(ndr_err)); return; } } if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_DHNQ) == 0) { io->smb2.in.durable_open = true; } if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_DHNC) == 0) { if (io->smb2.in.blobs.blobs[i].data.length != 16) { smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER); return; } io->smb2.in.durable_handle = talloc(io, struct smb2_handle); if (io->smb2.in.durable_handle == NULL) { smb2srv_send_error(req, NT_STATUS_NO_MEMORY); return; } smb2_pull_handle(io->smb2.in.blobs.blobs[i].data.data, io->smb2.in.durable_handle); } if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_ALSI) == 0) { if (io->smb2.in.blobs.blobs[i].data.length != 8) { smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER); return; } io->smb2.in.alloc_size = BVAL(io->smb2.in.blobs.blobs[i].data.data, 0); } if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_MXAC) == 0) { io->smb2.in.query_maximal_access = true; } if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_TWRP) == 0) { if (io->smb2.in.blobs.blobs[i].data.length != 8) { smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER); return; } io->smb2.in.timewarp = BVAL(io->smb2.in.blobs.blobs[i].data.data, 0); } if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_QFID) == 0) { io->smb2.in.query_on_disk_id = true; } } /* the VFS backend does not yet handle NULL filenames */ if (io->smb2.in.fname == NULL) { io->smb2.in.fname = ""; } SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, io)); }
NTSTATUS smbsrv_recv_smb2_request(void *private_data, DATA_BLOB blob) { struct smbsrv_connection *smb_conn = talloc_get_type(private_data, struct smbsrv_connection); struct smb2srv_request *req; struct timeval cur_time = timeval_current(); uint32_t protocol_version; uint16_t buffer_code; uint32_t dynamic_size; uint32_t flags; smb_conn->statistics.last_request_time = cur_time; /* see if its a special NBT packet */ if (CVAL(blob.data,0) != 0) { DEBUG(2,("Special NBT packet on SMB2 connection")); smbsrv_terminate_connection(smb_conn, "Special NBT packet on SMB2 connection"); return NT_STATUS_OK; } if (blob.length < (NBT_HDR_SIZE + SMB2_MIN_SIZE_NO_BODY)) { DEBUG(2,("Invalid SMB2 packet length count %ld\n", (long)blob.length)); smbsrv_terminate_connection(smb_conn, "Invalid SMB2 packet"); return NT_STATUS_OK; } protocol_version = IVAL(blob.data, NBT_HDR_SIZE); if (protocol_version != SMB2_MAGIC) { DEBUG(2,("Invalid SMB packet: protocol prefix: 0x%08X\n", protocol_version)); smbsrv_terminate_connection(smb_conn, "NON-SMB2 packet"); return NT_STATUS_OK; } req = smb2srv_init_request(smb_conn); NT_STATUS_HAVE_NO_MEMORY(req); req->in.buffer = talloc_steal(req, blob.data); req->in.size = blob.length; req->request_time = cur_time; req->in.allocated = req->in.size; req->in.hdr = req->in.buffer+ NBT_HDR_SIZE; req->in.body = req->in.hdr + SMB2_HDR_BODY; req->in.body_size = req->in.size - (SMB2_HDR_BODY+NBT_HDR_SIZE); req->in.dynamic = NULL; req->seqnum = BVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID); if (req->in.body_size < 2) { /* error handling for this is different for negprot to other packet types */ uint16_t opcode = SVAL(req->in.hdr, SMB2_HDR_OPCODE); if (opcode == SMB2_OP_NEGPROT) { smbsrv_terminate_connection(req->smb_conn, "Bad body size in SMB2 negprot"); return NT_STATUS_OK; } else { smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER); return NT_STATUS_OK; } } buffer_code = SVAL(req->in.body, 0); req->in.body_fixed = (buffer_code & ~1); dynamic_size = req->in.body_size - req->in.body_fixed; if (dynamic_size != 0 && (buffer_code & 1)) { req->in.dynamic = req->in.body + req->in.body_fixed; if (smb2_oob(&req->in, req->in.dynamic, dynamic_size)) { DEBUG(1,("SMB2 request invalid dynamic size 0x%x\n", dynamic_size)); smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER); return NT_STATUS_OK; } } smb2srv_setup_bufinfo(req); /* * TODO: - make sure the length field is 64 * - make sure it's a request */ flags = IVAL(req->in.hdr, SMB2_HDR_FLAGS); /* the first request should never have the related flag set */ if (flags & SMB2_HDR_FLAG_CHAINED) { req->chain_status = NT_STATUS_INVALID_PARAMETER; } return smb2srv_reply(req); }
static NTSTATUS smb2srv_reply(struct smb2srv_request *req) { uint16_t opcode; uint32_t tid; uint64_t uid; uint32_t flags; if (SVAL(req->in.hdr, SMB2_HDR_LENGTH) != SMB2_HDR_BODY) { smbsrv_terminate_connection(req->smb_conn, "Invalid SMB2 header length"); return NT_STATUS_INVALID_PARAMETER; } opcode = SVAL(req->in.hdr, SMB2_HDR_OPCODE); req->chain_offset = IVAL(req->in.hdr, SMB2_HDR_NEXT_COMMAND); req->seqnum = BVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID); tid = IVAL(req->in.hdr, SMB2_HDR_TID); uid = BVAL(req->in.hdr, SMB2_HDR_SESSION_ID); flags = IVAL(req->in.hdr, SMB2_HDR_FLAGS); if (opcode != SMB2_OP_CANCEL && req->smb_conn->highest_smb2_seqnum != 0 && req->seqnum <= req->smb_conn->highest_smb2_seqnum) { smbsrv_terminate_connection(req->smb_conn, "Invalid SMB2 sequence number"); return NT_STATUS_INVALID_PARAMETER; } if (opcode != SMB2_OP_CANCEL) { req->smb_conn->highest_smb2_seqnum = req->seqnum; } if (flags & SMB2_HDR_FLAG_CHAINED) { uid = req->chained_session_id; tid = req->chained_tree_id; } req->session = smbsrv_session_find(req->smb_conn, uid, req->request_time); req->tcon = smbsrv_smb2_tcon_find(req->session, tid, req->request_time); req->chained_session_id = uid; req->chained_tree_id = tid; errno = 0; /* supporting signing is mandatory in SMB2, and is per-packet. So we should check the signature on any incoming packet that is signed, and should give a signed reply to any signed request */ if (flags & SMB2_HDR_FLAG_SIGNED) { NTSTATUS status; if (!req->session) goto nosession; req->is_signed = true; status = smb2_check_signature(&req->in, req->session->session_info->session_key); if (!NT_STATUS_IS_OK(status)) { smb2srv_send_error(req, status); return NT_STATUS_OK; } } else if (req->session && req->session->smb2_signing.active) { /* we require signing and this request was not signed */ smb2srv_send_error(req, NT_STATUS_ACCESS_DENIED); return NT_STATUS_OK; } if (!NT_STATUS_IS_OK(req->chain_status)) { smb2srv_send_error(req, req->chain_status); return NT_STATUS_OK; } switch (opcode) { case SMB2_OP_NEGPROT: smb2srv_negprot_recv(req); return NT_STATUS_OK; case SMB2_OP_SESSSETUP: smb2srv_sesssetup_recv(req); return NT_STATUS_OK; case SMB2_OP_LOGOFF: if (!req->session) goto nosession; smb2srv_logoff_recv(req); return NT_STATUS_OK; case SMB2_OP_TCON: if (!req->session) goto nosession; smb2srv_tcon_recv(req); return NT_STATUS_OK; case SMB2_OP_TDIS: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_tdis_recv(req); return NT_STATUS_OK; case SMB2_OP_CREATE: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_create_recv(req); return NT_STATUS_OK; case SMB2_OP_CLOSE: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_close_recv(req); return NT_STATUS_OK; case SMB2_OP_FLUSH: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_flush_recv(req); return NT_STATUS_OK; case SMB2_OP_READ: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_read_recv(req); return NT_STATUS_OK; case SMB2_OP_WRITE: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_write_recv(req); return NT_STATUS_OK; case SMB2_OP_LOCK: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_lock_recv(req); return NT_STATUS_OK; case SMB2_OP_IOCTL: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_ioctl_recv(req); return NT_STATUS_OK; case SMB2_OP_CANCEL: smb2srv_cancel_recv(req); return NT_STATUS_OK; case SMB2_OP_KEEPALIVE: smb2srv_keepalive_recv(req); return NT_STATUS_OK; case SMB2_OP_FIND: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_find_recv(req); return NT_STATUS_OK; case SMB2_OP_NOTIFY: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_notify_recv(req); return NT_STATUS_OK; case SMB2_OP_GETINFO: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_getinfo_recv(req); return NT_STATUS_OK; case SMB2_OP_SETINFO: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_setinfo_recv(req); return NT_STATUS_OK; case SMB2_OP_BREAK: if (!req->session) goto nosession; if (!req->tcon) goto notcon; smb2srv_break_recv(req); return NT_STATUS_OK; } DEBUG(1,("Invalid SMB2 opcode: 0x%04X\n", opcode)); smbsrv_terminate_connection(req->smb_conn, "Invalid SMB2 opcode"); return NT_STATUS_OK; nosession: smb2srv_send_error(req, NT_STATUS_USER_SESSION_DELETED); return NT_STATUS_OK; notcon: smb2srv_send_error(req, NT_STATUS_NETWORK_NAME_DELETED); return NT_STATUS_OK; }
static void smb2srv_chain_reply(struct smb2srv_request *p_req) { NTSTATUS status; struct smb2srv_request *req; uint32_t chain_offset; uint32_t protocol_version; uint16_t buffer_code; uint32_t dynamic_size; uint32_t flags; uint32_t last_hdr_offset; last_hdr_offset = p_req->in.hdr - p_req->in.buffer; chain_offset = p_req->chain_offset; p_req->chain_offset = 0; if (p_req->in.size < (last_hdr_offset + chain_offset + SMB2_MIN_SIZE_NO_BODY)) { DEBUG(2,("Invalid SMB2 chained packet at offset 0x%X from last hdr 0x%X\n", chain_offset, last_hdr_offset)); smbsrv_terminate_connection(p_req->smb_conn, "Invalid SMB2 chained packet"); return; } protocol_version = IVAL(p_req->in.buffer, last_hdr_offset + chain_offset); if (protocol_version != SMB2_MAGIC) { DEBUG(2,("Invalid SMB chained packet: protocol prefix: 0x%08X\n", protocol_version)); smbsrv_terminate_connection(p_req->smb_conn, "NON-SMB2 chained packet"); return; } req = smb2srv_init_request(p_req->smb_conn); if (!req) { smbsrv_terminate_connection(p_req->smb_conn, "SMB2 chained packet - no memory"); return; } req->in.buffer = talloc_steal(req, p_req->in.buffer); req->in.size = p_req->in.size; req->request_time = p_req->request_time; req->in.allocated = req->in.size; req->in.hdr = req->in.buffer+ last_hdr_offset + chain_offset; req->in.body = req->in.hdr + SMB2_HDR_BODY; req->in.body_size = req->in.size - (last_hdr_offset+ chain_offset + SMB2_HDR_BODY); req->in.dynamic = NULL; req->seqnum = BVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID); if (req->in.body_size < 2) { /* error handling for this is different for negprot to other packet types */ uint16_t opcode = SVAL(req->in.hdr, SMB2_HDR_OPCODE); if (opcode == SMB2_OP_NEGPROT) { smbsrv_terminate_connection(req->smb_conn, "Bad body size in SMB2 negprot"); } else { smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER); } } buffer_code = SVAL(req->in.body, 0); req->in.body_fixed = (buffer_code & ~1); dynamic_size = req->in.body_size - req->in.body_fixed; if (dynamic_size != 0 && (buffer_code & 1)) { req->in.dynamic = req->in.body + req->in.body_fixed; if (smb2_oob(&req->in, req->in.dynamic, dynamic_size)) { DEBUG(1,("SMB2 chained request invalid dynamic size 0x%x\n", dynamic_size)); smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER); return; } } smb2srv_setup_bufinfo(req); flags = IVAL(req->in.hdr, SMB2_HDR_FLAGS); if (flags & SMB2_HDR_FLAG_CHAINED) { if (p_req->chained_file_handle) { memcpy(req->_chained_file_handle, p_req->_chained_file_handle, sizeof(req->_chained_file_handle)); req->chained_file_handle = req->_chained_file_handle; } req->chained_session_id = p_req->chained_session_id; req->chained_tree_id = p_req->chained_tree_id; req->chain_status = p_req->chain_status; } /* * TODO: - make sure the length field is 64 * - make sure it's a request */ status = smb2srv_reply(req); if (!NT_STATUS_IS_OK(status)) { smbsrv_terminate_connection(req->smb_conn, nt_errstr(status)); talloc_free(req); return; } }