r24408: Remove reply_prep_legacy from reply_lockingX
[ira/wip.git] / source3 / smbd / reply.c
index 4fbf179797c77405ef412372533a59333b679df1..4a8ecb86e988112ec9d6157212c63553f32076fc 100644 (file)
@@ -4,6 +4,7 @@
    Copyright (C) Andrew Tridgell 1992-1998
    Copyright (C) Andrew Bartlett      2001
    Copyright (C) Jeremy Allison 1992-2007.
+   Copyright (C) Volker Lendecke 2007
 
    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
@@ -283,6 +284,50 @@ size_t srvstr_get_path(const char *inbuf, uint16 smb_flags2, char *dest,
        return ret;
 }
 
+/****************************************************************************
+ Check if we have a correct fsp pointing to a file. Replacement for the
+ CHECK_FSP macro.
+****************************************************************************/
+
+BOOL check_fsp(connection_struct *conn, struct smb_request *req,
+              files_struct *fsp, struct current_user *user)
+{
+       if (!(fsp) || !(conn)) {
+               reply_nterror(req, NT_STATUS_INVALID_HANDLE);
+               return False;
+       }
+       if (((conn) != (fsp)->conn) || user->vuid != (fsp)->vuid) {
+               reply_nterror(req, NT_STATUS_INVALID_HANDLE);
+               return False;
+       }
+       if ((fsp)->is_directory) {
+               reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
+               return False;
+       }
+       if ((fsp)->fh->fd == -1) {
+               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+               return False;
+       }
+       (fsp)->num_smb_operations++;
+       return True;
+}
+
+/****************************************************************************
+ Check if we have a correct fsp. Replacement for the FSP_BELONGS_CONN macro
+****************************************************************************/
+
+BOOL fsp_belongs_conn(connection_struct *conn, struct smb_request *req,
+                     files_struct *fsp, struct current_user *user)
+{
+       if ((fsp) && (conn) && ((conn)==(fsp)->conn)
+           && (current_user.vuid==(fsp)->vuid)) {
+               return True;
+       }
+
+       reply_nterror(req, NT_STATUS_INVALID_HANDLE);
+       return False;
+}
+
 /****************************************************************************
  Reply to a (netbios-level) special message.
 ****************************************************************************/
@@ -1706,61 +1751,76 @@ void reply_ulogoffX(connection_struct *conn, struct smb_request *req)
  Reply to a mknew or a create.
 ****************************************************************************/
 
-int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+void reply_mknew(connection_struct *conn, struct smb_request *req)
 {
        pstring fname;
        int com;
-       int outsize = 0;
-       uint32 fattr = SVAL(inbuf,smb_vwv0);
+       uint32 fattr = 0;
        struct timespec ts[2];
        files_struct *fsp;
-       int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+       int oplock_request = 0;
        SMB_STRUCT_STAT sbuf;
        NTSTATUS status;
        uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
        uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
        uint32 create_disposition;
        uint32 create_options = 0;
-       struct smb_request req;
 
        START_PROFILE(SMBcreate);
 
-       init_smb_request(&req, (uint8 *)inbuf);
-       com = SVAL(inbuf,smb_com);
+        if (req->wct < 3) {
+               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               END_PROFILE(SMBcreate);
+               return;
+       }
 
-       ts[1] = convert_time_t_to_timespec(srv_make_unix_date3(inbuf + smb_vwv1)); /* mtime. */
+       fattr = SVAL(req->inbuf,smb_vwv0);
+       oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
+       com = SVAL(req->inbuf,smb_com);
 
-       srvstr_get_path(inbuf, SVAL(inbuf,smb_flg2), fname, smb_buf(inbuf) + 1,
-                       sizeof(fname), 0, STR_TERMINATE, &status);
+       ts[1] =convert_time_t_to_timespec(
+                       srv_make_unix_date3(req->inbuf + smb_vwv1));
+                       /* mtime. */
+
+       srvstr_get_path((char *)req->inbuf, req->flags2, fname,
+                        smb_buf(req->inbuf) + 1, sizeof(fname), 0,
+                       STR_TERMINATE, &status);
        if (!NT_STATUS_IS_OK(status)) {
+               reply_nterror(req, status);
                END_PROFILE(SMBcreate);
-               return ERROR_NT(status);
+               return;
        }
 
-       status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+       status = resolve_dfspath(conn, req->flags2 & FLAGS2_DFS_PATHNAMES,
+                       fname);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBcreate);
                if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
-                       return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+                       reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
+                                       ERRSRV, ERRbadpath);
+                       return;
                }
-               return ERROR_NT(status);
+               reply_nterror(req, status);
+               return;
        }
 
        status = unix_convert(conn, fname, False, NULL, &sbuf);
        if (!NT_STATUS_IS_OK(status)) {
+               reply_nterror(req, status);
                END_PROFILE(SMBcreate);
-               return ERROR_NT(status);
+               return;
        }
 
        status = check_name(conn, fname);
        if (!NT_STATUS_IS_OK(status)) {
+               reply_nterror(req, status);
                END_PROFILE(SMBcreate);
-               return ERROR_NT(status);
+               return;
        }
 
        if (fattr & aVOLID) {
-               DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
+               DEBUG(0,("Attempt to create file (%s) with volid set - "
+                       "please report this\n", fname));
        }
 
        if(com == SMBmknew) {
@@ -1772,7 +1832,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        }
 
        /* Open file using ntcreate. */
-       status = open_file_ntcreate(conn, &req, fname, &sbuf,
+       status = open_file_ntcreate(conn, req, fname, &sbuf,
                                access_mask,
                                share_mode,
                                create_disposition,
@@ -1780,35 +1840,40 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                                fattr,
                                oplock_request,
                                NULL, &fsp);
-  
+
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBcreate);
-               if (open_was_deferred(SVAL(inbuf,smb_mid))) {
+               if (open_was_deferred(req->mid)) {
                        /* We have re-scheduled this call. */
-                       return -1;
+                       return;
                }
-               return ERROR_NT(status);
+               reply_nterror(req, status);
+               return;
        }
+
        ts[0] = get_atimespec(&sbuf); /* atime. */
        file_ntimes(conn, fname, ts);
 
