The branch, master has been updated
       via  8f93068 s3: Add smb_request_done
       via  2c1caf5 s3: Remove unused smb_request->done
       via  3a7bc3a s3: Remove unused smb_request->chain_outbuf
       via  572bc64 s3: Remove "req_wct_ofs()"
       via  12068d4 s3: Fix the read&x offset within a chain
       via  11d087a s3: Remove chain_reply
       via  3b2c9be s3: Replace chain_reply
       via  c9870a6 s3: Add a new set of andx chain handling routines
       via  90b33a0 s3: Make sure the andX chains are ended correctly
      from  a28a740 s3: Fix a 64-bit warning

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 8f93068cf8fc3d282e0975cc5cbdcd2098b10d52
Author: Volker Lendecke <v...@samba.org>
Date:   Sun Mar 4 12:10:04 2012 +0100

    s3: Add smb_request_done
    
    This is used to enable async chained command sequences. A synchronous
    reply_xxx command does not need to take are anymore about and_x
    chaining. The async commands (pipe r/w at this moment) must do so
    however. When finished, they must inform the main chain engine that
    they are finished with a smb_request_done call.
    
    Autobuild-User: Volker Lendecke <v...@samba.org>
    Autobuild-Date: Sat Mar 10 17:14:05 CET 2012 on sn-devel-104

commit 2c1caf5fcb002f5a4e049fcb812c98c435d0f2c9
Author: Volker Lendecke <v...@samba.org>
Date:   Sat Mar 3 00:59:56 2012 +0100

    s3: Remove unused smb_request->done

commit 3a7bc3abb837b8c9df2c156440eb8a6f7e60c8d9
Author: Volker Lendecke <v...@samba.org>
Date:   Sat Mar 3 00:34:27 2012 +0100

    s3: Remove unused smb_request->chain_outbuf

commit 572bc64b594d0d30cb64976579a55e74f01800d2
Author: Volker Lendecke <v...@samba.org>
Date:   Sat Mar 3 00:33:15 2012 +0100

    s3: Remove "req_wct_ofs()"
    
    This is fixed up in construct_reply_chain

commit 12068d4aaca0579b58bbb121df4d1e947f8ea032
Author: Volker Lendecke <v...@samba.org>
Date:   Wed Feb 29 23:44:36 2012 +0100

    s3: Fix the read&x offset within a chain

commit 11d087aa04f436147e7a9dd1748a43bde24de8e3
Author: Volker Lendecke <v...@samba.org>
Date:   Tue Feb 28 01:21:44 2012 +0100

    s3: Remove chain_reply
    
    <insert your favourite tombstone ascii art here>

commit 3b2c9bebc0aa08fe9a65afe5870bea490c5fb33a
Author: Volker Lendecke <v...@samba.org>
Date:   Tue Feb 28 00:56:10 2012 +0100

    s3: Replace chain_reply
    
    This is a new implementation of our andx handling code. The old
    code was quite involved in that it was called from within the reply_
    handlers. This leads to pretty complex faking of smb_request
    structures to give them the same environment, independent of whether
    they are called directly or from within chain_reply.
    
    chain_reply needs to go because it blocks really async handling of
    chained requests.

commit c9870a62f5d8865e67ae519db3f8e890afb6ee70
Author: Volker Lendecke <v...@samba.org>
Date:   Tue Feb 28 00:19:48 2012 +0100

    s3: Add a new set of andx chain handling routines
    
    This is in preparation of getting rid of chain_reply.

commit 90b33a05e967e9e29c4584bed188ef6fa5a3fbf0
Author: Volker Lendecke <v...@samba.org>
Date:   Sun Feb 26 16:49:09 2012 +0100

    s3: Make sure the andX chains are ended correctly
    
    Normally chain_reply took care of this. This will go away soon.

-----------------------------------------------------------------------

Summary of changes:
 source3/Makefile.in             |    3 +-
 source3/include/smb.h           |   12 +-
 source3/smbd/blocking.c         |   11 +-
 source3/smbd/nttrans.c          |    9 +-
 source3/smbd/pipes.c            |   20 +-
 source3/smbd/process.c          |  638 ++++++++++++++++++++++++---------------
 source3/smbd/proto.h            |   15 +-
 source3/smbd/reply.c            |   23 +-
 source3/smbd/sesssetup.c        |    5 +-
 source3/torture/cmd_vfs.c       |    2 +
 source3/torture/vfstest.h       |    3 +
 source3/torture/vfstest_chain.c |  342 +++++++++++++++++++++
 source3/wscript_build           |    3 +-
 13 files changed, 804 insertions(+), 282 deletions(-)
 create mode 100644 source3/torture/vfstest_chain.c


