]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s4:torture:smb2:compound: compound read and padding
authorRalph Boehme <slow@samba.org>
Thu, 14 May 2015 02:27:54 +0000 (04:27 +0200)
committerKarolin Seeger <kseeger@samba.org>
Mon, 1 Jun 2015 21:46:18 +0000 (23:46 +0200)
Add test to check that compound read responses are padded to an 8 byte
boundary.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=11277

Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>

Signed-off-by: Ralph Boehme <slow@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Autobuild-User(master): Ralph Böhme <slow@samba.org>
Autobuild-Date(master): Thu May 28 16:50:39 CEST 2015 on sn-devel-104

(cherry picked from commit 2ffa939bbe2c02509e1790c8b3f6f9b6910e3cf6)

source4/torture/smb2/compound.c

index 9b3cacc0b085908d6e3f5cd2c1f856d0dba3363e..a502103be68317fc057c5de242d9ea7315822e46 100644 (file)
                goto done; \
        }} while (0)
 
+#define CHECK_VALUE(v, correct) do { \
+       if ((v) != (correct)) { \
+               torture_result(tctx, TORTURE_FAIL, \
+                   "(%s) Incorrect value %s=%d - should be %d\n", \
+                   __location__, #v, (int)v, (int)correct); \
+               ret = false; \
+       }} while (0)
+
 static struct {
        struct smb2_handle handle;
        uint8_t level;
@@ -433,6 +441,236 @@ done:
        return ret;
 }
 
