Author: metze Date: 2007-05-14 18:02:49 +0000 (Mon, 14 May 2007) New Revision: 22866
WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=22866 Log: handle incoming chained smb2 requests in our server code to let the windows explorer in longhorn beta3 work. metze Modified: branches/SAMBA_4_0/source/libcli/smb2/request.c branches/SAMBA_4_0/source/libcli/smb2/smb2.h branches/SAMBA_4_0/source/smb_server/smb2/fileio.c branches/SAMBA_4_0/source/smb_server/smb2/negprot.c branches/SAMBA_4_0/source/smb_server/smb2/receive.c branches/SAMBA_4_0/source/smb_server/smb2/smb2_server.h branches/SAMBA_4_0/source/smb_server/smb2/tcon.c Changeset: Modified: branches/SAMBA_4_0/source/libcli/smb2/request.c =================================================================== --- branches/SAMBA_4_0/source/libcli/smb2/request.c 2007-05-14 17:58:28 UTC (rev 22865) +++ branches/SAMBA_4_0/source/libcli/smb2/request.c 2007-05-14 18:02:49 UTC (rev 22866) @@ -80,18 +80,18 @@ req->out.body_size = body_fixed_size; req->out.dynamic = (body_dynamic_size ? req->out.body + body_fixed_size : NULL); - SIVAL(req->out.hdr, 0, SMB2_MAGIC); - SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY); - SSVAL(req->out.hdr, SMB2_HDR_PAD1, 0); - SIVAL(req->out.hdr, SMB2_HDR_STATUS, 0); - SSVAL(req->out.hdr, SMB2_HDR_OPCODE, opcode); - SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1,0); - SIVAL(req->out.hdr, SMB2_HDR_FLAGS, 0); - SIVAL(req->out.hdr, SMB2_HDR_UNKNOWN2,0); - SBVAL(req->out.hdr, SMB2_HDR_SEQNUM, req->seqnum); - SIVAL(req->out.hdr, SMB2_HDR_PID, 0); - SIVAL(req->out.hdr, SMB2_HDR_TID, 0); - SBVAL(req->out.hdr, SMB2_HDR_UID, 0); + SIVAL(req->out.hdr, 0, SMB2_MAGIC); + SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY); + SSVAL(req->out.hdr, SMB2_HDR_PAD1, 0); + SIVAL(req->out.hdr, SMB2_HDR_STATUS, 0); + SSVAL(req->out.hdr, SMB2_HDR_OPCODE, opcode); + SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1, 0); + SIVAL(req->out.hdr, SMB2_HDR_FLAGS, 0); + SIVAL(req->out.hdr, SMB2_HDR_CHAIN_OFFSET, 0); + SBVAL(req->out.hdr, SMB2_HDR_SEQNUM, req->seqnum); + SIVAL(req->out.hdr, SMB2_HDR_PID, 0); + SIVAL(req->out.hdr, SMB2_HDR_TID, 0); + SBVAL(req->out.hdr, SMB2_HDR_UID, 0); memset(req->out.hdr+SMB2_HDR_SIG, 0, 16); /* set the length of the fixed body part and +1 if there's a dynamic part also */ Modified: branches/SAMBA_4_0/source/libcli/smb2/smb2.h =================================================================== --- branches/SAMBA_4_0/source/libcli/smb2/smb2.h 2007-05-14 17:58:28 UTC (rev 22865) +++ branches/SAMBA_4_0/source/libcli/smb2/smb2.h 2007-05-14 18:02:49 UTC (rev 22866) @@ -164,7 +164,7 @@ #define SMB2_HDR_OPCODE 0x0c #define SMB2_HDR_UNKNOWN1 0x0e #define SMB2_HDR_FLAGS 0x10 -#define SMB2_HDR_UNKNOWN2 0x14 +#define SMB2_HDR_CHAIN_OFFSET 0x14 #define SMB2_HDR_SEQNUM 0x18 #define SMB2_HDR_PID 0x20 #define SMB2_HDR_TID 0x24 Modified: branches/SAMBA_4_0/source/smb_server/smb2/fileio.c =================================================================== --- branches/SAMBA_4_0/source/smb_server/smb2/fileio.c 2007-05-14 17:58:28 UTC (rev 22865) +++ branches/SAMBA_4_0/source/smb_server/smb2/fileio.c 2007-05-14 18:02:49 UTC (rev 22866) @@ -44,9 +44,13 @@ SBVAL(req->out.body, 0x30, io->smb2.out.size); SIVAL(req->out.body, 0x38, io->smb2.out.file_attr); SIVAL(req->out.body, 0x3C, io->smb2.out._pad); - smb2srv_push_handle(req->out.body, 0x40,io->smb2.out.file.ntvfs); + smb2srv_push_handle(req->out.body, 0x40, io->smb2.out.file.ntvfs); SMB2SRV_CHECK(smb2_push_o32s32_blob(&req->out, 0x50, io->smb2.out.blob)); + /* also setup the chained file handle */ + req->chained_file_handle = req->_chained_file_handle; + smb2srv_push_handle(req->chained_file_handle, 0, io->smb2.out.file.ntvfs); + smb2srv_send_reply(req); } Modified: branches/SAMBA_4_0/source/smb_server/smb2/negprot.c =================================================================== --- branches/SAMBA_4_0/source/smb_server/smb2/negprot.c 2007-05-14 17:58:28 UTC (rev 22865) +++ branches/SAMBA_4_0/source/smb_server/smb2/negprot.c 2007-05-14 18:02:49 UTC (rev 22866) @@ -204,18 +204,18 @@ req->in.body_size = body_fixed_size; req->in.dynamic = NULL; - SIVAL(req->in.hdr, 0, SMB2_MAGIC); - SSVAL(req->in.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY); - SSVAL(req->in.hdr, SMB2_HDR_PAD1, 0); - SIVAL(req->in.hdr, SMB2_HDR_STATUS, 0); - SSVAL(req->in.hdr, SMB2_HDR_OPCODE, SMB2_OP_NEGPROT); - SSVAL(req->in.hdr, SMB2_HDR_UNKNOWN1,0); - SIVAL(req->in.hdr, SMB2_HDR_FLAGS, 0); - SIVAL(req->in.hdr, SMB2_HDR_UNKNOWN2,0); - SBVAL(req->in.hdr, SMB2_HDR_SEQNUM, 0); - SIVAL(req->in.hdr, SMB2_HDR_PID, 0); - SIVAL(req->in.hdr, SMB2_HDR_TID, 0); - SBVAL(req->in.hdr, SMB2_HDR_UID, 0); + SIVAL(req->in.hdr, 0, SMB2_MAGIC); + SSVAL(req->in.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY); + SSVAL(req->in.hdr, SMB2_HDR_PAD1, 0); + SIVAL(req->in.hdr, SMB2_HDR_STATUS, 0); + SSVAL(req->in.hdr, SMB2_HDR_OPCODE, SMB2_OP_NEGPROT); + SSVAL(req->in.hdr, SMB2_HDR_UNKNOWN1, 0); + SIVAL(req->in.hdr, SMB2_HDR_FLAGS, 0); + SIVAL(req->in.hdr, SMB2_HDR_CHAIN_OFFSET, 0); + SBVAL(req->in.hdr, SMB2_HDR_SEQNUM, 0); + SIVAL(req->in.hdr, SMB2_HDR_PID, 0); + SIVAL(req->in.hdr, SMB2_HDR_TID, 0); + SBVAL(req->in.hdr, SMB2_HDR_UID, 0); memset(req->in.hdr+SMB2_HDR_SIG, 0, 16); /* this seems to be a bug, they use 0x24 but the length is 0x26 */ Modified: branches/SAMBA_4_0/source/smb_server/smb2/receive.c =================================================================== --- branches/SAMBA_4_0/source/smb_server/smb2/receive.c 2007-05-14 17:58:28 UTC (rev 22865) +++ branches/SAMBA_4_0/source/smb_server/smb2/receive.c 2007-05-14 18:02:49 UTC (rev 22866) @@ -91,18 +91,18 @@ req->out.body_size = body_fixed_size; req->out.dynamic = (body_dynamic_size ? req->out.body + body_fixed_size : NULL); - SIVAL(req->out.hdr, 0, SMB2_MAGIC); - SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY); - SSVAL(req->out.hdr, SMB2_HDR_PAD1, 0); - SIVAL(req->out.hdr, SMB2_HDR_STATUS, NT_STATUS_V(req->status)); - SSVAL(req->out.hdr, SMB2_HDR_OPCODE, SVAL(req->in.hdr, SMB2_HDR_OPCODE)); - SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1,0x0001); - SIVAL(req->out.hdr, SMB2_HDR_FLAGS, flags); - SIVAL(req->out.hdr, SMB2_HDR_UNKNOWN2,0); - SBVAL(req->out.hdr, SMB2_HDR_SEQNUM, req->seqnum); - SIVAL(req->out.hdr, SMB2_HDR_PID, pid); - SIVAL(req->out.hdr, SMB2_HDR_TID, tid); - SBVAL(req->out.hdr, SMB2_HDR_UID, BVAL(req->in.hdr, SMB2_HDR_UID)); + SIVAL(req->out.hdr, 0, SMB2_MAGIC); + SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY); + SSVAL(req->out.hdr, SMB2_HDR_PAD1, 0); + SIVAL(req->out.hdr, SMB2_HDR_STATUS, NT_STATUS_V(req->status)); + SSVAL(req->out.hdr, SMB2_HDR_OPCODE, SVAL(req->in.hdr, SMB2_HDR_OPCODE)); + SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1, 0x0001); + SIVAL(req->out.hdr, SMB2_HDR_FLAGS, flags); + SIVAL(req->out.hdr, SMB2_HDR_CHAIN_OFFSET, 0); + SBVAL(req->out.hdr, SMB2_HDR_SEQNUM, req->seqnum); + SIVAL(req->out.hdr, SMB2_HDR_PID, pid); + SIVAL(req->out.hdr, SMB2_HDR_TID, tid); + SBVAL(req->out.hdr, SMB2_HDR_UID, BVAL(req->in.hdr, SMB2_HDR_UID)); memset(req->out.hdr+SMB2_HDR_SIG, 0, 16); /* set the length of the fixed body part and +1 if there's a dynamic part also */ @@ -120,6 +120,85 @@ return NT_STATUS_OK; } +static NTSTATUS smb2srv_reply(struct smb2srv_request *req); + +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; + + chain_offset = p_req->chain_offset; + p_req->chain_offset = 0; + + if (p_req->in.size < (NBT_HDR_SIZE + chain_offset + SMB2_MIN_SIZE)) { + DEBUG(2,("Invalid SMB2 chained packet at offset 0x%X\n", + chain_offset)); + smbsrv_terminate_connection(p_req->smb_conn, "Invalid SMB2 chained packet"); + return; + } + + protocol_version = IVAL(p_req->in.buffer, NBT_HDR_SIZE + 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+ NBT_HDR_SIZE + chain_offset; + req->in.body = req->in.hdr + SMB2_HDR_BODY; + req->in.body_size = req->in.size - (NBT_HDR_SIZE+ chain_offset + SMB2_HDR_BODY); + req->in.dynamic = NULL; + + 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; + } + } + + 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; + } + + /* + * 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; + } +} + void smb2srv_send_reply(struct smb2srv_request *req) { DATA_BLOB blob; @@ -140,6 +219,10 @@ if (!NT_STATUS_IS_OK(status)) { smbsrv_terminate_connection(req->smb_conn, nt_errstr(status)); } + if (req->chain_offset) { + smb2srv_chain_reply(req); + return; + } talloc_free(req); } @@ -174,10 +257,11 @@ uint32_t tid; uint64_t uid; - opcode = SVAL(req->in.hdr, SMB2_HDR_OPCODE); - req->seqnum = BVAL(req->in.hdr, SMB2_HDR_SEQNUM); - tid = IVAL(req->in.hdr, SMB2_HDR_TID); - uid = BVAL(req->in.hdr, SMB2_HDR_UID); + opcode = SVAL(req->in.hdr, SMB2_HDR_OPCODE); + req->chain_offset = IVAL(req->in.hdr, SMB2_HDR_CHAIN_OFFSET); + req->seqnum = BVAL(req->in.hdr, SMB2_HDR_SEQNUM); + tid = IVAL(req->in.hdr, SMB2_HDR_TID); + uid = BVAL(req->in.hdr, SMB2_HDR_UID); req->session = smbsrv_session_find(req->smb_conn, uid, req->request_time); req->tcon = smbsrv_smb2_tcon_find(req->session, tid, req->request_time); @@ -311,7 +395,6 @@ } 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)); Modified: branches/SAMBA_4_0/source/smb_server/smb2/smb2_server.h =================================================================== --- branches/SAMBA_4_0/source/smb_server/smb2/smb2_server.h 2007-05-14 17:58:28 UTC (rev 22865) +++ branches/SAMBA_4_0/source/smb_server/smb2/smb2_server.h 2007-05-14 18:02:49 UTC (rev 22866) @@ -56,6 +56,13 @@ /* the id that can be used to cancel the request */ uint32_t pending_id; + /* the offset to the next SMB2 Header for chained requests */ + uint32_t chain_offset; + + /* chained file handle */ + uint8_t _chained_file_handle[16]; + uint8_t *chained_file_handle; + struct smb2_request_buffer in; struct smb2_request_buffer out; }; Modified: branches/SAMBA_4_0/source/smb_server/smb2/tcon.c =================================================================== --- branches/SAMBA_4_0/source/smb_server/smb2/tcon.c 2007-05-14 17:58:28 UTC (rev 22865) +++ branches/SAMBA_4_0/source/smb_server/smb2/tcon.c 2007-05-14 18:02:49 UTC (rev 22866) @@ -45,6 +45,17 @@ uint32_t tid; uint32_t pad; + /* + * if there're chained requests used the cached handle + * + * TODO: check if this also correct when the given handle + * isn't all 0xFF. + */ + if (req->chained_file_handle) { + base = req->chained_file_handle; + offset = 0; + } + hid = BVAL(base, offset); tid = IVAL(base, offset + 8); pad = IVAL(base, offset + 12);
