r4364: - added support for testing of chained SMB operations in smbtorture
authorAndrew Tridgell <tridge@samba.org>
Sun, 26 Dec 2004 08:13:01 +0000 (08:13 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:07:38 +0000 (13:07 -0500)
- added test for chained OpenX/ReadX, simulating the OS/2 workplace shell

- fixed a bug in handling chained fnum in openx and ntcreatex in the server

(yes, I'm on holiday, but this bug was annoying me ....)
(This used to be commit b3b8958a18e302b815d98c0e3879e404bced6a08)

source4/include/smb_interfaces.h
source4/libcli/raw/rawfile.c
source4/libcli/raw/rawreadwrite.c
source4/libcli/raw/rawrequest.c
source4/smb_server/reply.c
source4/torture/raw/open.c

index 91ed102d6aeaeb016d450e2bc42338fb601fd3fb..1eca1fe360150c22e4f5068e9a027f4bbac7cab3 100644 (file)
@@ -1092,7 +1092,8 @@ enum smb_open_level {
                 RAW_OPEN_MKNEW, RAW_OPEN_CREATE, 
                 RAW_OPEN_CTEMP, RAW_OPEN_SPLOPEN,
                 RAW_OPEN_NTCREATEX, RAW_OPEN_T2OPEN,
-                RAW_OPEN_NTTRANS_CREATE};
+                RAW_OPEN_NTTRANS_CREATE, 
+                RAW_OPEN_OPENX_READX};
 
 /* the generic interface is defined to be equal to the NTCREATEX interface */
 #define RAW_OPEN_GENERIC RAW_OPEN_NTCREATEX
@@ -1266,6 +1267,51 @@ union smb_open {
                        uint16_t fnum;
                } out;
        } splopen;
+
+
+       /* chained OpenX/ReadX interface */
+       struct {
+               enum smb_open_level level;
+
+               struct {
+                       uint16_t flags;
+                       uint16_t open_mode;
+                       uint16_t search_attrs; /* not honoured by win2003 */
+                       uint16_t file_attrs;
+                       time_t write_time; /* not honoured by win2003 */
+                       uint16_t open_func;
+                       uint32_t size; /* note that this sets the
+                                       initial file size, not
+                                       just allocation size */
+                       uint32_t timeout; /* not honoured by win2003 */
+                       const char *fname;
+
+                       /* readx part */
+                       uint64_t offset;
+                       uint16_t mincnt;
+                       uint32_t maxcnt;
+                       uint16_t remaining;
+               } in;
+               struct {
+                       uint16_t fnum;
+                       uint16_t attrib;
+                       time_t write_time;
+                       uint32_t size;
+                       uint16_t access;
+                       uint16_t ftype;
+                       uint16_t devstate;
+                       uint16_t action;
+                       uint32_t unique_fid;
+                       uint32_t access_mask;
+                       uint32_t unknown;
+                       
+                       /* readx part */
+                       uint8_t *data;
+                       uint16_t remaining;
+                       uint16_t compaction_mode;
+                       uint16_t nread;
+               } out;
+       } openxreadx;
 };
 
 
index 4a11fd383459b58903366b8377632fbcfefcc3f5..11be8ffba78d5c32a14eed3064fbde9c774b6469 100644 (file)
@@ -29,7 +29,6 @@
        if (!req) return NULL; \
 } while (0)
 
-
 /****************************************************************************
  Rename a file - async interface
 ****************************************************************************/
