summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);