-       outsize = set_message(inbuf,outbuf,1,0,True);
-       SSVAL(outbuf,smb_vwv0,fsp->fnum);
+       reply_outbuf(req, 1, 0);
+
+       SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
 
        if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
-               SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
+               SCVAL(req->outbuf,smb_flg,
+                               CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
        }
+
        if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
-               SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
+               SCVAL(req->outbuf,smb_flg,
+                               CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
        }
+
        DEBUG( 2, ( "reply_mknew: file %s\n", fname ) );
-       DEBUG( 3, ( "reply_mknew %s fd=%d dmode=0x%x\n", fname, fsp->fh->fd, (unsigned int)fattr ) );
+       DEBUG( 3, ( "reply_mknew %s fd=%d dmode=0x%x\n",
+                               fname, fsp->fh->fd, (unsigned int)fattr ) );
 
        END_PROFILE(SMBcreate);
-       return(outsize);
+       return;
 }
 
 /****************************************************************************
@@ -2305,9 +2370,22 @@ static void fail_readraw(void)
  Fake (read/write) sendfile. Returns -1 on read or write fail.
 ****************************************************************************/
 
-static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos, size_t nread, char *buf, size_t bufsize)
+static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos,
+                            size_t nread)
 {
+       size_t bufsize;
        size_t tosend = nread;
+       char *buf;
+
+       if (nread == 0) {
+               return 0;
+       }
+
+       bufsize = MIN(nread, 65536);
+
+       if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
+               return -1;
+       }
 
        while (tosend > 0) {
                ssize_t ret;
@@ -2320,6 +2398,7 @@ static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos, size_t nread
                }
                ret = read_file(fsp,buf,startpos,cur_read);
                if (ret == -1) {
+                       SAFE_FREE(buf);
                        return -1;
                }
 
@@ -2329,22 +2408,41 @@ static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos, size_t nread
                }
 
                if (write_data(smbd_server_fd(),buf,cur_read) != cur_read) {
+                       SAFE_FREE(buf);
                        return -1;
                }
                tosend -= cur_read;
                startpos += cur_read;
        }
 
+       SAFE_FREE(buf);
        return (ssize_t)nread;
 }
 
+/****************************************************************************
+ Return a readbraw error (4 bytes of zero).
+****************************************************************************/
+
+static void reply_readbraw_error(void)
+{
+       char header[4];
+       SIVAL(header,0,0);
+       if (write_data(smbd_server_fd(),header,4) != 4) {
+               fail_readraw();
+       }
+}
+
 /****************************************************************************
  Use sendfile in readbraw.
 ****************************************************************************/
 
-void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T startpos, size_t nread,
-               ssize_t mincount, char *outbuf, int out_buffsize)
+void send_file_readbraw(connection_struct *conn,
+                       files_struct *fsp,
+                       SMB_OFF_T startpos,
+                       size_t nread,
+                       ssize_t mincount)
 {
+       char *outbuf = NULL;
        ssize_t ret=0;
 
 #if defined(WITH_SENDFILE)
@@ -2357,15 +2455,16 @@ void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T st
 
        if ( (chain_size == 0) && (nread > 0) &&
            (fsp->wcp == NULL) && lp_use_sendfile(SNUM(conn)) ) {
-               DATA_BLOB header;
+               char header[4];
+               DATA_BLOB header_blob;
 
-               _smb_setlen(outbuf,nread);
-               header.data = (uint8 *)outbuf;
-               header.length = 4;
-               header.free = NULL;
+               _smb_setlen(header,nread);
+               header_blob = data_blob_const(header, 4);
 
-               if ( SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fh->fd, &header, startpos, nread) == -1) {
-                       /* Returning ENOSYS means no data at all was sent. Do this as a normal read. */
+               if ( SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fh->fd,
+                               &header_blob, startpos, nread) == -1) {
+                       /* Returning ENOSYS means no data at all was sent.
+                        * Do this as a normal read. */
                        if (errno == ENOSYS) {
                                goto normal_readbraw;
                        }
@@ -2380,7 +2479,7 @@ void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T st
                                set_use_sendfile(SNUM(conn), False);
                                DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
 
-                               if (fake_sendfile(fsp, startpos, nread, outbuf + 4, out_buffsize - 4) == -1) {
+                               if (fake_sendfile(fsp, startpos, nread) == -1) {
                                        DEBUG(0,("send_file_readbraw: fake_sendfile failed for file %s (%s).\n",
                                                fsp->fsp_name, strerror(errno) ));
                                        exit_server_cleanly("send_file_readbraw fake_sendfile failed");
@@ -2399,6 +2498,14 @@ void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T st
 
 normal_readbraw:
 
+       outbuf = TALLOC_ARRAY(NULL, char, nread+4);
+       if (!outbuf) {
+               DEBUG(0,("send_file_readbraw: TALLOC_ARRAY failed for size %u.\n",
+                       (unsigned)(nread+4)));
+               reply_readbraw_error();
+               return;
+       }
+
        if (nread > 0) {
                ret = read_file(fsp,outbuf+4,startpos,nread);
 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
@@ -2413,23 +2520,34 @@ normal_readbraw:
        _smb_setlen(outbuf,ret);
        if (write_data(smbd_server_fd(),outbuf,4+ret) != 4+ret)
                fail_readraw();
+
+       TALLOC_FREE(outbuf);
 }
 
 /****************************************************************************
  Reply to a readbraw (core+ protocol).
 ****************************************************************************/
 
-int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int out_buffsize)
+void reply_readbraw(connection_struct *conn, struct smb_request *req)
 {
        ssize_t maxcount,mincount;
        size_t nread = 0;
        SMB_OFF_T startpos;
-       char *header = outbuf;
        files_struct *fsp;
+       SMB_STRUCT_STAT st;
+       SMB_OFF_T size = 0;
+
        START_PROFILE(SMBreadbraw);
 
        if (srv_is_signing_active()) {
-               exit_server_cleanly("reply_readbraw: SMB signing is active - raw reads/writes are disallowed.");
+               exit_server_cleanly("reply_readbraw: SMB signing is active - "
+                       "raw reads/writes are disallowed.");
+       }
+
+       if (req->wct < 8) {
+               reply_readbraw_error();
+               END_PROFILE(SMBreadbraw);
+               return;
        }
 
        /*
@@ -2438,32 +2556,49 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
         * return a zero length response here.
         */
 
-       fsp = file_fsp(SVAL(inbuf,smb_vwv0));
+       fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
 
-       if (!FNUM_OK(fsp,conn) || !fsp->can_read) {
+       /* 
+        * We have to do a check_fsp by hand here, as
+        * we must always return 4 zero bytes on error,
+        * not a NTSTATUS.
+        */
+
+       if (!fsp || !conn || conn != fsp->conn ||
+                       current_user.vuid != fsp->vuid ||
+                       fsp->is_directory || fsp->fh->fd == -1) {
                /*
                 * fsp could be NULL here so use the value from the packet. JRA.
                 */
-               DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",(int)SVAL(inbuf,smb_vwv0)));
-               _smb_setlen(header,0);
-               if (write_data(smbd_server_fd(),header,4) != 4)
-                       fail_readraw();
+               DEBUG(3,("reply_readbraw: fnum %d not valid "
+                       "- cache prime?\n",
+                       (int)SVAL(req->inbuf,smb_vwv0)));
+               reply_readbraw_error();
                END_PROFILE(SMBreadbraw);
-               return(-1);
+               return;
        }
 
-       CHECK_FSP(fsp,conn);
+       /* Do a "by hand" version of CHECK_READ. */
+       if (!(fsp->can_read ||
+                       ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
+                               (fsp->access_mask & FILE_EXECUTE)))) {
+               DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
+                               (int)SVAL(req->inbuf,smb_vwv0)));
+               reply_readbraw_error();
+               END_PROFILE(SMBreadbraw);
+               return;
+       }
 
        flush_write_cache(fsp, READRAW_FLUSH);
 
-       startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv1);
-       if(CVAL(inbuf,smb_wct) == 10) {
+       startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv1);
+       if(req->wct == 10) {
                /*
                 * This is a large offset (64 bit) read.
                 */
 #ifdef LARGE_SMB_OFF_T
 
-               startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv8)) << 32);
+               startpos |= (((SMB_OFF_T)IVAL(req->inbuf,smb_vwv8)) << 32);
 
 #else /* !LARGE_SMB_OFF_T */
 
