From 5e4e61c8276d5f0a4a2d4c6cbc20047554096227 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 26 Dec 2004 08:13:01 +0000 Subject: 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) --- source4/include/smb_interfaces.h | 48 +++++++++++++++++++++++- source4/libcli/raw/rawfile.c | 78 ++++++++++++++++++++++++++++++++++++++- source4/libcli/raw/rawreadwrite.c | 5 +-- source4/libcli/raw/rawrequest.c | 63 ++++++++++++++++++++++++++++++- source4/smb_server/reply.c | 4 ++ source4/torture/raw/open.c | 58 +++++++++++++++++++++++++++++ 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 @@ -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 */ 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); -- cgit