s4:torture:smb2: add smb2_oplock_create_share() that takes sharemode as parameter
[bbaumbach/samba-autobuild/.git] / source4 / torture / smb2 / util.c
index d167f6690e67f1976b199fdf19098a3595b69897..094161e6eb9ab0e8281d46c71ec7dc93da8f7fbd 100644 (file)
@@ -7,7 +7,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
+#include "libcli/security/security_descriptor.h"
 #include "libcli/smb2/smb2.h"
 #include "libcli/smb2/smb2_calls.h"
 #include "lib/cmdline/popt_common.h"
-#include "lib/events/events.h"
 #include "system/time.h"
 #include "librpc/gen_ndr/ndr_security.h"
+#include "param/param.h"
+#include "libcli/resolve/resolve.h"
 
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
 
-/*
-  close a handle with SMB2
-*/
-NTSTATUS smb2_util_close(struct smb2_tree *tree, struct smb2_handle h)
-{
-       struct smb2_close c;
-
-       ZERO_STRUCT(c);
-       c.in.file.handle = h;
-
-       return smb2_close(tree, &c);
-}
-
-/*
-  unlink a file with SMB2
-*/
-NTSTATUS smb2_util_unlink(struct smb2_tree *tree, const char *fname)
-{
-       struct smb2_create io;
-       NTSTATUS status;
-
-       ZERO_STRUCT(io);
-       io.in.access_mask = SEC_RIGHTS_FILE_ALL;
-       io.in.file_attr   = FILE_ATTRIBUTE_NORMAL;
-       io.in.open_disposition = NTCREATEX_DISP_OPEN;
-       io.in.share_access = 
-               NTCREATEX_SHARE_ACCESS_DELETE|
-               NTCREATEX_SHARE_ACCESS_READ|
-               NTCREATEX_SHARE_ACCESS_WRITE;
-       io.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
-       io.in.fname = fname;
-
-       status = smb2_create(tree, tree, &io);
-       if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
-               return NT_STATUS_OK;
-       }
-       NT_STATUS_NOT_OK_RETURN(status);
-
-       return smb2_util_close(tree, io.out.file.handle);
-}
 
 /*
   write to a file on SMB2
@@ -91,7 +54,7 @@ NTSTATUS smb2_util_write(struct smb2_tree *tree,
   create a complex file/dir using the SMB2 protocol
 */
 static NTSTATUS smb2_create_complex(struct smb2_tree *tree, const char *fname, 
-                                        struct smb2_handle *handle, BOOL dir)
+                                        struct smb2_handle *handle, bool dir)
 {
        TALLOC_CTX *tmp_ctx = talloc_new(tree);
        char buf[7] = "abc";
@@ -103,9 +66,9 @@ static NTSTATUS smb2_create_complex(struct smb2_tree *tree, const char *fname,
 
        smb2_util_unlink(tree, fname);
        ZERO_STRUCT(io);
-       io.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
-       io.in.file_attr   = FILE_ATTRIBUTE_NORMAL;
-       io.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+       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|
@@ -115,10 +78,11 @@ static NTSTATUS smb2_create_complex(struct smb2_tree *tree, const char *fname,
        if (dir) {
                io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
                io.in.share_access &= ~NTCREATEX_SHARE_ACCESS_DELETE;
-               io.in.file_attr   = FILE_ATTRIBUTE_DIRECTORY;
-               io.in.open_disposition = NTCREATEX_DISP_CREATE;
+               io.in.file_attributes   = FILE_ATTRIBUTE_DIRECTORY;
+               io.in.create_disposition = NTCREATEX_DISP_CREATE;
        }
 
+       /* it seems vista is now fussier about alignment? */
        if (strchr(fname, ':') == NULL) {
                /* setup some EAs */
                io.in.eas.num_eas = 2;
@@ -196,7 +160,7 @@ static NTSTATUS smb2_create_complex(struct smb2_tree *tree, const char *fname,
 NTSTATUS smb2_create_complex_file(struct smb2_tree *tree, const char *fname, 
                                         struct smb2_handle *handle)
 {
-       return smb2_create_complex(tree, fname, handle, False);
+       return smb2_create_complex(tree, fname, handle, false);
 }
 
 /*
@@ -205,7 +169,7 @@ NTSTATUS smb2_create_complex_file(struct smb2_tree *tree, const char *fname,
 NTSTATUS smb2_create_complex_dir(struct smb2_tree *tree, const char *fname, 
                                 struct smb2_handle *handle)
 {
-       return smb2_create_complex(tree, fname, handle, True);
+       return smb2_create_complex(tree, fname, handle, true);
 }
 
 /*
@@ -299,21 +263,34 @@ void torture_smb2_all_info(struct smb2_tree *tree, struct smb2_handle handle)
 /*
   open a smb2 connection
 */
-BOOL torture_smb2_connection(TALLOC_CTX *mem_ctx, struct smb2_tree **tree)
+bool torture_smb2_connection(struct torture_context *tctx, struct smb2_tree **tree)
 {
        NTSTATUS status;
-       const char *host = lp_parm_string(-1, "torture", "host");
-       const char *share = lp_parm_string(-1, "torture", "share");
+       const char *host = torture_setting_string(tctx, "host", NULL);
+       const char *share = torture_setting_string(tctx, "share", NULL);
        struct cli_credentials *credentials = cmdline_credentials;
-
-       status = smb2_connect(mem_ctx, host, share, credentials, tree, 
-                             event_context_find(mem_ctx));
+       struct smbcli_options options;
+
+       lpcfg_smbcli_options(tctx->lp_ctx, &options);
+
+       status = smb2_connect(tctx,
+                             host,
+                             lpcfg_smb_ports(tctx->lp_ctx),
+                             share,
+                             lpcfg_resolve_context(tctx->lp_ctx),
+                             credentials,
+                             tree,
+                             tctx->ev,
+                             &options,
+                             lpcfg_socket_options(tctx->lp_ctx),
+                             lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+                             );
        if (!NT_STATUS_IS_OK(status)) {
                printf("Failed to connect to SMB2 share \\\\%s\\%s - %s\n",
                       host, share, nt_errstr(status));
-               return False;
+               return false;
        }
-       return True;
+       return true;
 }
 
 
@@ -324,14 +301,13 @@ NTSTATUS torture_smb2_testfile(struct smb2_tree *tree, const char *fname,
                               struct smb2_handle *handle)
 {
        struct smb2_create io;
-       struct smb2_read r;
        NTSTATUS status;
 
        ZERO_STRUCT(io);
-       io.in.oplock_flags = 0;
-       io.in.access_mask = SEC_RIGHTS_FILE_ALL;
-       io.in.file_attr   = FILE_ATTRIBUTE_NORMAL;
-       io.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+       io.in.oplock_level = 0;
+       io.in.desired_access = SEC_RIGHTS_FILE_ALL;
+       io.in.file_attributes   = FILE_ATTRIBUTE_NORMAL;
+       io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
        io.in.share_access = 
                NTCREATEX_SHARE_ACCESS_DELETE|
                NTCREATEX_SHARE_ACCESS_READ|
@@ -344,13 +320,6 @@ NTSTATUS torture_smb2_testfile(struct smb2_tree *tree, const char *fname,
 
        *handle = io.out.file.handle;
 
-       ZERO_STRUCT(r);
-       r.in.file.handle = *handle;
-       r.in.length      = 5;
-       r.in.offset      = 0;
-
-       smb2_read(tree, tree, &r);
-
        return NT_STATUS_OK;
 }
 
@@ -364,10 +333,10 @@ NTSTATUS torture_smb2_testdir(struct smb2_tree *tree, const char *fname,
        NTSTATUS status;
 
        ZERO_STRUCT(io);
-       io.in.oplock_flags = 0;
-       io.in.access_mask = SEC_RIGHTS_DIR_ALL;
-       io.in.file_attr   = FILE_ATTRIBUTE_DIRECTORY;
-       io.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+       io.in.oplock_level = 0;
+       io.in.desired_access = SEC_RIGHTS_DIR_ALL;
+       io.in.file_attributes   = FILE_ATTRIBUTE_DIRECTORY;
+       io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
        io.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE;
        io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
        io.in.fname = fname;
@@ -382,7 +351,7 @@ NTSTATUS torture_smb2_testdir(struct smb2_tree *tree, const char *fname,
 
 
 /*
-  create a complex file using the old SMB protocol, to make it easier to 
+  create a complex file using SMB2, to make it easier to
   find fields in SMB2 getinfo levels
 */
 NTSTATUS torture_setup_complex_file(struct smb2_tree *tree, const char *fname)
@@ -395,7 +364,7 @@ NTSTATUS torture_setup_complex_file(struct smb2_tree *tree, const char *fname)
 
 
 /*
-  create a complex dir using the old SMB protocol, to make it easier to 
+  create a complex dir using SMB2, to make it easier to
   find fields in SMB2 getinfo levels
 */
 NTSTATUS torture_setup_complex_dir(struct smb2_tree *tree, const char *fname)
@@ -416,13 +385,13 @@ NTSTATUS smb2_util_roothandle(struct smb2_tree *tree, struct smb2_handle *handle
        NTSTATUS status;
 
        ZERO_STRUCT(io);
-       io.in.oplock_flags = 0;
-       io.in.access_mask = SEC_STD_SYNCHRONIZE | SEC_DIR_READ_ATTRIBUTE | SEC_DIR_LIST;
-       io.in.file_attr   = 0;
-       io.in.open_disposition = NTCREATEX_DISP_OPEN;
+       io.in.oplock_level = 0;
+       io.in.desired_access = SEC_STD_SYNCHRONIZE | SEC_DIR_READ_ATTRIBUTE | SEC_DIR_LIST;
+       io.in.file_attributes   = 0;
+       io.in.create_disposition = NTCREATEX_DISP_OPEN;
        io.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE;
        io.in.create_options = NTCREATEX_OPTIONS_ASYNC_ALERT;
-       io.in.fname = "";
+       io.in.fname = NULL;
 
        status = smb2_create(tree, tree, &io);
        NT_STATUS_NOT_OK_RETURN(status);
@@ -431,3 +400,251 @@ NTSTATUS smb2_util_roothandle(struct smb2_tree *tree, struct smb2_handle *handle
 
        return NT_STATUS_OK;
 }
+
+/* Comparable to torture_setup_dir, but for SMB2. */
+bool smb2_util_setup_dir(struct torture_context *tctx, struct smb2_tree *tree,
+    const char *dname)
+{
+       NTSTATUS status;
+
+       /* XXX: smb_raw_exit equivalent?
+       smb_raw_exit(cli->session); */
+       if (smb2_deltree(tree, dname) == -1) {
+               torture_result(tctx, TORTURE_ERROR, "Unable to deltree when setting up %s.\n", dname);
+               return false;
+       }
+
+       status = smb2_util_mkdir(tree, dname);
+       if (NT_STATUS_IS_ERR(status)) {
+               torture_result(tctx, TORTURE_ERROR, "Unable to mkdir when setting up %s - %s\n", dname,
+                   nt_errstr(status));
+               return false;
+       }
+
+       return true;
+}
+
+#define CHECK_STATUS(status, correct) do { \
+       if (!NT_STATUS_EQUAL(status, correct)) { \
+               torture_result(tctx, TORTURE_FAIL, "(%s) Incorrect status %s - should be %s\n", \
+                      __location__, nt_errstr(status), nt_errstr(correct)); \
+               ret = false; \
+               goto done; \
+       }} while (0)
+
+/*
+ * Helper function to verify a security descriptor, by querying
+ * and comparing against the passed in sd.
+ */
+bool smb2_util_verify_sd(TALLOC_CTX *tctx, struct smb2_tree *tree,
+    struct smb2_handle handle, struct security_descriptor *sd)
+{
+       NTSTATUS status;
+       bool ret = true;
+       union smb_fileinfo q = {};
+
+       q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+       q.query_secdesc.in.file.handle = handle;
+       q.query_secdesc.in.secinfo_flags =
+           SECINFO_OWNER |
+           SECINFO_GROUP |
+           SECINFO_DACL;
+       status = smb2_getinfo_file(tree, tctx, &q);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       if (!security_acl_equal(
+           q.query_secdesc.out.sd->dacl, sd->dacl)) {
+               torture_warning(tctx, "%s: security descriptors don't match!\n",
+                   __location__);
+               torture_warning(tctx, "got:\n");
+               NDR_PRINT_DEBUG(security_descriptor,
+                   q.query_secdesc.out.sd);
+               torture_warning(tctx, "expected:\n");
+               NDR_PRINT_DEBUG(security_descriptor, sd);
+               ret = false;
+       }
+
+ done:
+       return ret;
+}
+
+/*
+ * Helper function to verify attributes, by querying
+ * and comparing against the passed in attrib.
+ */
+bool smb2_util_verify_attrib(TALLOC_CTX *tctx, struct smb2_tree *tree,
+    struct smb2_handle handle, uint32_t attrib)
+{
+       NTSTATUS status;
+       bool ret = true;
+       union smb_fileinfo q = {};
+
+       q.standard.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+       q.standard.in.file.handle = handle;
+       status = smb2_getinfo_file(tree, tctx, &q);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       q.all_info2.out.attrib &= ~FILE_ATTRIBUTE_ARCHIVE;
+
+       if (q.all_info2.out.attrib != attrib) {
+               torture_warning(tctx, "%s: attributes don't match! "
+                   "got %x, expected %x\n", __location__,
+                   (uint32_t)q.standard.out.attrib,
+                   (uint32_t)attrib);
+               ret = false;
+       }
+
+ done:
+       return ret;
+}
+
+
+uint32_t smb2_util_lease_state(const char *ls)
+{
+       uint32_t val = 0;
+       int i;
+
+       for (i = 0; i < strlen(ls); i++) {
+               switch (ls[i]) {
+               case 'R':
+                       val |= SMB2_LEASE_READ;
+                       break;
+               case 'H':
+                       val |= SMB2_LEASE_HANDLE;
+                       break;
+               case 'W':
+                       val |= SMB2_LEASE_WRITE;
+                       break;
+               }
+       }
+
+       return val;
+}
+
+
+uint32_t smb2_util_share_access(const char *sharemode)
+{
+       uint32_t val = NTCREATEX_SHARE_ACCESS_NONE; /* 0 */
+       int i;
+
+       for (i = 0; i < strlen(sharemode); i++) {
+               switch(sharemode[i]) {
+               case 'R':
+                       val |= NTCREATEX_SHARE_ACCESS_READ;
+                       break;
+               case 'W':
+                       val |= NTCREATEX_SHARE_ACCESS_WRITE;
+                       break;
+               case 'D':
+                       val |= NTCREATEX_SHARE_ACCESS_DELETE;
+                       break;
+               }
+       }
+
+       return val;
+}
+
+uint8_t smb2_util_oplock_level(const char *op)
+{
+       uint8_t val = SMB2_OPLOCK_LEVEL_NONE;
+       int i;
+
+       for (i = 0; i < strlen(op); i++) {
+               switch (op[i]) {
+               case 's':
+                       return SMB2_OPLOCK_LEVEL_II;
+               case 'x':
+                       return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+               case 'b':
+                       return SMB2_OPLOCK_LEVEL_BATCH;
+               default:
+                       continue;
+               }
+       }
+
+       return val;
+}
+
+/**
+ * Helper functions to fill a smb2_create struct for several
+ * open scenarios.
+ */
+void smb2_generic_create_share(struct smb2_create *io, struct smb2_lease *ls,
+                              bool dir, const char *name, uint32_t disposition,
+                              uint32_t share_access,
+                              uint8_t oplock, uint64_t leasekey,
+                              uint32_t leasestate)
+{
+       ZERO_STRUCT(*io);
+       io->in.security_flags           = 0x00;
+       io->in.oplock_level             = oplock;
+       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             = share_access;
+       io->in.create_disposition       = disposition;
+       io->in.create_options           = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
+                                         NTCREATEX_OPTIONS_ASYNC_ALERT |
+                                         NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
+                                         0x00200000;
+       io->in.fname                    = name;
+
+       if (dir) {
+               io->in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+               io->in.share_access &= ~NTCREATEX_SHARE_ACCESS_DELETE;
+               io->in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+               io->in.create_disposition = NTCREATEX_DISP_CREATE;
+       }
+
+       if (ls) {
+               ZERO_STRUCT(*ls);
+               ls->lease_key.data[0] = leasekey;
+               ls->lease_key.data[1] = ~leasekey;
+               ls->lease_state = leasestate;
+               io->in.lease_request = ls;
+       }
+}
+
+void smb2_generic_create(struct smb2_create *io, struct smb2_lease *ls,
+                        bool dir, const char *name, uint32_t disposition,
+                        uint8_t oplock, uint64_t leasekey,
+                        uint32_t leasestate)
+{
+       smb2_generic_create_share(io, ls, dir, name, disposition,
+                                 smb2_util_share_access("RWD"),
+                                 oplock,
+                                 leasekey, leasestate);
+}
+
+void smb2_lease_create_share(struct smb2_create *io, struct smb2_lease *ls,
+                            bool dir, const char *name, uint32_t share_access,
+                            uint64_t leasekey, uint32_t leasestate)
+{
+       smb2_generic_create_share(io, ls, dir, name, NTCREATEX_DISP_OPEN_IF,
+                                 share_access, SMB2_OPLOCK_LEVEL_LEASE,
+                                 leasekey, leasestate);
+}
+
+void smb2_lease_create(struct smb2_create *io, struct smb2_lease *ls,
+                      bool dir, const char *name, uint64_t leasekey,
+                      uint32_t leasestate)
+{
+       smb2_lease_create_share(io, ls, dir, name,
+                               smb2_util_share_access("RWD"),
+                               leasekey, leasestate);
+}
+
+void smb2_oplock_create_share(struct smb2_create *io, const char *name,
+                             uint32_t share_access, uint8_t oplock)
+{
+       smb2_generic_create_share(io, NULL, false, name, NTCREATEX_DISP_OPEN_IF,
+                                 share_access, oplock, 0, 0);
+}
+void smb2_oplock_create(struct smb2_create *io, const char *name, uint8_t oplock)
+{
+       smb2_oplock_create_share(io, name, smb2_util_share_access("RWD"),
+                                oplock);
+}
+