summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2004-12-26 08:13:01 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:07:38 -0500
commit5e4e61c8276d5f0a4a2d4c6cbc20047554096227 (patch)
tree198c7cbc34543e05b5d71edb6ed4eff7b1a3d789 /source4
parent5ba0e02fbe8408dd2023694101d61be2beba567d (diff)
downloadsamba-5e4e61c8276d5f0a4a2d4c6cbc20047554096227.tar.gz
samba-5e4e61c8276d5f0a4a2d4c6cbc20047554096227.tar.bz2
samba-5e4e61c8276d5f0a4a2d4c6cbc20047554096227.zip
r4364: - added support for testing of chained SMB operations in smbtorture
- 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)
Diffstat (limited to 'source4')
-rw-r--r--source4/include/smb_interfaces.h48
-rw-r--r--source4/libcli/raw/rawfile.c78
-rw-r--r--source4/libcli/raw/rawreadwrite.c5
-rw-r--r--source4/libcli/raw/rawrequest.c63
-rw-r--r--source4/smb_server/reply.c4
-rw-r--r--source4/torture/raw/open.c58
6 files changed, 249 insertions, 7 deletions
diff --git a/source4/include/smb_interfaces.h b/source4/include/smb_interfaces.h
index 91ed102d6a..1eca1fe360 100644
--- a/source4/include/smb_interfaces.h
+++ b/source4/include/smb_interfaces.h
@@ -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;
};
diff --git a/source4/libcli/raw/rawfile.c b/source4/libcli/raw/rawfile.c
index 4a11fd3834..11be8ffba7 100644
--- a/source4/libcli/raw/rawfile.c
+++ b/source4/libcli/raw/rawfile.c
@@ -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:
diff --git a/source4/libcli/raw/rawreadwrite.c b/source4/libcli/raw/rawreadwrite.c
index 8381c7b2b0..d9fe3fdce0 100644
--- a/source4/libcli/raw/rawreadwrite.c
+++ b/source4/libcli/raw/rawreadwrite.c
@@ -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);
diff --git a/source4/libcli/raw/rawrequest.c b/source4/libcli/raw/rawrequest.c
index 5c35618e00..178ccdbf48 100644
--- a/source4/libcli/raw/rawrequest.c
+++ b/source4/libcli/raw/rawrequest.c
@@ -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
@@ -247,6 +248,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
*/
BOOL smbcli_request_send(struct smbcli_request *req)
diff --git a/source4/smb_server/reply.c b/source4/smb_server/reply.c
index 91423b05f8..be5120c991 100644
--- a/source4/smb_server/reply.c
+++ b/source4/smb_server/reply.c
@@ -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);
}
diff --git a/source4/torture/raw/open.c b/source4/torture/raw/open.c
index f3d5daeade..3fa248e0a4 100644
--- a/source4/torture/raw/open.c
+++ b/source4/torture/raw/open.c
@@ -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);