r24445: Convert SMBwritebraw. No test suite unfortunately.... I need to write one...
authorJeremy Allison <jra@samba.org>
Wed, 15 Aug 2007 01:54:37 +0000 (01:54 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:29:48 +0000 (12:29 -0500)
Jeremy

source/smbd/process.c
source/smbd/reply.c

index 6405ddf1f51d616fd92342daab970f93b5e37a78..b4de0edc289834233e6f82c1f3ac0cc2fc879e7e 100644 (file)
@@ -719,7 +719,7 @@ static const struct smb_message_struct {
 /* 0x1a */ { "SMBreadbraw",NULL,reply_readbraw,AS_USER},
 /* 0x1b */ { "SMBreadBmpx",reply_readbmpx,NULL,AS_USER},
 /* 0x1c */ { "SMBreadBs",NULL, NULL,0 },
-/* 0x1d */ { "SMBwritebraw",reply_writebraw,NULL,AS_USER},
+/* 0x1d */ { "SMBwritebraw",NULL,reply_writebraw,AS_USER},
 /* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,NULL,AS_USER},
 /* 0x1f */ { "SMBwriteBs",reply_writebs,NULL,AS_USER},
 /* 0x20 */ { "SMBwritec",NULL, NULL,0},
index 7ab503906d67e9a190184e9f0813540988075ad2..1a14d6c594d911ba3d123d70e7ff0a1387b1567a 100644 (file)
@@ -3258,12 +3258,28 @@ void reply_read_and_X(connection_struct *conn, struct smb_request *req)
        return;
 }
 
+/****************************************************************************
+ Error replies to writebraw must have smb_wct == 1. Fix this up.
+****************************************************************************/
+
+void error_to_writebrawerr(struct smb_request *req)
+{
+       uint8 *old_outbuf = req->outbuf;
+
+       reply_outbuf(req, 1, 0);
+
+       memcpy(req->outbuf, old_outbuf, smb_size);
+       TALLOC_FREE(old_outbuf);
+}
+
 /****************************************************************************
  Reply to a writebraw (core+ or LANMAN1.0 protocol).
 ****************************************************************************/
 
-int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
+void reply_writebraw(connection_struct *conn, struct smb_request *req)
 {
+       int outsize = 0;
+       char *buf = NULL;
        ssize_t nwritten=0;
        ssize_t total_written=0;
        size_t numtowrite=0;
@@ -3271,140 +3287,212 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
        SMB_OFF_T startpos;
        char *data=NULL;
        BOOL write_through;
-       files_struct *fsp = file_fsp(SVAL(inbuf,smb_vwv0));
-       int outsize = 0;
+       files_struct *fsp;
        NTSTATUS status;
+
        START_PROFILE(SMBwritebraw);
 
+       /*
+        * If we ever reply with an error, it must have the SMB command
+        * type of SMBwritec, not SMBwriteBraw, as this tells the client
+        * we're finished.
+        */
+       SCVAL(req->inbuf,smb_com,SMBwritec);
+
        if (srv_is_signing_active()) {
-               exit_server_cleanly("reply_writebraw: SMB signing is active - raw reads/writes are disallowed.");
+               END_PROFILE(SMBwritebraw);
+               exit_server_cleanly("reply_writebraw: SMB signing is active - "
+                               "raw reads/writes are disallowed.");
+       }
+
+       if (req->wct < 12) {
+               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               error_to_writebrawerr(req);
+               END_PROFILE(SMBwritebraw);
+               return;
+       }
+
+       fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
+       if (!check_fsp(conn, req, fsp, &current_user)) {
+               error_to_writebrawerr(req);
+               END_PROFILE(SMBwritebraw);
+               return;
        }
 
-       CHECK_FSP(fsp,conn);
        if (!CHECK_WRITE(fsp)) {
-               return(ERROR_DOS(ERRDOS,ERRbadaccess));
+               reply_doserror(req, ERRDOS, ERRbadaccess);
+               error_to_writebrawerr(req);
+               END_PROFILE(SMBwritebraw);
+               return;
        }
-  
-       tcount = IVAL(inbuf,smb_vwv1);
-       startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
-       write_through = BITSETW(inbuf+smb_vwv7,0);
+
+       tcount = IVAL(req->inbuf,smb_vwv1);
+       startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv3);
+       write_through = BITSETW(req->inbuf+smb_vwv7,0);
 
        /* We have to deal with slightly different formats depending
                on whether we are using the core+ or lanman1.0 protocol */
 
        if(Protocol <= PROTOCOL_COREPLUS) {
-               numtowrite = SVAL(smb_buf(inbuf),-2);
-               data = smb_buf(inbuf);
+               numtowrite = SVAL(smb_buf(req->inbuf),-2);
+               data = smb_buf(req->inbuf);
        } else {
-               numtowrite = SVAL(inbuf,smb_vwv10);
-               data = smb_base(inbuf) + SVAL(inbuf, smb_vwv11);
+               numtowrite = SVAL(req->inbuf,smb_vwv10);
+               data = smb_base(req->inbuf) + SVAL(req->inbuf, smb_vwv11);
        }
 
-       /* force the error type */
-       SCVAL(inbuf,smb_com,SMBwritec);
-       SCVAL(outbuf,smb_com,SMBwritec);
+       /* Ensure we don't write bytes past the end of this packet. */
+       if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
+               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               error_to_writebrawerr(req);
+               END_PROFILE(SMBwritebraw);
+               return;
+       }
 