@@ -2471,46 +2606,51 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
                 * Ensure we haven't been sent a >32 bit offset.
                 */
 
-               if(IVAL(inbuf,smb_vwv8) != 0) {
-                       DEBUG(0,("readbraw - large offset (%x << 32) used and we don't support \
-64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv8) ));
-                       _smb_setlen(header,0);
-                       if (write_data(smbd_server_fd(),header,4) != 4)
-                               fail_readraw();
+               if(IVAL(req->inbuf,smb_vwv8) != 0) {
+                       DEBUG(0,("reply_readbraw: large offset "
+                               "(%x << 32) used and we don't support "
+                               "64 bit offsets.\n",
+                       (unsigned int)IVAL(req->inbuf,smb_vwv8) ));
+                       reply_readbraw_error();
                        END_PROFILE(SMBreadbraw);
-                       return(-1);
+                       return;
                }
 
 #endif /* LARGE_SMB_OFF_T */
 
                if(startpos < 0) {
-                       DEBUG(0,("readbraw - negative 64 bit readraw offset (%.0f) !\n", (double)startpos ));
-                       _smb_setlen(header,0);
-                       if (write_data(smbd_server_fd(),header,4) != 4)
-                               fail_readraw();
+                       DEBUG(0,("reply_readbraw: negative 64 bit "
+                               "readraw offset (%.0f) !\n",
+                               (double)startpos ));
+                       reply_readbraw_error();
                        END_PROFILE(SMBreadbraw);
-                       return(-1);
+                       return;
                }      
        }
-       maxcount = (SVAL(inbuf,smb_vwv3) & 0xFFFF);
-       mincount = (SVAL(inbuf,smb_vwv4) & 0xFFFF);
+
+       maxcount = (SVAL(req->inbuf,smb_vwv3) & 0xFFFF);
+       mincount = (SVAL(req->inbuf,smb_vwv4) & 0xFFFF);
 
        /* ensure we don't overrun the packet size */
        maxcount = MIN(65535,maxcount);
 
-       if (!is_locked(fsp,(uint32)SVAL(inbuf,smb_pid),(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK)) {
-               SMB_STRUCT_STAT st;
-               SMB_OFF_T size = 0;
-  
-               if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st) == 0) {
-                       size = st.st_size;
-               }
+       if (is_locked(fsp,(uint32)req->smbpid,
+                       (SMB_BIG_UINT)maxcount,
+                       (SMB_BIG_UINT)startpos,
+                       READ_LOCK)) {
+               reply_readbraw_error();
+               END_PROFILE(SMBreadbraw);
+               return;
+       }
 
-               if (startpos >= size) {
-                       nread = 0;
-               } else {
-                       nread = MIN(maxcount,(size - startpos));          
-               }
+       if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st) == 0) {
+               size = st.st_size;
+       }
+
+       if (startpos >= size) {
+               nread = 0;
+       } else {
+               nread = MIN(maxcount,(size - startpos));          
        }
 
 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
@@ -2518,14 +2658,17 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
                nread = 0;
 #endif
   
-       DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%lu min=%lu nread=%lu\n", fsp->fnum, (double)startpos,
-                               (unsigned long)maxcount, (unsigned long)mincount, (unsigned long)nread ) );
+       DEBUG( 3, ( "reply_readbraw: fnum=%d start=%.0f max=%lu "
+               "min=%lu nread=%lu\n",
+               fsp->fnum, (double)startpos,
+               (unsigned long)maxcount,
+               (unsigned long)mincount,
+               (unsigned long)nread ) );
   
-       send_file_readbraw(conn, fsp, startpos, nread, mincount, outbuf, out_buffsize);
+       send_file_readbraw(conn, fsp, startpos, nread, mincount);
 
-       DEBUG(5,("readbraw finished\n"));
+       DEBUG(5,("reply_readbraw finished\n"));
        END_PROFILE(SMBreadbraw);
-       return -1;
 }
 
 #undef DBGC_CLASS
@@ -2684,10 +2827,15 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n",
  Setup readX header.
 ****************************************************************************/
 
