summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/libcli/raw/rawnotify.c4
-rw-r--r--source4/torture/raw/notify.c100
2 files changed, 102 insertions, 2 deletions
diff --git a/source4/libcli/raw/rawnotify.c b/source4/libcli/raw/rawnotify.c
index 2155076dd7..40256aa405 100644
--- a/source4/libcli/raw/rawnotify.c
+++ b/source4/libcli/raw/rawnotify.c
@@ -71,10 +71,12 @@ _PUBLIC_ NTSTATUS smb_raw_changenotify_recv(struct smbcli_request *req,
parms->nttrans.out.changes = NULL;
parms->nttrans.out.num_changes = 0;
-
+
/* count them */
for (ofs=0; nt.out.params.length - ofs > 12; ) {
uint32_t next = IVAL(nt.out.params.data, ofs);
+ if (next % 4 != 0)
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
parms->nttrans.out.num_changes++;
if (next == 0 ||
ofs + next >= nt.out.params.length) break;
diff --git a/source4/torture/raw/notify.c b/source4/torture/raw/notify.c
index 5bf7f4aa3b..dd3aae3d66 100644
--- a/source4/torture/raw/notify.c
+++ b/source4/torture/raw/notify.c
@@ -50,6 +50,14 @@
goto done; \
}} while (0)
+#define CHECK_WSTR2(tctx, field, value, flags) \
+do { \
+ if (!field.s || strcmp(field.s, value) || \
+ wire_bad_flags(&field, flags, cli->transport)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%d) %s [%s] != %s\n", __LINE__, #field, field.s, value); \
+ } \
+} while (0)
/*
basic testing of change notify on directories
@@ -1594,7 +1602,96 @@ done:
}
-/*
+/*
+ testing alignment of multiple change notify infos
+*/
+static bool test_notify_alignment(struct smbcli_state *cli,
+ struct torture_context *tctx)
+{
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ int i, fnum, fnum2;
+ struct smbcli_request *req;
+ const char *fname = BASEDIR "\\starter";
+ const char *fnames[] = { "a",
+ "ab",
+ "abc",
+ "abcd" };
+ int num_names = ARRAY_SIZE(fnames);
+ const char *fpath = NULL;
+
+ torture_comment(tctx, "TESTING CHANGE NOTIFY REPLY ALIGNMENT\n");
+
+ /* get a handle on the directory */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_ALL;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = BASEDIR;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, "");
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /* ask for a change notify, on file creation */
+ notify.nttrans.level = RAW_NOTIFY_NTTRANS;
+ notify.nttrans.in.buffer_size = 1000;
+ notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_FILE_NAME;
+ notify.nttrans.in.file.fnum = fnum;
+ notify.nttrans.in.recursive = false;
+
+ /* start change tracking */
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+
+ fnum2 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum2 != -1, smbcli_errstr(cli->tree));
+ smbcli_close(cli->tree, fnum2);
+
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_ok(tctx, status, "");
+
+ /* create 4 files that will cause CHANGE_NOTIFY_INFO structures
+ * to be returned in the same packet with all possible 4-byte padding
+ * permutations. As per MS-CIFS 2.2.7.4.2 these structures should be
+ * 4-byte aligned. */
+
+ for (i = 0; i < num_names; i++) {
+ fpath = talloc_asprintf(tctx, "%s\\%s", BASEDIR, fnames[i]);
+ fnum2 = smbcli_open(cli->tree, fpath,
+ O_CREAT|O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum2 != -1, smbcli_errstr(cli->tree));
+ smbcli_close(cli->tree, fnum2);
+ talloc_free(fpath);
+ }
+
+ /* We send a notify packet, and let smb_raw_changenotify_recv() do
+ * the alignment checking for us. */
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_ok(tctx, status, "");
+
+ /* Do basic checking for correctness. */
+ torture_assert(tctx, notify.nttrans.out.num_changes == num_names, "");
+ for (i = 0; i < num_names; i++) {
+ torture_assert(tctx, notify.nttrans.out.changes[i].action ==
+ NOTIFY_ACTION_ADDED, "");
+ CHECK_WSTR2(tctx, notify.nttrans.out.changes[i].name, fnames[i],
+ STR_UNICODE);
+ }
+
+ return true;
+}
+
+/*
basic testing of change notify
*/
bool torture_raw_notify(struct torture_context *torture,
@@ -1621,6 +1718,7 @@ bool torture_raw_notify(struct torture_context *torture,
ret &= test_notify_tree(cli, torture);
ret &= test_notify_overflow(cli, torture);
ret &= test_notify_basedir(cli, torture);
+ ret &= test_notify_alignment(cli, torture);
smb_raw_exit(cli->session);
smbcli_deltree(cli->tree, BASEDIR);