r22866: handle incoming chained smb2 requests in our server code to let
authorStefan Metzmacher <metze@samba.org>
Mon, 14 May 2007 18:02:49 +0000 (18:02 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 19:52:26 +0000 (14:52 -0500)
the windows explorer in longhorn beta3 work.

metze
(This used to be commit 2390c9f24daccec917608cac0870890cdc73cb1c)

source4/libcli/smb2/request.c
source4/libcli/smb2/smb2.h
source4/smb_server/smb2/fileio.c
source4/smb_server/smb2/negprot.c
source4/smb_server/smb2/receive.c
source4/smb_server/smb2/smb2_server.h
source4/smb_server/smb2/tcon.c

index 87c4dd78e19990561821962734fdb9ff71393279..ef024d53f88f156fafca235c2fc68297458b8d5e 100644 (file)
@@ -80,18 +80,18 @@ struct smb2_request *smb2_request_init(struct smb2_transport *transport, uint16_
        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 */
index 586acaccf608de7ef60482df329889b0e6eebd86..4db7c126d88bd3926231e47d16a5d8ecffc847db 100644 (file)
@@ -164,7 +164,7 @@ struct smb2_request {
 #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
index 8e420458beb61976d5f79b4ae08187a234c7a07b..e399bfb90133d8a488460bb342b70b6a7ee40a69 100644 (file)
@@ -44,9 +44,13 @@ static void smb2srv_create_send(struct ntvfs_request *ntvfs)
        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);
 }
 
index fe65917275a6624c820d3ddf97f440b0d9577f57..c666b3d761978db0a4739406099f2b61bc2c8ca7 100644 (file)
@@ -204,18 +204,18 @@ void smb2srv_reply_smb_negprot(struct smbsrv_request *smb_req)
        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 */
index f2a34bdcbfd1a2ff4193b6037d1145348a154bd5..bae3486014f5e817907048c0854de92b228b343f 100644 (file)
@@ -91,18 +91,18 @@ NTSTATUS smb2srv_setup_reply(struct smb2srv_request *req, uint16_t body_fixed_si
        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 @@ NTSTATUS smb2srv_setup_reply(struct smb2srv_request *req, uint16_t body_fixed_si
        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 @@ void smb2srv_send_reply(struct smb2srv_request *req)
        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 @@ static NTSTATUS smb2srv_reply(struct smb2srv_request *req)
        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 @@ NTSTATUS smbsrv_recv_smb2_request(void *private, DATA_BLOB blob)
        }
 
        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));
index 353300681f746c8b9a39609128ceebcb1adf7b03..909a4228dfd9cf9e7ee024f5ff1afd3c3eac3363 100644 (file)
@@ -56,6 +56,13 @@ struct smb2srv_request {
        /* 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;
 };
index a98110ab850058641dc57f362080c97a92505195..023ca9b0a40198346dcc4cba4d53973b9dbc0bae 100644 (file)
@@ -45,6 +45,17 @@ struct ntvfs_handle *smb2srv_pull_handle(struct smb2srv_request *req, const uint
        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);