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
-   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,
@@ -15,8 +15,7 @@
    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"
@@ -29,6 +28,7 @@
 #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)
 {
@@ -44,7 +44,7 @@ static int smb2srv_request_deny_destructor(struct smb2srv_request *req)
        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;
 
@@ -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.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;
@@ -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);
 
-       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 +121,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 +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 (req->chain_offset) {
+               smb2srv_chain_reply(req);
+               return;
+       }
        talloc_free(req);
 }
 
@@ -174,10 +258,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 +396,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));
@@ -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 */
-       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));