r25398: Parse loadparm context to all lp_*() functions.
[kai/samba.git] / source4 / smb_server / smb2 / receive.c
index f2a34bdcbfd1a2ff4193b6037d1145348a154bd5..31b7f72ccaaa534b4d9bdf2682a836f120f0365c 100644 (file)
@@ -6,7 +6,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
@@ -15,8 +15,7 @@
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 */
 
 #include "includes.h"
@@ -29,6 +28,7 @@
 #include "smbd/service_stream.h"
 #include "lib/stream/packet.h"
 #include "ntvfs/ntvfs.h"
 #include "smbd/service_stream.h"
 #include "lib/stream/packet.h"
 #include "ntvfs/ntvfs.h"
+#include "param/param.h"
 
 static int smb2srv_request_destructor(struct smb2srv_request *req)
 {
 
 static int smb2srv_request_destructor(struct smb2srv_request *req)
 {
@@ -44,7 +44,7 @@ static int smb2srv_request_deny_destructor(struct smb2srv_request *req)
        return -1;
 }
 
        return -1;
 }
 
-static struct smb2srv_request *smb2srv_init_request(struct smbsrv_connection *smb_conn)
+struct smb2srv_request *smb2srv_init_request(struct smbsrv_connection *smb_conn)
 {
        struct smb2srv_request *req;
 
 {
        struct smb2srv_request *req;
 
@@ -82,7 +82,8 @@ NTSTATUS smb2srv_setup_reply(struct smb2srv_request *req, uint16_t body_fixed_si
        req->out.size           = SMB2_HDR_BODY+NBT_HDR_SIZE+body_fixed_size;
 
        req->out.allocated      = req->out.size + body_dynamic_size;
        req->out.size           = SMB2_HDR_BODY+NBT_HDR_SIZE+body_fixed_size;
 
        req->out.allocated      = req->out.size + body_dynamic_size;
-       req->out.buffer         = talloc_size(req, req->out.allocated);
+       req->out.buffer         = talloc_array(req, uint8_t, 
+                                              req->out.allocated);
        NT_STATUS_HAVE_NO_MEMORY(req->out.buffer);
 
        req->out.hdr            = req->out.buffer       + NBT_HDR_SIZE;
        NT_STATUS_HAVE_NO_MEMORY(req->out.buffer);
 
        req->out.hdr            = req->out.buffer       + NBT_HDR_SIZE;
@@ -91,18 +92,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);
 
        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 */
        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 +121,85 @@ NTSTATUS smb2srv_setup_reply(struct smb2srv_request *req, uint16_t body_fixed_si
        return NT_STATUS_OK;
 }
 
        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;
 void smb2srv_send_reply(struct smb2srv_request *req)
 {
        DATA_BLOB blob;
@@ -140,6 +220,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 (!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);
 }
 
        talloc_free(req);
 }
 
@@ -174,10 +258,11 @@ static NTSTATUS smb2srv_reply(struct smb2srv_request *req)
        uint32_t tid;
        uint64_t uid;
 
        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);
 
        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 +396,6 @@ NTSTATUS smbsrv_recv_smb2_request(void *private, DATA_BLOB blob)
        }
 
        protocol_version = IVAL(blob.data, NBT_HDR_SIZE);
        }
 
        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));
        if (protocol_version != SMB2_MAGIC) {
                DEBUG(2,("Invalid SMB packet: protocol prefix: 0x%08X\n",
                         protocol_version));
@@ -432,7 +516,7 @@ NTSTATUS smbsrv_init_smb2_connection(struct smbsrv_connection *smb_conn)
 
        /* this is the size that w2k uses, and it appears to be important for
           good performance */
 
        /* this is the size that w2k uses, and it appears to be important for
           good performance */
-       smb_conn->negotiate.max_recv = lp_max_xmit();
+       smb_conn->negotiate.max_recv = lp_max_xmit(global_loadparm);
 
        smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
 
 
        smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));