Changeset truncated at 500 lines:

diff --git a/source3/Makefile.in b/source3/Makefile.in
index 2b0002b..dc02b6a 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -1299,7 +1299,8 @@ PDBTEST_OBJ = torture/pdbtest.o $(PARAM_OBJ) 
$(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \
                $(SMBLDAP_OBJ) $(POPT_LIB_OBJ) \
                $(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ)
 
-VFSTEST_OBJ = torture/cmd_vfs.o torture/vfstest.o $(SMBD_OBJ_BASE) 
$(READLINE_OBJ)
+VFSTEST_OBJ = torture/cmd_vfs.o torture/vfstest.o $(SMBD_OBJ_BASE) 
$(READLINE_OBJ) \
+               torture/vfstest_chain.o
 
 LOG2PCAP_OBJ = utils/log2pcaphex.o
 
diff --git a/source3/include/smb.h b/source3/include/smb.h
index d93f30d..382926c 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -481,17 +481,10 @@ struct smb_request {
        struct files_struct *chain_fsp;
 
        /*
-        * Here we collect the outbufs from the chain handlers
-        */
-       uint8_t *chain_outbuf;
-
-       /*
         * state information for async smb handling
         */
        void *async_priv;
 
-       bool done;
-
        /*
         * Back pointer to smb2 request.
         */
@@ -502,6 +495,11 @@ struct smb_request {
         * under privilege.
         */
        struct privilege_paths *priv_paths;
+
+       /*
+        * Request list for chained requests, we're part of it.
+        */
+       struct smb_request **chain;
 };
 
 /* Defines for the sent_oplock_break field above. */
diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c
index 6496e43..d512b96 100644
--- a/source3/smbd/blocking.c
+++ b/source3/smbd/blocking.c
@@ -271,6 +271,8 @@ static void reply_lockingX_success(struct 
blocking_lock_record *blr)
        struct smb_request *req = blr->req;
 
        reply_outbuf(req, 2, 0);
+       SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
+       SSVAL(req->outbuf, smb_vwv1, 0);    /* no andx offset */
 
        /*
         * As this message is a lockingX call we must handle
@@ -280,7 +282,14 @@ static void reply_lockingX_success(struct 
blocking_lock_record *blr)
         * that here and must set up the chain info manually.
         */
 
-       chain_reply(req);
+       if (!srv_send_smb(req->sconn,
+                       (char *)req->outbuf,
+                       true, req->seqnum+1,
+                       IS_CONN_ENCRYPTED(req->conn)||req->encrypted,
+                       &req->pcd)) {
+               exit_server_cleanly("construct_reply: srv_send_smb failed.");
+       }
+
        TALLOC_FREE(req->outbuf);
 }
 
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index cfa048b..fc52ee5 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -352,6 +352,9 @@ static void do_ntcreate_pipe_open(connection_struct *conn,
                reply_outbuf(req, 34, 0);
        }
 
+       SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
+       SSVAL(req->outbuf, smb_vwv1, 0);    /* no andx offset */
+
        p = (char *)req->outbuf + smb_vwv2;
        p++;
        SSVAL(p,0,pnum);
@@ -379,8 +382,6 @@ static void do_ntcreate_pipe_open(connection_struct *conn,
        }
 
        DEBUG(5,("do_ntcreate_pipe_open: open pipe = %s\n", fname));
-
-       chain_reply(req);
 }
 
 struct case_semantics_state {
@@ -634,6 +635,9 @@ void reply_ntcreate_and_X(struct smb_request *req)
                reply_outbuf(req, 34, 0);
        }
 
+       SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
+       SSVAL(req->outbuf, smb_vwv1, 0);    /* no andx offset */
+
        p = (char *)req->outbuf + smb_vwv2;
 
        SCVAL(p, 0, oplock_granted);
@@ -728,7 +732,6 @@ void reply_ntcreate_and_X(struct smb_request *req)
        DEBUG(5,("reply_ntcreate_and_X: fnum = %d, open name = %s\n",
                fsp->fnum, smb_fname_str_dbg(smb_fname)));
 
-       chain_reply(req);
  out:
        END_PROFILE(SMBntcreateX);
        return;
diff --git a/source3/smbd/pipes.c b/source3/smbd/pipes.c
index 9e5dfc3..c3a5cb3 100644
--- a/source3/smbd/pipes.c
+++ b/source3/smbd/pipes.c
@@ -146,6 +146,9 @@ void reply_open_pipe_and_X(connection_struct *conn, struct 
smb_request *req)
        /* Prepare the reply */
        reply_outbuf(req, 15, 0);
 
