SMB2-CREATE: be more strict in error checking
[tprouty/samba.git] / source4 / torture / smb2 / create.c
index 211b418a125b46c0f1bd3af33c3d97b0533627a9..6edacbfd0799097e09b295ad00894863e701237a 100644 (file)
@@ -26,6 +26,7 @@
 #include "torture/smb2/proto.h"
 #include "param/param.h"
 #include "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/security.h"
 
 #define FNAME "test_create.dat"
 
        if (v != correct) { \
                printf("(%s) Incorrect value for %s 0x%08llx - should be 0x%08llx\n", \
                       __location__, #v, (unsigned long long)v, (unsigned long long)correct); \
-               return false; \
+               return false;                                   \
        }} while (0)
 
 /*
   test some interesting combinations found by gentest
  */
-bool torture_smb2_create_gentest(struct torture_context *torture, struct smb2_tree *tree)
+static bool test_create_gentest(struct torture_context *torture, struct smb2_tree *tree)
 {
        struct smb2_create io;
        NTSTATUS status;
        TALLOC_CTX *tmp_ctx = talloc_new(tree);
-       uint32_t access_mask, file_attributes, denied_mask;
+       uint32_t access_mask, file_attributes, file_attributes_set, denied_mask;
+       uint32_t ok_mask, not_supported_mask, invalid_parameter_mask;
+       uint32_t not_a_directory_mask, unexpected_mask;
+       union smb_fileinfo q;
 
        ZERO_STRUCT(io);
        io.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
@@ -74,14 +78,6 @@ bool torture_smb2_create_gentest(struct torture_context *torture, struct smb2_tr
        status = smb2_create(tree, tmp_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
 
-       io.in.create_options = 0x00100000;
-       status = smb2_create(tree, tmp_ctx, &io);
-       CHECK_STATUS(status, NT_STATUS_NOT_SUPPORTED);
-
-       io.in.create_options = 0xF0100000;
-       status = smb2_create(tree, tmp_ctx, &io);
-       CHECK_STATUS(status, NT_STATUS_NOT_SUPPORTED);
-
        io.in.create_options = 0;
 
        io.in.file_attributes = FILE_ATTRIBUTE_DEVICE;
@@ -106,6 +102,46 @@ bool torture_smb2_create_gentest(struct torture_context *torture, struct smb2_tr
        status = smb2_create(tree, tmp_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
 
+       io.in.file_attributes = 0;
+       io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+       io.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
+       ok_mask = 0;
+       not_supported_mask = 0;
+       invalid_parameter_mask = 0;
+       not_a_directory_mask = 0;
+       unexpected_mask = 0;
+       {
+               int i;
+               for (i=0;i<32;i++) {
+                       io.in.create_options = 1<<i;
+                       if (io.in.create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
+                               continue;
+                       }
+                       status = smb2_create(tree, tmp_ctx, &io);
+                       if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
+                               not_supported_mask |= 1<<i;
+                       } else if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+                               invalid_parameter_mask |= 1<<i;
+                       } else if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
+                               not_a_directory_mask |= 1<<i;
+                       } else if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
+                               ok_mask |= 1<<i;
+                               status = smb2_util_close(tree, io.out.file.handle);
+                               CHECK_STATUS(status, NT_STATUS_OK);
+                       } else {
+                               unexpected_mask |= 1<<i;
+                               printf("create option 0x%08x returned %s\n", 1<<i, nt_errstr(status));
+                       }
+               }
+       }
+       io.in.create_options = 0;
+
+       CHECK_EQUAL(ok_mask,                0x00efcf7e);
+       CHECK_EQUAL(not_a_directory_mask,   0x00000001);
+       CHECK_EQUAL(not_supported_mask,     0x00102080);
+       CHECK_EQUAL(invalid_parameter_mask, 0xff000000);
+       CHECK_EQUAL(unexpected_mask,        0x00000000);
+
        io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
        io.in.file_attributes = 0;
        access_mask = 0;
@@ -114,7 +150,8 @@ bool torture_smb2_create_gentest(struct torture_context *torture, struct smb2_tr
                for (i=0;i<32;i++) {
                        io.in.desired_access = 1<<i;
                        status = smb2_create(tree, tmp_ctx, &io);
-                       if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+                       if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
+                           NT_STATUS_EQUAL(status, NT_STATUS_PRIVILEGE_NOT_HELD)) {
                                access_mask |= io.in.desired_access;
                        } else {
                                CHECK_STATUS(status, NT_STATUS_OK);
@@ -130,6 +167,7 @@ bool torture_smb2_create_gentest(struct torture_context *torture, struct smb2_tr
        io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
        io.in.file_attributes = 0;
        file_attributes = 0;
+       file_attributes_set = 0;
        denied_mask = 0;
        {
                int i;
@@ -145,12 +183,14 @@ bool torture_smb2_create_gentest(struct torture_context *torture, struct smb2_tr
                                CHECK_STATUS(status, NT_STATUS_OK);
                                status = smb2_util_close(tree, io.out.file.handle);
                                CHECK_STATUS(status, NT_STATUS_OK);
+                               file_attributes_set |= io.out.file_attr;
                        }
                }
        }
 
        CHECK_EQUAL(file_attributes, 0xffff8048);
        CHECK_EQUAL(denied_mask, 0x4000);
+       CHECK_EQUAL(file_attributes_set, 0x00001127);
 
        smb2_deltree(tree, FNAME);
 
@@ -176,6 +216,20 @@ bool torture_smb2_create_gentest(struct torture_context *torture, struct smb2_tr
        status = smb2_create(tree, tmp_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
 
+       io.in.fname = FNAME;
+       io.in.file_attributes = 0;
+       io.in.desired_access  = SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA;
+       io.in.query_maximal_access = true;
+       status = smb2_create(tree, tmp_ctx, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       CHECK_EQUAL(io.out.maximal_access, 0x001f01ff);
+
+       q.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION;
+       q.access_information.in.file.handle = io.out.file.handle;
+       status = smb2_getinfo_file(tree, tmp_ctx, &q);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       CHECK_EQUAL(q.access_information.out.access_flags, io.in.desired_access);
+       
        talloc_free(tmp_ctx);
 
        smb2_deltree(tree, FNAME);
@@ -187,7 +241,7 @@ bool torture_smb2_create_gentest(struct torture_context *torture, struct smb2_tr
 /*
   try the various request blobs
  */
-bool torture_smb2_create_blob(struct torture_context *torture, struct smb2_tree *tree)
+static bool test_create_blob(struct torture_context *torture, struct smb2_tree *tree)
 {
        struct smb2_create io;
        NTSTATUS status;
@@ -203,20 +257,6 @@ bool torture_smb2_create_blob(struct torture_context *torture, struct smb2_tree
                NTCREATEX_SHARE_ACCESS_DELETE|
                NTCREATEX_SHARE_ACCESS_READ|
                NTCREATEX_SHARE_ACCESS_WRITE;
-       io.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
-                                         NTCREATEX_OPTIONS_ASYNC_ALERT |
-                                         NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
-                                         0x00200000;
-       io.in.security_flags            = 0x00;
-       io.in.impersonation_level       = NTCREATEX_IMPERSONATION_IMPERSONATION;
-       io.in.create_flags              = 0x00000000;
-       io.in.reserved                  = 0x00000000;
-       io.in.desired_access            = SEC_RIGHTS_FILE_ALL;
-       io.in.file_attributes           = FILE_ATTRIBUTE_NORMAL;
-       io.in.share_access              = NTCREATEX_SHARE_ACCESS_READ |
-                                         NTCREATEX_SHARE_ACCESS_WRITE |
-                                         NTCREATEX_SHARE_ACCESS_DELETE;
-       io.in.create_disposition        = NTCREATEX_DISP_OVERWRITE_IF;
        io.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
                                          NTCREATEX_OPTIONS_ASYNC_ALERT |
                                          NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
@@ -250,6 +290,7 @@ bool torture_smb2_create_blob(struct torture_context *torture, struct smb2_tree
        io.in.query_maximal_access = true;
        status = smb2_create(tree, tmp_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
+       CHECK_EQUAL(io.out.maximal_access, 0x001f01ff);
 
        status = smb2_util_close(tree, io.out.file.handle);
        CHECK_STATUS(status, NT_STATUS_OK);
@@ -294,25 +335,101 @@ bool torture_smb2_create_blob(struct torture_context *torture, struct smb2_tree
        return true;
 }
 
-/* 
-   basic testing of SMB2 create calls
-*/
-bool torture_smb2_create(struct torture_context *torture)
+/*
+  try creating with acls
+ */
+static bool test_create_acl(struct torture_context *torture, struct smb2_tree *tree)
 {
-       TALLOC_CTX *mem_ctx = talloc_new(NULL);
-       struct smb2_tree *tree;
-       bool ret = true;
+       struct smb2_create io;
+       NTSTATUS status;
+       TALLOC_CTX *tmp_ctx = talloc_new(tree);
+       struct security_ace ace;
+       struct security_descriptor *sd, *sd2;
+       struct dom_sid *test_sid;
+       union smb_fileinfo q;
+
+       smb2_deltree(tree, FNAME);
+
+       ZERO_STRUCT(io);
+       io.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
+       io.in.file_attributes    = FILE_ATTRIBUTE_NORMAL;
+       io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+       io.in.share_access = 
+               NTCREATEX_SHARE_ACCESS_DELETE|
+               NTCREATEX_SHARE_ACCESS_READ|
+               NTCREATEX_SHARE_ACCESS_WRITE;
+       io.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
+                                         NTCREATEX_OPTIONS_ASYNC_ALERT |
+                                         NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
+                                         0x00200000;
+       io.in.fname = FNAME;
+
+       status = smb2_create(tree, tmp_ctx, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+       q.query_secdesc.in.file.handle = io.out.file.handle;
+       q.query_secdesc.in.secinfo_flags = 
+               SECINFO_OWNER |
+               SECINFO_GROUP |
+               SECINFO_DACL;
+       status = smb2_getinfo_file(tree, tmp_ctx, &q);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       sd = q.query_secdesc.out.sd;
+
+       status = smb2_util_close(tree, io.out.file.handle);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       smb2_util_unlink(tree, FNAME);
+
+       printf("adding a new ACE\n");
+       test_sid = dom_sid_parse_talloc(tmp_ctx, "S-1-5-32-1234-54321");
+
+       ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
+       ace.flags = 0;
+       ace.access_mask = SEC_STD_ALL;
+       ace.trustee = *test_sid;
+
+       status = security_descriptor_dacl_add(sd, &ace);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       
+       printf("creating a file with an initial ACL\n");
+
+       io.in.sec_desc = sd;
+       status = smb2_create(tree, tmp_ctx, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
 
-       if (!torture_smb2_connection(torture, &tree)) {
+       q.query_secdesc.in.file.handle = io.out.file.handle;
+       status = smb2_getinfo_file(tree, tmp_ctx, &q);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       sd2 = q.query_secdesc.out.sd;
+
+       if (!security_acl_equal(sd->dacl, sd2->dacl)) {
+               printf("%s: security descriptors don't match!\n", __location__);
+               printf("got:\n");
+               NDR_PRINT_DEBUG(security_descriptor, sd2);
+               printf("expected:\n");
+               NDR_PRINT_DEBUG(security_descriptor, sd);
                return false;
        }
 
-       ret &= torture_smb2_create_gentest(torture, tree);
-       ret &= torture_smb2_create_blob(torture, tree);
+       talloc_free(tmp_ctx);
+       
+       return true;
+}
+
+/* 
+   basic testing of SMB2 read
+*/
+struct torture_suite *torture_smb2_create_init(void)
+{
+       struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "CREATE");
 
-       smb2_deltree(tree, FNAME);
+       torture_suite_add_1smb2_test(suite, "GENTEST", test_create_gentest);
+       torture_suite_add_1smb2_test(suite, "BLOB", test_create_blob);
+       torture_suite_add_1smb2_test(suite, "ACL", test_create_acl);
 
-       talloc_free(mem_ctx);
+       suite->description = talloc_strdup(suite, "SMB2-CREATE tests");
 
-       return ret;
+       return suite;
 }