-static int setup_readX_header(char *inbuf, char *outbuf, size_t smb_maxcnt)
+static int setup_readX_header(const uint8 *inbuf, uint8 *outbuf,
+                             size_t smb_maxcnt)
 {
        int outsize;
-       char *data = smb_buf(outbuf);
+       char *data;
+
+       outsize = set_message((char *)inbuf, (char *)outbuf,12,smb_maxcnt,
+                             False);
+       data = smb_buf(outbuf);
 
        SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
        SSVAL(outbuf,smb_vwv5,smb_maxcnt);
@@ -2695,7 +2843,6 @@ static int setup_readX_header(char *inbuf, char *outbuf, size_t smb_maxcnt)
        SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
        SSVAL(smb_buf(outbuf),-2,smb_maxcnt);
        SCVAL(outbuf,smb_vwv0,0xFF);
-       outsize = set_message(inbuf, outbuf,12,smb_maxcnt,False);
        /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
        _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
        return outsize;
@@ -2705,16 +2852,16 @@ static int setup_readX_header(char *inbuf, char *outbuf, size_t smb_maxcnt)
  Reply to a read and X - possibly using sendfile.
 ****************************************************************************/
 
-int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length, int len_outbuf,
-               files_struct *fsp, SMB_OFF_T startpos, size_t smb_maxcnt)
+static void send_file_readX(connection_struct *conn, struct smb_request *req,
+                           files_struct *fsp, SMB_OFF_T startpos,
+                           size_t smb_maxcnt)
 {
        SMB_STRUCT_STAT sbuf;
-       int outsize = 0;
        ssize_t nread = -1;
-       char *data = smb_buf(outbuf);
 
        if(SMB_VFS_FSTAT(fsp,fsp->fh->fd, &sbuf) == -1) {
-               return(UNIXERROR(ERRDOS,ERRnoaccess));
+               reply_unixerror(req, ERRDOS, ERRnoaccess);
+               return;
        }
 
        if (startpos > sbuf.st_size) {
@@ -2734,8 +2881,9 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
         * on a train in Germany :-). JRA.
         */
 
-       if ((chain_size == 0) && (CVAL(inbuf,smb_vwv0) == 0xFF) &&
+       if ((chain_size == 0) && (CVAL(req->inbuf,smb_vwv0) == 0xFF) &&
            lp_use_sendfile(SNUM(conn)) && (fsp->wcp == NULL) ) {
+               uint8 headerbuf[smb_size + 12 * 2];
                DATA_BLOB header;
 
                /* 
@@ -2744,11 +2892,10 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
                 * correct amount of data).
                 */
 
-               setup_readX_header(inbuf,outbuf,smb_maxcnt);
-               set_message(inbuf,outbuf,12,smb_maxcnt,False);
-               header.data = (uint8 *)outbuf;
-               header.length = data - outbuf;
-               header.free = NULL;
+               header = data_blob_const(headerbuf, sizeof(headerbuf));
+
+               construct_reply_common((char *)req->inbuf, (char *)headerbuf);
+               setup_readX_header(req->inbuf, headerbuf, smb_maxcnt);
 
                if ((nread = SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fh->fd, &header, startpos, smb_maxcnt)) == -1) {
                        /* Returning ENOSYS means no data at all was sent. Do this as a normal read. */
@@ -2766,17 +2913,18 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
                                /* Ensure we don't do this again. */
                                set_use_sendfile(SNUM(conn), False);
                                DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
-
-                               if ((nread = fake_sendfile(fsp, startpos, smb_maxcnt, data,
-                                                       len_outbuf - (data-outbuf))) == -1) {
+                               nread = fake_sendfile(fsp, startpos,
+                                                     smb_maxcnt);
+                               if (nread == -1) {
                                        DEBUG(0,("send_file_readX: fake_sendfile failed for file %s (%s).\n",
                                                fsp->fsp_name, strerror(errno) ));
                                        exit_server_cleanly("send_file_readX: fake_sendfile failed");
                                }
                                DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n",
                                        fsp->fnum, (int)smb_maxcnt, (int)nread ) );
-                               /* Returning -1 here means successful sendfile. */
-                               return -1;
+                               /* No outbuf here means successful sendfile. */
+                               TALLOC_FREE(req->outbuf);
+                               return;
                        }
 
                        DEBUG(0,("send_file_readX: sendfile failed for file %s (%s). Terminating\n",
@@ -2786,8 +2934,9 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
 
                DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
                        fsp->fnum, (int)smb_maxcnt, (int)nread ) );
-               /* Returning -1 here means successful sendfile. */
-               return -1;
+               /* No outbuf here means successful sendfile. */
+               TALLOC_FREE(req->outbuf);
+               return;
        }
 
 #endif
@@ -2795,34 +2944,44 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
 normal_read:
 
        if ((smb_maxcnt & 0xFF0000) > 0x10000) {
-               int sendlen = setup_readX_header(inbuf,outbuf,smb_maxcnt) - smb_maxcnt;
+               uint8 headerbuf[smb_size + 2*12];
+
+               construct_reply_common((char *)req->inbuf, (char *)headerbuf);
+               setup_readX_header(req->inbuf, headerbuf, smb_maxcnt);
+
                /* Send out the header. */
-               if (write_data(smbd_server_fd(),outbuf,sendlen) != sendlen) {
+               if (write_data(smbd_server_fd(), (char *)headerbuf,
+                              sizeof(headerbuf)) != sizeof(headerbuf)) {
                        DEBUG(0,("send_file_readX: write_data failed for file %s (%s). Terminating\n",
                                fsp->fsp_name, strerror(errno) ));
                        exit_server_cleanly("send_file_readX sendfile failed");
                }
-               if ((nread = fake_sendfile(fsp, startpos, smb_maxcnt, data,
-                                       len_outbuf - (data-outbuf))) == -1) {
+               nread = fake_sendfile(fsp, startpos, smb_maxcnt);
+               if (nread == -1) {
                        DEBUG(0,("send_file_readX: fake_sendfile failed for file %s (%s).\n",
                                fsp->fsp_name, strerror(errno) ));
                        exit_server_cleanly("send_file_readX: fake_sendfile failed");
                }
-               return -1;
+               TALLOC_FREE(req->outbuf);
+               return;
        } else {
-               nread = read_file(fsp,data,startpos,smb_maxcnt);
+               reply_outbuf(req, 12, smb_maxcnt);
 
+               nread = read_file(fsp, smb_buf(req->outbuf), startpos,
+                                 smb_maxcnt);
                if (nread < 0) {
-                       return(UNIXERROR(ERRDOS,ERRnoaccess));
+                       reply_unixerror(req, ERRDOS, ERRnoaccess);
+                       return;
                }
 
-               outsize = setup_readX_header(inbuf, outbuf,nread);
+               setup_readX_header(req->inbuf, req->outbuf, nread);
 
                DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
                        fsp->fnum, (int)smb_maxcnt, (int)nread ) );
 
-               /* Returning the number of bytes we want to send back - including header. */
-               return outsize;
+               chain_reply_new(req);
+
+               return;
        }
 }
 