-       if (is_locked(fsp,(uint32)SVAL(inbuf,smb_pid),(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
+       if (is_locked(fsp,(uint32)req->smbpid,(SMB_BIG_UINT)tcount,
+                               (SMB_BIG_UINT)startpos, WRITE_LOCK)) {
+               reply_doserror(req, ERRDOS, ERRlock);
+               error_to_writebrawerr(req);
                END_PROFILE(SMBwritebraw);
-               return(ERROR_DOS(ERRDOS,ERRlock));
+               return;
        }
 
-       if (numtowrite>0)
+       if (numtowrite>0) {
                nwritten = write_file(fsp,data,startpos,numtowrite);
-  
-       DEBUG(3,("writebraw1 fnum=%d start=%.0f num=%d wrote=%d sync=%d\n",
-               fsp->fnum, (double)startpos, (int)numtowrite, (int)nwritten, (int)write_through));
+       }
+
+       DEBUG(3,("reply_writebraw: initial write fnum=%d start=%.0f num=%d "
+                       "wrote=%d sync=%d\n",
+               fsp->fnum, (double)startpos, (int)numtowrite,
+               (int)nwritten, (int)write_through));
 
        if (nwritten < (ssize_t)numtowrite)  {
+               reply_unixerror(req, ERRHRD, ERRdiskfull);
+               error_to_writebrawerr(req);
                END_PROFILE(SMBwritebraw);
-               return(UNIXERROR(ERRHRD,ERRdiskfull));
+               return;
        }
 
        total_written = nwritten;
 
-       /* Return a message to the redirector to tell it to send more bytes */
-       SCVAL(outbuf,smb_com,SMBwritebraw);
-       SSVALS(outbuf,smb_vwv0,-1);
-       outsize = set_message(inbuf,outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
-       show_msg(outbuf);
-       if (!send_smb(smbd_server_fd(),outbuf))
-               exit_server_cleanly("reply_writebraw: send_smb failed.");
-  
+       /* Allocate a buffer of 64k + length. */
+       buf = TALLOC_ARRAY(NULL, char, 65540);
+       if (!buf) {
+               reply_doserror(req, ERRDOS, ERRnomem);
+               error_to_writebrawerr(req);
+               END_PROFILE(SMBwritebraw);
+               return;
+       }
+
+       /* Return a SMBwritebraw message to the redirector to tell
+        * it to send more bytes */
+
+       memcpy(buf, req->inbuf, smb_size);
+       outsize = set_message(NULL,buf,
+                       Protocol>PROTOCOL_COREPLUS?1:0,0,True);
+       SCVAL(buf,smb_com,SMBwritebraw);
+       SSVALS(buf,smb_vwv0,0xFFFF);
+       show_msg(buf);
+       if (!send_smb(smbd_server_fd(),buf)) {
+               exit_server_cleanly("reply_writebraw: send_smb "
+                       "failed.");
+       }
+
        /* Now read the raw data into the buffer and write it */
-       if (read_smb_length(smbd_server_fd(),inbuf,SMB_SECONDARY_WAIT) == -1) {
+       if (read_smb_length(smbd_server_fd(),buf,SMB_SECONDARY_WAIT) == -1) {
                exit_server_cleanly("secondary writebraw failed");
        }
-  
-       /* Even though this is not an smb message, smb_len returns the generic length of an smb message */
-       numtowrite = smb_len(inbuf);
 
-       /* Set up outbuf to return the correct return */
-       outsize = set_message(inbuf,outbuf,1,0,True);
-       SCVAL(outbuf,smb_com,SMBwritec);
+       /*
+        * Even though this is not an smb message,
+        * smb_len returns the generic length of a packet.
+        */
+
+       numtowrite = smb_len(buf);
+
+       /* Set up outbuf to return the correct size */
+       reply_outbuf(req, 1, 0);
 
        if (numtowrite != 0) {
 
-               if (numtowrite > BUFFER_SIZE) {
-                       DEBUG(0,("reply_writebraw: Oversize secondary write raw requested (%u). Terminating\n",
+               if (numtowrite > 0xFFFF) {
+                       DEBUG(0,("reply_writebraw: Oversize secondary write "
+                               "raw requested (%u). Terminating\n",
                                (unsigned int)numtowrite ));
                        exit_server_cleanly("secondary writebraw failed");
                }
 
                if (tcount > nwritten+numtowrite) {
-                       DEBUG(3,("Client overestimated the write %d %d %d\n",
+                       DEBUG(3,("reply_writebraw: Client overestimated the "
+                               "write %d %d %d\n",
                                (int)tcount,(int)nwritten,(int)numtowrite));
                }
 
-               if (read_data( smbd_server_fd(), inbuf+4, numtowrite) != numtowrite ) {
-                       DEBUG(0,("reply_writebraw: Oversize secondary write raw read failed (%s). Terminating\n",
+               if (read_data(smbd_server_fd(), buf+4, numtowrite)
+                                       != numtowrite ) {
+                       DEBUG(0,("reply_writebraw: Oversize secondary write "
+                               "raw read failed (%s). Terminating\n",
                                strerror(errno) ));
                        exit_server_cleanly("secondary writebraw failed");
                }
 
-               nwritten = write_file(fsp,inbuf+4,startpos+nwritten,numtowrite);
+               nwritten = write_file(fsp,buf+4,startpos+nwritten,numtowrite);
                if (nwritten == -1) {
+                       TALLOC_FREE(buf);
+                       reply_unixerror(req, ERRHRD, ERRdiskfull);
+                       error_to_writebrawerr(req);
                        END_PROFILE(SMBwritebraw);
-                       return(UNIXERROR(ERRHRD,ERRdiskfull));
+                       return;
                }
 
                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);
                }
 
-               if (nwritten > 0)
+               if (nwritten > 0) {
                        total_written += nwritten;
+               }
        }
-       SSVAL(outbuf,smb_vwv0,total_written);
+
+       TALLOC_FREE(buf);
+       SSVAL(req->outbuf,smb_vwv0,total_written);
 
        status = sync_file(conn, fsp, write_through);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
                        fsp->fsp_name, nt_errstr(status) ));
+               reply_nterror(req, status);
+               error_to_writebrawerr(req);
                END_PROFILE(SMBwritebraw);
-               return ERROR_NT(status);
+               return;
        }
 
-       DEBUG(3,("writebraw2 fnum=%d start=%.0f num=%d wrote=%d\n",
-               fsp->fnum, (double)startpos, (int)numtowrite,(int)total_written));
+       DEBUG(3,("reply_writebraw: secondart write fnum=%d start=%.0f num=%d "
+               "wrote=%d\n",
+               fsp->fnum, (double)startpos, (int)numtowrite,
+               (int)total_written));
 
-       /* we won't return a status if write through is not selected - this follows what WfWg does */
+       /* We won't return a status if write through is not selected - this
+        * follows what WfWg does */
        END_PROFILE(SMBwritebraw);
+
        if (!write_through && total_written==tcount) {
 
 #if RABBIT_PELLET_FIX
                /*
                 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
-                * sending a SMBkeepalive. Thanks to DaveCB at Sun for this. JRA.
+                * sending a SMBkeepalive. Thanks to DaveCB at Sun for this.
+                * JRA.
                 */
-               if (!send_keepalive(smbd_server_fd()))
-                       exit_server_cleanly("reply_writebraw: send of keepalive failed");
+               if (!send_keepalive(smbd_server_fd())) {
+                       exit_server_cleanly("reply_writebraw: send of "
+                               "keepalive failed");
+               }
 #endif
-               return(-1);
+               TALLOC_FREE(req->outbuf);
        }
-
-       return(outsize);
+       return;
 }
 
 #undef DBGC_CLASS
@@ -3540,6 +3628,7 @@ void reply_write(connection_struct *conn, struct smb_request *req)
        fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
 
        if (!check_fsp(conn, req, fsp, &current_user)) {
+               END_PROFILE(SMBwrite);
                return;
        }