+static bool test_compound_padding(struct torture_context *tctx,
+                                 struct smb2_tree *tree)
+{
+       struct smb2_handle h;
+       struct smb2_create cr;
+       struct smb2_read r;
+       const char *fname = "compound_read.dat";
+       const char *sname = "compound_read.dat:foo";
+       struct smb2_request *req[3];
+       NTSTATUS status;
+       bool ret = false;
+
+       smb2_util_unlink(tree, fname);
+
+       /* Write file */
+       ZERO_STRUCT(cr);
+       cr.in.desired_access = SEC_FILE_WRITE_DATA;
+       cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+       cr.in.create_disposition = NTCREATEX_DISP_CREATE;
+       cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+       cr.in.fname = fname;
+       cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+               NTCREATEX_SHARE_ACCESS_WRITE|
+               NTCREATEX_SHARE_ACCESS_DELETE;
+       status = smb2_create(tree, tctx, &cr);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       h = cr.out.file.handle;
+
+       status = smb2_util_write(tree, h, "123", 0, 3);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       smb2_util_close(tree, h);
+
+       /* Write stream */
+       ZERO_STRUCT(cr);
+       cr.in.desired_access = SEC_FILE_WRITE_DATA;
+       cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+       cr.in.create_disposition = NTCREATEX_DISP_CREATE;
+       cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+       cr.in.fname = sname;
+       cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+               NTCREATEX_SHARE_ACCESS_WRITE|
+               NTCREATEX_SHARE_ACCESS_DELETE;
+       status = smb2_create(tree, tctx, &cr);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       h = cr.out.file.handle;
+
+       status = smb2_util_write(tree, h, "456", 0, 3);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       smb2_util_close(tree, h);
+
+       /* Check compound read from basefile */
+       smb2_transport_compound_start(tree->session->transport, 2);
+
+       ZERO_STRUCT(cr);
+       cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+       cr.in.desired_access    = SEC_FILE_READ_DATA;
+       cr.in.file_attributes   = FILE_ATTRIBUTE_NORMAL;
+       cr.in.create_disposition = NTCREATEX_DISP_OPEN;
+       cr.in.fname             = fname;
+       cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+               NTCREATEX_SHARE_ACCESS_WRITE|
+               NTCREATEX_SHARE_ACCESS_DELETE;
+       req[0] = smb2_create_send(tree, &cr);
+
+       smb2_transport_compound_set_related(tree->session->transport, true);
+
+       ZERO_STRUCT(r);
+       h.data[0] = UINT64_MAX;
+       h.data[1] = UINT64_MAX;
+       r.in.file.handle = h;
+       r.in.length      = 3;
+       r.in.offset      = 0;
+       r.in.min_count      = 1;
+       req[1] = smb2_read_send(tree, &r);
+
+       status = smb2_create_recv(req[0], tree, &cr);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       /*
+        * We must do a manual smb2_request_receive() in order to be
+        * able to check the transport layer info, as smb2_read_recv()
+        * will destroy the req. smb2_read_recv() will call
+        * smb2_request_receive() again, but that's ok.
+        */
+       if (!smb2_request_receive(req[1]) ||
+           !smb2_request_is_ok(req[1])) {
+               torture_fail(tctx, "failed to receive read request");
+       }
+
+       /*
+        * size must be 24: 16 byte read response header plus 3
+        * requested bytes padded to an 8 byte boundary.
+        */
+       CHECK_VALUE(req[1]->in.body_size, 24);
+
+       status = smb2_read_recv(req[1], tree, &r);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       smb2_util_close(tree, cr.out.file.handle);
+
+       /* Check compound read from stream */
+       smb2_transport_compound_start(tree->session->transport, 2);
+
+       ZERO_STRUCT(cr);
+       cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+       cr.in.desired_access    = SEC_FILE_READ_DATA;
+       cr.in.file_attributes   = FILE_ATTRIBUTE_NORMAL;
+       cr.in.create_disposition = NTCREATEX_DISP_OPEN;
+       cr.in.fname             = sname;
+       cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+               NTCREATEX_SHARE_ACCESS_WRITE|
+               NTCREATEX_SHARE_ACCESS_DELETE;
+       req[0] = smb2_create_send(tree, &cr);
+
+       smb2_transport_compound_set_related(tree->session->transport, true);
+
+       ZERO_STRUCT(r);
+       h.data[0] = UINT64_MAX;
+       h.data[1] = UINT64_MAX;
+       r.in.file.handle = h;
+       r.in.length      = 3;
+       r.in.offset      = 0;
+       r.in.min_count   = 1;
+       req[1] = smb2_read_send(tree, &r);
+
+       status = smb2_create_recv(req[0], tree, &cr);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       /*
+        * We must do a manual smb2_request_receive() in order to be
+        * able to check the transport layer info, as smb2_read_recv()
+        * will destroy the req. smb2_read_recv() will call
+        * smb2_request_receive() again, but that's ok.
+        */
+       if (!smb2_request_receive(req[1]) ||
+           !smb2_request_is_ok(req[1])) {
+               torture_fail(tctx, "failed to receive read request");
+       }
+
+       /*
+        * size must be 24: 16 byte read response header plus 3
+        * requested bytes padded to an 8 byte boundary.
+        */
+       CHECK_VALUE(req[1]->in.body_size, 24);
+
+       status = smb2_read_recv(req[1], tree, &r);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       h = cr.out.file.handle;
+
+       /* Check 2 compound (unrelateated) reads from existing stream handle */
+       smb2_transport_compound_start(tree->session->transport, 2);
+
+       ZERO_STRUCT(r);
+       r.in.file.handle = h;
+       r.in.length      = 3;
+       r.in.offset      = 0;
+       r.in.min_count   = 1;
+       req[0] = smb2_read_send(tree, &r);
+       req[1] = smb2_read_send(tree, &r);
+
+       /*
+        * We must do a manual smb2_request_receive() in order to be
+        * able to check the transport layer info, as smb2_read_recv()
+        * will destroy the req. smb2_read_recv() will call
+        * smb2_request_receive() again, but that's ok.
+        */
+       if (!smb2_request_receive(req[0]) ||
+           !smb2_request_is_ok(req[0])) {
+               torture_fail(tctx, "failed to receive read request");
+       }
+       if (!smb2_request_receive(req[1]) ||
+           !smb2_request_is_ok(req[1])) {
+               torture_fail(tctx, "failed to receive read request");
+       }
+
+       /*
+        * size must be 24: 16 byte read response header plus 3
+        * requested bytes padded to an 8 byte boundary.
+        */
+       CHECK_VALUE(req[0]->in.body_size, 24);
+       CHECK_VALUE(req[1]->in.body_size, 24);
+
+       status = smb2_read_recv(req[0], tree, &r);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       status = smb2_read_recv(req[1], tree, &r);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       /*
+        * now try a single read from the stream and verify there's no padding
+        */
+       ZERO_STRUCT(r);
+       r.in.file.handle = h;
+       r.in.length      = 3;
+       r.in.offset      = 0;
+       r.in.min_count   = 1;
+       req[0] = smb2_read_send(tree, &r);
+
+       /*
+        * We must do a manual smb2_request_receive() in order to be
+        * able to check the transport layer info, as smb2_read_recv()
+        * will destroy the req. smb2_read_recv() will call
+        * smb2_request_receive() again, but that's ok.
+        */
+       if (!smb2_request_receive(req[0]) ||
+           !smb2_request_is_ok(req[0])) {
+               torture_fail(tctx, "failed to receive read request");
+       }
+
+       /*
+        * size must be 19: 16 byte read response header plus 3
+        * requested bytes without padding.
+        */
+       CHECK_VALUE(req[0]->in.body_size, 19);
+
+       status = smb2_read_recv(req[0], tree, &r);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       smb2_util_close(tree, h);
+
+       status = smb2_util_unlink(tree, fname);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       ret = true;
+done:
+       return ret;
+}
+
 static bool test_compound_unrelated1(struct torture_context *tctx,
                                     struct smb2_tree *tree)
 {
@@ -880,6 +1118,7 @@ struct torture_suite *torture_smb2_compound_init(void)
        torture_suite_add_1smb2_test(suite, "interim1",  test_compound_interim1);
        torture_suite_add_1smb2_test(suite, "interim2",  test_compound_interim2);
        torture_suite_add_1smb2_test(suite, "compound-break", test_compound_break);
+       torture_suite_add_1smb2_test(suite, "compound-padding", test_compound_padding);
 
        suite->description = talloc_strdup(suite, "SMB2-COMPOUND tests");