@@ -2830,58 +2989,78 @@ normal_read:
  Reply to a read and X.
 ****************************************************************************/
 
-int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
+void reply_read_and_X(connection_struct *conn, struct smb_request *req)
 {
-       files_struct *fsp = file_fsp(SVAL(inbuf,smb_vwv2));
-       SMB_OFF_T startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
-       ssize_t nread = -1;
-       size_t smb_maxcnt = SVAL(inbuf,smb_vwv5);
+       files_struct *fsp;
+       SMB_OFF_T startpos;
+       size_t smb_maxcnt;
        BOOL big_readX = False;
 #if 0
-       size_t smb_mincnt = SVAL(inbuf,smb_vwv6);
+       size_t smb_mincnt = SVAL(req->inbuf,smb_vwv6);
 #endif
 
        START_PROFILE(SMBreadX);
 
+       if ((req->wct != 10) && (req->wct != 12)) {
+               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               return;
+       }
+
+       fsp = file_fsp(SVAL(req->inbuf,smb_vwv2));
+       startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv3);
+       smb_maxcnt = SVAL(req->inbuf,smb_vwv5);
+
        /* If it's an IPC, pass off the pipe handler. */
        if (IS_IPC(conn)) {
+               reply_pipe_read_and_X(req);
                END_PROFILE(SMBreadX);
-               return reply_pipe_read_and_X(inbuf,outbuf,length,bufsize);
+               return;
        }
 
-       CHECK_FSP(fsp,conn);
-       if (!CHECK_READ(fsp,inbuf)) {
-               return(ERROR_DOS(ERRDOS,ERRbadaccess));
+       if (!check_fsp(conn, req, fsp, &current_user)) {
+               END_PROFILE(SMBreadX);
+               return;
        }
 
-       set_message(inbuf,outbuf,12,0,True);
+       if (!CHECK_READ(fsp,req->inbuf)) {
+               reply_doserror(req, ERRDOS,ERRbadaccess);
+               END_PROFILE(SMBreadX);
+               return;
+       }
 
        if (global_client_caps & CAP_LARGE_READX) {
-               size_t upper_size = SVAL(inbuf,smb_vwv7);
+               size_t upper_size = SVAL(req->inbuf,smb_vwv7);
                smb_maxcnt |= (upper_size<<16);
                if (upper_size > 1) {
                        /* Can't do this on a chained packet. */
-                       if ((CVAL(inbuf,smb_vwv0) != 0xFF)) {
-                               return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+                       if ((CVAL(req->inbuf,smb_vwv0) != 0xFF)) {
+                               reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
+                               END_PROFILE(SMBreadX);
+                               return;
                        }
                        /* We currently don't do this on signed or sealed data. */
                        if (srv_is_signing_active() || srv_encryption_on()) {
-                               return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+                               reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
+                               END_PROFILE(SMBreadX);
+                               return;
                        }
                        /* Is there room in the reply for this data ? */
                        if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2)))  {
-                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                               reply_nterror(req,
+                                             NT_STATUS_INVALID_PARAMETER);
+                               END_PROFILE(SMBreadX);
+                               return;
                        }
                        big_readX = True;
                }
        }
 
-       if(CVAL(inbuf,smb_wct) == 12) {
+       if (req->wct == 12) {
 #ifdef LARGE_SMB_OFF_T
                /*
                 * This is a large offset (64 bit) read.
                 */
-               startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv10)) << 32);
+               startpos |= (((SMB_OFF_T)IVAL(req->inbuf,smb_vwv10)) << 32);
 
 #else /* !LARGE_SMB_OFF_T */
 
@@ -2889,35 +3068,37 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                 * Ensure we haven't been sent a >32 bit offset.
                 */
 