+       SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
+       SSVAL(req->outbuf, smb_vwv1, 0);    /* no andx offset */
+
        /* Mark the opened file as an existing named pipe in message mode. */
        SSVAL(req->outbuf,smb_vwv9,2);
        SSVAL(req->outbuf,smb_vwv10,0xc700);
@@ -156,9 +159,6 @@ void reply_open_pipe_and_X(connection_struct *conn, struct 
smb_request *req)
        SIVAL(req->outbuf, smb_vwv6, 0);        /* size */
        SSVAL(req->outbuf, smb_vwv8, 0);        /* rmode */
        SSVAL(req->outbuf, smb_vwv11, 0x0001);
-
-       chain_reply(req);
-       return;
 }
 
 /****************************************************************************
@@ -354,18 +354,20 @@ static void pipe_write_andx_done(struct tevent_req 
*subreq)
 
        reply_outbuf(req, 6, 0);
 
+       SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
+       SSVAL(req->outbuf, smb_vwv1, 0);    /* no andx offset */
+
        nwritten = (state->pipe_start_message_raw ? nwritten + 2 : nwritten);
        SSVAL(req->outbuf,smb_vwv2,nwritten);
 
        DEBUG(3,("writeX-IPC nwritten=%d\n", (int)nwritten));
 
  done:
-       chain_reply(req);
        /*
         * We must free here as the ownership of req was
         * moved to the connection struct in reply_pipe_write_and_X().
         */
-       TALLOC_FREE(req);
+       smb_request_done(req);
 }
 
 /****************************************************************************
@@ -417,6 +419,9 @@ void reply_pipe_read_and_X(struct smb_request *req)
        state->smb_mincnt = SVAL(req->vwv+6, 0);
 
        reply_outbuf(req, 12, state->smb_maxcnt);
+       SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
+       SSVAL(req->outbuf, smb_vwv1, 0);    /* no andx offset */
+
        data = (uint8_t *)smb_buf(req->outbuf);
 
        /*
@@ -474,7 +479,7 @@ static void pipe_read_andx_done(struct tevent_req *subreq)
 
        SSVAL(req->outbuf,smb_vwv5,nread);
        SSVAL(req->outbuf,smb_vwv6,
-             req_wct_ofs(req)
+             (smb_wct - 4)     /* offset from smb header to wct */
              + 1               /* the wct field */
              + 12 * sizeof(uint16_t) /* vwv */
              + 2);             /* the buflen field */
@@ -484,10 +489,9 @@ static void pipe_read_andx_done(struct tevent_req *subreq)
                 state->smb_mincnt, state->smb_maxcnt, (int)nread));
 
  done:
-       chain_reply(req);
        /*
         * We must free here as the ownership of req was
         * moved to the connection struct in reply_pipe_read_and_X().
         */
-       TALLOC_FREE(req);
+       smb_request_done(req);
 }
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index f87eccf..8b15ac8 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -60,6 +60,7 @@ static void construct_reply_common(struct smb_request *req, 
const char *inbuf,
                                   char *outbuf);
 static struct pending_message_list *get_deferred_open_message_smb(
        struct smbd_server_connection *sconn, uint64_t mid);