@@ -426,6 +425,7 @@ struct smbcli_request *smb_raw_open_send(struct smbcli_tree *tree, union smb_ope
 {
        int len;
        struct smbcli_request *req = NULL; 
+       BOOL bigoffset = False;
 
        switch (parms->generic.level) {
        case RAW_OPEN_T2OPEN:
@@ -507,6 +507,42 @@ struct smbcli_request *smb_raw_open_send(struct smbcli_tree *tree, union smb_ope
 
        case RAW_OPEN_NTTRANS_CREATE:
                return smb_raw_nttrans_create_send(tree, parms);
+
+
+       case RAW_OPEN_OPENX_READX:
+               SETUP_REQUEST(SMBopenX, 15, 0);
+               SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
+               SSVAL(req->out.vwv, VWV(1), 0);
+               SSVAL(req->out.vwv, VWV(2), parms->openxreadx.in.flags);
+               SSVAL(req->out.vwv, VWV(3), parms->openxreadx.in.open_mode);
+               SSVAL(req->out.vwv, VWV(4), parms->openxreadx.in.search_attrs);
+               SSVAL(req->out.vwv, VWV(5), parms->openxreadx.in.file_attrs);
+               raw_push_dos_date3(tree->session->transport, 
+                                 req->out.vwv, VWV(6), parms->openxreadx.in.write_time);
+               SSVAL(req->out.vwv, VWV(8), parms->openxreadx.in.open_func);
+               SIVAL(req->out.vwv, VWV(9), parms->openxreadx.in.size);
+               SIVAL(req->out.vwv, VWV(11),parms->openxreadx.in.timeout);
+               SIVAL(req->out.vwv, VWV(13),0);
+               smbcli_req_append_string(req, parms->openxreadx.in.fname, STR_TERMINATE);
+
+               if (tree->session->transport->negotiate.capabilities & CAP_LARGE_FILES) {
+                       bigoffset = True;
+               }
+
+               smbcli_chained_request_setup(req, SMBreadX, bigoffset ? 12 : 10, 0);
+
+               SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
+               SSVAL(req->out.vwv, VWV(1), 0);
+               SSVAL(req->out.vwv, VWV(2), 0);
+               SIVAL(req->out.vwv, VWV(3), parms->openxreadx.in.offset);
+               SSVAL(req->out.vwv, VWV(5), parms->openxreadx.in.maxcnt & 0xFFFF);
+               SSVAL(req->out.vwv, VWV(6), parms->openxreadx.in.mincnt);
+               SIVAL(req->out.vwv, VWV(7), parms->openxreadx.in.maxcnt >> 16);
+               SSVAL(req->out.vwv, VWV(9), parms->openxreadx.in.remaining);
+               if (bigoffset) {
+                       SIVAL(req->out.vwv, VWV(10),parms->openxreadx.in.offset>>32);
+               }
+               break;
        }
 
        if (!smbcli_request_send(req)) {
@@ -522,6 +558,8 @@ struct smbcli_request *smb_raw_open_send(struct smbcli_tree *tree, union smb_ope
 ****************************************************************************/
 NTSTATUS smb_raw_open_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx, union smb_open *parms)
 {
+       NTSTATUS status;
+
        if (!smbcli_request_receive(req) ||
            smbcli_request_is_error(req)) {
                goto failed;
@@ -602,6 +640,44 @@ NTSTATUS smb_raw_open_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx, unio
 
        case RAW_OPEN_NTTRANS_CREATE:
                return smb_raw_nttrans_create_recv(req, mem_ctx, parms);
+
+       case RAW_OPEN_OPENX_READX:
+               SMBCLI_CHECK_MIN_WCT(req, 15);
+               parms->openxreadx.out.fnum = SVAL(req->in.vwv, VWV(2));
+               parms->openxreadx.out.attrib = SVAL(req->in.vwv, VWV(3));
+               parms->openxreadx.out.write_time = raw_pull_dos_date3(req->transport,
+                                                                req->in.vwv + VWV(4));
+               parms->openxreadx.out.size = IVAL(req->in.vwv, VWV(6));
+               parms->openxreadx.out.access = SVAL(req->in.vwv, VWV(8));
+               parms->openxreadx.out.ftype = SVAL(req->in.vwv, VWV(9));
+               parms->openxreadx.out.devstate = SVAL(req->in.vwv, VWV(10));
+               parms->openxreadx.out.action = SVAL(req->in.vwv, VWV(11));
+               parms->openxreadx.out.unique_fid = IVAL(req->in.vwv, VWV(12));
+               if (req->in.wct >= 19) {
+                       parms->openxreadx.out.access_mask = IVAL(req->in.vwv, VWV(15));
+                       parms->openxreadx.out.unknown =     IVAL(req->in.vwv, VWV(17));
+               } else {
+                       parms->openxreadx.out.access_mask = 0;
+                       parms->openxreadx.out.unknown = 0;
+               }
+
+               status = smbcli_chained_advance(req);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+
+               SMBCLI_CHECK_WCT(req, 12);
+               parms->openxreadx.out.remaining       = SVAL(req->in.vwv, VWV(2));
+               parms->openxreadx.out.compaction_mode = SVAL(req->in.vwv, VWV(3));
+               parms->openxreadx.out.nread = SVAL(req->in.vwv, VWV(5));
+               if (parms->openxreadx.out.nread > 
+                   MAX(parms->openxreadx.in.mincnt, parms->openxreadx.in.maxcnt) ||
+                   !smbcli_raw_pull_data(req, req->in.hdr + SVAL(req->in.vwv, VWV(6)), 
+                                         parms->openxreadx.out.nread, 
+                                         parms->openxreadx.out.data)) {
+                       req->status = NT_STATUS_BUFFER_TOO_SMALL;
+               }
+               break;
        }
 
 failed:
index 8381c7b2b0121ab6a9572dcbe7298d01e1f9c349..d9fe3fdce0d598e0d19b80a3a396930222e7e79c 100644 (file)
@@ -27,7 +27,6 @@
        if (!req) return NULL; \
 } while (0)
 
-
 /****************************************************************************
  low level read operation (async send)
 ****************************************************************************/
@@ -74,7 +73,7 @@ struct smbcli_request *smb_raw_read_send(struct smbcli_tree *tree, union smb_rea
                        bigoffset = True;
                }
                SETUP_REQUEST(SMBreadX, bigoffset ? 12 : 10, 0);
-               SSVAL(req->out.vwv, VWV(0), 0xFF);
+               SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
                SSVAL(req->out.vwv, VWV(1), 0);
                SSVAL(req->out.vwv, VWV(2), parms->readx.in.fnum);
                SIVAL(req->out.vwv, VWV(3), parms->readx.in.offset);
@@ -228,7 +227,7 @@ struct smbcli_request *smb_raw_write_send(struct smbcli_tree *tree, union smb_wr
                        bigoffset = True;
                }
                SETUP_REQUEST(SMBwriteX, bigoffset ? 14 : 12, parms->writex.in.count);
-               SSVAL(req->out.vwv, VWV(0), 0xFF);
+               SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
                SSVAL(req->out.vwv, VWV(1), 0);
                SSVAL(req->out.vwv, VWV(2), parms->writex.in.fnum);
                SIVAL(req->out.vwv, VWV(3), parms->writex.in.offset);
index 5c35618e000002aff7b7ed2b34c43b588aa2b31b..178ccdbf48351d1c1219aa8ac615052efe997c7e 100644 (file)
@@ -168,8 +168,8 @@ struct smbcli_request *smbcli_request_setup_session(struct smbcli_session *sessi
   setup a request for tree based commands
 */
 struct smbcli_request *smbcli_request_setup(struct smbcli_tree *tree,
-                                     uint8_t command, 
-                                     uint_t wct, uint_t buflen)
+                                           uint8_t command, 
+                                           uint_t wct, uint_t buflen)
 {
        struct smbcli_request *req;
 
@@ -181,6 +181,7 @@ struct smbcli_request *smbcli_request_setup(struct smbcli_tree *tree,
        return req;
 }
 
+
 /*
   grow the allocation of the data buffer portion of a reply
   packet. Note that as this can reallocate the packet buffer this
@@ -246,6 +247,64 @@ static void smbcli_req_grow_data(struct smbcli_request *req, uint_t new_size)
 }
 
 
+/*
+  setup a chained reply in req->out with the given word count and
+  initial data buffer size.
+*/
+NTSTATUS smbcli_chained_request_setup(struct smbcli_request *req,
+                                     uint8_t command, 
+                                     uint_t wct, uint_t buflen)
+{
+       uint_t new_size = 1 + (wct*2) + 2 + buflen;
+
+       SSVAL(req->out.vwv, VWV(0), command);
+       SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
+
+       smbcli_req_grow_allocation(req, req->out.data_size + new_size);
+
+       req->out.vwv = req->out.buffer + req->out.size + 1;
+       SCVAL(req->out.vwv, -1, wct);
+       SSVAL(req->out.vwv, VWV(wct), buflen);
+
+       req->out.size += new_size;
+
+       return NT_STATUS_OK;
+}
+
+/*
+  aadvance to the next chained reply in a request
+*/
+NTSTATUS smbcli_chained_advance(struct smbcli_request *req)
+{
+       uint8_t *buffer;
+
+       if (CVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE) {
+               return NT_STATUS_NOT_FOUND;
+       }
+
+       buffer = req->in.hdr + SVAL(req->in.vwv, VWV(1));
+
+       if (buffer + 3 > req->in.buffer + req->in.size) {
+               return NT_STATUS_BUFFER_TOO_SMALL;
+       }
+
+       req->in.vwv = buffer + 1;
+       req->in.wct = CVAL(buffer, 0);
+       if (buffer + 3 + req->in.wct*2 > req->in.buffer + req->in.size) {
+               return NT_STATUS_BUFFER_TOO_SMALL;
+       }
+       req->in.data = req->in.vwv + 2 + req->in.wct * 2;
+       req->in.data_size = SVAL(req->in.vwv, VWV(req->in.wct));
+
+       if (buffer + 3 + req->in.wct*2 + req->in.data_size > 
+           req->in.buffer + req->in.size) {
+               return NT_STATUS_BUFFER_TOO_SMALL;
+       }
+
+       return NT_STATUS_OK;
+}
+
+
 /*
   send a message
 */
index 91423b05f843146fc4a7819a7399c4ed0dce6a7f..be5120c991a8416f64e63accc80d7fc2afd7b8fe 100644 (file)
@@ -484,6 +484,8 @@ static void reply_open_and_X_send(struct smbsrv_request *req)
                REQ_VWV_RESERVED(17, 2);
        }
 
+       req->chained_fnum = oi->openx.out.fnum;
+
        chain_reply(req);
 }
 
@@ -2262,6 +2264,8 @@ static void reply_ntcreate_and_X_send(struct smbsrv_request *req)
        SSVAL(req->out.vwv,       65, io->ntcreatex.out.ipc_state);
        SCVAL(req->out.vwv,       67, io->ntcreatex.out.is_directory);
 
+       req->chained_fnum = io->ntcreatex.out.fnum;
+
        chain_reply(req);
 }
 
index f3d5daeadeb9b71ac2bf2c0b7fdf3f4f85fdef20..3fa248e0a49927e5b408dad434ea0c58dac85293 100644 (file)
@@ -1178,6 +1178,63 @@ done:
        return ret;
 }
 
+
+/*
+  test chained RAW_OPEN_OPENX_READX
+*/
+static BOOL test_chained(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
+{
+       union smb_open io;
+       const char *fname = BASEDIR "\\torture_chained.txt";
+       NTSTATUS status;
+       int fnum = -1;
+       BOOL ret = True;
+       const char *buf = "test";
+       char buf2[4];
+
+       printf("Checking RAW_OPEN_OPENX chained with READX\n");
+       smbcli_unlink(cli->tree, fname);
+
+       fnum = create_complex_file(cli, mem_ctx, fname);
+
+       smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
+
+       smbcli_close(cli->tree, fnum);  
+
+       io.openxreadx.level = RAW_OPEN_OPENX_READX;
+       io.openxreadx.in.fname = fname;
+       io.openxreadx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
+       io.openxreadx.in.open_mode = OPENX_MODE_ACCESS_RDWR;
+       io.openxreadx.in.open_func = OPENX_OPEN_FUNC_OPEN;
+       io.openxreadx.in.search_attrs = 0;
+       io.openxreadx.in.file_attrs = 0;
+       io.openxreadx.in.write_time = 0;
+       io.openxreadx.in.size = 1024*1024;
+       io.openxreadx.in.timeout = 0;
+       
+       io.openxreadx.in.offset = 0;
+       io.openxreadx.in.mincnt = sizeof(buf);
+       io.openxreadx.in.maxcnt = sizeof(buf);
+       io.openxreadx.in.remaining = 0;
+       io.openxreadx.out.data = buf2;
+
+       status = smb_raw_open(cli->tree, mem_ctx, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       fnum = io.openxreadx.out.fnum;
+
+       if (memcmp(buf, buf2, sizeof(buf)) != 0) {
+               d_printf("wrong data in reply buffer\n");
+               ret = False;
+       }
+
+done:
+       smbcli_close(cli->tree, fnum);
+       smbcli_unlink(cli->tree, fname);
+
+       return ret;
+}
+
+
 /* basic testing of all RAW_OPEN_* calls 
 */
 BOOL torture_raw_open(void)
@@ -1205,6 +1262,7 @@ BOOL torture_raw_open(void)
        ret &= test_mknew(cli, mem_ctx);
        ret &= test_create(cli, mem_ctx);
        ret &= test_ctemp(cli, mem_ctx);
+       ret &= test_chained(cli, mem_ctx);
 
        smb_raw_exit(cli->session);
        smbcli_deltree(cli->tree, BASEDIR);