-               if(IVAL(inbuf,smb_vwv10) != 0) {
-                       DEBUG(0,("reply_read_and_X - large offset (%x << 32) used and we don't support \
-64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv10) ));
+               if(IVAL(req->inbuf,smb_vwv10) != 0) {
+                       DEBUG(0,("reply_read_and_X - large offset (%x << 32) "
+                                "used and we don't support 64 bit offsets.\n",
+                                (unsigned int)IVAL(req->inbuf,smb_vwv10) ));
                        END_PROFILE(SMBreadX);
-                       return ERROR_DOS(ERRDOS,ERRbadaccess);
+                       reply_doserror(req, ERRDOS, ERRbadaccess);
+                       return;
                }
 
 #endif /* LARGE_SMB_OFF_T */
 
        }
 
-       if (is_locked(fsp,(uint32)SVAL(inbuf,smb_pid),(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK)) {
+       if (is_locked(fsp, (uint32)req->smbpid, (SMB_BIG_UINT)smb_maxcnt,
+                     (SMB_BIG_UINT)startpos, READ_LOCK)) {
                END_PROFILE(SMBreadX);
-               return ERROR_DOS(ERRDOS,ERRlock);
+               reply_doserror(req, ERRDOS, ERRlock);
+               return;
        }
 
-       if (!big_readX && schedule_aio_read_and_X(conn, inbuf, outbuf, length, bufsize, fsp, startpos, smb_maxcnt)) {
+       if (!big_readX
+           && schedule_aio_read_and_X(conn, req, fsp, startpos, smb_maxcnt)) {
                END_PROFILE(SMBreadX);
-               return -1;
+               reply_post_legacy(req, -1);
+               return;
        }
 
-       nread = send_file_readX(conn, inbuf, outbuf, length, bufsize, fsp, startpos, smb_maxcnt);
-       /* Only call chain_reply if not an error. */
-       if (nread != -1 && SVAL(outbuf,smb_rcls) == 0) {
-               nread = chain_reply(inbuf,&outbuf,length,bufsize);
-       }
+       send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
 
        END_PROFILE(SMBreadX);
-       return nread;
+       return;
 }
 
 /****************************************************************************
@@ -3243,51 +3424,73 @@ int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int d
  Reply to a write and X.
 ****************************************************************************/
 
-int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
+void reply_write_and_X(connection_struct *conn, struct smb_request *req)
 {
-       files_struct *fsp = file_fsp(SVAL(inbuf,smb_vwv2));
-       SMB_OFF_T startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
-       size_t numtowrite = SVAL(inbuf,smb_vwv10);
-       BOOL write_through = BITSETW(inbuf+smb_vwv7,0);
-       ssize_t nwritten = -1;
-       unsigned int smb_doff = SVAL(inbuf,smb_vwv11);
-       unsigned int smblen = smb_len(inbuf);
+       files_struct *fsp;
+       SMB_OFF_T startpos;
+       size_t numtowrite;
+       BOOL write_through;
+       ssize_t nwritten;
+       unsigned int smb_doff;
+       unsigned int smblen;
        char *data;
-       BOOL large_writeX = ((CVAL(inbuf,smb_wct) == 14) && (smblen > 0xFFFF));
+       BOOL large_writeX;
        NTSTATUS status;
+
        START_PROFILE(SMBwriteX);
 
-       /* If it's an IPC, pass off the pipe handler. */
-       if (IS_IPC(conn)) {
+       if ((req->wct != 12) && (req->wct != 14)) {
+               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
                END_PROFILE(SMBwriteX);
-               return reply_pipe_write_and_X(inbuf,outbuf,length,bufsize);
+               return;
        }
 
-       CHECK_FSP(fsp,conn);
-       if (!CHECK_WRITE(fsp)) {
-               return(ERROR_DOS(ERRDOS,ERRbadaccess));
-       }
+       numtowrite = SVAL(req->inbuf,smb_vwv10);
+       smb_doff = SVAL(req->inbuf,smb_vwv11);
+       smblen = smb_len(req->inbuf);
+       large_writeX = ((req->wct == 14) && (smblen > 0xFFFF));
 
-       set_message(inbuf,outbuf,6,0,True);
-  
        /* Deal with possible LARGE_WRITEX */
        if (large_writeX) {
-               numtowrite |= ((((size_t)SVAL(inbuf,smb_vwv9)) & 1 )<<16);
+               numtowrite |= ((((size_t)SVAL(req->inbuf,smb_vwv9)) & 1 )<<16);
        }
 
        if(smb_doff > smblen || (smb_doff + numtowrite > smblen)) {
+               reply_doserror(req, ERRDOS, ERRbadmem);
                END_PROFILE(SMBwriteX);
-               return ERROR_DOS(ERRDOS,ERRbadmem);
+               return;
        }
 
-       data = smb_base(inbuf) + smb_doff;
+       /* If it's an IPC, pass off the pipe handler. */
+       if (IS_IPC(conn)) {
+               reply_pipe_write_and_X(req);
+               END_PROFILE(SMBwriteX);
+               return;
+       }
+
+       fsp = file_fsp(SVAL(req->inbuf,smb_vwv2));
+       startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv3);
+       write_through = BITSETW(req->inbuf+smb_vwv7,0);
 
-       if(CVAL(inbuf,smb_wct) == 14) {
+       if (!check_fsp(conn, req, fsp, &current_user)) {
+               END_PROFILE(SMBwriteX);
+               return;
+       }
+
+       if (!CHECK_WRITE(fsp)) {
+               reply_doserror(req, ERRDOS, ERRbadaccess);
+               END_PROFILE(SMBwriteX);
+               return;
+       }
+
+       data = smb_base(req->inbuf) + smb_doff;
+
+       if(req->wct == 14) {
 #ifdef LARGE_SMB_OFF_T
                /*
                 * This is a large offset (64 bit) write.
                 */
-               startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv12)) << 32);
+               startpos |= (((SMB_OFF_T)IVAL(req->inbuf,smb_vwv12)) << 32);
 
 #else /* !LARGE_SMB_OFF_T */
 
@@ -3295,19 +3498,24 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
                 * Ensure we haven't been sent a >32 bit offset.
                 */
 
-               if(IVAL(inbuf,smb_vwv12) != 0) {
-                       DEBUG(0,("reply_write_and_X - large offset (%x << 32) used and we don't support \
-64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv12) ));
+               if(IVAL(req->inbuf,smb_vwv12) != 0) {
+                       DEBUG(0,("reply_write_and_X - large offset (%x << 32) "
+                                "used and we don't support 64 bit offsets.\n",
+                                (unsigned int)IVAL(inbuf,smb_vwv12) ));
+                       reply_doserror(req, ERRDOS, ERRbadaccess);
                        END_PROFILE(SMBwriteX);
-                       return ERROR_DOS(ERRDOS,ERRbadaccess);
+                       return;
                }
 
 #endif /* LARGE_SMB_OFF_T */
        }
 
-       if (is_locked(fsp,(uint32)SVAL(inbuf,smb_pid),(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
+       if (is_locked(fsp,(uint32)req->smbpid,
+                     (SMB_BIG_UINT)numtowrite,
+                     (SMB_BIG_UINT)startpos, WRITE_LOCK)) {
+               reply_doserror(req, ERRDOS, ERRlock);
                END_PROFILE(SMBwriteX);
-               return ERROR_DOS(ERRDOS,ERRlock);
+               return;
        }
 
        /* X/Open SMB protocol says that, unlike SMBwrite
@@ -3319,27 +3527,29 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
                nwritten = 0;
        } else {
 
-               if (schedule_aio_write_and_X(conn, inbuf, outbuf, length, bufsize,
-                                       fsp,data,startpos,numtowrite)) {
+               if (schedule_aio_write_and_X(conn, req, fsp, data, startpos,
+                                            numtowrite)) {
                        END_PROFILE(SMBwriteX);
-                       return -1;
+                       return;
                }
 
                nwritten = write_file(fsp,data,startpos,numtowrite);
        }
   
        if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
+               reply_unixerror(req, ERRHRD, ERRdiskfull);
                END_PROFILE(SMBwriteX);
-               return(UNIXERROR(ERRHRD,ERRdiskfull));
+               return;
        }
 
-       SSVAL(outbuf,smb_vwv2,nwritten);
+       reply_outbuf(req, 6, 0);
+       SSVAL(req->outbuf,smb_vwv2,nwritten);
        if (large_writeX)
-               SSVAL(outbuf,smb_vwv4,(nwritten>>16)&1);
+               SSVAL(req->outbuf,smb_vwv4,(nwritten>>16)&1);
 
        if (nwritten < (ssize_t)numtowrite) {
-               SCVAL(outbuf,smb_rcls,ERRHRD);
-               SSVAL(outbuf,smb_err,ERRdiskfull);      
+               SCVAL(req->outbuf,smb_rcls,ERRHRD);
+               SSVAL(req->outbuf,smb_err,ERRdiskfull);
        }
 
        DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
@@ -3347,14 +3557,16 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
 
        status = sync_file(conn, fsp, write_through);
        if (!NT_STATUS_IS_OK(status)) {
-               END_PROFILE(SMBwriteX);
                DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
                        fsp->fsp_name, nt_errstr(status) ));
-               return ERROR_NT(status);
+               reply_nterror(req, status);
+               END_PROFILE(SMBwriteX);
+               return;
        }
 
        END_PROFILE(SMBwriteX);
-       return chain_reply(inbuf,&outbuf,length,bufsize);
+       chain_reply_new(req);
+       return;
 }
 
 /****************************************************************************
@@ -3435,31 +3647,43 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int
  Reply to a flush.
 ****************************************************************************/
 
-int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
+void reply_flush(connection_struct *conn, struct smb_request *req)
 {
-       int outsize = set_message(inbuf,outbuf,0,0,False);
-       uint16 fnum = SVAL(inbuf,smb_vwv0);
-       files_struct *fsp = file_fsp(SVAL(inbuf,smb_vwv0));
+       uint16 fnum;
+       files_struct *fsp;
+
        START_PROFILE(SMBflush);
 
-       if (fnum != 0xFFFF)
-               CHECK_FSP(fsp,conn);
+       if (req->wct < 1) {
+               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               return;
+       }
+
+       fnum = SVAL(req->inbuf,smb_vwv0);
+       fsp = file_fsp(fnum);
+
+       if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp, &current_user)) {
+               return;
+       }
        
        if (!fsp) {
                file_sync_all(conn);
        } else {
                NTSTATUS status = sync_file(conn, fsp, True);
                if (!NT_STATUS_IS_OK(status)) {
-                       END_PROFILE(SMBflush);
                        DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
                                fsp->fsp_name, nt_errstr(status) ));
-                       return ERROR_NT(status);
+                       reply_nterror(req, status);
+                       END_PROFILE(SMBflush);
+                       return;
                }
        }
        
+       reply_outbuf(req, 0, 0);
+
        DEBUG(3,("flush\n"));
        END_PROFILE(SMBflush);
-       return(outsize);
+       return;
 }
 
 /****************************************************************************
@@ -3747,24 +3971,35 @@ void reply_tdis(connection_struct *conn, struct smb_request *req)
  conn POINTER CAN BE NULL HERE !
 ****************************************************************************/
 
-int reply_echo(connection_struct *conn,
-              char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+void reply_echo(connection_struct *conn, struct smb_request *req)
 {
-       int smb_reverb = SVAL(inbuf,smb_vwv0);
+       int smb_reverb;
        int seq_num;
-       unsigned int data_len = smb_buflen(inbuf);
-       int outsize = set_message(inbuf,outbuf,1,data_len,True);
+       unsigned int data_len = smb_buflen(req->inbuf);
+
        START_PROFILE(SMBecho);
 
+       if (req->wct < 1) {
+               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               END_PROFILE(SMBecho);
+               return;
+       }
+
        if (data_len > BUFFER_SIZE) {
                DEBUG(0,("reply_echo: data_len too large.\n"));
+               reply_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
                END_PROFILE(SMBecho);
-               return -1;
+               return;
        }
 
+       smb_reverb = SVAL(req->inbuf,smb_vwv0);
+
+       reply_outbuf(req, 1, data_len);
+
        /* copy any incoming data back out */
-       if (data_len > 0)
-               memcpy(smb_buf(outbuf),smb_buf(inbuf),data_len);
+       if (data_len > 0) {
+               memcpy(smb_buf(req->outbuf),smb_buf(req->inbuf),data_len);
+       }
 
        if (smb_reverb > 100) {
                DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
@@ -3772,21 +4007,21 @@ int reply_echo(connection_struct *conn,
        }
 
        for (seq_num =1 ; seq_num <= smb_reverb ; seq_num++) {
-               SSVAL(outbuf,smb_vwv0,seq_num);
-
-               smb_setlen(inbuf,outbuf,outsize - 4);
+               SSVAL(req->outbuf,smb_vwv0,seq_num);
 
-               show_msg(outbuf);
-               if (!send_smb(smbd_server_fd(),outbuf))
+               show_msg((char *)req->outbuf);
+               if (!send_smb(smbd_server_fd(),(char *)req->outbuf))
                        exit_server_cleanly("reply_echo: send_smb failed.");
        }
 
        DEBUG(3,("echo %d times\n", smb_reverb));
 
+       TALLOC_FREE(req->outbuf);
+
        smb_echo_count++;
 
        END_PROFILE(SMBecho);
-       return -1;
+       return;
 }
 
 /****************************************************************************
@@ -5535,35 +5770,52 @@ SMB_BIG_UINT get_lock_offset( char *data, int data_offset, BOOL large_file_forma
  Reply to a lockingX request.
 ****************************************************************************/
 
-int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
-                  int length, int bufsize)
+void reply_lockingX(connection_struct *conn, struct smb_request *req)
 {
-       files_struct *fsp = file_fsp(SVAL(inbuf,smb_vwv2));
-       unsigned char locktype = CVAL(inbuf,smb_vwv3);
-       unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1);
-       uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
-       uint16 num_locks = SVAL(inbuf,smb_vwv7);
+       files_struct *fsp;
+       unsigned char locktype;
+       unsigned char oplocklevel;
+       uint16 num_ulocks;
+       uint16 num_locks;
        SMB_BIG_UINT count = 0, offset = 0;
        uint32 lock_pid;
-       int32 lock_timeout = IVAL(inbuf,smb_vwv4);
+       int32 lock_timeout;
        int i;
        char *data;
-       BOOL large_file_format =
-               (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
+       BOOL large_file_format;
        BOOL err;
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
 
        START_PROFILE(SMBlockingX);
+
+       if (req->wct < 8) {
+               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               END_PROFILE(SMBlockingX);
+               return;
+       }
        
-       CHECK_FSP(fsp,conn);
+       fsp = file_fsp(SVAL(req->inbuf,smb_vwv2));
+       locktype = CVAL(req->inbuf,smb_vwv3);
+       oplocklevel = CVAL(req->inbuf,smb_vwv3+1);
+       num_ulocks = SVAL(req->inbuf,smb_vwv6);
+       num_locks = SVAL(req->inbuf,smb_vwv7);
+       lock_timeout = IVAL(req->inbuf,smb_vwv4);
+       large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
+
+       if (!check_fsp(conn, req, fsp, &current_user)) {
+               END_PROFILE(SMBlockingX);
+               return;
+       }
        
-       data = smb_buf(inbuf);
+       data = smb_buf(req->inbuf);
 
        if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
                /* we don't support these - and CANCEL_LOCK makes w2k
                   and XP reboot so I don't really want to be
                   compatible! (tridge) */
-               return ERROR_NT(NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks));
+               reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks));
+               END_PROFILE(SMBlockingX);
+               return;
        }
        
        /* Check if this is an oplock break on a file
@@ -5600,10 +5852,12 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
                         * send a reply */
                        if (num_locks == 0 && num_ulocks == 0) {
                                END_PROFILE(SMBlockingX);
-                               return -1;
+                               reply_post_legacy(req, -1);
+                               return;
                        } else {
                                END_PROFILE(SMBlockingX);
-                               return ERROR_DOS(ERRDOS,ERRlock);
+                               reply_doserror(req, ERRDOS, ERRlock);
+                               return;
                        }
                }
 
@@ -5628,12 +5882,13 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
                if (num_locks == 0 && num_ulocks == 0) {
                        /* Sanity check - ensure a pure oplock break is not a
                           chained request. */
-                       if(CVAL(inbuf,smb_vwv0) != 0xff)
+                       if(CVAL(req->inbuf,smb_vwv0) != 0xff)
                                DEBUG(0,("reply_lockingX: Error : pure oplock "
                                         "break is a chained %d request !\n",
-                                        (unsigned int)CVAL(inbuf,smb_vwv0) ));
+                                        (unsigned int)CVAL(req->inbuf,
+                                                           smb_vwv0) ));
                        END_PROFILE(SMBlockingX);
-                       return -1;
+                       return;
                }
        }
 