+static bool smb_splice_chain(uint8_t **poutbuf, const uint8_t *andx_buf);
 
 static bool smbd_lock_socket_internal(struct smbd_server_connection *sconn)
 {
@@ -537,10 +538,9 @@ static bool init_smb_request(struct smb_request *req,
        req->sconn = sconn;
        req->conn = conn_find(sconn,req->tid);
        req->chain_fsp = NULL;
-       req->chain_outbuf = NULL;
-       req->done = false;
        req->smb2req = NULL;
        req->priv_paths = NULL;
+       req->chain = NULL;
        smb_init_perfcount_data(&req->pcd);
 
        /* Ensure we have at least wct words and 2 bytes of bcc. */
@@ -1537,11 +1537,6 @@ static void construct_reply(struct 
smbd_server_connection *sconn,
 
        conn = switch_message(req->cmd, req);
 
-       if (req->done) {
-               TALLOC_FREE(req);
-               return;
-       }
-
        if (req->outbuf == NULL) {
                return;
        }
@@ -1563,6 +1558,162 @@ static void construct_reply(struct 
smbd_server_connection *sconn,
        return;
 }
 
+static void construct_reply_chain(struct smbd_server_connection *sconn,
+                                 char *inbuf, int size, uint32_t seqnum,
+                                 bool encrypted,
+                                 struct smb_perfcount_data *deferred_pcd)
+{
+       struct smb_request **reqs = NULL;
+       struct smb_request *req;
+       unsigned num_reqs;
+       bool ok;
+
+       ok = smb1_parse_chain(talloc_tos(), (uint8_t *)inbuf, sconn, encrypted,
+                             seqnum, &reqs, &num_reqs);
+       if (!ok) {
+               char errbuf[smb_size];
+               error_packet(errbuf, 0, 0, NT_STATUS_INVALID_PARAMETER,
+                            __LINE__, __FILE__);
+               if (!srv_send_smb(sconn, errbuf, true, seqnum, encrypted,
+                                 NULL)) {
+                       exit_server_cleanly("construct_reply_chain: "
+                                           "srv_send_smb failed.");
+               }
+               return;
+       }
+
+       req = reqs[0];
+       req->inbuf = (uint8_t *)talloc_move(reqs, &inbuf);
+
+       req->conn = switch_message(req->cmd, req);
+
+       if (req->outbuf == NULL) {
+               /*
+                * Request has suspended itself, will come
+                * back here.
+                */
+               return;
+       }
+       smb_request_done(req);
+}
+
+/*
+ * To be called from an async SMB handler that is potentially chained
+ * when it is finished for shipping.
+ */
+
+void smb_request_done(struct smb_request *req)
+{
+       struct smb_request **reqs = NULL;
+       struct smb_request *first_req;
+       size_t i, num_reqs, next_index;
+       NTSTATUS status;
+
+       if (req->chain == NULL) {
+               first_req = req;
+               goto shipit;
+       }
+
+       reqs = req->chain;
+       num_reqs = talloc_array_length(reqs);
+
+       for (i=0; i<num_reqs; i++) {
+               if (reqs[i] == req) {
+                       break;
+               }
+       }
+       if (i == num_reqs) {
+               /*
+                * Invalid chain, should not happen
+                */
+               status = NT_STATUS_INTERNAL_ERROR;
+               goto error;
+       }
+       next_index = i+1;
+
+       while ((next_index < num_reqs) && (IVAL(req->outbuf, smb_rcls) == 0)) {
+               struct smb_request *next = reqs[next_index];
+
+               next->vuid = SVAL(req->outbuf, smb_uid);
+               next->tid  = SVAL(req->outbuf, smb_tid);
+               next->conn = conn_find(req->sconn, req->tid);
+               next->chain_fsp = req->chain_fsp;
+               next->inbuf = (uint8_t *)req->inbuf;
+
+               req = next;
+               req->conn = switch_message(req->cmd, req);
+
+               if (req->outbuf == NULL) {
+                       /*
+                        * Request has suspended itself, will come
+                        * back here.
+                        */
+                       return;
+               }
+               next_index += 1;
+       }
+
+       first_req = reqs[0];
+
+       for (i=1; i<next_index; i++) {
+               bool ok;
+
+               ok = smb_splice_chain(&first_req->outbuf, reqs[i]->outbuf);
+               if (!ok) {
+                       status = NT_STATUS_INTERNAL_ERROR;
+                       goto error;
+               }
+       }
+
+       SSVAL(first_req->outbuf, smb_uid, SVAL(req->outbuf, smb_uid));
+       SSVAL(first_req->outbuf, smb_tid, SVAL(req->outbuf, smb_tid));
+
+       /*
+        * This scary statement intends to set the
+        * FLAGS2_32_BIT_ERROR_CODES flg2 field in first_req->outbuf
+        * to the value last_req->outbuf carries
+        */
+       SSVAL(first_req->outbuf, smb_flg2,
+             (SVAL(first_req->outbuf, smb_flg2) & ~FLAGS2_32_BIT_ERROR_CODES)
+             |(SVAL(req->outbuf, smb_flg2) & FLAGS2_32_BIT_ERROR_CODES));
+
+       /*
+        * Transfer the error codes from the subrequest to the main one
+        */
+       SSVAL(first_req->outbuf, smb_rcls, SVAL(req->outbuf, smb_rcls));
+       SSVAL(first_req->outbuf, smb_err,  SVAL(req->outbuf, smb_err));
+
+       _smb_setlen_large(
+               first_req->outbuf, talloc_get_size(first_req->outbuf) - 4);
+
+shipit:
+       if (!srv_send_smb(first_req->sconn,
+                         (char *)first_req->outbuf,
+                         true, first_req->seqnum+1,
+                         IS_CONN_ENCRYPTED(req->conn)||first_req->encrypted,
+                         &first_req->pcd)) {
+               exit_server_cleanly("construct_reply_chain: srv_send_smb "
+                                   "failed.");
+       }
+       TALLOC_FREE(req);       /* non-chained case */
+       TALLOC_FREE(reqs);      /* chained case */
+       return;
+
+error:
+       {
+               char errbuf[smb_size];
+               error_packet(errbuf, 0, 0, status, __LINE__, __FILE__);
+               if (!srv_send_smb(req->sconn, errbuf, true,
+                                 req->seqnum+1, req->encrypted,
+                                 NULL)) {
+                       exit_server_cleanly("construct_reply_chain: "
+                                           "srv_send_smb failed.");
+               }
+       }
+       TALLOC_FREE(req);       /* non-chained case */
+       TALLOC_FREE(reqs);      /* chained case */
+}
+
 /****************************************************************************
  Process an smb from the client
 ****************************************************************************/
@@ -1623,8 +1774,14 @@ static void process_smb(struct smbd_server_connection 
*sconn,
 
        show_msg((char *)inbuf);
 
-       construct_reply(sconn, (char *)inbuf, nread, unread_bytes, seqnum,
-                       encrypted, deferred_pcd);
+       if ((unread_bytes == 0) && smb1_is_chain(inbuf)) {
+               construct_reply_chain(sconn, (char *)inbuf, nread,
+                                     seqnum, encrypted, deferred_pcd);
+       } else {
+               construct_reply(sconn, (char *)inbuf, nread, unread_bytes,
+                               seqnum, encrypted, deferred_pcd);
+       }
+
        sconn->trans_num++;
 
 done:
@@ -1702,40 +1859,6 @@ void construct_reply_common_req(struct smb_request *req, 
char *outbuf)
        construct_reply_common(req, (const char *)req->inbuf, outbuf);
 }
 
-/*
- * How many bytes have we already accumulated up to the current wct field
- * offset?
- */
-
-size_t req_wct_ofs(struct smb_request *req)
-{
-       size_t buf_size;
-
-       if (req->chain_outbuf == NULL) {
-               return smb_wct - 4;
-       }
-       buf_size = talloc_get_size(req->chain_outbuf);
-       if ((buf_size % 4) != 0) {
-               buf_size += (4 - (buf_size % 4));
-       }
-       return buf_size - 4;
-}
-
-/*
- * Hack around reply_nterror & friends not being aware of chained requests,
- * generating illegal (i.e. wct==0) chain replies.
- */
-
-static void fixup_chain_error_packet(struct smb_request *req)
-{
-       uint8_t *outbuf = req->outbuf;
-       req->outbuf = NULL;
-       reply_outbuf(req, 2, 0);
-       memcpy(req->outbuf, outbuf, smb_wct);
-       TALLOC_FREE(outbuf);
-       SCVAL(req->outbuf, smb_vwv0, 0xff);
-}
-
 /**
  * @brief Find the smb_cmd offset of the last command pushed
  * @param[in] buf      The buffer we're building up
@@ -1862,6 +1985,38 @@ static bool smb_splice_chain(uint8_t **poutbuf, const 
uint8_t *andx_buf)
         */
 
        memcpy(outbuf + ofs, vwv, sizeof(uint16_t) * wct);
+
+       /*
+        * HACK ALERT
+        *
+        * Read&X has an offset into its data buffer at
+        * vwv[6]. reply_read_andx has no idea anymore that it's
+        * running from within a chain, so we have to fix up the
+        * offset here.
+        *
+        * Although it looks disgusting at this place, I want to keep
+        * it here. The alternative would be to push knowledge about
+        * the andx chain down into read&x again.
+        */
+
+       if (smb_command == SMBreadX) {
+               uint8_t *bytes_addr;
+
+               if (wct < 7) {
+                       /*
+                        * Invalid read&x response
+                        */
+                       return false;
+               }
+
+               bytes_addr = outbuf + ofs        /* vwv start */
+                       + sizeof(uint16_t) * wct /* vwv array */
+                       + sizeof(uint16_t);      /* bcc */
+
+               SSVAL(outbuf + ofs, 6 * sizeof(uint16_t),
+                     bytes_addr - outbuf - 4);
+       }
+
        ofs += sizeof(uint16_t) * wct;
 
        /*
@@ -1880,257 +2035,244 @@ static bool smb_splice_chain(uint8_t **poutbuf, const 
uint8_t *andx_buf)
        return true;
 }
 
-/****************************************************************************
- Construct a chained reply and add it to the already made reply
-****************************************************************************/
-


-- 
Samba Shared Repository

Reply via email to