s4-loadparm: 2nd half of lp_ to lpcfg_ conversion
[nivanova/samba-autobuild/.git] / source4 / torture / basic / denytest.c
index 7709ccebcae38a3debe7ac74fe85ddeed5e942af..174a1b2d6cbd3a4f2a21b9b88b75ec8650b3c04d 100644 (file)
 */
 
 #include "includes.h"
-#include "torture/torture.h"
 #include "system/filesys.h"
-#include "libcli/raw/libcliraw.h"
 #include "libcli/libcli.h"
+#include "libcli/security/security.h"
 #include "torture/util.h"
+#include "cxd_known.h"
 
 extern int torture_failures;
 
@@ -1399,7 +1399,7 @@ static const struct {
 };
 
 
-static void progress_bar(struct torture_context *tctx, uint_t i, uint_t total)
+static void progress_bar(struct torture_context *tctx, unsigned int i, unsigned int total)
 {
        if (torture_setting_bool(tctx, "progress", true)) {
                torture_comment(tctx, "%5d/%5d\r", i, total);
@@ -1415,7 +1415,7 @@ bool torture_denytest1(struct torture_context *tctx,
 {
        int fnum1, fnum2;
        int i;
-       BOOL correct = True;
+       bool correct = true;
        struct timeval tv, tv_start;
        const char *fnames[2] = {"\\denytest1.dat", "\\denytest1.exe"};
        int failures=0;
@@ -1429,7 +1429,7 @@ bool torture_denytest1(struct torture_context *tctx,
                smbcli_close(cli1->tree, fnum1);
        }
 
-       torture_comment(tctx, "testing %d entries\n", (int)ARRAY_SIZE(denytable1));
+       torture_comment(tctx, "Testing %d entries\n", (int)ARRAY_SIZE(denytable1));
 
        GetTimeOfDay(&tv_start);
 
@@ -1439,6 +1439,16 @@ bool torture_denytest1(struct torture_context *tctx,
 
                progress_bar(tctx, i, ARRAY_SIZE(denytable1));
 
+               if (!torture_setting_bool(tctx, "deny_fcb_support", true) &&
+                   (denytable1[i].deny1 == DENY_FCB ||
+                       denytable1[i].deny2 == DENY_FCB))
+                       continue;
+
+               if (!torture_setting_bool(tctx, "deny_dos_support", true) &&
+                   (denytable1[i].deny1 == DENY_DOS ||
+                       denytable1[i].deny2 == DENY_DOS))
+                       continue;
+
                fnum1 = smbcli_open(cli1->tree, fname, 
                                 denytable1[i].mode1,
                                 denytable1[i].deny1);
@@ -1461,7 +1471,7 @@ bool torture_denytest1(struct torture_context *tctx,
                        }
                }
 
-               if (torture_setting_bool(tctx, "showall", False) || 
+               if (torture_setting_bool(tctx, "showall", false) || 
                        res != denytable1[i].result) {
                        int64_t tdif;
                        GetTimeOfDay(&tv);
@@ -1479,7 +1489,7 @@ bool torture_denytest1(struct torture_context *tctx,
                }
 
                if (res != denytable1[i].result) {
-                       correct = False;
+                       correct = false;
                        CHECK_MAX_FAILURES(failed);
                }
 
@@ -1506,7 +1516,7 @@ bool torture_denytest2(struct torture_context *tctx,
 {
        int fnum1, fnum2;
        int i;
-       BOOL correct = True;
+       bool correct = true;
        const char *fnames[2] = {"\\denytest2.dat", "\\denytest2.exe"};
        struct timeval tv, tv_start;
        int failures=0;
@@ -1526,6 +1536,16 @@ bool torture_denytest2(struct torture_context *tctx,
 
                progress_bar(tctx, i, ARRAY_SIZE(denytable1));
 
+               if (!torture_setting_bool(tctx, "deny_fcb_support", true) &&
+                   (denytable1[i].deny1 == DENY_FCB ||
+                       denytable1[i].deny2 == DENY_FCB))
+                       continue;
+
+               if (!torture_setting_bool(tctx, "deny_dos_support", true) &&
+                   (denytable1[i].deny1 == DENY_DOS ||
+                       denytable1[i].deny2 == DENY_DOS))
+                       continue;
+
                fnum1 = smbcli_open(cli1->tree, fname, 
                                 denytable2[i].mode1,
                                 denytable2[i].deny1);
@@ -1548,7 +1568,7 @@ bool torture_denytest2(struct torture_context *tctx,
                        }
                }
 
-               if (torture_setting_bool(tctx, "showall", False) || 
+               if (torture_setting_bool(tctx, "showall", false) || 
                        res != denytable2[i].result) {
                        int64_t tdif;
                        GetTimeOfDay(&tv);
@@ -1566,7 +1586,7 @@ bool torture_denytest2(struct torture_context *tctx,
                }
 
                if (res != denytable2[i].result) {
-                       correct = False;
+                       correct = false;
                        CHECK_MAX_FAILURES(failed);
                }
 
@@ -1616,7 +1636,7 @@ bool torture_denytest3(struct torture_context *tctx,
        smbcli_unlink(cli1->tree, fname);
        torture_comment(tctx, "fnum1=%d fnum2=%d\n", fnum1, fnum2);
 
-       return True;
+       return true;
 }
 
 struct bit_value {
@@ -1658,7 +1678,7 @@ static const char *bit_string(TALLOC_CTX *mem_ctx, const struct bit_value *bv, i
   determine if two opens conflict
 */
 static NTSTATUS predict_share_conflict(uint32_t sa1, uint32_t am1, uint32_t sa2, uint32_t am2,
-                                      BOOL read_for_execute, enum deny_result *res)
+                                      bool read_for_execute, enum deny_result *res)
 {
 #define CHECK_MASK(am, sa, right, share) do { \
        if (((am) & (right)) && !((sa) & (share))) { \
@@ -1721,8 +1741,9 @@ static NTSTATUS predict_share_conflict(uint32_t sa1, uint32_t am1, uint32_t sa2,
 /*
   a denytest for ntcreatex
  */
-static BOOL torture_ntdenytest(struct torture_context *tctx, 
-                                                          struct smbcli_state *cli1, struct smbcli_state *cli2, int client)
+static bool torture_ntdenytest(struct torture_context *tctx, 
+                              struct smbcli_state *cli1,
+                              struct smbcli_state *cli2, int client)
 {
        const struct bit_value share_access_bits[] = {
                { NTCREATEX_SHARE_ACCESS_READ,   "S_R" },
@@ -1741,7 +1762,7 @@ static BOOL torture_ntdenytest(struct torture_context *tctx,
        };
        int fnum1;
        int i;
-       BOOL correct = True;
+       bool correct = true;
        struct timeval tv, tv_start;
        const char *fname;
        int nbits1 = ARRAY_SIZE(share_access_bits);
@@ -1765,7 +1786,7 @@ static BOOL torture_ntdenytest(struct torture_context *tctx,
        GetTimeOfDay(&tv_start);
 
        io1.ntcreatex.level = RAW_OPEN_NTCREATEX;
-       io1.ntcreatex.in.root_fid = 0;
+       io1.ntcreatex.in.root_fid.fnum = 0;
        io1.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
        io1.ntcreatex.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
        io1.ntcreatex.in.file_attr = 0;
@@ -1776,7 +1797,7 @@ static BOOL torture_ntdenytest(struct torture_context *tctx,
        io1.ntcreatex.in.fname = fname;
        io2 = io1;
 
-       torture_comment(tctx, "testing %d entries on %s\n", torture_numops, fname);
+       torture_comment(tctx, "Testing %d entries on %s\n", torture_numops, fname);
 
        for (i=0;i<torture_numops;i++) {
                NTSTATUS status1, status2, status2_p;
@@ -1787,7 +1808,7 @@ static BOOL torture_ntdenytest(struct torture_context *tctx,
                int b_am1 = random() & ((1<<nbits2)-1);
                int b_sa2 = random() & ((1<<nbits1)-1);
                int b_am2 = random() & ((1<<nbits2)-1);
-               BOOL read_for_execute;
+               bool read_for_execute;
 
                progress_bar(tctx, i, torture_numops);
                
@@ -1801,9 +1822,9 @@ static BOOL torture_ntdenytest(struct torture_context *tctx,
                status2 = smb_raw_open(cli2->tree, mem_ctx, &io2);
 
                if (random() % 2 == 0) {
-                       read_for_execute = True;
+                       read_for_execute = true;
                } else {
-                       read_for_execute = False;
+                       read_for_execute = false;
                }
                
                if (!NT_STATUS_IS_OK(status1)) {
@@ -1853,7 +1874,7 @@ static BOOL torture_ntdenytest(struct torture_context *tctx,
                GetTimeOfDay(&tv);
                tdif = usec_time_diff(&tv, &tv_start);
                tdif /= 1000;
-               if (torture_setting_bool(tctx, "showall", False) || 
+               if (torture_setting_bool(tctx, "showall", false) || 
                    !NT_STATUS_EQUAL(status2, status2_p) ||
                    res != res2) {
                        torture_comment(tctx, "\n%-20s %-70s\n%-20s %-70s %4s %4s  %s/%s\n",
@@ -1871,7 +1892,7 @@ static BOOL torture_ntdenytest(struct torture_context *tctx,
                if (res != res2 ||
                    !NT_STATUS_EQUAL(status2, status2_p)) {
                        CHECK_MAX_FAILURES(failed);
-                       correct = False;
+                       correct = false;
                }
                
                talloc_free(mem_ctx);
@@ -1911,20 +1932,30 @@ bool torture_ntdenytest2(struct torture_context *torture,
        return torture_ntdenytest(torture, cli1, cli2, 0);
 }
 
+#define COMPARE_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; \
+               failed = true; \
+       }} while (0)
 
 #define CHECK_STATUS(status, correct) do { \
        if (!NT_STATUS_EQUAL(status, correct)) { \
-               torture_comment(tctx, "(%s) Incorrect status %s - should be %s\n", \
+               torture_result(tctx, TORTURE_FAIL, \
+                       "(%s) Incorrect status %s - should be %s\n", \
                       __location__, nt_errstr(status), nt_errstr(correct)); \
-               ret = False; \
+               ret = false; \
                goto done; \
        }} while (0)
 
 #define CHECK_VAL(v, correct) do { \
        if ((v) != (correct)) { \
-               torture_comment(tctx, "(%s) wrong value for %s  0x%x - should be 0x%x\n", \
+               torture_result(tctx, TORTURE_FAIL, \
+                     "(%s) wrong value for %s  0x%x - should be 0x%x\n", \
                       __location__, #v, (int)(v), (int)correct); \
-               ret = False; \
+               ret = false; \
        }} while (0)
 
 /*
@@ -1938,7 +1969,7 @@ bool torture_denydos_sharing(struct torture_context *tctx,
        const char *fname = "\\torture_denydos.txt";
        NTSTATUS status;
        int fnum1 = -1, fnum2 = -1;
-       BOOL ret = True;
+       bool ret = true;
        union smb_setfileinfo sfinfo;
        TALLOC_CTX *mem_ctx;
 
@@ -2030,4 +2061,737 @@ done:
        return ret;
 }
 
+#define CXD_MATCHES(_cxd, i)                                            \
+       ((cxd_known[i].cxd_test == (_cxd)->cxd_test) &&                 \
+        (cxd_known[i].cxd_flags == (_cxd)->cxd_flags) &&               \
+        (cxd_known[i].cxd_access1 == (_cxd)->cxd_access1) &&           \
+        (cxd_known[i].cxd_sharemode1 == (_cxd)->cxd_sharemode1) &&     \
+        (cxd_known[i].cxd_access2 == (_cxd)->cxd_access2) &&           \
+        (cxd_known[i].cxd_sharemode2 == (_cxd)->cxd_sharemode2))
+
+static int cxd_find_known(struct createx_data *cxd)
+{
+       static int i = -1;
+
+       /* Optimization for tests which we don't have results saved for. */
+       if ((cxd->cxd_test == CXD_TEST_CREATEX_ACCESS_EXHAUSTIVE) ||
+           (cxd->cxd_test == CXD_TEST_CREATEX_SHAREMODE_EXTENDED))
+               return -1;
+
+       /* Optimization: If our cxd_known table is too large, it hurts test
+        * performance to search through the entire table each time. If the
+        * caller can pass in the previous result, we can try the next entry.
+        * This works if results are taken directly from the same code. */
+       i++;
+       if ((i >= 0) && (i < sizeof(cxd_known) / sizeof(cxd_known[0])) &&
+           CXD_MATCHES(cxd, i))
+               return i;
+
+       for (i = 0; i < (sizeof(cxd_known) / sizeof(cxd_known[0])); i++) {
+               if (CXD_MATCHES(cxd, i))
+                       return i;
+       }
+
+       return -1;
+}
+
+#define CREATEX_NAME "\\createx_dir"
+
+static bool createx_make_dir(struct torture_context *tctx,
+    struct smbcli_tree *tree, TALLOC_CTX *mem_ctx, const char *fname)
+{
+       bool ret = true;
+       NTSTATUS status;
+
+       status = smbcli_mkdir(tree, fname);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+ done:
+       return ret;
+}
+
+static bool createx_make_file(struct torture_context *tctx,
+    struct smbcli_tree *tree, TALLOC_CTX *mem_ctx, const char *fname)
+{
+       union smb_open open_parms;
+       bool ret = true;
+       NTSTATUS status;
+
+       ZERO_STRUCT(open_parms);
+       open_parms.generic.level = RAW_OPEN_NTCREATEX;
+       open_parms.ntcreatex.in.flags = 0;
+       open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+       open_parms.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+       open_parms.ntcreatex.in.share_access = 0;
+       open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+       open_parms.ntcreatex.in.create_options = 0;
+       open_parms.ntcreatex.in.fname = fname;
+
+       status = smb_raw_open(tree, mem_ctx, &open_parms);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       status = smbcli_close(tree, open_parms.ntcreatex.out.file.fnum);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+ done:
+       return ret;
+}
+
+static void createx_fill_dir(union smb_open *open_parms, int accessmode,
+    int sharemode, const char *fname)
+{
+       ZERO_STRUCTP(open_parms);
+       open_parms->generic.level = RAW_OPEN_NTCREATEX;
+       open_parms->ntcreatex.in.flags = 0;
+       open_parms->ntcreatex.in.access_mask = accessmode;
+       open_parms->ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
+       open_parms->ntcreatex.in.share_access = sharemode;
+       open_parms->ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+       open_parms->ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+       open_parms->ntcreatex.in.fname = fname;
+}
+
+static void createx_fill_file(union smb_open *open_parms, int accessmode,
+    int sharemode, const char *fname)
+{
+       ZERO_STRUCTP(open_parms);
+       open_parms->generic.level = RAW_OPEN_NTCREATEX;
+       open_parms->ntcreatex.in.flags = 0;
+       open_parms->ntcreatex.in.access_mask = accessmode;
+       open_parms->ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+       open_parms->ntcreatex.in.share_access = sharemode;
+       open_parms->ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+       open_parms->ntcreatex.in.create_options = 0;
+       open_parms->ntcreatex.in.fname = fname;
+       open_parms->ntcreatex.in.root_fid.fnum = 0;
+}
+
+static int data_file_fd = -1;
+
+#define KNOWN   "known"
+#define CHILD   "child"
+static bool createx_test_dir(struct torture_context *tctx,
+    struct smbcli_tree *tree, int fnum, TALLOC_CTX *mem_ctx, NTSTATUS *result)
+{
+       bool ret = true;
+       NTSTATUS status;
+       union smb_open open_parms;
+
+       /* bypass original handle to guarantee creation */
+       ZERO_STRUCT(open_parms);
+       open_parms.generic.level = RAW_OPEN_NTCREATEX;
+       open_parms.ntcreatex.in.flags = 0;
+       open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+       open_parms.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+       open_parms.ntcreatex.in.share_access = 0;
+       open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+       open_parms.ntcreatex.in.create_options = 0;
+       open_parms.ntcreatex.in.fname = CREATEX_NAME "\\" KNOWN;
+
+       status = smb_raw_open(tree, mem_ctx, &open_parms);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       smbcli_close(tree, open_parms.ntcreatex.out.file.fnum);
+
+       result[CXD_DIR_ENUMERATE] = NT_STATUS_OK;
+
+       /* try to create a child */
+       ZERO_STRUCT(open_parms);
+       open_parms.generic.level = RAW_OPEN_NTCREATEX;
+       open_parms.ntcreatex.in.flags = 0;
+       open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+       open_parms.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+       open_parms.ntcreatex.in.share_access = 0;
+       open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+       open_parms.ntcreatex.in.create_options = 0;
+       open_parms.ntcreatex.in.fname = CHILD;
+       open_parms.ntcreatex.in.root_fid.fnum = fnum;
+
+       result[CXD_DIR_CREATE_CHILD] =
+           smb_raw_open(tree, mem_ctx, &open_parms);
+       smbcli_close(tree, open_parms.ntcreatex.out.file.fnum);
+
+       /* try to traverse dir to known good file */
+       ZERO_STRUCT(open_parms);
+       open_parms.generic.level = RAW_OPEN_NTCREATEX;
+       open_parms.ntcreatex.in.flags = 0;
+       open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+       open_parms.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+       open_parms.ntcreatex.in.share_access = 0;
+       open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+       open_parms.ntcreatex.in.create_options = 0;
+       open_parms.ntcreatex.in.fname = KNOWN;
+       open_parms.ntcreatex.in.root_fid.fnum = fnum;
+
+       result[CXD_DIR_TRAVERSE] =
+           smb_raw_open(tree, mem_ctx, &open_parms);
+
+
+       smbcli_close(tree, open_parms.ntcreatex.out.file.fnum);
+       smbcli_unlink(tree, CREATEX_NAME "\\" KNOWN);
+       smbcli_unlink(tree, CREATEX_NAME "\\" CHILD);
+
+ done:
+       return ret;
+}
+
+static bool createx_test_file(struct torture_context *tctx,
+    struct smbcli_tree *tree, int fnum, TALLOC_CTX *mem_ctx, NTSTATUS *result)
+{
+       union smb_read rd;
+       union smb_write wr;
+       char buf[256] = "";
+
+       memset(&rd, 0, sizeof(rd));
+       rd.readx.level = RAW_READ_READX;
+       rd.readx.in.file.fnum = fnum;
+       rd.readx.in.mincnt = sizeof(buf);
+       rd.readx.in.maxcnt = sizeof(buf);
+       rd.readx.out.data = (uint8_t *)buf;
+
+       result[CXD_FILE_READ] = smb_raw_read(tree, &rd);
+
+       memset(&wr, 0, sizeof(wr));
+       wr.writex.level = RAW_WRITE_WRITEX;
+       wr.writex.in.file.fnum = fnum;
+       wr.writex.in.count = sizeof(buf);
+       wr.writex.in.data = (uint8_t *)buf;
+
+       result[CXD_FILE_WRITE] = smb_raw_write(tree, &wr);
+
+       memset(&rd, 0, sizeof(rd));
+       rd.readx.level = RAW_READ_READX;
+       rd.readx.in.file.fnum = fnum;
+       rd.readx.in.mincnt = sizeof(buf);
+       rd.readx.in.maxcnt = sizeof(buf);
+       rd.readx.in.read_for_execute = 1;
+       rd.readx.out.data = (uint8_t *)buf;
+
+       result[CXD_FILE_EXECUTE] = smb_raw_read(tree, &rd);
+
+       return true;
+}
+
+/* TODO When redirecting stdout to a file, the progress bar really screws up
+ * the output. Could use a switch "--noprogress", or direct the progress bar to
+ * stderr? No other solution? */
+static void createx_progress_bar(struct torture_context *tctx, unsigned int i,
+    unsigned int total, unsigned int skipped)
+{
+       if (torture_setting_bool(tctx, "progress", true)) {
+               torture_comment(tctx, "%5d/%5d (%d skipped)\r", i, total,
+                   skipped);
+               fflush(stdout);
+       }
+}
+
+static bool torture_createx_specific(struct torture_context *tctx, struct
+    smbcli_state *cli, struct smbcli_state *cli2, TALLOC_CTX *mem_ctx, struct
+    createx_data *cxd, int estimated_count)
+{
+       static int call_count = 1;
+       static int unskipped_call_count = 1;
+       const char *fname = CREATEX_NAME;
+       int fnum = -1, fnum2 = -1, res, i;
+       union smb_open open_parms1, open_parms2;
+       bool ret = true;
+       bool is_dir = cxd->cxd_flags & CXD_FLAGS_DIRECTORY;
+       NTSTATUS *result = &cxd->cxd_result[0];
+       NTSTATUS *result2 = &cxd->cxd_result2[0];
+       bool found = false, failed = false;
+
+       bool (*make_func)(struct torture_context *,
+           struct smbcli_tree *, TALLOC_CTX *, const char *);
+       void (*fill_func)(union smb_open *, int, int, const char *);
+       bool (*test_func)(struct torture_context *,
+           struct smbcli_tree *, int, TALLOC_CTX *, NTSTATUS *);
+       NTSTATUS (*destroy_func)(struct smbcli_tree *, const char *);
+
+       if (is_dir) {
+               make_func = createx_make_dir;
+               fill_func = createx_fill_dir;
+               test_func = createx_test_dir;
+               destroy_func = smbcli_rmdir;
+       } else {
+               make_func = createx_make_file;
+               fill_func = createx_fill_file;
+               test_func = createx_test_file;
+               destroy_func = smbcli_unlink;
+       }
+
+       /* Skip all SACL related tests. */
+       if ((!torture_setting_bool(tctx, "sacl_support", true)) &&
+           ((cxd->cxd_access1 & SEC_FLAG_SYSTEM_SECURITY) ||
+            (cxd->cxd_access2 & SEC_FLAG_SYSTEM_SECURITY)))
+               goto done;
+
+       if (cxd->cxd_flags & CXD_FLAGS_MAKE_BEFORE_CREATEX) {
+               ret = make_func(tctx, cli->tree, mem_ctx, fname);
+               if (!ret) {
+                       torture_result(tctx, TORTURE_FAIL,
+                               "Initial creation failed\n");
+                       goto done;
+               }
+       }
+
+       /* Initialize. */
+       fill_func(&open_parms1, cxd->cxd_access1, cxd->cxd_sharemode1, fname);
+
+       if (cxd->cxd_test == CXD_TEST_CREATEX_SHAREMODE) {
+               fill_func(&open_parms2, cxd->cxd_access2, cxd->cxd_sharemode2,
+                   fname);
+       }
+
+       for (i = CXD_CREATEX + 1; i < CXD_MAX; i++) {
+               result[i] = NT_STATUS_UNSUCCESSFUL;
+               result2[i] = NT_STATUS_UNSUCCESSFUL;
+       }
+
+       /* Perform open(s). */
+       result[CXD_CREATEX] = smb_raw_open(cli->tree, mem_ctx, &open_parms1);
+       if (NT_STATUS_IS_OK(result[CXD_CREATEX])) {
+               fnum = open_parms1.ntcreatex.out.file.fnum;
+               ret = test_func(tctx, cli->tree, fnum, mem_ctx, result);
+               smbcli_close(cli->tree, fnum);
+       }
+
+       if (cxd->cxd_test == CXD_TEST_CREATEX_SHAREMODE) {
+               result2[CXD_CREATEX] = smb_raw_open(cli2->tree, mem_ctx,
+                   &open_parms2);
+               if (NT_STATUS_IS_OK(result2[CXD_CREATEX])) {
+                       fnum2 = open_parms2.ntcreatex.out.file.fnum;
+                       ret = test_func(tctx, cli2->tree, fnum2, mem_ctx,
+                           result2);
+                       smbcli_close(cli2->tree, fnum2);
+               }
+       }
+
+       if (data_file_fd >= 0) {
+               found = true;
+               res = write(data_file_fd, &cxd, sizeof(cxd));
+               if (res != sizeof(cxd)) {
+                       torture_result(tctx, TORTURE_FAIL,
+                               "(%s): write failed: %s!",
+                               __location__, strerror(errno));
+                       ret = false;
+               }
+       } else if ((res = cxd_find_known(cxd)) >= 0) {
+               found = true;
+               for (i = 0; i < CXD_MAX; i++) {
+                       /* Note: COMPARE_STATUS will set the "failed" bool. */
+                       COMPARE_STATUS(result[i], cxd_known[res].cxd_result[i]);
+                       if (i == 0 && !NT_STATUS_IS_OK(result[i]))
+                               break;
+
+                       if (cxd->cxd_test == CXD_TEST_CREATEX_SHAREMODE) {
+                               COMPARE_STATUS(result2[i],
+                                   cxd_known[res].cxd_result2[i]);
+                               if (i == 0 && !NT_STATUS_IS_OK(result2[i]))
+                                       break;
+                       }
+               }
+       }
+
+       /* We print if its not in the "cxd_known" list or if we fail. */
+       if (!found || failed) {
+               torture_comment(tctx,
+                   "  { .cxd_test = %d, .cxd_flags = %#3x, "
+                   ".cxd_access1 = %#10x, .cxd_sharemode1=%1x, "
+                   ".cxd_access2=%#10x, .cxd_sharemode2=%1x, "
+                   ".cxd_result = { ", cxd->cxd_test, cxd->cxd_flags,
+                   cxd->cxd_access1, cxd->cxd_sharemode1, cxd->cxd_access2,
+                   cxd->cxd_sharemode2);
+               for (i = 0; i < CXD_MAX; i++) {
+                       torture_comment(tctx, "%s, ", nt_errstr(result[i]));
+                       if (i == 0 && !NT_STATUS_IS_OK(result[i]))
+                               break;
+               }
+               torture_comment(tctx, "}");
+               if (cxd->cxd_test == CXD_TEST_CREATEX_SHAREMODE) {
+                       torture_comment(tctx, ", .cxd_result2 = { ");
+                       for (i = 0; i < CXD_MAX; i++) {
+                               torture_comment(tctx, "%s, ",
+                                               nt_errstr(result2[i]));
+                               if (i == 0 && !NT_STATUS_IS_OK(result2[i]))
+                                       break;
+                       }
+                       torture_comment(tctx, "}");
+               }
+               torture_comment(tctx, "}, \n");
+       } else {
+               createx_progress_bar(tctx, call_count, estimated_count,
+                   call_count - unskipped_call_count);
+       }
+       /* Count tests that we didn't skip. */
+       unskipped_call_count++;
+ done:
+       call_count++;
+
+       destroy_func(cli->tree, fname);
+       return ret;
+}
+
+uint32_t sec_access_bit_groups[] = {
+       SEC_RIGHTS_FILE_READ,
+       SEC_RIGHTS_FILE_WRITE,
+       SEC_RIGHTS_FILE_EXECUTE
+};
+#define NUM_ACCESS_GROUPS     (sizeof(sec_access_bit_groups) / sizeof(uint32_t))
+#define ACCESS_GROUPS_COUNT   ((1 << NUM_ACCESS_GROUPS))
+#define BITSINBYTE 8
+
+/* Note: See NTCREATEX_SHARE_ACCESS_{NONE,READ,WRITE,DELETE} for share mode
+ * declarations. */
+#define NUM_SHAREMODE_PERMUTATIONS 8
+
+/**
+ * NTCREATEX and SHARE MODE test.
+ *
+ * Open with combinations of (access_mode, share_mode).
+ *  - Check status
+ * Open 2nd time with combination of (access_mode2, share_mode2).
+ *  - Check status
+ * Perform operations to verify?
+ *  - Read
+ *  - Write
+ *  - Delete
+ */
+bool torture_createx_sharemodes(struct torture_context *tctx,
+                               struct smbcli_state *cli,
+                               struct smbcli_state *cli2,
+                               bool dir,
+                               bool extended)
+{
+       TALLOC_CTX *mem_ctx;
+       bool ret = true;
+       int i, j, est;
+       int gp1, gp2; /* group permuters */
+       struct createx_data cxd = {0};
+       int num_access_bits1 = sizeof(cxd.cxd_access1) * BITSINBYTE;
+       int num_access_bits2 = sizeof(cxd.cxd_access2) * BITSINBYTE;
+
+       mem_ctx = talloc_init("createx_sharemodes");
+       if (!mem_ctx)
+               return false;
+
+       if (!torture_setting_bool(tctx, "sacl_support", true))
+               torture_warning(tctx, "Skipping SACL related tests!\n");
+
+       cxd.cxd_test = extended ? CXD_TEST_CREATEX_SHAREMODE_EXTENDED :
+           CXD_TEST_CREATEX_SHAREMODE;
+       cxd.cxd_flags = dir ? CXD_FLAGS_DIRECTORY: 0;
+
+       /* HACK for progress bar: figure out estimated count. */
+       est = (NUM_SHAREMODE_PERMUTATIONS * NUM_SHAREMODE_PERMUTATIONS) *
+           ((ACCESS_GROUPS_COUNT * ACCESS_GROUPS_COUNT) +
+            (extended ? num_access_bits1 * num_access_bits2 : 0));
+
+       /* Blank slate. */
+       smbcli_deltree(cli->tree, CREATEX_NAME);
+       smbcli_unlink(cli->tree, CREATEX_NAME);
+
+       /* Choose 2 random share modes. */
+       for (cxd.cxd_sharemode1 = 0;
+            cxd.cxd_sharemode1 < NUM_SHAREMODE_PERMUTATIONS;
+            cxd.cxd_sharemode1++) {
+               for (cxd.cxd_sharemode2 = 0;
+                    cxd.cxd_sharemode2 < NUM_SHAREMODE_PERMUTATIONS;
+                    cxd.cxd_sharemode2++) {
+
+                       /* Permutate through our access_bit_groups. */
+                       for (gp1 = 0; gp1 < ACCESS_GROUPS_COUNT; gp1++) {
+                               for (gp2 = 0; gp2 < ACCESS_GROUPS_COUNT; gp2++)
+                               {
+                                       cxd.cxd_access1 = cxd.cxd_access2 = 0;
+
+                                       for (i = 0; i < NUM_ACCESS_GROUPS; i++)
+                                       {
+                                               cxd.cxd_access1 |=
+                                                   (gp1 & (1 << i)) ?
+                                                   sec_access_bit_groups[i]:0;
+                                               cxd.cxd_access2 |=
+                                                   (gp2 & (1 << i)) ?
+                                                   sec_access_bit_groups[i]:0;
+                                       }
+
+                                       torture_createx_specific(tctx, cli,
+                                          cli2, mem_ctx, &cxd, est);
+                               }
+                       }
+
+                       /* Only do the single access bits on an extended run. */
+                       if (!extended)
+                               continue;
+
+                       for (i = 0; i < num_access_bits1; i++) {
+                               for (j = 0; j < num_access_bits2; j++) {
+                                       cxd.cxd_access1 = 1ull << i;
+                                       cxd.cxd_access2 = 1ull << j;
+
+                                       torture_createx_specific(tctx, cli,
+                                           cli2, mem_ctx, &cxd, est);
+                               }
+                       }
+               }
+       }
+       torture_comment(tctx, "\n");
+
+       talloc_free(mem_ctx);
+       return ret;
+}
+
+bool torture_createx_sharemodes_file(struct torture_context *tctx,
+    struct smbcli_state *cli, struct smbcli_state *cli2)
+{
+       return torture_createx_sharemodes(tctx, cli, cli2, false, false);
+}
+
+bool torture_createx_sharemodes_dir(struct torture_context *tctx,
+    struct smbcli_state *cli, struct smbcli_state *cli2)
+{
+       return torture_createx_sharemodes(tctx, cli, cli2, true, false);
+}
+
+bool torture_createx_access(struct torture_context *tctx,
+    struct smbcli_state *cli)
+{
+       TALLOC_CTX *mem_ctx;
+       bool ret = true;
+       uint32_t group_permuter;
+       uint32_t i;
+       struct createx_data cxd = {0};
+       int est;
+       int num_access_bits = sizeof(cxd.cxd_access1) * BITSINBYTE;
+
+       mem_ctx = talloc_init("createx_dir");
+       if (!mem_ctx)
+               return false;
+
+       if (!torture_setting_bool(tctx, "sacl_support", true))
+               torture_warning(tctx, "Skipping SACL related tests!\n");
+
+       cxd.cxd_test = CXD_TEST_CREATEX_ACCESS;
+
+       /* HACK for progress bar: figure out estimated count. */
+       est = CXD_FLAGS_COUNT * (ACCESS_GROUPS_COUNT + (num_access_bits * 3));
+
+       /* Blank slate. */
+       smbcli_deltree(cli->tree, CREATEX_NAME);
+       smbcli_unlink(cli->tree, CREATEX_NAME);
+
+       for (cxd.cxd_flags = 0; cxd.cxd_flags <= CXD_FLAGS_MASK;
+            cxd.cxd_flags++) {
+               /**
+                * This implements a basic permutation of all elements of
+                * 'bit_group'.  group_permuter is a bit field representing
+                * which groups to turn on.
+               */
+               for (group_permuter = 0; group_permuter < (1 <<
+                       NUM_ACCESS_GROUPS); group_permuter++) {
+                       for (i = 0, cxd.cxd_access1 = 0;
+                            i < NUM_ACCESS_GROUPS; i++) {
+                               cxd.cxd_access1 |= (group_permuter & (1 << i))
+                                   ? sec_access_bit_groups[i] : 0;
+                       }
+
+                       torture_createx_specific(tctx, cli, NULL, mem_ctx,
+                           &cxd, est);
+               }
+               for (i = 0; i < num_access_bits; i++) {
+                       /* And now run through the single access bits. */
+                       cxd.cxd_access1 = 1 << i;
+                       torture_createx_specific(tctx, cli, NULL, mem_ctx,
+                           &cxd, est);
+
+                       /* Does SEC_FLAG_MAXIMUM_ALLOWED override? */
+                       cxd.cxd_access1 |= SEC_FLAG_MAXIMUM_ALLOWED;
+                       torture_createx_specific(tctx, cli, NULL, mem_ctx,
+                           &cxd, est);
+
+                       /* What about SEC_FLAG_SYSTEM_SECURITY? */
+                       cxd.cxd_access1 |= SEC_FLAG_SYSTEM_SECURITY;
+                       torture_createx_specific(tctx, cli, NULL, mem_ctx,
+                           &cxd, est);
+               }
+       }
 
+       talloc_free(mem_ctx);
+       return ret;
+}
+
+#define ACCESS_KNOWN_MASK 0xF31F01FFull
+
+bool torture_createx_access_exhaustive(struct torture_context *tctx,
+    struct smbcli_state *cli)
+{
+       char *data_file;
+       TALLOC_CTX *mem_ctx;
+       bool ret = true, first;
+       uint32_t i;
+       struct createx_data cxd = {0};
+
+       mem_ctx = talloc_init("createx_dir");
+       if (!mem_ctx)
+               return false;
+
+       if (!torture_setting_bool(tctx, "sacl_support", true))
+               torture_warning(tctx, "Skipping SACL related tests!\n");
+
+       data_file = getenv("CREATEX_DATA");
+       if (data_file) {
+               data_file_fd = open(data_file, O_WRONLY|O_CREAT|O_TRUNC, 0666);
+               if (data_file_fd < 0) {
+                       torture_result(tctx, TORTURE_FAIL,
+                               "(%s): data file open failedu: %s!",
+                               __location__, strerror(errno));
+                       ret = false;
+                       goto done;
+               }
+       }
+
+       /* Blank slate. */
+       smbcli_deltree(cli->tree, CREATEX_NAME);
+       smbcli_unlink(cli->tree, CREATEX_NAME);
+
+       cxd.cxd_test = CXD_TEST_CREATEX_ACCESS_EXHAUSTIVE;
+
+       for (cxd.cxd_flags = 0; cxd.cxd_flags <= CXD_FLAGS_MASK;
+            cxd.cxd_flags++) {
+               for (i = 0, first = true; (i != 0) || first; first = false,
+                    i = ((i | ~ACCESS_KNOWN_MASK) + 1) & ACCESS_KNOWN_MASK) {
+                       cxd.cxd_access1 = i;
+                       ret = torture_createx_specific(tctx, cli, NULL,
+                           mem_ctx, &cxd, 0);
+                       if (!ret)
+                               break;
+               }
+       }
+
+       close(data_file_fd);
+       data_file_fd = -1;
+
+ done:
+       talloc_free(mem_ctx);
+       return ret;
+}
+
+#define MAXIMUM_ALLOWED_FILE    "torture_maximum_allowed"
+bool torture_maximum_allowed(struct torture_context *tctx,
+    struct smbcli_state *cli)
+{
+       struct security_descriptor *sd, *sd_orig;
+       union smb_open io;
+       static TALLOC_CTX *mem_ctx;
+       int fnum, i;
+       bool ret = true;
+       NTSTATUS status;
+       union smb_fileinfo q;
+       const char *owner_sid;
+       bool has_restore_privilege, has_backup_privilege;
+
+       mem_ctx = talloc_init("torture_maximum_allowed");
+
+       if (!torture_setting_bool(tctx, "sacl_support", true))
+               torture_warning(tctx, "Skipping SACL related tests!\n");
+
+       sd = security_descriptor_dacl_create(mem_ctx,
+           0, NULL, NULL,
+           SID_NT_AUTHENTICATED_USERS,
+           SEC_ACE_TYPE_ACCESS_ALLOWED,
+           SEC_RIGHTS_FILE_READ,
+           0, NULL);
+
+       /* Blank slate */
+       smbcli_unlink(cli->tree, MAXIMUM_ALLOWED_FILE);
+
+       /* create initial file with restrictive SD */
+       memset(&io, 0, sizeof(io));
+       io.generic.level = RAW_OPEN_NTTRANS_CREATE;
+       io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+       io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+       io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+       io.ntcreatex.in.fname = MAXIMUM_ALLOWED_FILE;
+       io.ntcreatex.in.sec_desc = sd;
+
+       status = smb_raw_open(cli->tree, mem_ctx, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       fnum = io.ntcreatex.out.file.fnum;
+
+       /* the correct answers for this test depends on whether the
+          user has restore privileges. To find that out we first need
+          to know our SID - get it from the owner_sid of the file we
+          just created */
+       q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+       q.query_secdesc.in.file.fnum = fnum;
+       q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+       status = smb_raw_fileinfo(cli->tree, tctx, &q);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       sd_orig = q.query_secdesc.out.sd;
+
+       owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+       status = torture_check_privilege(cli, 
+                                        owner_sid, 
+                                        sec_privilege_name(SEC_PRIV_RESTORE));
+       has_restore_privilege = NT_STATUS_IS_OK(status);
+       torture_comment(tctx, "Checked SEC_PRIV_RESTORE for %s - %s\n", 
+                       owner_sid,
+                       has_restore_privilege?"Yes":"No");
+
+       status = torture_check_privilege(cli, 
+                                        owner_sid, 
+                                        sec_privilege_name(SEC_PRIV_BACKUP));
+       has_backup_privilege = NT_STATUS_IS_OK(status);
+       torture_comment(tctx, "Checked SEC_PRIV_BACKUP for %s - %s\n", 
+                       owner_sid,
+                       has_backup_privilege?"Yes":"No");
+
+       smbcli_close(cli->tree, fnum);
+
+       for (i = 0; i < 32; i++) {
+               uint32_t mask = SEC_FLAG_MAXIMUM_ALLOWED | (1u << i);
+               uint32_t ok_mask = SEC_RIGHTS_FILE_READ | SEC_GENERIC_READ | 
+                       SEC_STD_DELETE | SEC_STD_WRITE_DAC;
+
+               if (has_restore_privilege) {
+                       ok_mask |= SEC_RIGHTS_PRIV_RESTORE;
+               }
+               if (has_backup_privilege) {
+                       ok_mask |= SEC_RIGHTS_PRIV_BACKUP;
+               }
+
+               /* Skip all SACL related tests. */
+               if ((!torture_setting_bool(tctx, "sacl_support", true)) &&
+                   (mask & SEC_FLAG_SYSTEM_SECURITY))
+                       continue;
+
+               memset(&io, 0, sizeof(io));
+               io.generic.level = RAW_OPEN_NTTRANS_CREATE;
+               io.ntcreatex.in.access_mask = mask;
+               io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+               io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+               io.ntcreatex.in.impersonation =
+                   NTCREATEX_IMPERSONATION_ANONYMOUS;
+               io.ntcreatex.in.fname = MAXIMUM_ALLOWED_FILE;
+
+               status = smb_raw_open(cli->tree, mem_ctx, &io);
+               if (mask & ok_mask ||
+                   mask == SEC_FLAG_MAXIMUM_ALLOWED) {
+                       CHECK_STATUS(status, NT_STATUS_OK);
+               } else {
+                       if (mask & SEC_FLAG_SYSTEM_SECURITY) {
+                               CHECK_STATUS(status, NT_STATUS_PRIVILEGE_NOT_HELD);
+                       } else {
+                               CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+                       }
+               }
+
+               fnum = io.ntcreatex.out.file.fnum;
+
+               smbcli_close(cli->tree, fnum);
+       }
+
+ done:
+       smbcli_unlink(cli->tree, MAXIMUM_ALLOWED_FILE);
+       return ret;
+}