@@ -5643,6 +5898,13 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
         */
        
        release_level_2_oplocks_on_change(fsp);
+
+       if (smb_buflen(req->inbuf) <
+           (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
+               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               END_PROFILE(SMBlockingX);
+               return;
+       }
        
        /* Data now points at the beginning of the list
           of smb_unlkrng structs */
@@ -5656,7 +5918,8 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
                 */
                if(err) {
                        END_PROFILE(SMBlockingX);
-                       return ERROR_DOS(ERRDOS,ERRnoaccess);
+                       reply_doserror(req, ERRDOS, ERRnoaccess);
+                       return;
                }
 
                DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for "
@@ -5672,7 +5935,8 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
 
                if (NT_STATUS_V(status)) {
                        END_PROFILE(SMBlockingX);
-                       return ERROR_NT(status);
+                       reply_nterror(req, status);
+                       return;
                }
        }
 
@@ -5700,7 +5964,8 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
                 */
                if(err) {
                        END_PROFILE(SMBlockingX);
-                       return ERROR_DOS(ERRDOS,ERRnoaccess);
+                       reply_doserror(req, ERRDOS, ERRnoaccess);
+                       return;
                }
                
                DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid "
@@ -5723,7 +5988,12 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
                                                locktype,
                                                NT_STATUS_FILE_LOCK_CONFLICT)) {
                                        END_PROFILE(SMBlockingX);
-                                       return ERROR_NT(NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
+                                       reply_nterror(
+                                               req,
+                                               NT_STATUS_DOS(
+                                                       ERRDOS,
+                                                       ERRcancelviolation));
+                                       return;
                                }
                        }
                        /* Remove a matching pending lock. */
@@ -5776,7 +6046,8 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
                                 * onto the blocking lock queue.
                                 */
                                if(push_blocking_lock_request(br_lck,
-                                                       inbuf, length,
+                                                       (char *)req->inbuf,
+                                                       smb_len(req->inbuf)+4,
                                                        fsp,
                                                        lock_timeout,
                                                        i,
@@ -5788,7 +6059,8 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
                                                        block_smbpid)) {
                                        TALLOC_FREE(br_lck);
                                        END_PROFILE(SMBlockingX);
-                                       return -1;
+                                       reply_post_legacy(req, -1);
+                                       return;
                                }
                        }
 
@@ -5797,7 +6069,8 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
 
                if (NT_STATUS_V(status)) {
                        END_PROFILE(SMBlockingX);
-                       return ERROR_NT(status);
+                       reply_nterror(req, status);
+                       return;
                }
        }
        
@@ -5824,7 +6097,8 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
                         */
                        if(err) {
                                END_PROFILE(SMBlockingX);
-                               return ERROR_DOS(ERRDOS,ERRnoaccess);
+                               reply_doserror(req, ERRDOS, ERRnoaccess);
+                               return;
                        }
                        
                        do_unlock(smbd_messaging_context(),
@@ -5835,16 +6109,17 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
                                WINDOWS_LOCK);
                }
                END_PROFILE(SMBlockingX);
-               return ERROR_NT(status);
+               reply_nterror(req, status);
+               return;
        }
 
-       set_message(inbuf,outbuf,2,0,True);
+       reply_outbuf(req, 2, 0);
        
        DEBUG(3, ("lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
                  fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks));
        
        END_PROFILE(SMBlockingX);
-       return chain_reply(inbuf,&outbuf,length,bufsize);
+       chain_reply_new(req);
 }
 
 #undef DBGC_CLASS