libsmb: Move cli_raw_ioctl() to torture3
[samba.git] / source3 / torture / torture.c
index c3d8fb4e30ca09b9b043d86eb02c2d725aec42bb..bfce1c9dcd659df64c6d52b885678b7b082a8565 100644 (file)
@@ -50,6 +50,8 @@
 #include "lib/util/asn1.h"
 #include "lib/param/param.h"
 #include "auth/gensec/gensec.h"
+#include "lib/util/string_wrappers.h"
+#include "source3/lib/substitute.h"
 
 #include <gnutls/gnutls.h>
 #include <gnutls/crypto.h>
@@ -148,10 +150,6 @@ static struct cli_state *open_nbt_connection(void)
                flags |= CLI_FULL_CONNECTION_LEVEL_II_OPLOCKS;
        }
 
-       if (use_kerberos) {
-               flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
-       }
-
        if (force_dos_errors) {
                flags |= CLI_FULL_CONNECTION_FORCE_DOS_ERRORS;
        }
@@ -349,8 +347,7 @@ static bool torture_open_connection_share(struct cli_state **c,
                                           sharename,
                                           "?????",
                                           torture_creds,
-                                          flags,
-                                          signing_state);
+                                          flags);
        if (!NT_STATUS_IS_OK(status)) {
                printf("failed to open share connection: //%s/%s port:%d - %s\n",
                        hostname, sharename, port_to_use, nt_errstr(status));
@@ -456,6 +453,137 @@ bool torture_close_connection(struct cli_state *c)
        return ret;
 }
 
+void torture_conn_set_sockopt(struct cli_state *cli)
+{
+       smbXcli_conn_set_sockopt(cli->conn, sockops);
+}
+
+static NTSTATUS torture_delete_fn(struct file_info *finfo,
+                                 const char *pattern,
+                                 void *state)
+{
+       NTSTATUS status;
+       char *filename = NULL;
+       char *dirname = NULL;
+       char *p = NULL;
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct cli_state *cli = (struct cli_state *)state;
+
+       if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_OK;
+       }
+
+       dirname = talloc_strdup(frame, pattern);
+       if (dirname == NULL) {
+               TALLOC_FREE(frame);
+                return NT_STATUS_NO_MEMORY;
+        }
+        p = strrchr_m(dirname, '\\');
+        if (p != NULL) {
+                /* Remove the terminating '\' */
+                *p = '\0';
+        }
+        if (dirname[0] != '\0') {
+                filename = talloc_asprintf(frame,
+                                           "%s\\%s",
+                                           dirname,
+                                           finfo->name);
+        } else {
+                filename = talloc_asprintf(frame,
+                                           "%s",
+                                           finfo->name);
+        }
+        if (filename == NULL) {
+                TALLOC_FREE(frame);
+                return NT_STATUS_NO_MEMORY;
+        }
+       if (finfo->attr & FILE_ATTRIBUTE_DIRECTORY) {
+               char *subdirname = talloc_asprintf(frame,
+                                                  "%s\\*",
+                                                  filename);
+               if (subdirname == NULL) {
+                       TALLOC_FREE(frame);
+                       return NT_STATUS_NO_MEMORY;
+               }
+               status = cli_list(cli,
+                                 subdirname,
+                                 FILE_ATTRIBUTE_DIRECTORY |
+                                         FILE_ATTRIBUTE_HIDDEN |
+                                         FILE_ATTRIBUTE_SYSTEM,
+                                 torture_delete_fn,
+                                 cli);
+               if (!NT_STATUS_IS_OK(status)) {
+                       printf("torture_delete_fn: cli_list "
+                               "of %s failed (%s)\n",
+                               subdirname,
+                               nt_errstr(status));
+                       TALLOC_FREE(frame);
+                       return status;
+               }
+               status = cli_rmdir(cli, filename);
+       } else {
+               status = cli_unlink(cli,
+                                   filename,
+                                   FILE_ATTRIBUTE_SYSTEM |
+                                       FILE_ATTRIBUTE_HIDDEN);
+       }
+       if (!NT_STATUS_IS_OK(status)) {
+               if (finfo->attr & FILE_ATTRIBUTE_DIRECTORY) {
+                       printf("torture_delete_fn: cli_rmdir"
+                               " of %s failed (%s)\n",
+                               filename,
+                               nt_errstr(status));
+               } else {
+                       printf("torture_delete_fn: cli_unlink"
+                               " of %s failed (%s)\n",
+                               filename,
+                               nt_errstr(status));
+               }
+       }
+       TALLOC_FREE(frame);
+       return status;
+}
+
+void torture_deltree(struct cli_state *cli, const char *dname)
+{
+       char *mask = NULL;
+       NTSTATUS status;
+
+       /* It might be a file */
+       (void)cli_unlink(cli,
+                        dname,
+                        FILE_ATTRIBUTE_SYSTEM |
+                               FILE_ATTRIBUTE_HIDDEN);
+
+       mask = talloc_asprintf(cli,
+                              "%s\\*",
+                              dname);
+       if (mask == NULL) {
+               printf("torture_deltree: talloc_asprintf failed\n");
+               return;
+       }
+
+       status = cli_list(cli,
+                       mask,
+                       FILE_ATTRIBUTE_DIRECTORY |
+                               FILE_ATTRIBUTE_HIDDEN|
+                               FILE_ATTRIBUTE_SYSTEM,
+                       torture_delete_fn,
+                       cli);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("torture_deltree: cli_list of %s failed (%s)\n",
+                       mask,
+                       nt_errstr(status));
+       }
+       TALLOC_FREE(mask);
+       status = cli_rmdir(cli, dname);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("torture_deltree: cli_rmdir of %s failed (%s)\n",
+                       dname,
+                       nt_errstr(status));
+       }
+}
 
 /* check if the server produced the expected dos or nt error code */
 static bool check_both_error(int line, NTSTATUS status,
@@ -528,6 +656,54 @@ static bool check_error(int line, NTSTATUS status,
        return True;
 }
 
+NTSTATUS cli_qpathinfo1(struct cli_state *cli,
+                       const char *fname,
+                       time_t *change_time,
+                       time_t *access_time,
+                       time_t *write_time,
+                       off_t *size,
+                       uint32_t *pattr)
+{
+       int timezone = smb1cli_conn_server_time_zone(cli->conn);
+       time_t (*date_fn)(const void *buf, int serverzone) = NULL;
+       uint8_t *rdata = NULL;
+       uint32_t num_rdata;
+       NTSTATUS status;
+
+       status = cli_qpathinfo(talloc_tos(),
+                              cli,
+                              fname,
+                              SMB_INFO_STANDARD,
+                              22,
+                              CLI_BUFFER_SIZE,
+                              &rdata,
+                              &num_rdata);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+       if (cli->win95) {
+               date_fn = make_unix_date;
+       } else {
+               date_fn = make_unix_date2;
+       }
+
+       if (change_time) {
+               *change_time = date_fn(rdata + 0, timezone);
+       }
+       if (access_time) {
+               *access_time = date_fn(rdata + 4, timezone);
+       }
+       if (write_time) {
+               *write_time = date_fn(rdata + 8, timezone);
+       }
+       if (size) {
+               *size = PULL_LE_U32(rdata, 12);
+       }
+       if (pattr) {
+               *pattr = PULL_LE_U16(rdata, l1_attrFile);
+       }
+       return NT_STATUS_OK;
+}
 
 static bool wait_lock(struct cli_state *c, int fnum, uint32_t offset, uint32_t len)
 {
@@ -1014,21 +1190,6 @@ static bool run_readwritelarge_internal(void)
                correct = False;
        }
 
-#if 0
-       /* ToDo - set allocation. JRA */
-       if(!cli_set_allocation_size(cli1, fnum1, 0)) {
-               printf("set allocation size to zero failed (%s)\n", cli_errstr(&cli1));
-               return False;
-       }
-       if (!cli_qfileinfo_basic(cli1, fnum1, NULL, &fsize, NULL, NULL, NULL,
-                                NULL, NULL)) {
-               printf("qfileinfo failed (%s)\n", cli_errstr(cli1));
-               correct = False;
-       }
-       if (fsize != 0)
-               printf("readwritelarge test 3 (truncate test) succeeded (size = %x)\n", fsize);
-#endif
-
        status = cli_close(cli1, fnum1);
        if (!NT_STATUS_IS_OK(status)) {
                printf("close failed (%s)\n", nt_errstr(status));
@@ -1322,6 +1483,7 @@ static bool run_tcon_test(int dummy)
        uint16_t fnum1;
        uint32_t cnum1, cnum2, cnum3;
        struct smbXcli_tcon *orig_tcon = NULL;
+       char *orig_share = NULL;
        uint16_t vuid1, vuid2;
        char buf[4];
        bool ret = True;
@@ -1353,15 +1515,13 @@ static bool run_tcon_test(int dummy)
                return False;
        }
 
-       orig_tcon = cli_state_save_tcon(cli);
-       if (orig_tcon == NULL) {
-               return false;
-       }
+       cli_state_save_tcon_share(cli, &orig_tcon, &orig_share);
 
        status = cli_tree_connect_creds(cli, share, "?????", torture_creds);
        if (!NT_STATUS_IS_OK(status)) {
                printf("%s refused 2nd tree connect (%s)\n", host,
                       nt_errstr(status));
+               cli_state_restore_tcon_share(cli, orig_tcon, orig_share);
                cli_shutdown(cli);
                return False;
        }
@@ -1414,6 +1574,8 @@ static bool run_tcon_test(int dummy)
        status = cli_close(cli, fnum1);
        if (!NT_STATUS_IS_OK(status)) {
                printf("close failed (%s)\n", nt_errstr(status));
+               cli_state_restore_tcon_share(cli, orig_tcon, orig_share);
+               cli_shutdown(cli);
                return False;
        }
 
@@ -1422,10 +1584,12 @@ static bool run_tcon_test(int dummy)
        status = cli_tdis(cli);
        if (!NT_STATUS_IS_OK(status)) {
                printf("secondary tdis failed (%s)\n", nt_errstr(status));
+               cli_state_restore_tcon_share(cli, orig_tcon, orig_share);
+               cli_shutdown(cli);
                return False;
        }
 
-       cli_state_restore_tcon(cli, orig_tcon);
+       cli_state_restore_tcon_share(cli, orig_tcon, orig_share);
 
        cli_state_set_tid(cli, cnum1);
 
@@ -1542,8 +1706,7 @@ static bool run_tcon_devtype_test(int dummy)
                                           NULL, /* service */
                                           NULL, /* service_type */
                                           torture_creds,
-                                          flags,
-                                          signing_state);
+                                          flags);
 
        if (!NT_STATUS_IS_OK(status)) {
                printf("could not open connection\n");
@@ -3836,8 +3999,15 @@ static bool run_negprot_nowait(int dummy)
        for (i=0;i<50000;i++) {
                struct tevent_req *req;
 
-               req = smbXcli_negprot_send(ev, ev, cli->conn, cli->timeout,
-                                          PROTOCOL_CORE, PROTOCOL_NT1, 0);
+               req = smbXcli_negprot_send(
+                       ev,
+                       ev,
+                       cli->conn,
+                       cli->timeout,
+                       PROTOCOL_CORE,
+                       PROTOCOL_NT1,
+                       0,
+                       NULL);
                if (req == NULL) {
                        TALLOC_FREE(ev);
                        return false;
@@ -3994,9 +4164,9 @@ static bool run_browsetest(int dummy)
 
 static bool check_attributes(struct cli_state *cli,
                                const char *fname,
-                               uint16_t expected_attrs)
+                               uint32_t expected_attrs)
 {
-       uint16_t attrs = 0;
+       uint32_t attrs = 0;
        NTSTATUS status = cli_getatr(cli,
                                fname,
                                &attrs,
@@ -4034,6 +4204,13 @@ static bool run_attrtest(int dummy)
                return False;
        }
 
+       /* Ensure we can't unlink with out-of-range (unknown) attribute. */
+       status = cli_unlink(cli, fname, 0x20000);
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+               correct = false;
+               goto out;
+       }
+
        cli_unlink(cli, fname, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
        cli_openx(cli, fname, 
                        O_RDWR | O_CREAT | O_TRUNC, DENY_NONE, &fnum);
@@ -4054,6 +4231,13 @@ static bool run_attrtest(int dummy)
 
        t2 = t-60*60*24; /* 1 day ago */
 
+       /* Ensure we can't set with out-of-range (unknown) attribute. */
+       status = cli_setatr(cli, fname, 0x20000, t2);
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+               correct = false;
+               goto out;
+       }
+
        status = cli_setatr(cli, fname, 0, t2);
        if (!NT_STATUS_IS_OK(status)) {
                printf("setatr failed (%s)\n", nt_errstr(status));
@@ -4145,7 +4329,7 @@ static bool run_attrtest(int dummy)
                (struct timespec) { .tv_nsec = SAMBA_UTIME_OMIT }, /* access */
                (struct timespec) { .tv_nsec = SAMBA_UTIME_OMIT }, /* write */
                (struct timespec) { .tv_nsec = SAMBA_UTIME_OMIT }, /* change */
-               (uint16_t)-1);
+               (uint32_t)-1);
        if (!NT_STATUS_IS_OK(status)) {
                printf("cli_setpathinfo_ext failed with %s\n",
                        nt_errstr(status));
@@ -4202,6 +4386,50 @@ static bool run_attrtest(int dummy)
        return correct;
 }
 
+static NTSTATUS cli_qfilename(
+       struct cli_state *cli,
+       uint16_t fnum,
+       TALLOC_CTX *mem_ctx,
+       char **_name)
+{
+       uint16_t recv_flags2;
+       uint8_t *rdata;
+       uint32_t num_rdata;
+       NTSTATUS status;
+       char *name = NULL;
+       uint32_t namelen;
+
+       status = cli_qfileinfo(talloc_tos(), cli, fnum,
+                              SMB_QUERY_FILE_NAME_INFO,
+                              4, CLI_BUFFER_SIZE, &recv_flags2,
+                              &rdata, &num_rdata);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       namelen = IVAL(rdata, 0);
+       if (namelen > (num_rdata - 4)) {
+               TALLOC_FREE(rdata);
+               return NT_STATUS_INVALID_NETWORK_RESPONSE;
+       }
+
+       pull_string_talloc(mem_ctx,
+                          (const char *)rdata,
+                          recv_flags2,
+                          &name,
+                          rdata + 4,
+                          namelen,
+                          STR_UNICODE);
+       if (name == NULL) {
+               status = map_nt_error_from_unix(errno);
+               TALLOC_FREE(rdata);
+               return status;
+       }
+
+       *_name = name;
+       TALLOC_FREE(rdata);
+       return NT_STATUS_OK;
+}
 
 /*
   This checks a couple of trans2 calls
@@ -4216,7 +4444,7 @@ static bool run_trans2test(int dummy)
        const char *fname = "\\trans2.tst";
        const char *dname = "\\trans2";
        const char *fname2 = "\\trans2\\trans2.tst";
-       char *pname;
+       char *pname = NULL;
        bool correct = True;
        NTSTATUS status;
        uint32_t fs_attr;
@@ -5666,7 +5894,7 @@ static bool run_deletetest(int dummy)
 
   fail:
        /* FIXME: This will crash if we aborted before cli2 got
-        * intialized, because these functions don't handle
+        * initialized, because these functions don't handle
         * uninitialized connections. */
 
        if (fnum1 != (uint16_t)-1) cli_close(cli1, fnum1);
@@ -5990,71 +6218,6 @@ static bool run_delete_print_test(int dummy)
        return correct;
 }
 
-/*
-  Test wildcard delete.
- */
-static bool run_wild_deletetest(int dummy)
-{
-       struct cli_state *cli = NULL;
-       const char *dname = "\\WTEST";
-       const char *fname = "\\WTEST\\A";
-       const char *wunlink_name = "\\WTEST\\*";
-       uint16_t fnum1 = (uint16_t)-1;
-       bool correct = false;
-       NTSTATUS status;
-
-       printf("starting wildcard delete test\n");
-
-       if (!torture_open_connection(&cli, 0)) {
-               return false;
-       }
-
-       smbXcli_conn_set_sockopt(cli->conn, sockops);
-
-       cli_unlink(cli, fname, 0);
-       cli_rmdir(cli, dname);
-       status = cli_mkdir(cli, dname);
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("mkdir of %s failed %s!\n", dname, nt_errstr(status));
-               goto fail;
-       }
-       status = cli_openx(cli, fname, O_CREAT|O_RDONLY, DENY_NONE, &fnum1);
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("open of %s failed %s!\n", fname, nt_errstr(status));
-               goto fail;
-       }
-       status = cli_close(cli, fnum1);
-       fnum1 = -1;
-
-       /*
-        * Note the unlink attribute-type of zero. This should
-        * map into FILE_ATTRIBUTE_NORMAL at the server even
-        * on a wildcard delete.
-        */
-
-       status = cli_unlink(cli, wunlink_name, 0);
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("unlink of %s failed %s!\n",
-                       wunlink_name, nt_errstr(status));
-               goto fail;
-       }
-
-       printf("finished wildcard delete test\n");
-
-       correct = true;
-
-  fail:
-
-       if (fnum1 != (uint16_t)-1) cli_close(cli, fnum1);
-       cli_unlink(cli, fname, 0);
-       cli_rmdir(cli, dname);
-
-       if (cli && !torture_close_connection(cli)) {
-               correct = false;
-       }
-       return correct;
-}
-
 static bool run_deletetest_ln(int dummy)
 {
        struct cli_state *cli;
@@ -6267,7 +6430,7 @@ static bool run_rename(int dummy)
        const char *fname1 = "\\test1.txt";
        bool correct = True;
        uint16_t fnum1;
-       uint16_t attr;
+       uint32_t attr;
        NTSTATUS status;
 
        printf("starting rename test\n");
@@ -6341,27 +6504,6 @@ static bool run_rename(int dummy)
        }
 
 
-#if 0
-  {
-       uint16_t fnum2;
-
-       if (!NT_STATUS_IS_OK(cli_ntcreate(cli1, fname, 0, DELETE_ACCESS, FILE_ATTRIBUTE_NORMAL,
-                                  FILE_SHARE_NONE, FILE_OVERWRITE_IF, 0, 0, &fnum2, NULL))) {
-               printf("Fourth open failed - %s\n", cli_errstr(cli1));
-               return False;
-       }
-       if (!NT_STATUS_IS_OK(cli_nt_delete_on_close(cli1, fnum2, true))) {
-               printf("[8] setting delete_on_close on file failed !\n");
-               return False;
-       }
-
-       if (!NT_STATUS_IS_OK(cli_close(cli1, fnum2))) {
-               printf("close - 4 failed (%s)\n", cli_errstr(cli1));
-               return False;
-       }
-  }
-#endif
-
        status = cli_rename(cli1, fname, fname1, false);
        if (!NT_STATUS_IS_OK(status)) {
                printf("Third rename failed (SHARE_NONE) - this should have succeeded - %s\n", nt_errstr(status));
@@ -6426,21 +6568,6 @@ static bool run_rename(int dummy)
                printf("Fifth rename succeeded (SHARE_READ | SHARE_WRITE | SHARE_DELETE) (this is correct) - %s\n", nt_errstr(status));
        }
 
-        /*
-         * Now check if the first name still exists ...
-         */
-
-        /* if (!NT_STATUS_OP(cli_ntcreate(cli1, fname, 0, GENERIC_READ_ACCESS, FILE_ATTRIBUTE_NORMAL,
-                                  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                                  FILE_OVERWRITE_IF, 0, 0, &fnum2, NULL))) {
-          printf("Opening original file after rename of open file fails: %s\n",
-              cli_errstr(cli1));
-        }
-        else {
-          printf("Opening original file after rename of open file works ...\n");
-          (void)cli_close(cli1, fnum2);
-          } */
-
         /*--*/
        status = cli_close(cli1, fnum1);
        if (!NT_STATUS_IS_OK(status)) {
@@ -7684,6 +7811,7 @@ static bool run_simple_posix_open_test(int dummy)
        size_t nread;
        const char *fname_windows = "windows_file";
        uint16_t fnum2 = (uint16_t)-1;
+       bool ok;
 
        printf("Starting simple POSIX open test\n");
 
@@ -7952,18 +8080,19 @@ static bool run_simple_posix_open_test(int dummy)
        if (NT_STATUS_IS_OK(status)) {
                printf("POSIX open of %s succeeded (should have failed)\n", sname);
                goto out;
-       } else {
-               if (!check_both_error(__LINE__, status, ERRDOS, ERRbadpath,
-                               NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
-                       printf("POSIX open of %s should have failed "
-                               "with NT_STATUS_OBJECT_PATH_NOT_FOUND, "
-                               "failed with %s instead.\n",
-                               sname, nt_errstr(status));
-                       goto out;
-               }
+       }
+       ok = check_both_error(
+               __LINE__, status, ERRDOS, ERRbadpath,
+               NT_STATUS_OBJECT_NAME_NOT_FOUND);
+       if (!ok) {
+               printf("POSIX open of %s should have failed "
+                      "with NT_STATUS_OBJECT_NAME_NOT_FOUND, "
+                      "failed with %s instead.\n",
+                      sname, nt_errstr(status));
+               goto out;
        }
 
-       status = cli_posix_readlink(cli1, sname, talloc_tos(), &target);
+       status = cli_readlink(cli1, sname, talloc_tos(), &target, NULL, NULL);
        if (!NT_STATUS_IS_OK(status)) {
                printf("POSIX readlink on %s failed (%s)\n", sname, nt_errstr(status));
                goto out;
@@ -8083,7 +8212,6 @@ static bool run_acl_symlink_test(int dummy)
        char *posix_acl_sym = NULL;
        size_t posix_acl_len_sym = 0;
        struct security_descriptor *sd = NULL;
-       struct security_descriptor *sd_sym = NULL;
        TALLOC_CTX *frame = NULL;
 
        frame = talloc_stackframe();
@@ -8188,7 +8316,7 @@ static bool run_acl_symlink_test(int dummy)
                goto out;
        }
 
-       /* Open a handle on the symlink. */
+       /* Try a stat-open on the symlink, should also fail. */
        status = cli_ntcreate(cli,
                        sname,
                        0,
@@ -8201,23 +8329,8 @@ static bool run_acl_symlink_test(int dummy)
                        &fnum,
                        NULL);
 
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("cli_posix_open of %s failed (%s)\n",
-                       sname,
-                       nt_errstr(status));
-               goto out;
-       }
-
-       /* Get the Windows ACL on the symlink handle. Should fail */
-       status = cli_query_secdesc(cli,
-                               fnum,
-                               frame,
-                               &sd_sym);
-
-       if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
-               printf("cli_query_secdesc on a symlink gave %s. "
-                       "Should be NT_STATUS_ACCESS_DENIED.\n",
-                       nt_errstr(status));
+       if (NT_STATUS_IS_OK(status)) {
+               printf("Stat-open of symlink succeeded (should fail)\n");
                goto out;
        }
 
@@ -8235,19 +8348,6 @@ static bool run_acl_symlink_test(int dummy)
                goto out;
        }
 
-       /* Set the Windows ACL on the symlink handle. Should fail */
-       status = cli_set_security_descriptor(cli,
-                               fnum,
-                               SECINFO_DACL,
-                               sd);
-
-       if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
-               printf("cli_query_secdesc on a symlink gave %s. "
-                       "Should be NT_STATUS_ACCESS_DENIED.\n",
-                       nt_errstr(status));
-               goto out;
-       }
-
        /* Set the POSIX ACL on the symlink pathname. Should fail. */
        status = cli_posix_setacl(cli,
                                sname,
@@ -8928,6 +9028,11 @@ static bool run_posix_blocking_lock(int dummy)
                return false;
        }
 
+       status = torture_setup_unix_extensions(cli2);
+       if (!NT_STATUS_IS_OK(status)) {
+               return false;
+       }
+
        cli_setatr(cli1, fname, 0, 0);
        cli_posix_unlink(cli1, fname);
 
@@ -9594,7 +9699,7 @@ static bool run_openattrtest(int dummy)
        const char *fname = "\\openattr.file";
        uint16_t fnum1;
        bool correct = True;
-       uint16_t attr;
+       uint32_t attr;
        unsigned int i, j, k, l;
        NTSTATUS status;
 
@@ -9701,7 +9806,7 @@ static bool run_openattrtest(int dummy)
        return correct;
 }
 
-static NTSTATUS list_fn(const char *mnt, struct file_info *finfo,
+static NTSTATUS list_fn(struct file_info *finfo,
                    const char *name, void *state)
 {
        int *matched = (int *)state;
@@ -9774,7 +9879,7 @@ static bool run_dirtest(int dummy)
        return correct;
 }
 
-static NTSTATUS del_fn(const char *mnt, struct file_info *finfo, const char *mask,
+static NTSTATUS del_fn(struct file_info *finfo, const char *mask,
                   void *state)
 {
        struct cli_state *pcli = (struct cli_state *)state;
@@ -9784,7 +9889,7 @@ static NTSTATUS del_fn(const char *mnt, struct file_info *finfo, const char *mas
        if (strcmp(finfo->name, ".") == 0 || strcmp(finfo->name, "..") == 0)
                return NT_STATUS_OK;
 
-       if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
+       if (finfo->attr & FILE_ATTRIBUTE_DIRECTORY) {
                if (!NT_STATUS_IS_OK(cli_rmdir(pcli, fname)))
                        printf("del_fn: failed to rmdir %s\n,", fname );
        } else {
@@ -9795,6 +9900,42 @@ static NTSTATUS del_fn(const char *mnt, struct file_info *finfo, const char *mas
 }
 
 
+/*
+   send a raw ioctl - used by the torture code
+*/
+static NTSTATUS cli_raw_ioctl(struct cli_state *cli,
+                             uint16_t fnum,
+                             uint32_t code,
+                             DATA_BLOB *blob)
+{
+       uint16_t vwv[3];
+       NTSTATUS status;
+
+       PUSH_LE_U16(vwv + 0, 0, fnum);
+       PUSH_LE_U16(vwv + 1, 0, code >> 16);
+       PUSH_LE_U16(vwv + 2, 0, (code & 0xFFFF));
+
+       status = cli_smb(talloc_tos(),
+                        cli,
+                        SMBioctl,
+                        0,
+                        3,
+                        vwv,
+                        0,
+                        NULL,
+                        NULL,
+                        0,
+                        NULL,
+                        NULL,
+                        NULL,
+                        NULL);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+       *blob = data_blob_null;
+       return NT_STATUS_OK;
+}
+
 /*
   sees what IOCTLs are supported
  */
@@ -9851,7 +9992,7 @@ bool torture_ioctl_test(int dummy)
 
 
 /*
-  tries varients of chkpath
+  tries variants of chkpath
  */
 bool torture_chkpath_test(int dummy)
 {
@@ -9867,9 +10008,7 @@ bool torture_chkpath_test(int dummy)
        printf("starting chkpath test\n");
 
        /* cleanup from an old run */
-       cli_rmdir(cli, "\\chkpath.dir\\dir2");
-       cli_unlink(cli, "\\chkpath.dir\\*", FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
-       cli_rmdir(cli, "\\chkpath.dir");
+       torture_deltree(cli, "\\chkpath.dir");
 
        status = cli_mkdir(cli, "\\chkpath.dir");
        if (!NT_STATUS_IS_OK(status)) {
@@ -9930,9 +10069,7 @@ bool torture_chkpath_test(int dummy)
                ret = False;
        }
 
-       cli_rmdir(cli, "\\chkpath.dir\\dir2");
-       cli_unlink(cli, "\\chkpath.dir\\*", FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
-       cli_rmdir(cli, "\\chkpath.dir");
+       torture_deltree(cli, "\\chkpath.dir");
 
        if (!torture_close_connection(cli)) {
                return False;
@@ -9947,8 +10084,7 @@ static bool run_eatest(int dummy)
        const char *fname = "\\eatest.txt";
        bool correct = True;
        uint16_t fnum;
-       int i;
-       size_t num_eas;
+       size_t i, num_eas;
        struct ea_struct *ea_list = NULL;
        TALLOC_CTX *mem_ctx = talloc_init("eatest");
        NTSTATUS status;
@@ -9975,7 +10111,7 @@ static bool run_eatest(int dummy)
        for (i = 0; i < 10; i++) {
                fstring ea_name, ea_val;
 
-               slprintf(ea_name, sizeof(ea_name), "EA_%d", i);
+               slprintf(ea_name, sizeof(ea_name), "EA_%zu", i);
                memset(ea_val, (char)i+1, i+1);
                status = cli_set_ea_fnum(cli, fnum, ea_name, ea_val, i+1);
                if (!NT_STATUS_IS_OK(status)) {
@@ -9990,7 +10126,7 @@ static bool run_eatest(int dummy)
        for (i = 0; i < 10; i++) {
                fstring ea_name, ea_val;
 
-               slprintf(ea_name, sizeof(ea_name), "EA_%d", i+10);
+               slprintf(ea_name, sizeof(ea_name), "EA_%zu", i+10);
                memset(ea_val, (char)i+1, i+1);
                status = cli_set_ea_path(cli, fname, ea_name, ea_val, i+1);
                if (!NT_STATUS_IS_OK(status)) {
@@ -10015,13 +10151,13 @@ static bool run_eatest(int dummy)
        }
 
        for (i = 0; i < num_eas; i++) {
-               printf("%d: ea_name = %s. Val = ", i, ea_list[i].name);
+               printf("%zu: ea_name = %s. Val = ", i, ea_list[i].name);
                dump_data(0, ea_list[i].value.data,
                          ea_list[i].value.length);
        }
 
        /* Setting EA's to zero length deletes them. Test this */
-       printf("Now deleting all EA's - case indepenent....\n");
+       printf("Now deleting all EA's - case independent....\n");
 
 #if 1
        cli_set_ea_path(cli, fname, "", "", 0);
@@ -10047,7 +10183,7 @@ static bool run_eatest(int dummy)
 
        printf("num_eas = %d\n", (int)num_eas);
        for (i = 0; i < num_eas; i++) {
-               printf("%d: ea_name = %s. Val = ", i, ea_list[i].name);
+               printf("%zu: ea_name = %s. Val = ", i, ea_list[i].name);
                dump_data(0, ea_list[i].value.data,
                          ea_list[i].value.length);
        }
@@ -10124,7 +10260,7 @@ static bool run_dirtest1(int dummy)
                correct = False;
 
        /* Ensure if we have the "must have" bits we only see the
-        * relevent entries.
+        * relevant entries.
         */
        num_seen = 0;
        cli_list_old(cli, "\\LISTDIR\\*", (FILE_ATTRIBUTE_DIRECTORY<<8)|FILE_ATTRIBUTE_DIRECTORY, list_fn, &num_seen);
@@ -10648,10 +10784,9 @@ static void torture_createdels_done(struct tevent_req *subreq)
                subreq, struct tevent_req);
        struct torture_createdels_state *state = tevent_req_data(
                req, struct torture_createdels_state);
-       size_t num_parallel = talloc_array_length(state->reqs);
+       size_t i, num_parallel = talloc_array_length(state->reqs);
        NTSTATUS status;
        char *name;
-       int i;
 
        status = torture_createdel_recv(subreq);
        if (!NT_STATUS_IS_OK(status)){
@@ -10904,9 +11039,6 @@ static bool run_mangle1(int dummy)
        uint16_t fnum;
        fstring alt_name;
        NTSTATUS status;
-       time_t change_time, access_time, write_time;
-       off_t size;
-       uint16_t mode;
 
        printf("starting mangle1 test\n");
        if (!torture_open_connection(&cli, 0)) {
@@ -10940,8 +11072,7 @@ static bool run_mangle1(int dummy)
        }
        cli_close(cli, fnum);
 
-       status = cli_qpathinfo1(cli, alt_name, &change_time, &access_time,
-                               &write_time, &size, &mode);
+       status = cli_qpathinfo1(cli, alt_name, NULL, NULL, NULL, NULL, NULL);
        if (!NT_STATUS_IS_OK(status)) {
                d_printf("cli_qpathinfo1(%s) failed: %s\n", alt_name,
                         nt_errstr(status));
@@ -10951,8 +11082,7 @@ static bool run_mangle1(int dummy)
        return true;
 }
 
-static NTSTATUS mangle_illegal_list_shortname_fn(const char *mntpoint,
-                                                struct file_info *f,
+static NTSTATUS mangle_illegal_list_shortname_fn(struct file_info *f,
                                                 const char *mask,
                                                 void *state)
 {
@@ -10969,8 +11099,7 @@ static NTSTATUS mangle_illegal_list_shortname_fn(const char *mntpoint,
        return NT_STATUS_OBJECT_NAME_INVALID;
 }
 
-static NTSTATUS mangle_illegal_list_name_fn(const char *mntpoint,
-                                           struct file_info *f,
+static NTSTATUS mangle_illegal_list_name_fn(struct file_info *f,
                                            const char *mask,
                                            void *state)
 {
@@ -11503,56 +11632,130 @@ static bool run_large_readx(int dummy)
        return correct;
 }
 
-static bool run_cli_echo(int dummy)
+static NTSTATUS msdfs_attribute_list_fn(struct file_info *finfo,
+                                 const char *mask,
+                                 void *private_data)
 {
-       struct cli_state *cli;
-       NTSTATUS status;
+       uint32_t *p_attr = (uint32_t *)private_data;
 
-       printf("starting cli_echo test\n");
-       if (!torture_open_connection(&cli, 0)) {
-               return false;
+       if (strequal(finfo->name, test_filename)) {
+               *p_attr = finfo->attr;
        }
-       smbXcli_conn_set_sockopt(cli->conn, sockops);
-
-       status = cli_echo(cli, 5, data_blob_const("hello", 5));
-
-       d_printf("cli_echo returned %s\n", nt_errstr(status));
-
-       torture_close_connection(cli);
-       return NT_STATUS_IS_OK(status);
-}
 
-static int splice_status(off_t written, void *priv)
-{
-        return true;
+       return NT_STATUS_OK;
 }
 
-static bool run_cli_splice(int dummy)
+static bool run_msdfs_attribute(int dummy)
 {
-       uint8_t *buf = NULL;
-       struct cli_state *cli1 = NULL;
+       static struct cli_state *cli;
        bool correct = false;
-       const char *fname_src = "\\splice_src.dat";
-       const char *fname_dst = "\\splice_dst.dat";
+       uint32_t attr = 0;
        NTSTATUS status;
-       uint16_t fnum1 = UINT16_MAX;
-       uint16_t fnum2 = UINT16_MAX;
-       size_t file_size = 2*1024*1024;
-       size_t splice_size = 1*1024*1024 + 713;
-       uint8_t digest1[16], digest2[16];
-       off_t written = 0;
-       size_t nread = 0;
-       TALLOC_CTX *frame = talloc_stackframe();
 
-       printf("starting cli_splice test\n");
+       printf("Starting MSDFS-ATTRIBUTE test\n");
 
-       if (!torture_open_connection(&cli1, 0)) {
-               goto out;
+       if (test_filename == NULL || test_filename[0] == '\0') {
+               printf("MSDFS-ATTRIBUTE test "
+                       "needs -f filename-of-msdfs-link\n");
+               return false;
        }
 
-       cli_unlink(cli1, fname_src,
-               FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
-       cli_unlink(cli1, fname_dst,
+       /*
+        * NB. We use torture_open_connection_flags() not
+        * torture_open_connection() as the latter forces
+        * SMB1.
+        */
+       if (!torture_open_connection_flags(&cli, 0, 0)) {
+               return false;
+       }
+
+       smbXcli_conn_set_sockopt(cli->conn, sockops);
+
+       status = cli_list(cli,
+                       "*",
+                       FILE_ATTRIBUTE_DIRECTORY,
+                       msdfs_attribute_list_fn,
+                       &attr);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("cli_list failed with %s\n",
+                       nt_errstr(status));
+               goto out;
+       }
+       if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) == 0) {
+               printf("file %s should have "
+                       "FILE_ATTRIBUTE_REPARSE_POINT set. attr = 0x%x\n",
+                       test_filename,
+                       (unsigned int)attr);
+               goto out;
+       }
+
+       if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
+               printf("file %s should have "
+                       "FILE_ATTRIBUTE_DIRECTORY set. attr = 0x%x\n",
+                       test_filename,
+                       (unsigned int)attr);
+               goto out;
+       }
+
+       correct = true;
+
+  out:
+
+       torture_close_connection(cli);
+       return correct;
+}
+
+static bool run_cli_echo(int dummy)
+{
+       struct cli_state *cli;
+       NTSTATUS status;
+
+       printf("starting cli_echo test\n");
+       if (!torture_open_connection(&cli, 0)) {
+               return false;
+       }
+       smbXcli_conn_set_sockopt(cli->conn, sockops);
+
+       status = cli_echo(cli, 5, data_blob_const("hello", 5));
+
+       d_printf("cli_echo returned %s\n", nt_errstr(status));
+
+       torture_close_connection(cli);
+       return NT_STATUS_IS_OK(status);
+}
+
+static int splice_status(off_t written, void *priv)
+{
+        return true;
+}
+
+static bool run_cli_splice(int dummy)
+{
+       uint8_t *buf = NULL;
+       struct cli_state *cli1 = NULL;
+       bool correct = false;
+       const char *fname_src = "\\splice_src.dat";
+       const char *fname_dst = "\\splice_dst.dat";
+       NTSTATUS status;
+       uint16_t fnum1 = UINT16_MAX;
+       uint16_t fnum2 = UINT16_MAX;
+       size_t file_size = 2*1024*1024;
+       size_t splice_size = 1*1024*1024 + 713;
+       uint8_t digest1[16], digest2[16];
+       off_t written = 0;
+       size_t nread = 0;
+       TALLOC_CTX *frame = talloc_stackframe();
+
+       printf("starting cli_splice test\n");
+
+       if (!torture_open_connection(&cli1, 0)) {
+               goto out;
+       }
+
+       cli_unlink(cli1, fname_src,
+               FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
+       cli_unlink(cli1, fname_dst,
                FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
 
        /* Create a file */
@@ -11680,7 +11883,7 @@ static bool run_uid_regression_test(int dummy)
        int16_t old_vuid;
        int32_t old_cnum;
        bool correct = True;
-       struct smbXcli_tcon *orig_tcon = NULL;
+       struct smbXcli_tcon *tcon_copy = NULL;
        NTSTATUS status;
 
        printf("starting uid regression test\n");
@@ -11721,8 +11924,20 @@ static bool run_uid_regression_test(int dummy)
        }
 
        old_cnum = cli_state_get_tid(cli);
-       orig_tcon = cli_state_save_tcon(cli);
-       if (orig_tcon == NULL) {
+       /*
+        * This is an SMB1-only test.
+        * Copy the tcon, not "save/restore".
+        *
+        * In SMB1 the cli_tdis() below frees
+        * cli->smb1.tcon so we need a copy
+        * of the struct to put back for the
+        * second tdis call with invalid vuid.
+        *
+        * This is a test-only hack. Real client code
+        * uses cli_state_save_tcon_share()/cli_state_restore_tcon_share().
+        */
+       tcon_copy = smbXcli_tcon_copy(cli, cli->smb1.tcon);
+       if (tcon_copy == NULL) {
                correct = false;
                goto out;
        }
@@ -11738,11 +11953,11 @@ static bool run_uid_regression_test(int dummy)
        } else {
                d_printf("First tdis failed (%s)\n", nt_errstr(status));
                correct = false;
-               cli_state_restore_tcon(cli, orig_tcon);
+               cli->smb1.tcon = tcon_copy;
                goto out;
        }
 
-       cli_state_restore_tcon(cli, orig_tcon);
+       cli->smb1.tcon = tcon_copy;
        cli_state_set_uid(cli, old_vuid);
        cli_state_set_tid(cli, old_cnum);
 
@@ -11773,7 +11988,7 @@ static bool run_uid_regression_test(int dummy)
 static const char *illegal_chars = "*\\/?<>|\":";
 static char force_shortname_chars[] = " +,.[];=\177";
 
-static NTSTATUS shortname_del_fn(const char *mnt, struct file_info *finfo,
+static NTSTATUS shortname_del_fn(struct file_info *finfo,
                             const char *mask, void *state)
 {
        struct cli_state *pcli = (struct cli_state *)state;
@@ -11785,7 +12000,7 @@ static NTSTATUS shortname_del_fn(const char *mnt, struct file_info *finfo,
        if (strcmp(finfo->name, ".") == 0 || strcmp(finfo->name, "..") == 0)
                return NT_STATUS_OK;
 
-       if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
+       if (finfo->attr & FILE_ATTRIBUTE_DIRECTORY) {
                status = cli_rmdir(pcli, fname);
                if (!NT_STATUS_IS_OK(status)) {
                        printf("del_fn: failed to rmdir %s\n,", fname );
@@ -11805,7 +12020,7 @@ struct sn_state {
        bool val;
 };
 
-static NTSTATUS shortname_list_fn(const char *mnt, struct file_info *finfo,
+static NTSTATUS shortname_list_fn(struct file_info *finfo,
                              const char *name, void *state)
 {
        struct sn_state *s = (struct sn_state  *)state;
@@ -12310,15 +12525,15 @@ static bool run_streamerror(int dummy)
        NTSTATUS status;
        time_t change_time, access_time, write_time;
        off_t size;
-       uint16_t mode, fnum;
+       uint16_t fnum;
+       uint32_t attr;
        bool ret = true;
 
        if (!torture_open_connection(&cli, 0)) {
                return false;
        }
 
-       cli_unlink(cli, "\\testdir_streamerror\\*", FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
-       cli_rmdir(cli, dname);
+       torture_deltree(cli, dname);
 
        status = cli_mkdir(cli, dname);
        if (!NT_STATUS_IS_OK(status)) {
@@ -12327,7 +12542,7 @@ static bool run_streamerror(int dummy)
        }
 
        status = cli_qpathinfo1(cli, streamname, &change_time, &access_time,
-                               &write_time, &size, &mode);
+                               &write_time, &size, &attr);
        if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
                printf("pathinfo returned %s, expected "
                       "NT_STATUS_OBJECT_NAME_NOT_FOUND\n",
@@ -12611,958 +12826,1333 @@ static bool run_symlink_open_test(int dummy)
        return correct;
 }
 
-/*
- * Only testing minimal time strings, as the others
- * need (locale-dependent) guessing at what strftime does and
- * even may differ in builds.
- */
-static bool timesubst_test(void)
+static NTSTATUS smb1_wild_mangle_list_fn(struct file_info *finfo,
+                                       const char *name,
+                                       void *state)
 {
-       TALLOC_CTX *ctx = NULL;
-       /* Sa 23. Dez 04:33:20 CET 2017 */
-       const struct timeval tv = { 1514000000, 123 };
-       const char* expect_minimal = "20171223_033320";
-       const char* expect_minus   = "20171223_033320_000123";
-       char *s;
-       char *env_tz, *orig_tz = NULL;
-       bool result = true;
-
-       ctx = talloc_new(NULL);
-
-       env_tz = getenv("TZ");
-       if(env_tz) {
-               orig_tz = talloc_strdup(ctx, env_tz);
-       }
-       setenv("TZ", "UTC", 1);
-
-       s = minimal_timeval_string(ctx, &tv, false);
-
-       if(!s || strcmp(s, expect_minimal)) {
-               printf("minimal_timeval_string(ctx, tv, false) returned [%s], expected "
-                      "[%s]\n", s ? s : "<nil>", expect_minimal);
-               result = false;
-       }
-       TALLOC_FREE(s);
-       s = minimal_timeval_string(ctx, &tv, true);
-       if(!s || strcmp(s, expect_minus)) {
-               printf("minimal_timeval_string(ctx, tv, true) returned [%s], expected "
-                      "[%s]\n", s ? s : "<nil>", expect_minus);
-               result = false;
-       }
-       TALLOC_FREE(s);
+       char **mangled_name_return = (char **)state;
+       bool is_mangled = strchr(finfo->name, '~');
 
-       if(orig_tz) {
-               setenv("TZ", orig_tz, 1);
+       if (is_mangled) {
+               *mangled_name_return = talloc_strdup(NULL, finfo->name);
+               if (*mangled_name_return == NULL) {
+                       return NT_STATUS_NO_MEMORY;
+               }
        }
-
-       TALLOC_FREE(ctx);
-       return result;
+       return NT_STATUS_OK;
 }
 
-static bool run_local_substitute(int dummy)
+static bool run_smb1_wild_mangle_unlink_test(int dummy)
 {
-       bool ok = true;
-
-       ok &= subst_test("%U", "bla", "", -1, -1, "bla");
-       ok &= subst_test("%u%U", "bla", "", -1, -1, "blabla");
-       ok &= subst_test("%g", "", "", -1, -1, "NO_GROUP");
-       ok &= subst_test("%G", "", "", -1, -1, "NO_GROUP");
-       ok &= subst_test("%g", "", "", -1, 0, gidtoname(0));
-       ok &= subst_test("%G", "", "", -1, 0, gidtoname(0));
-       ok &= subst_test("%D%u", "u", "dom", -1, 0, "domu");
-       ok &= subst_test("%i %I", "", "", -1, -1, "0.0.0.0 0.0.0.0");
-       ok &= subst_test("%j %J", "", "", -1, -1, "0_0_0_0 0_0_0_0");
-       /* Substitution depends on current time, so better test the underlying
-          formatting function. At least covers %t. */
-       ok &= timesubst_test();
-
-       /* Different captialization rules in sub_basic... */
-
-       ok &=  (strcmp(talloc_sub_basic(talloc_tos(), "BLA", "dom", "%U%D"),
-                      "blaDOM") == 0);
+       static struct cli_state *cli_posix = NULL;
+       static struct cli_state *cli = NULL;
+       uint16_t fnum = (uint16_t)-1;
+       bool correct = false;
+       const char *dname = "smb1_wild_mangle_unlink";
+       const char *aname = "smb1_wild_mangle_unlink/a";
+       const char *star_name = "smb1_wild_mangle_unlink/*";
+       char *windows_unlink_name = NULL;
+       char *mangled_name = NULL;
+       NTSTATUS status;
 
-       return ok;
-}
+       printf("Starting SMB1 wild mangle unlink test\n");
 
-static bool run_local_base64(int dummy)
-{
-       int i;
-       bool ret = true;
+       /* Open a Windows connection. */
+       if (!torture_open_connection(&cli, 0)) {
+               return false;
+       }
 
-       for (i=1; i<2000; i++) {
-               DATA_BLOB blob1, blob2;
-               char *b64;
+       smbXcli_conn_set_sockopt(cli->conn, sockops);
 
-               blob1.data = talloc_array(talloc_tos(), uint8_t, i);
-               blob1.length = i;
-               generate_random_buffer(blob1.data, blob1.length);
+       /* Open a POSIX connection. */
+       if (!torture_open_connection(&cli_posix, 0)) {
+               goto out;
+       }
 
-               b64 = base64_encode_data_blob(talloc_tos(), blob1);
-               if (b64 == NULL) {
-                       d_fprintf(stderr, "base64_encode_data_blob failed "
-                                 "for %d bytes\n", i);
-                       ret = false;
-               }
-               blob2 = base64_decode_data_blob(b64);
-               TALLOC_FREE(b64);
+       smbXcli_conn_set_sockopt(cli_posix->conn, sockops);
 
-               if (data_blob_cmp(&blob1, &blob2)) {
-                       d_fprintf(stderr, "data_blob_cmp failed for %d "
-                                 "bytes\n", i);
-                       ret = false;
-               }
-               TALLOC_FREE(blob1.data);
-               data_blob_free(&blob2);
+       status = torture_setup_unix_extensions(cli_posix);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("server doesn't support POSIX\n");
+               goto out;
        }
-       return ret;
-}
 
-static void parse_fn(const struct gencache_timeout *t,
-                    DATA_BLOB blob,
-                    void *private_data)
-{
-       return;
-}
+       /* Start fresh. */
+       torture_deltree(cli, dname);
 
-static bool run_local_gencache(int dummy)
-{
-       char *val;
-       time_t tm;
-       DATA_BLOB blob;
-       char v;
-       struct memcache *mem;
-       int i;
+       /*
+        * Create two files - 'a' and '*'.
+        * We need POSIX extensions for this as '*'
+        * is not a valid Windows name.
+        */
 
-       mem = memcache_init(NULL, 0);
-       if (mem == NULL) {
-               d_printf("%s: memcache_init failed\n", __location__);
-               return false;
+       status = cli_mkdir(cli, dname);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("cli_mkdir of %s returned %s\n",
+                       dname,
+                       nt_errstr(status));
+               goto out;
        }
-       memcache_set_global(mem);
 
-       if (!gencache_set("foo", "bar", time(NULL) + 1000)) {
-               d_printf("%s: gencache_set() failed\n", __location__);
-               return False;
+       status = cli_posix_open(cli_posix,
+                               aname,
+                               O_RDWR|O_CREAT|O_EXCL,
+                               0660,
+                               &fnum);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("cli_posix_open (create) of %s returned %s\n",
+                       aname,
+                       nt_errstr(status));
+               goto out;
        }
-
-       if (!gencache_get("foo", NULL, NULL, NULL)) {
-               d_printf("%s: gencache_get() failed\n", __location__);
-               return False;
+       status = cli_close(cli_posix, fnum);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto out;
        }
-
-       for (i=0; i<1000000; i++) {
-               gencache_parse("foo", parse_fn, NULL);
+       status = cli_posix_open(cli_posix,
+                               star_name,
+                               O_RDWR|O_CREAT|O_EXCL,
+                               0660,
+                               &fnum);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("cli_posix_open (create) of %s returned %s\n",
+                       star_name,
+                       nt_errstr(status));
+               goto out;
+       }
+       status = cli_close(cli_posix, fnum);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto out;
        }
 
-       if (!gencache_get("foo", talloc_tos(), &val, &tm)) {
-               d_printf("%s: gencache_get() failed\n", __location__);
-               return False;
+       status = cli_list(cli,
+                       star_name,
+                       0,
+                       smb1_wild_mangle_list_fn,
+                       &mangled_name);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("cli_list of %s returned %s\n",
+                       star_name,
+                       nt_errstr(status));
+               goto out;
        }
-       TALLOC_FREE(val);
 
-       if (!gencache_get("foo", talloc_tos(), &val, &tm)) {
-               d_printf("%s: gencache_get() failed\n", __location__);
-               return False;
+       if (mangled_name == NULL) {
+               goto out;
        }
 
-       if (strcmp(val, "bar") != 0) {
-               d_printf("%s: gencache_get() returned %s, expected %s\n",
-                        __location__, val, "bar");
-               TALLOC_FREE(val);
-               return False;
-       }
+       printf("mangled_name = %s\n",
+               mangled_name);
 
-       TALLOC_FREE(val);
+       /*
+        * Try a Windows unlink with the mangled name.
+        * This should *NOT* unlink the 'a' name.
+        */
 
-       if (!gencache_del("foo")) {
-               d_printf("%s: gencache_del() failed\n", __location__);
-               return False;
-       }
-       if (gencache_del("foo")) {
-               d_printf("%s: second gencache_del() succeeded\n",
-                        __location__);
-               return False;
-       }
+       windows_unlink_name = talloc_asprintf(cli_posix,
+                                       "%s\\%s",
+                                       dname,
+                                       mangled_name);
 
-       if (gencache_get("foo", talloc_tos(), &val, &tm)) {
-               d_printf("%s: gencache_get() on deleted entry "
-                        "succeeded\n", __location__);
-               return False;
+       status = cli_unlink(cli, windows_unlink_name, 0);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("cli_unlink of %s returned %s\n",
+                       windows_unlink_name,
+                       nt_errstr(status));
+               goto out;
        }
 
-       blob = data_blob_string_const_null("bar");
-       tm = time(NULL) + 60;
-
-       if (!gencache_set_data_blob("foo", blob, tm)) {
-               d_printf("%s: gencache_set_data_blob() failed\n", __location__);
-               return False;
+       /* Does 'a' still exist ? */
+       status = cli_posix_open(cli_posix,
+                               aname,
+                               O_RDONLY,
+                               0,
+                               &fnum);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("cli_posix_open O_RNONLY of %s returned %s\n",
+                       aname,
+                       nt_errstr(status));
+               goto out;
        }
 
-       if (!gencache_get_data_blob("foo", talloc_tos(), &blob, NULL, NULL)) {
-               d_printf("%s: gencache_get_data_blob() failed\n", __location__);
-               return False;
+       status = cli_close(cli_posix, fnum);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto out;
        }
 
-       if (strcmp((const char *)blob.data, "bar") != 0) {
-               d_printf("%s: gencache_get_data_blob() returned %s, expected %s\n",
-                        __location__, (const char *)blob.data, "bar");
-               data_blob_free(&blob);
-               return False;
-       }
+       correct = true;
 
-       data_blob_free(&blob);
+  out:
 
-       if (!gencache_del("foo")) {
-               d_printf("%s: gencache_del() failed\n", __location__);
-               return False;
-       }
-       if (gencache_del("foo")) {
-               d_printf("%s: second gencache_del() succeeded\n",
-                        __location__);
-               return False;
-       }
+       TALLOC_FREE(windows_unlink_name);
+       TALLOC_FREE(mangled_name);
 
-       if (gencache_get_data_blob("foo", talloc_tos(), &blob, NULL, NULL)) {
-               d_printf("%s: gencache_get_data_blob() on deleted entry "
-                        "succeeded\n", __location__);
-               return False;
+       if (cli != NULL) {
+               torture_deltree(cli, dname);
+               torture_close_connection(cli);
        }
 
-       v = 1;
-       blob.data = (uint8_t *)&v;
-       blob.length = sizeof(v);
-
-       if (!gencache_set_data_blob("blob", blob, tm)) {
-               d_printf("%s: gencache_set_data_blob() failed\n",
-                        __location__);
-               return false;
-       }
-       if (gencache_get("blob", talloc_tos(), &val, &tm)) {
-               d_printf("%s: gencache_get succeeded\n", __location__);
-               return false;
+       if (cli_posix != NULL) {
+               torture_close_connection(cli_posix);
        }
 
-       return True;
+       return correct;
 }
 
-static bool rbt_testval(struct db_context *db, const char *key,
-                       const char *value)
+static bool run_smb1_wild_mangle_rename_test(int dummy)
 {
-       struct db_record *rec;
-       TDB_DATA data = string_tdb_data(value);
-       bool ret = false;
+       static struct cli_state *cli_posix = NULL;
+       static struct cli_state *cli = NULL;
+       uint16_t fnum = (uint16_t)-1;
+       bool correct = false;
+       const char *dname = "smb1_wild_mangle_rename";
+       const char *fooname = "smb1_wild_mangle_rename/foo";
+       const char *foostar_name = "smb1_wild_mangle_rename/fo*";
+       const char *wild_name = "smb1_wild_mangle_rename/*";
+       char *windows_rename_src = NULL;
+       const char *windows_rename_dst = "smb1_wild_mangle_rename\\bar";
+       char *mangled_name = NULL;
        NTSTATUS status;
-       TDB_DATA dbvalue;
 
-       rec = dbwrap_fetch_locked(db, db, string_tdb_data(key));
-       if (rec == NULL) {
-               d_fprintf(stderr, "fetch_locked failed\n");
-               goto done;
+       printf("Starting SMB1 wild mangle rename test\n");
+
+       if (!torture_open_connection(&cli_posix, 0)) {
+               return false;
        }
-       status = dbwrap_record_store(rec, data, 0);
+
+       smbXcli_conn_set_sockopt(cli_posix->conn, sockops);
+
+       status = torture_setup_unix_extensions(cli_posix);
        if (!NT_STATUS_IS_OK(status)) {
-               d_fprintf(stderr, "store failed: %s\n", nt_errstr(status));
-               goto done;
+               printf("server doesn't support POSIX\n");
+               return false;
        }
-       TALLOC_FREE(rec);
 
-       rec = dbwrap_fetch_locked(db, db, string_tdb_data(key));
-       if (rec == NULL) {
-               d_fprintf(stderr, "second fetch_locked failed\n");
-               goto done;
+       /* Open a Windows connection. */
+       if (!torture_open_connection(&cli, 0)) {
+               goto out;
        }
 
-       dbvalue = dbwrap_record_get_value(rec);
-       if ((dbvalue.dsize != data.dsize)
-           || (memcmp(dbvalue.dptr, data.dptr, data.dsize) != 0)) {
-               d_fprintf(stderr, "Got wrong data back\n");
-               goto done;
-       }
+       smbXcli_conn_set_sockopt(cli->conn, sockops);
 
-       ret = true;
- done:
-       TALLOC_FREE(rec);
-       return ret;
-}
+       /* Ensure we start from fresh. */
+       torture_deltree(cli, dname);
 
-static int local_rbtree_traverse_read(struct db_record *rec, void *private_data)
-{
-       int *count2 = (int *)private_data;
-       (*count2)++;
-       return 0;
-}
+       /*
+        * Create two files - 'foo' and 'fo*'.
+        * We need POSIX extensions for this as 'fo*'
+        * is not a valid Windows name.
+        */
 
-static int local_rbtree_traverse_delete(struct db_record *rec, void *private_data)
-{
-       int *count2 = (int *)private_data;
-       (*count2)++;
-       dbwrap_record_delete(rec);
-       return 0;
-}
+       status = cli_posix_mkdir(cli_posix, dname, 0770);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("cli_posix_mkdir of %s returned %s\n",
+                       dname,
+                       nt_errstr(status));
+               goto out;
+       }
 
-static bool run_local_rbtree(int dummy)
-{
-       struct db_context *db;
-       bool ret = false;
-       int i;
-       NTSTATUS status;
-       int count = 0;
-       int count2 = 0;
+       status = cli_posix_open(cli_posix,
+                               fooname,
+                               O_RDWR|O_CREAT|O_EXCL,
+                               0660,
+                               &fnum);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("cli_posix_open (create) of %s returned %s\n",
+                       fooname,
+                       nt_errstr(status));
+               goto out;
+       }
+       status = cli_close(cli_posix, fnum);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto out;
+       }
+       status = cli_posix_open(cli_posix,
+                               foostar_name,
+                               O_RDWR|O_CREAT|O_EXCL,
+                               0660,
+                               &fnum);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("cli_posix_open (create) of %s returned %s\n",
+                       foostar_name,
+                       nt_errstr(status));
+               goto out;
+       }
+       status = cli_close(cli_posix, fnum);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto out;
+       }
 
-       db = db_open_rbt(NULL);
+       /*
+        * Get the mangled name. We can re-use the
+        * previous smb1_wild_mangle_list_fn for this.
+        */
 
-       if (db == NULL) {
-               d_fprintf(stderr, "db_open_rbt failed\n");
-               return false;
+       status = cli_list(cli,
+                       wild_name,
+                       0,
+                       smb1_wild_mangle_list_fn,
+                       &mangled_name);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("cli_list of %s returned %s\n",
+                       wild_name,
+                       nt_errstr(status));
+               goto out;
        }
 
-       for (i=0; i<1000; i++) {
-               char *key, *value;
-
-               if (asprintf(&key, "key%ld", random()) == -1) {
-                       goto done;
-               }
-               if (asprintf(&value, "value%ld", random()) == -1) {
-                       SAFE_FREE(key);
-                       goto done;
-               }
+       if (mangled_name == NULL) {
+               goto out;
+       }
 
-               if (!rbt_testval(db, key, value)) {
-                       SAFE_FREE(key);
-                       SAFE_FREE(value);
-                       goto done;
-               }
+       printf("mangled_name = %s\n",
+               mangled_name);
 
-               SAFE_FREE(value);
-               if (asprintf(&value, "value%ld", random()) == -1) {
-                       SAFE_FREE(key);
-                       goto done;
-               }
+       /*
+        * Try a Windows rename with the mangled name.
+        * This should *NOT* rename the 'foo' name.
+        */
 
-               if (!rbt_testval(db, key, value)) {
-                       SAFE_FREE(key);
-                       SAFE_FREE(value);
-                       goto done;
-               }
+       windows_rename_src = talloc_asprintf(cli_posix,
+                                       "%s\\%s",
+                                       dname,
+                                       mangled_name);
 
-               SAFE_FREE(key);
-               SAFE_FREE(value);
+       status = cli_rename(cli,
+                       windows_rename_src,
+                       windows_rename_dst,
+                       false);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("cli_rename of %s -> %s returned %s\n",
+                       windows_rename_src,
+                       windows_rename_dst,
+                       nt_errstr(status));
+               goto out;
        }
 
-       ret = true;
-       count = 0; count2 = 0;
-       status = dbwrap_traverse_read(db, local_rbtree_traverse_read,
-                                     &count2, &count);
-       printf("%s: read1: %d %d, %s\n", __func__, count, count2, nt_errstr(status));
-       if ((count != count2) || (count != 1000)) {
-               ret = false;
+       /* Does 'foo' still exist ? */
+       status = cli_posix_open(cli_posix,
+                               fooname,
+                               O_RDONLY,
+                               0,
+                               &fnum);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("cli_posix_open O_RNONLY of %s returned %s\n",
+                       fooname,
+                       nt_errstr(status));
+               goto out;
        }
-       count = 0; count2 = 0;
-       status = dbwrap_traverse(db, local_rbtree_traverse_delete,
-                                &count2, &count);
-       printf("%s: delete: %d %d, %s\n", __func__, count, count2, nt_errstr(status));
-       if ((count != count2) || (count != 1000)) {
-               ret = false;
+
+       status = cli_close(cli_posix, fnum);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto out;
        }
-       count = 0; count2 = 0;
-       status = dbwrap_traverse_read(db, local_rbtree_traverse_read,
-                                     &count2, &count);
-       printf("%s: read2: %d %d, %s\n", __func__, count, count2, nt_errstr(status));
-       if ((count != count2) || (count != 0)) {
-               ret = false;
+
+       correct = true;
+
+  out:
+
+       TALLOC_FREE(mangled_name);
+       TALLOC_FREE(windows_rename_src);
+
+       if (cli != NULL) {
+               torture_deltree(cli, dname);
+               torture_close_connection(cli);
        }
 
- done:
-       TALLOC_FREE(db);
-       return ret;
-}
+       torture_close_connection(cli_posix);
 
+       return correct;
+}
 
 /*
 local test for character set functions
-
-  This is a very simple test for the functionality in convert_string_error()
* Only testing minimal time strings, as the others
+ * need (locale-dependent) guessing at what strftime does and
+ * even may differ in builds.
  */
-static bool run_local_convert_string(int dummy)
+static bool timesubst_test(void)
 {
-       TALLOC_CTX *tmp_ctx = talloc_new(NULL);
-       const char *test_strings[2] = { "March", "M\303\244rz" };
-       char dst[7];
-       int i;
+       TALLOC_CTX *ctx = NULL;
+       /* Sa 23. Dez 04:33:20 CET 2017 */
+       const struct timeval tv = { 1514000000, 123 };
+       const char* expect_minimal = "20171223_033320";
+       const char* expect_minus   = "20171223_033320_000123";
+       char *s;
+       char *env_tz, *orig_tz = NULL;
+       bool result = true;
 
-       for (i=0; i<2; i++) {
-               const char *str = test_strings[i];
-               int len = strlen(str);
-               size_t converted_size;
-               bool ret;
+       ctx = talloc_new(NULL);
 
-               memset(dst, 'X', sizeof(dst));
+       env_tz = getenv("TZ");
+       if(env_tz) {
+               orig_tz = talloc_strdup(ctx, env_tz);
+       }
+       setenv("TZ", "UTC", 1);
 
-               /* first try with real source length */
-               ret = convert_string_error(CH_UNIX, CH_UTF8,
-                                          str, len,
-                                          dst, sizeof(dst),
-                                          &converted_size);
-               if (ret != true) {
-                       d_fprintf(stderr, "Failed to convert '%s' to CH_DISPLAY\n", str);
-                       goto failed;
-               }
+       s = minimal_timeval_string(ctx, &tv, false);
 
-               if (converted_size != len) {
-                       d_fprintf(stderr, "Converted size of '%s' should be %d - got %d\n",
-                                 str, len, (int)converted_size);
-                       goto failed;
-               }
+       if(!s || strcmp(s, expect_minimal)) {
+               printf("minimal_timeval_string(ctx, tv, false) returned [%s], expected "
+                      "[%s]\n", s ? s : "<nil>", expect_minimal);
+               result = false;
+       }
+       TALLOC_FREE(s);
+       s = minimal_timeval_string(ctx, &tv, true);
+       if(!s || strcmp(s, expect_minus)) {
+               printf("minimal_timeval_string(ctx, tv, true) returned [%s], expected "
+                      "[%s]\n", s ? s : "<nil>", expect_minus);
+               result = false;
+       }
+       TALLOC_FREE(s);
 
-               if (strncmp(str, dst, converted_size) != 0) {
-                       d_fprintf(stderr, "Expected '%s' to match '%s'\n", str, dst);
-                       goto failed;
-               }
+       if(orig_tz) {
+               setenv("TZ", orig_tz, 1);
+       }
 
-               if (strlen(str) != converted_size) {
-                       d_fprintf(stderr, "Expected '%s' length %d - got %d\n", str,
-                                 (int)strlen(str), (int)converted_size);
-                       goto failed;
-               }
+       TALLOC_FREE(ctx);
+       return result;
+}
 
-               if (dst[converted_size] != 'X') {
-                       d_fprintf(stderr, "Expected no termination of '%s'\n", dst);
-                       goto failed;
-               }
+static bool run_local_substitute(int dummy)
+{
+       bool ok = true;
 
-               /* now with srclen==-1, this causes the nul to be
-                * converted too */
-               ret = convert_string_error(CH_UNIX, CH_UTF8,
-                                          str, -1,
-                                          dst, sizeof(dst),
-                                          &converted_size);
-               if (ret != true) {
-                       d_fprintf(stderr, "Failed to convert '%s' to CH_DISPLAY\n", str);
-                       goto failed;
-               }
+       ok &= subst_test("%U", "bla", "", -1, -1, "bla");
+       ok &= subst_test("%u%U", "bla", "", -1, -1, "blabla");
+       ok &= subst_test("%g", "", "", -1, -1, "NO_GROUP");
+       ok &= subst_test("%G", "", "", -1, -1, "NO_GROUP");
+       ok &= subst_test("%g", "", "", -1, 0, gidtoname(0));
+       ok &= subst_test("%G", "", "", -1, 0, gidtoname(0));
+       ok &= subst_test("%D%u", "u", "dom", -1, 0, "domu");
+       ok &= subst_test("%i %I", "", "", -1, -1, "0.0.0.0 0.0.0.0");
+       ok &= subst_test("%j %J", "", "", -1, -1, "0_0_0_0 0_0_0_0");
+       /* Substitution depends on current time, so better test the underlying
+          formatting function. At least covers %t. */
+       ok &= timesubst_test();
 
-               if (converted_size != len+1) {
-                       d_fprintf(stderr, "Converted size of '%s' should be %d - got %d\n",
-                                 str, len, (int)converted_size);
-                       goto failed;
-               }
+       /* Different captialization rules in sub_basic... */
 
-               if (strncmp(str, dst, converted_size) != 0) {
-                       d_fprintf(stderr, "Expected '%s' to match '%s'\n", str, dst);
-                       goto failed;
-               }
+       ok &=  (strcmp(talloc_sub_basic(talloc_tos(), "BLA", "dom", "%U%D"),
+                      "blaDOM") == 0);
 
-               if (len+1 != converted_size) {
-                       d_fprintf(stderr, "Expected '%s' length %d - got %d\n", str,
-                                 len+1, (int)converted_size);
-                       goto failed;
-               }
+       return ok;
+}
 
-               if (dst[converted_size] != 'X') {
-                       d_fprintf(stderr, "Expected no termination of '%s'\n", dst);
-                       goto failed;
+static bool run_local_base64(int dummy)
+{
+       int i;
+       bool ret = true;
+
+       for (i=1; i<2000; i++) {
+               DATA_BLOB blob1, blob2;
+               char *b64;
+
+               blob1.data = talloc_array(talloc_tos(), uint8_t, i);
+               blob1.length = i;
+               generate_random_buffer(blob1.data, blob1.length);
+
+               b64 = base64_encode_data_blob(talloc_tos(), blob1);
+               if (b64 == NULL) {
+                       d_fprintf(stderr, "base64_encode_data_blob failed "
+                                 "for %d bytes\n", i);
+                       ret = false;
                }
+               blob2 = base64_decode_data_blob(b64);
+               TALLOC_FREE(b64);
 
+               if (data_blob_cmp(&blob1, &blob2)) {
+                       d_fprintf(stderr, "data_blob_cmp failed for %d "
+                                 "bytes\n", i);
+                       ret = false;
+               }
+               TALLOC_FREE(blob1.data);
+               data_blob_free(&blob2);
        }
+       return ret;
+}
 
-
-       TALLOC_FREE(tmp_ctx);
-       return true;
-failed:
-       TALLOC_FREE(tmp_ctx);
-       return false;
+static void parse_fn(const struct gencache_timeout *t,
+                    DATA_BLOB blob,
+                    void *private_data)
+{
+       return;
 }
 
-static bool run_local_string_to_sid(int dummy) {
-       struct dom_sid sid;
+static bool run_local_gencache(int dummy)
+{
+       char *val;
+       time_t tm;
+       DATA_BLOB blob;
+       char v;
+       struct memcache *mem;
+       int i;
 
-       if (string_to_sid(&sid, "S--1-5-32-545")) {
-               printf("allowing S--1-5-32-545\n");
+       mem = memcache_init(NULL, 0);
+       if (mem == NULL) {
+               d_printf("%s: memcache_init failed\n", __location__);
                return false;
        }
-       if (string_to_sid(&sid, "S-1-5-32-+545")) {
-               printf("allowing S-1-5-32-+545\n");
-               return false;
+       memcache_set_global(mem);
+
+       if (!gencache_set("foo", "bar", time(NULL) + 1000)) {
+               d_printf("%s: gencache_set() failed\n", __location__);
+               return False;
        }
-       if (string_to_sid(&sid, "S-1-2-3-4-5-6-7-8-9-0-1-2-3-4-5-6-7-8-9-0")) {
-               printf("allowing S-1-2-3-4-5-6-7-8-9-0-1-2-3-4-5-6-7-8-9-0\n");
-               return false;
+
+       if (!gencache_get("foo", NULL, NULL, NULL)) {
+               d_printf("%s: gencache_get() failed\n", __location__);
+               return False;
        }
-       if (string_to_sid(&sid, "S-1-5-32-545-abc")) {
-               printf("allowing S-1-5-32-545-abc\n");
-               return false;
+
+       for (i=0; i<1000000; i++) {
+               gencache_parse("foo", parse_fn, NULL);
        }
-       if (string_to_sid(&sid, "S-300-5-32-545")) {
-               printf("allowing S-300-5-32-545\n");
-               return false;
+
+       if (!gencache_get("foo", talloc_tos(), &val, &tm)) {
+               d_printf("%s: gencache_get() failed\n", __location__);
+               return False;
        }
-       if (string_to_sid(&sid, "S-1-0xfffffffffffffe-32-545")) {
-               printf("allowing S-1-0xfffffffffffffe-32-545\n");
-               return false;
+       TALLOC_FREE(val);
+
+       if (!gencache_get("foo", talloc_tos(), &val, &tm)) {
+               d_printf("%s: gencache_get() failed\n", __location__);
+               return False;
        }
-       if (string_to_sid(&sid, "S-1-0xffffffffffff-5294967297-545")) {
-               printf("allowing S-1-0xffffffffffff-5294967297-545\n");
-               return false;
+
+       if (strcmp(val, "bar") != 0) {
+               d_printf("%s: gencache_get() returned %s, expected %s\n",
+                        __location__, val, "bar");
+               TALLOC_FREE(val);
+               return False;
        }
-       if (!string_to_sid(&sid, "S-1-0xfffffffffffe-32-545")) {
-               printf("could not parse S-1-0xfffffffffffe-32-545\n");
-               return false;
+
+       TALLOC_FREE(val);
+
+       if (!gencache_del("foo")) {
+               d_printf("%s: gencache_del() failed\n", __location__);
+               return False;
        }
-       if (!string_to_sid(&sid, "S-1-5-32-545")) {
-               printf("could not parse S-1-5-32-545\n");
-               return false;
+       if (gencache_del("foo")) {
+               d_printf("%s: second gencache_del() succeeded\n",
+                        __location__);
+               return False;
        }
-       if (!dom_sid_equal(&sid, &global_sid_Builtin_Users)) {
-               struct dom_sid_buf buf;
-               printf("mis-parsed S-1-5-32-545 as %s\n",
-                      dom_sid_str_buf(&sid, &buf));
-               return false;
+
+       if (gencache_get("foo", talloc_tos(), &val, &tm)) {
+               d_printf("%s: gencache_get() on deleted entry "
+                        "succeeded\n", __location__);
+               return False;
        }
-       return true;
-}
 
-static bool sid_to_string_test(const char *expected) {
-       char *str;
-       bool res = true;
-       struct dom_sid sid;
+       blob = data_blob_string_const_null("bar");
+       tm = time(NULL) + 60;
 
-       if (!string_to_sid(&sid, expected)) {
-               printf("could not parse %s\n", expected);
-               return false;
+       if (!gencache_set_data_blob("foo", blob, tm)) {
+               d_printf("%s: gencache_set_data_blob() failed\n", __location__);
+               return False;
        }
 
-       str = dom_sid_string(NULL, &sid);
-       if (strcmp(str, expected)) {
-               printf("Comparison failed (%s != %s)\n", str, expected);
-               res = false;
+       if (!gencache_get_data_blob("foo", talloc_tos(), &blob, NULL, NULL)) {
+               d_printf("%s: gencache_get_data_blob() failed\n", __location__);
+               return False;
        }
-       TALLOC_FREE(str);
-       return res;
-}
 
-static bool run_local_sid_to_string(int dummy) {
-       if (!sid_to_string_test("S-1-0xffffffffffff-1-1-1-1-1-1-1-1-1-1-1-1"))
-               return false;
-       if (!sid_to_string_test("S-1-545"))
-               return false;
-       if (!sid_to_string_test("S-255-3840-1-1-1-1"))
-               return false;
-       return true;
-}
-
-static bool run_local_binary_to_sid(int dummy) {
-       ssize_t ret;
-       struct dom_sid *sid = talloc(NULL, struct dom_sid);
-       static const uint8_t good_binary_sid[] = {
-               0x1, /* revision number */
-               15, /* num auths */
-               0x1, 0x1, 0x1, 0x1, 0x1, 0x1, /* id_auth */
-               0x1, 0x1, 0x1, 0x1, /* auth[0] */
-               0x1, 0x1, 0x1, 0x1, /* auth[1] */
-               0x1, 0x1, 0x1, 0x1, /* auth[2] */
-               0x1, 0x1, 0x1, 0x1, /* auth[3] */
-               0x1, 0x1, 0x1, 0x1, /* auth[4] */
-               0x1, 0x1, 0x1, 0x1, /* auth[5] */
-               0x1, 0x1, 0x1, 0x1, /* auth[6] */
-               0x1, 0x1, 0x1, 0x1, /* auth[7] */
-               0x1, 0x1, 0x1, 0x1, /* auth[8] */
-               0x1, 0x1, 0x1, 0x1, /* auth[9] */
-               0x1, 0x1, 0x1, 0x1, /* auth[10] */
-               0x1, 0x1, 0x1, 0x1, /* auth[11] */
-               0x1, 0x1, 0x1, 0x1, /* auth[12] */
-               0x1, 0x1, 0x1, 0x1, /* auth[13] */
-               0x1, 0x1, 0x1, 0x1, /* auth[14] */
-       };
+       if (strcmp((const char *)blob.data, "bar") != 0) {
+               d_printf("%s: gencache_get_data_blob() returned %s, expected %s\n",
+                        __location__, (const char *)blob.data, "bar");
+               data_blob_free(&blob);
+               return False;
+       }
 
-       static const uint8_t long_binary_sid[] = {
-               0x1, /* revision number */
-               15, /* num auths */
-               0x1, 0x1, 0x1, 0x1, 0x1, 0x1, /* id_auth */
-               0x1, 0x1, 0x1, 0x1, /* auth[0] */
-               0x1, 0x1, 0x1, 0x1, /* auth[1] */
-               0x1, 0x1, 0x1, 0x1, /* auth[2] */
-               0x1, 0x1, 0x1, 0x1, /* auth[3] */
-               0x1, 0x1, 0x1, 0x1, /* auth[4] */
-               0x1, 0x1, 0x1, 0x1, /* auth[5] */
-               0x1, 0x1, 0x1, 0x1, /* auth[6] */
-               0x1, 0x1, 0x1, 0x1, /* auth[7] */
-               0x1, 0x1, 0x1, 0x1, /* auth[8] */
-               0x1, 0x1, 0x1, 0x1, /* auth[9] */
-               0x1, 0x1, 0x1, 0x1, /* auth[10] */
-               0x1, 0x1, 0x1, 0x1, /* auth[11] */
-               0x1, 0x1, 0x1, 0x1, /* auth[12] */
-               0x1, 0x1, 0x1, 0x1, /* auth[13] */
-               0x1, 0x1, 0x1, 0x1, /* auth[14] */
-               0x1, 0x1, 0x1, 0x1, /* auth[15] */
-               0x1, 0x1, 0x1, 0x1, /* auth[16] */
-               0x1, 0x1, 0x1, 0x1, /* auth[17] */
-       };
+       data_blob_free(&blob);
 
-       static const uint8_t long_binary_sid2[] = {
-               0x1, /* revision number */
-               32, /* num auths */
-               0x1, 0x1, 0x1, 0x1, 0x1, 0x1, /* id_auth */
-               0x1, 0x1, 0x1, 0x1, /* auth[0] */
-               0x1, 0x1, 0x1, 0x1, /* auth[1] */
-               0x1, 0x1, 0x1, 0x1, /* auth[2] */
-               0x1, 0x1, 0x1, 0x1, /* auth[3] */
-               0x1, 0x1, 0x1, 0x1, /* auth[4] */
-               0x1, 0x1, 0x1, 0x1, /* auth[5] */
-               0x1, 0x1, 0x1, 0x1, /* auth[6] */
-               0x1, 0x1, 0x1, 0x1, /* auth[7] */
-               0x1, 0x1, 0x1, 0x1, /* auth[8] */
-               0x1, 0x1, 0x1, 0x1, /* auth[9] */
-               0x1, 0x1, 0x1, 0x1, /* auth[10] */
-               0x1, 0x1, 0x1, 0x1, /* auth[11] */
-               0x1, 0x1, 0x1, 0x1, /* auth[12] */
-               0x1, 0x1, 0x1, 0x1, /* auth[13] */
-               0x1, 0x1, 0x1, 0x1, /* auth[14] */
-               0x1, 0x1, 0x1, 0x1, /* auth[15] */
-               0x1, 0x1, 0x1, 0x1, /* auth[16] */
-               0x1, 0x1, 0x1, 0x1, /* auth[17] */
-               0x1, 0x1, 0x1, 0x1, /* auth[18] */
-               0x1, 0x1, 0x1, 0x1, /* auth[19] */
-               0x1, 0x1, 0x1, 0x1, /* auth[20] */
-               0x1, 0x1, 0x1, 0x1, /* auth[21] */
-               0x1, 0x1, 0x1, 0x1, /* auth[22] */
-               0x1, 0x1, 0x1, 0x1, /* auth[23] */
-               0x1, 0x1, 0x1, 0x1, /* auth[24] */
-               0x1, 0x1, 0x1, 0x1, /* auth[25] */
-               0x1, 0x1, 0x1, 0x1, /* auth[26] */
-               0x1, 0x1, 0x1, 0x1, /* auth[27] */
-               0x1, 0x1, 0x1, 0x1, /* auth[28] */
-               0x1, 0x1, 0x1, 0x1, /* auth[29] */
-               0x1, 0x1, 0x1, 0x1, /* auth[30] */
-               0x1, 0x1, 0x1, 0x1, /* auth[31] */
-       };
+       if (!gencache_del("foo")) {
+               d_printf("%s: gencache_del() failed\n", __location__);
+               return False;
+       }
+       if (gencache_del("foo")) {
+               d_printf("%s: second gencache_del() succeeded\n",
+                        __location__);
+               return False;
+       }
 
-       ret = sid_parse(good_binary_sid, sizeof(good_binary_sid), sid);
-       if (ret == -1) {
-               return false;
+       if (gencache_get_data_blob("foo", talloc_tos(), &blob, NULL, NULL)) {
+               d_printf("%s: gencache_get_data_blob() on deleted entry "
+                        "succeeded\n", __location__);
+               return False;
        }
-       ret = sid_parse(long_binary_sid2, sizeof(long_binary_sid2), sid);
-       if (ret != -1) {
+
+       v = 1;
+       blob.data = (uint8_t *)&v;
+       blob.length = sizeof(v);
+
+       if (!gencache_set_data_blob("blob", blob, tm)) {
+               d_printf("%s: gencache_set_data_blob() failed\n",
+                        __location__);
                return false;
        }
-       ret = sid_parse(long_binary_sid, sizeof(long_binary_sid), sid);
-       if (ret != -1) {
+       if (gencache_get("blob", talloc_tos(), &val, &tm)) {
+               d_printf("%s: gencache_get succeeded\n", __location__);
                return false;
        }
-       return true;
-}
 
-/* Split a path name into filename and stream name components. Canonicalise
- * such that an implicit $DATA token is always explicit.
- *
- * The "specification" of this function can be found in the
- * run_local_stream_name() function in torture.c, I've tried those
- * combinations against a W2k3 server.
- */
+       return True;
+}
 
-static NTSTATUS split_ntfs_stream_name(TALLOC_CTX *mem_ctx, const char *fname,
-                                      char **pbase, char **pstream)
+static bool rbt_testflags(struct db_context *db, const char *key,
+                         const char *value)
 {
-       char *base = NULL;
-       char *stream = NULL;
-       char *sname; /* stream name */
-       const char *stype; /* stream type */
-
-       DEBUG(10, ("split_ntfs_stream_name called for [%s]\n", fname));
-
-       sname = strchr_m(fname, ':');
+       bool ret = false;
+       NTSTATUS status;
+       struct db_record *rec;
 
-       if (sname == NULL) {
-               if (pbase != NULL) {
-                       base = talloc_strdup(mem_ctx, fname);
-                       NT_STATUS_HAVE_NO_MEMORY(base);
-               }
+       rec = dbwrap_fetch_locked(db, db, string_tdb_data(key));
+       if (rec == NULL) {
+               d_fprintf(stderr, "fetch_locked failed\n");
                goto done;
        }
 
-       if (pbase != NULL) {
-               base = talloc_strndup(mem_ctx, fname, PTR_DIFF(sname, fname));
-               NT_STATUS_HAVE_NO_MEMORY(base);
-       }
-
-       sname += 1;
-
-       stype = strchr_m(sname, ':');
-
-       if (stype == NULL) {
-               sname = talloc_strdup(mem_ctx, sname);
-               stype = "$DATA";
-       }
-       else {
-               if (strcasecmp_m(stype, ":$DATA") != 0) {
-                       /*
-                        * If there is an explicit stream type, so far we only
-                        * allow $DATA. Is there anything else allowed? -- vl
-                        */
-                       DEBUG(10, ("[%s] is an invalid stream type\n", stype));
-                       TALLOC_FREE(base);
-                       return NT_STATUS_OBJECT_NAME_INVALID;
-               }
-               sname = talloc_strndup(mem_ctx, sname, PTR_DIFF(stype, sname));
-               stype += 1;
+       status = dbwrap_record_store(rec, string_tdb_data(value), TDB_MODIFY);
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+               d_fprintf(stderr, "store TDB_MODIFY unexpected status: %s\n",
+                         nt_errstr(status));
+               goto done;
        }
 
-       if (sname == NULL) {
-               TALLOC_FREE(base);
-               return NT_STATUS_NO_MEMORY;
+       status = dbwrap_record_store(rec, string_tdb_data("overwriteme"),
+                                    TDB_INSERT);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "store TDB_INSERT failed: %s\n",
+                         nt_errstr(status));
+               goto done;
        }
 
-       if (sname[0] == '\0') {
-               /*
-                * no stream name, so no stream
-                */
+       status = dbwrap_record_store(rec, string_tdb_data(value), TDB_INSERT);
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
+               d_fprintf(stderr, "store TDB_INSERT unexpected status: %s\n",
+                         nt_errstr(status));
                goto done;
        }
 
-       if (pstream != NULL) {
-               stream = talloc_asprintf(mem_ctx, "%s:%s", sname, stype);
-               if (stream == NULL) {
-                       TALLOC_FREE(sname);
-                       TALLOC_FREE(base);
-                       return NT_STATUS_NO_MEMORY;
-               }
-               /*
-                * upper-case the type field
-                */
-               (void)strupper_m(strchr_m(stream, ':')+1);
+       status = dbwrap_record_store(rec, string_tdb_data(value), TDB_MODIFY);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "store TDB_MODIFY failed: %s\n",
+                         nt_errstr(status));
+               goto done;
        }
 
- done:
-       if (pbase != NULL) {
-               *pbase = base;
-       }
-       if (pstream != NULL) {
-               *pstream = stream;
-       }
-       return NT_STATUS_OK;
+       ret = true;
+done:
+       TALLOC_FREE(rec);
+       return ret;
 }
 
-static bool test_stream_name(const char *fname, const char *expected_base,
-                            const char *expected_stream,
-                            NTSTATUS expected_status)
+static bool rbt_testval(struct db_context *db, const char *key,
+                       const char *value)
 {
+       struct db_record *rec;
+       TDB_DATA data = string_tdb_data(value);
+       bool ret = false;
        NTSTATUS status;
-       char *base = NULL;
-       char *stream = NULL;
+       TDB_DATA dbvalue;
 
-       status = split_ntfs_stream_name(talloc_tos(), fname, &base, &stream);
-       if (!NT_STATUS_EQUAL(status, expected_status)) {
-               goto error;
+       rec = dbwrap_fetch_locked(db, db, string_tdb_data(key));
+       if (rec == NULL) {
+               d_fprintf(stderr, "fetch_locked failed\n");
+               goto done;
        }
-
+       status = dbwrap_record_store(rec, data, 0);
        if (!NT_STATUS_IS_OK(status)) {
-               return true;
+               d_fprintf(stderr, "store failed: %s\n", nt_errstr(status));
+               goto done;
        }
+       TALLOC_FREE(rec);
 
-       if (base == NULL) goto error;
-
-       if (strcmp(expected_base, base) != 0) goto error;
+       rec = dbwrap_fetch_locked(db, db, string_tdb_data(key));
+       if (rec == NULL) {
+               d_fprintf(stderr, "second fetch_locked failed\n");
+               goto done;
+       }
 
-       if ((expected_stream != NULL) && (stream == NULL)) goto error;
-       if ((expected_stream == NULL) && (stream != NULL)) goto error;
-
-       if ((stream != NULL) && (strcmp(expected_stream, stream) != 0))
-               goto error;
-
-       TALLOC_FREE(base);
-       TALLOC_FREE(stream);
-       return true;
+       dbvalue = dbwrap_record_get_value(rec);
+       if ((dbvalue.dsize != data.dsize)
+           || (memcmp(dbvalue.dptr, data.dptr, data.dsize) != 0)) {
+               d_fprintf(stderr, "Got wrong data back\n");
+               goto done;
+       }
 
- error:
-       d_fprintf(stderr, "Do test_stream(%s, %s, %s, %s)\n",
-                 fname, expected_base ? expected_base : "<NULL>",
-                 expected_stream ? expected_stream : "<NULL>",
-                 nt_errstr(expected_status));
-       d_fprintf(stderr, "-> base=%s, stream=%s, status=%s\n",
-                 base ? base : "<NULL>", stream ? stream : "<NULL>",
-                 nt_errstr(status));
-       TALLOC_FREE(base);
-       TALLOC_FREE(stream);
-       return false;
+       ret = true;
+ done:
+       TALLOC_FREE(rec);
+       return ret;
 }
 
-static bool run_local_stream_name(int dummy)
+static int local_rbtree_traverse_read(struct db_record *rec, void *private_data)
 {
-       bool ret = true;
-
-       ret &= test_stream_name(
-               "bla", "bla", NULL, NT_STATUS_OK);
-       ret &= test_stream_name(
-               "bla::$DATA", "bla", NULL, NT_STATUS_OK);
-       ret &= test_stream_name(
-               "bla:blub:", "bla", NULL, NT_STATUS_OBJECT_NAME_INVALID);
-       ret &= test_stream_name(
-               "bla::", NULL, NULL, NT_STATUS_OBJECT_NAME_INVALID);
-       ret &= test_stream_name(
-               "bla::123", "bla", NULL, NT_STATUS_OBJECT_NAME_INVALID);
-       ret &= test_stream_name(
-               "bla:$DATA", "bla", "$DATA:$DATA", NT_STATUS_OK);
-       ret &= test_stream_name(
-               "bla:x:$DATA", "bla", "x:$DATA", NT_STATUS_OK);
-       ret &= test_stream_name(
-               "bla:x", "bla", "x:$DATA", NT_STATUS_OK);
-
-       return ret;
+       int *count2 = (int *)private_data;
+       (*count2)++;
+       return 0;
 }
 
-static bool data_blob_equal(DATA_BLOB a, DATA_BLOB b)
+static int local_rbtree_traverse_delete(struct db_record *rec, void *private_data)
 {
-       if (a.length != b.length) {
-               printf("a.length=%d != b.length=%d\n",
-                      (int)a.length, (int)b.length);
-               return false;
-       }
-       if (memcmp(a.data, b.data, a.length) != 0) {
-               printf("a.data and b.data differ\n");
-               return false;
-       }
-       return true;
+       int *count2 = (int *)private_data;
+       (*count2)++;
+       dbwrap_record_delete(rec);
+       return 0;
 }
 
-static bool run_local_memcache(int dummy)
+static bool run_local_rbtree(int dummy)
 {
-       struct memcache *cache;
-       DATA_BLOB k1, k2, k3, k4, k5;
-       DATA_BLOB d1, d3;
-       DATA_BLOB v1, v3;
-
-       TALLOC_CTX *mem_ctx;
-       char *ptr1 = NULL;
-       char *ptr2 = NULL;
-       char *ptr3 = NULL;
-
-       char *str1, *str2;
-       size_t size1, size2;
+       struct db_context *db;
        bool ret = false;
+       int i;
+       NTSTATUS status;
+       int count = 0;
+       int count2 = 0;
 
-       mem_ctx = talloc_init("foo");
-       if (mem_ctx == NULL) {
-               return false;
-       }
-
-       /* STAT_CACHE TESTS */
-
-       cache = memcache_init(NULL, sizeof(void *) == 8 ? 200 : 100);
+       db = db_open_rbt(NULL);
 
-       if (cache == NULL) {
-               printf("memcache_init failed\n");
+       if (db == NULL) {
+               d_fprintf(stderr, "db_open_rbt failed\n");
                return false;
        }
 
-       d1 = data_blob_const("d1", 2);
-       d3 = data_blob_const("d3", 2);
-
-       k1 = data_blob_const("d1", 2);
-       k2 = data_blob_const("d2", 2);
-       k3 = data_blob_const("d3", 2);
-       k4 = data_blob_const("d4", 2);
-       k5 = data_blob_const("d5", 2);
-
-       memcache_add(cache, STAT_CACHE, k1, d1);
-
-       if (!memcache_lookup(cache, STAT_CACHE, k1, &v1)) {
-               printf("could not find k1\n");
-               return false;
-       }
-       if (!data_blob_equal(d1, v1)) {
-               return false;
+       if (!rbt_testflags(db, "firstkey", "firstval")) {
+               goto done;
        }
 
-       memcache_add(cache, STAT_CACHE, k1, d3);
+       for (i = 0; i < 999; i++) {
+               char key[sizeof("key-9223372036854775807")];
+               char value[sizeof("value-9223372036854775807")];
 
-       if (!memcache_lookup(cache, STAT_CACHE, k1, &v3)) {
-               printf("could not find replaced k1\n");
-               return false;
-       }
-       if (!data_blob_equal(d3, v3)) {
-               return false;
-       }
+               snprintf(key, sizeof(key), "key%ld", random());
+               snprintf(value, sizeof(value) ,"value%ld", random());
 
-       TALLOC_FREE(cache);
+               if (!rbt_testval(db, key, value)) {
+                       goto done;
+               }
 
-       /* GETWD_CACHE TESTS */
-       str1 = talloc_strdup(mem_ctx, "string1");
-       if (str1 == NULL) {
-               return false;
-       }
-       ptr2 = str1; /* Keep an alias for comparison. */
+               snprintf(value, sizeof(value) ,"value%ld", random());
 
-       str2 = talloc_strdup(mem_ctx, "string2");
-       if (str2 == NULL) {
-               return false;
+               if (!rbt_testval(db, key, value)) {
+                       goto done;
+               }
        }
 
-       cache = memcache_init(NULL, sizeof(void *) == 8 ? 200 : 100);
-       if (cache == NULL) {
-               printf("memcache_init failed\n");
-               return false;
+       ret = true;
+       count = 0; count2 = 0;
+       status = dbwrap_traverse_read(db, local_rbtree_traverse_read,
+                                     &count2, &count);
+       printf("%s: read1: %d %d, %s\n", __func__, count, count2, nt_errstr(status));
+       if ((count != count2) || (count != 1000)) {
+               ret = false;
        }
-
-       memcache_add_talloc(cache, GETWD_CACHE, k2, &str1);
-       /* str1 == NULL now. */
-       ptr1 = memcache_lookup_talloc(cache, GETWD_CACHE, k2);
-       if (ptr1 == NULL) {
-               printf("could not find k2\n");
-               return false;
+       count = 0; count2 = 0;
+       status = dbwrap_traverse(db, local_rbtree_traverse_delete,
+                                &count2, &count);
+       printf("%s: delete: %d %d, %s\n", __func__, count, count2, nt_errstr(status));
+       if ((count != count2) || (count != 1000)) {
+               ret = false;
        }
-       if (ptr1 != ptr2) {
-               printf("fetch of k2 got wrong string\n");
-               return false;
+       count = 0; count2 = 0;
+       status = dbwrap_traverse_read(db, local_rbtree_traverse_read,
+                                     &count2, &count);
+       printf("%s: read2: %d %d, %s\n", __func__, count, count2, nt_errstr(status));
+       if ((count != count2) || (count != 0)) {
+               ret = false;
        }
 
-       /* Add a blob to ensure k2 gets purged. */
-       d3 = data_blob_talloc_zero(mem_ctx, 180);
-       memcache_add(cache, STAT_CACHE, k3, d3);
+ done:
+       TALLOC_FREE(db);
+       return ret;
+}
 
-       ptr2 = memcache_lookup_talloc(cache, GETWD_CACHE, k2);
-       if (ptr2 != NULL) {
-               printf("Did find k2, should have been purged\n");
-               return false;
-       }
 
-       /*
-        * Test that talloc size also is accounted in memcache and
-        * causes purge of other object.
-        */
+/*
+  local test for character set functions
 
-       str1 = talloc_zero_size(mem_ctx, 100);
-       str2 = talloc_zero_size(mem_ctx, 100);
+  This is a very simple test for the functionality in convert_string_error()
+ */
+static bool run_local_convert_string(int dummy)
+{
+       TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+       const char *test_strings[2] = { "March", "M\303\244rz" };
+       char dst[7];
+       int i;
 
-       memcache_add_talloc(cache, GETWD_CACHE, k4, &str1);
-       memcache_add_talloc(cache, GETWD_CACHE, k5, &str1);
+       for (i=0; i<2; i++) {
+               const char *str = test_strings[i];
+               int len = strlen(str);
+               size_t converted_size;
+               bool ret;
 
-       ptr3 = memcache_lookup_talloc(cache, GETWD_CACHE, k4);
-       if (ptr3 != NULL) {
-               printf("Did find k4, should have been purged\n");
-               return false;
-       }
+               memset(dst, 'X', sizeof(dst));
 
-       /*
-        * Test that adding a duplicate non-talloced
-        * key/value on top of a talloced key/value takes account
-        * of the talloc_freed value size.
-        */
-       TALLOC_FREE(cache);
-       TALLOC_FREE(mem_ctx);
+               /* first try with real source length */
+               ret = convert_string_error(CH_UNIX, CH_UTF8,
+                                          str, len,
+                                          dst, sizeof(dst),
+                                          &converted_size);
+               if (ret != true) {
+                       d_fprintf(stderr, "Failed to convert '%s' to CH_DISPLAY\n", str);
+                       goto failed;
+               }
 
-       mem_ctx = talloc_init("key_replace");
-       if (mem_ctx == NULL) {
-               return false;
-       }
+               if (converted_size != len) {
+                       d_fprintf(stderr, "Converted size of '%s' should be %d - got %d\n",
+                                 str, len, (int)converted_size);
+                       goto failed;
+               }
 
-       cache = memcache_init(NULL, sizeof(void *) == 8 ? 200 : 100);
-       if (cache == NULL) {
-               return false;
-       }
+               if (strncmp(str, dst, converted_size) != 0) {
+                       d_fprintf(stderr, "Expected '%s' to match '%s'\n", str, dst);
+                       goto failed;
+               }
 
-       /*
-        * Add a 100 byte talloced string. This will
-        * store a (4 or 8 byte) pointer and record the
-        * total talloced size.
+               if (strlen(str) != converted_size) {
+                       d_fprintf(stderr, "Expected '%s' length %d - got %d\n", str,
+                                 (int)strlen(str), (int)converted_size);
+                       goto failed;
+               }
+
+               if (dst[converted_size] != 'X') {
+                       d_fprintf(stderr, "Expected no termination of '%s'\n", dst);
+                       goto failed;
+               }
+
+               /* now with srclen==-1, this causes the nul to be
+                * converted too */
+               ret = convert_string_error(CH_UNIX, CH_UTF8,
+                                          str, -1,
+                                          dst, sizeof(dst),
+                                          &converted_size);
+               if (ret != true) {
+                       d_fprintf(stderr, "Failed to convert '%s' to CH_DISPLAY\n", str);
+                       goto failed;
+               }
+
+               if (converted_size != len+1) {
+                       d_fprintf(stderr, "Converted size of '%s' should be %d - got %d\n",
+                                 str, len, (int)converted_size);
+                       goto failed;
+               }
+
+               if (strncmp(str, dst, converted_size) != 0) {
+                       d_fprintf(stderr, "Expected '%s' to match '%s'\n", str, dst);
+                       goto failed;
+               }
+
+               if (len+1 != converted_size) {
+                       d_fprintf(stderr, "Expected '%s' length %d - got %d\n", str,
+                                 len+1, (int)converted_size);
+                       goto failed;
+               }
+
+               if (dst[converted_size] != 'X') {
+                       d_fprintf(stderr, "Expected no termination of '%s'\n", dst);
+                       goto failed;
+               }
+
+       }
+
+
+       TALLOC_FREE(tmp_ctx);
+       return true;
+failed:
+       TALLOC_FREE(tmp_ctx);
+       return false;
+}
+
+static bool run_local_string_to_sid(int dummy) {
+       struct dom_sid sid;
+
+       if (string_to_sid(&sid, "S--1-5-32-545")) {
+               printf("allowing S--1-5-32-545\n");
+               return false;
+       }
+       if (string_to_sid(&sid, "S-1-5-32-+545")) {
+               printf("allowing S-1-5-32-+545\n");
+               return false;
+       }
+       if (string_to_sid(&sid, "S-1-2-3-4-5-6-7-8-9-0-1-2-3-4-5-6-7-8-9-0")) {
+               printf("allowing S-1-2-3-4-5-6-7-8-9-0-1-2-3-4-5-6-7-8-9-0\n");
+               return false;
+       }
+       if (string_to_sid(&sid, "S-1-5-32-545-abc")) {
+               printf("allowing S-1-5-32-545-abc\n");
+               return false;
+       }
+       if (string_to_sid(&sid, "S-300-5-32-545")) {
+               printf("allowing S-300-5-32-545\n");
+               return false;
+       }
+       if (string_to_sid(&sid, "S-1-0xfffffffffffffe-32-545")) {
+               printf("allowing S-1-0xfffffffffffffe-32-545\n");
+               return false;
+       }
+       if (string_to_sid(&sid, "S-1-0xffffffffffff-5294967297-545")) {
+               printf("allowing S-1-0xffffffffffff-5294967297-545\n");
+               return false;
+       }
+       if (!string_to_sid(&sid, "S-1-0xfffffffffffe-32-545")) {
+               printf("could not parse S-1-0xfffffffffffe-32-545\n");
+               return false;
+       }
+       if (!string_to_sid(&sid, "S-1-5-32-545")) {
+               printf("could not parse S-1-5-32-545\n");
+               return false;
+       }
+       if (!dom_sid_equal(&sid, &global_sid_Builtin_Users)) {
+               struct dom_sid_buf buf;
+               printf("mis-parsed S-1-5-32-545 as %s\n",
+                      dom_sid_str_buf(&sid, &buf));
+               return false;
+       }
+       return true;
+}
+
+static bool sid_to_string_test(const char *expected) {
+       char *str;
+       bool res = true;
+       struct dom_sid sid;
+
+       if (!string_to_sid(&sid, expected)) {
+               printf("could not parse %s\n", expected);
+               return false;
+       }
+
+       str = dom_sid_string(NULL, &sid);
+       if (strcmp(str, expected)) {
+               printf("Comparison failed (%s != %s)\n", str, expected);
+               res = false;
+       }
+       TALLOC_FREE(str);
+       return res;
+}
+
+static bool run_local_sid_to_string(int dummy) {
+       if (!sid_to_string_test("S-1-0xffffffffffff-1-1-1-1-1-1-1-1-1-1-1-1"))
+               return false;
+       if (!sid_to_string_test("S-1-545"))
+               return false;
+       if (!sid_to_string_test("S-255-3840-1-1-1-1"))
+               return false;
+       return true;
+}
+
+static bool run_local_binary_to_sid(int dummy) {
+       ssize_t ret;
+       struct dom_sid *sid = talloc(NULL, struct dom_sid);
+       static const uint8_t good_binary_sid[] = {
+               0x1, /* revision number */
+               15, /* num auths */
+               0x1, 0x1, 0x1, 0x1, 0x1, 0x1, /* id_auth */
+               0x1, 0x1, 0x1, 0x1, /* auth[0] */
+               0x1, 0x1, 0x1, 0x1, /* auth[1] */
+               0x1, 0x1, 0x1, 0x1, /* auth[2] */
+               0x1, 0x1, 0x1, 0x1, /* auth[3] */
+               0x1, 0x1, 0x1, 0x1, /* auth[4] */
+               0x1, 0x1, 0x1, 0x1, /* auth[5] */
+               0x1, 0x1, 0x1, 0x1, /* auth[6] */
+               0x1, 0x1, 0x1, 0x1, /* auth[7] */
+               0x1, 0x1, 0x1, 0x1, /* auth[8] */
+               0x1, 0x1, 0x1, 0x1, /* auth[9] */
+               0x1, 0x1, 0x1, 0x1, /* auth[10] */
+               0x1, 0x1, 0x1, 0x1, /* auth[11] */
+               0x1, 0x1, 0x1, 0x1, /* auth[12] */
+               0x1, 0x1, 0x1, 0x1, /* auth[13] */
+               0x1, 0x1, 0x1, 0x1, /* auth[14] */
+       };
+
+       static const uint8_t long_binary_sid[] = {
+               0x1, /* revision number */
+               15, /* num auths */
+               0x1, 0x1, 0x1, 0x1, 0x1, 0x1, /* id_auth */
+               0x1, 0x1, 0x1, 0x1, /* auth[0] */
+               0x1, 0x1, 0x1, 0x1, /* auth[1] */
+               0x1, 0x1, 0x1, 0x1, /* auth[2] */
+               0x1, 0x1, 0x1, 0x1, /* auth[3] */
+               0x1, 0x1, 0x1, 0x1, /* auth[4] */
+               0x1, 0x1, 0x1, 0x1, /* auth[5] */
+               0x1, 0x1, 0x1, 0x1, /* auth[6] */
+               0x1, 0x1, 0x1, 0x1, /* auth[7] */
+               0x1, 0x1, 0x1, 0x1, /* auth[8] */
+               0x1, 0x1, 0x1, 0x1, /* auth[9] */
+               0x1, 0x1, 0x1, 0x1, /* auth[10] */
+               0x1, 0x1, 0x1, 0x1, /* auth[11] */
+               0x1, 0x1, 0x1, 0x1, /* auth[12] */
+               0x1, 0x1, 0x1, 0x1, /* auth[13] */
+               0x1, 0x1, 0x1, 0x1, /* auth[14] */
+               0x1, 0x1, 0x1, 0x1, /* auth[15] */
+               0x1, 0x1, 0x1, 0x1, /* auth[16] */
+               0x1, 0x1, 0x1, 0x1, /* auth[17] */
+       };
+
+       static const uint8_t long_binary_sid2[] = {
+               0x1, /* revision number */
+               32, /* num auths */
+               0x1, 0x1, 0x1, 0x1, 0x1, 0x1, /* id_auth */
+               0x1, 0x1, 0x1, 0x1, /* auth[0] */
+               0x1, 0x1, 0x1, 0x1, /* auth[1] */
+               0x1, 0x1, 0x1, 0x1, /* auth[2] */
+               0x1, 0x1, 0x1, 0x1, /* auth[3] */
+               0x1, 0x1, 0x1, 0x1, /* auth[4] */
+               0x1, 0x1, 0x1, 0x1, /* auth[5] */
+               0x1, 0x1, 0x1, 0x1, /* auth[6] */
+               0x1, 0x1, 0x1, 0x1, /* auth[7] */
+               0x1, 0x1, 0x1, 0x1, /* auth[8] */
+               0x1, 0x1, 0x1, 0x1, /* auth[9] */
+               0x1, 0x1, 0x1, 0x1, /* auth[10] */
+               0x1, 0x1, 0x1, 0x1, /* auth[11] */
+               0x1, 0x1, 0x1, 0x1, /* auth[12] */
+               0x1, 0x1, 0x1, 0x1, /* auth[13] */
+               0x1, 0x1, 0x1, 0x1, /* auth[14] */
+               0x1, 0x1, 0x1, 0x1, /* auth[15] */
+               0x1, 0x1, 0x1, 0x1, /* auth[16] */
+               0x1, 0x1, 0x1, 0x1, /* auth[17] */
+               0x1, 0x1, 0x1, 0x1, /* auth[18] */
+               0x1, 0x1, 0x1, 0x1, /* auth[19] */
+               0x1, 0x1, 0x1, 0x1, /* auth[20] */
+               0x1, 0x1, 0x1, 0x1, /* auth[21] */
+               0x1, 0x1, 0x1, 0x1, /* auth[22] */
+               0x1, 0x1, 0x1, 0x1, /* auth[23] */
+               0x1, 0x1, 0x1, 0x1, /* auth[24] */
+               0x1, 0x1, 0x1, 0x1, /* auth[25] */
+               0x1, 0x1, 0x1, 0x1, /* auth[26] */
+               0x1, 0x1, 0x1, 0x1, /* auth[27] */
+               0x1, 0x1, 0x1, 0x1, /* auth[28] */
+               0x1, 0x1, 0x1, 0x1, /* auth[29] */
+               0x1, 0x1, 0x1, 0x1, /* auth[30] */
+               0x1, 0x1, 0x1, 0x1, /* auth[31] */
+       };
+
+       ret = sid_parse(good_binary_sid, sizeof(good_binary_sid), sid);
+       if (ret == -1) {
+               return false;
+       }
+       ret = sid_parse(long_binary_sid2, sizeof(long_binary_sid2), sid);
+       if (ret != -1) {
+               return false;
+       }
+       ret = sid_parse(long_binary_sid, sizeof(long_binary_sid), sid);
+       if (ret != -1) {
+               return false;
+       }
+       return true;
+}
+
+/* Split a path name into filename and stream name components. Canonicalise
+ * such that an implicit $DATA token is always explicit.
+ *
+ * The "specification" of this function can be found in the
+ * run_local_stream_name() function in torture.c, I've tried those
+ * combinations against a W2k3 server.
+ */
+
+static NTSTATUS split_ntfs_stream_name(TALLOC_CTX *mem_ctx, const char *fname,
+                                      char **pbase, char **pstream)
+{
+       char *base = NULL;
+       char *stream = NULL;
+       char *sname; /* stream name */
+       const char *stype; /* stream type */
+
+       DEBUG(10, ("split_ntfs_stream_name called for [%s]\n", fname));
+
+       sname = strchr_m(fname, ':');
+
+       if (sname == NULL) {
+               if (pbase != NULL) {
+                       base = talloc_strdup(mem_ctx, fname);
+                       NT_STATUS_HAVE_NO_MEMORY(base);
+               }
+               goto done;
+       }
+
+       if (pbase != NULL) {
+               base = talloc_strndup(mem_ctx, fname, PTR_DIFF(sname, fname));
+               NT_STATUS_HAVE_NO_MEMORY(base);
+       }
+
+       sname += 1;
+
+       stype = strchr_m(sname, ':');
+
+       if (stype == NULL) {
+               sname = talloc_strdup(mem_ctx, sname);
+               stype = "$DATA";
+       }
+       else {
+               if (strcasecmp_m(stype, ":$DATA") != 0) {
+                       /*
+                        * If there is an explicit stream type, so far we only
+                        * allow $DATA. Is there anything else allowed? -- vl
+                        */
+                       DEBUG(10, ("[%s] is an invalid stream type\n", stype));
+                       TALLOC_FREE(base);
+                       return NT_STATUS_OBJECT_NAME_INVALID;
+               }
+               sname = talloc_strndup(mem_ctx, sname, PTR_DIFF(stype, sname));
+               stype += 1;
+       }
+
+       if (sname == NULL) {
+               TALLOC_FREE(base);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if (sname[0] == '\0') {
+               /*
+                * no stream name, so no stream
+                */
+               goto done;
+       }
+
+       if (pstream != NULL) {
+               stream = talloc_asprintf(mem_ctx, "%s:%s", sname, stype);
+               if (stream == NULL) {
+                       TALLOC_FREE(sname);
+                       TALLOC_FREE(base);
+                       return NT_STATUS_NO_MEMORY;
+               }
+               /*
+                * upper-case the type field
+                */
+               (void)strupper_m(strchr_m(stream, ':')+1);
+       }
+
+ done:
+       if (pbase != NULL) {
+               *pbase = base;
+       }
+       if (pstream != NULL) {
+               *pstream = stream;
+       }
+       return NT_STATUS_OK;
+}
+
+static bool test_stream_name(const char *fname, const char *expected_base,
+                            const char *expected_stream,
+                            NTSTATUS expected_status)
+{
+       NTSTATUS status;
+       char *base = NULL;
+       char *stream = NULL;
+
+       status = split_ntfs_stream_name(talloc_tos(), fname, &base, &stream);
+       if (!NT_STATUS_EQUAL(status, expected_status)) {
+               goto error;
+       }
+
+       if (!NT_STATUS_IS_OK(status)) {
+               return true;
+       }
+
+       if (base == NULL) goto error;
+
+       if (strcmp(expected_base, base) != 0) goto error;
+
+       if ((expected_stream != NULL) && (stream == NULL)) goto error;
+       if ((expected_stream == NULL) && (stream != NULL)) goto error;
+
+       if ((stream != NULL) && (strcmp(expected_stream, stream) != 0))
+               goto error;
+
+       TALLOC_FREE(base);
+       TALLOC_FREE(stream);
+       return true;
+
+ error:
+       d_fprintf(stderr, "Do test_stream(%s, %s, %s, %s)\n",
+                 fname, expected_base ? expected_base : "<NULL>",
+                 expected_stream ? expected_stream : "<NULL>",
+                 nt_errstr(expected_status));
+       d_fprintf(stderr, "-> base=%s, stream=%s, status=%s\n",
+                 base ? base : "<NULL>", stream ? stream : "<NULL>",
+                 nt_errstr(status));
+       TALLOC_FREE(base);
+       TALLOC_FREE(stream);
+       return false;
+}
+
+static bool run_local_stream_name(int dummy)
+{
+       bool ret = true;
+
+       ret &= test_stream_name(
+               "bla", "bla", NULL, NT_STATUS_OK);
+       ret &= test_stream_name(
+               "bla::$DATA", "bla", NULL, NT_STATUS_OK);
+       ret &= test_stream_name(
+               "bla:blub:", "bla", NULL, NT_STATUS_OBJECT_NAME_INVALID);
+       ret &= test_stream_name(
+               "bla::", NULL, NULL, NT_STATUS_OBJECT_NAME_INVALID);
+       ret &= test_stream_name(
+               "bla::123", "bla", NULL, NT_STATUS_OBJECT_NAME_INVALID);
+       ret &= test_stream_name(
+               "bla:$DATA", "bla", "$DATA:$DATA", NT_STATUS_OK);
+       ret &= test_stream_name(
+               "bla:x:$DATA", "bla", "x:$DATA", NT_STATUS_OK);
+       ret &= test_stream_name(
+               "bla:x", "bla", "x:$DATA", NT_STATUS_OK);
+
+       return ret;
+}
+
+static bool data_blob_equal(DATA_BLOB a, DATA_BLOB b)
+{
+       if (a.length != b.length) {
+               printf("a.length=%d != b.length=%d\n",
+                      (int)a.length, (int)b.length);
+               return false;
+       }
+       if (memcmp(a.data, b.data, a.length) != 0) {
+               printf("a.data and b.data differ\n");
+               return false;
+       }
+       return true;
+}
+
+static bool run_local_memcache(int dummy)
+{
+       struct memcache *cache;
+       DATA_BLOB k1, k2, k3, k4, k5;
+       DATA_BLOB d1, d3;
+       DATA_BLOB v1, v3;
+
+       TALLOC_CTX *mem_ctx;
+       char *ptr1 = NULL;
+       char *ptr2 = NULL;
+       char *ptr3 = NULL;
+
+       char *str1, *str2;
+       size_t size1, size2;
+       bool ret = false;
+
+       mem_ctx = talloc_init("foo");
+       if (mem_ctx == NULL) {
+               return false;
+       }
+
+       /* STAT_CACHE TESTS */
+
+       cache = memcache_init(NULL, sizeof(void *) == 8 ? 200 : 100);
+
+       if (cache == NULL) {
+               printf("memcache_init failed\n");
+               return false;
+       }
+
+       d1 = data_blob_const("d1", 2);
+       d3 = data_blob_const("d3", 2);
+
+       k1 = data_blob_const("d1", 2);
+       k2 = data_blob_const("d2", 2);
+       k3 = data_blob_const("d3", 2);
+       k4 = data_blob_const("d4", 2);
+       k5 = data_blob_const("d5", 2);
+
+       memcache_add(cache, STAT_CACHE, k1, d1);
+
+       if (!memcache_lookup(cache, STAT_CACHE, k1, &v1)) {
+               printf("could not find k1\n");
+               return false;
+       }
+       if (!data_blob_equal(d1, v1)) {
+               return false;
+       }
+
+       memcache_add(cache, STAT_CACHE, k1, d3);
+
+       if (!memcache_lookup(cache, STAT_CACHE, k1, &v3)) {
+               printf("could not find replaced k1\n");
+               return false;
+       }
+       if (!data_blob_equal(d3, v3)) {
+               return false;
+       }
+
+       TALLOC_FREE(cache);
+
+       /* GETWD_CACHE TESTS */
+       str1 = talloc_strdup(mem_ctx, "string1");
+       if (str1 == NULL) {
+               return false;
+       }
+       ptr2 = str1; /* Keep an alias for comparison. */
+
+       str2 = talloc_strdup(mem_ctx, "string2");
+       if (str2 == NULL) {
+               return false;
+       }
+
+       cache = memcache_init(NULL, sizeof(void *) == 8 ? 200 : 100);
+       if (cache == NULL) {
+               printf("memcache_init failed\n");
+               return false;
+       }
+
+       memcache_add_talloc(cache, GETWD_CACHE, k2, &str1);
+       /* str1 == NULL now. */
+       ptr1 = memcache_lookup_talloc(cache, GETWD_CACHE, k2);
+       if (ptr1 == NULL) {
+               printf("could not find k2\n");
+               return false;
+       }
+       if (ptr1 != ptr2) {
+               printf("fetch of k2 got wrong string\n");
+               return false;
+       }
+
+       /* Add a blob to ensure k2 gets purged. */
+       d3 = data_blob_talloc_zero(mem_ctx, 180);
+       memcache_add(cache, STAT_CACHE, k3, d3);
+
+       ptr2 = memcache_lookup_talloc(cache, GETWD_CACHE, k2);
+       if (ptr2 != NULL) {
+               printf("Did find k2, should have been purged\n");
+               return false;
+       }
+
+       /*
+        * Test that talloc size also is accounted in memcache and
+        * causes purge of other object.
+        */
+
+       str1 = talloc_zero_size(mem_ctx, 100);
+       str2 = talloc_zero_size(mem_ctx, 100);
+
+       memcache_add_talloc(cache, GETWD_CACHE, k4, &str1);
+       memcache_add_talloc(cache, GETWD_CACHE, k5, &str1);
+
+       ptr3 = memcache_lookup_talloc(cache, GETWD_CACHE, k4);
+       if (ptr3 != NULL) {
+               printf("Did find k4, should have been purged\n");
+               return false;
+       }
+
+       /*
+        * Test that adding a duplicate non-talloced
+        * key/value on top of a talloced key/value takes account
+        * of the talloc_freed value size.
+        */
+       TALLOC_FREE(cache);
+       TALLOC_FREE(mem_ctx);
+
+       mem_ctx = talloc_init("key_replace");
+       if (mem_ctx == NULL) {
+               return false;
+       }
+
+       cache = memcache_init(NULL, sizeof(void *) == 8 ? 200 : 100);
+       if (cache == NULL) {
+               return false;
+       }
+
+       /*
+        * Add a 100 byte talloced string. This will
+        * store a (4 or 8 byte) pointer and record the
+        * total talloced size.
         */
        str1 = talloc_zero_size(mem_ctx, 100);
        memcache_add_talloc(cache, GETWD_CACHE, k4, &str1);
@@ -13583,555 +14173,944 @@ static bool run_local_memcache(int dummy)
        str2 = talloc_zero_size(mem_ctx, 20);
        memcache_add_talloc(cache, GETWD_CACHE, k5, &str2);
 
-       ptr3 = memcache_lookup_talloc(cache, GETWD_CACHE, k4);
-       if (ptr3 == NULL) {
-               printf("Did not find k4, should not have been purged\n");
+       ptr3 = memcache_lookup_talloc(cache, GETWD_CACHE, k4);
+       if (ptr3 == NULL) {
+               printf("Did not find k4, should not have been purged\n");
+               return false;
+       }
+
+       TALLOC_FREE(cache);
+       TALLOC_FREE(mem_ctx);
+
+       mem_ctx = talloc_init("foo");
+       if (mem_ctx == NULL) {
+               return false;
+       }
+
+       cache = memcache_init(NULL, 0);
+       if (cache == NULL) {
+               return false;
+       }
+
+       str1 = talloc_strdup(mem_ctx, "string1");
+       if (str1 == NULL) {
+               return false;
+       }
+       str2 = talloc_strdup(mem_ctx, "string2");
+       if (str2 == NULL) {
+               return false;
+       }
+       memcache_add_talloc(cache, SINGLETON_CACHE_TALLOC,
+                           data_blob_string_const("torture"), &str1);
+       size1 = talloc_total_size(cache);
+
+       memcache_add_talloc(cache, SINGLETON_CACHE_TALLOC,
+                           data_blob_string_const("torture"), &str2);
+       size2 = talloc_total_size(cache);
+
+       printf("size1=%d, size2=%d\n", (int)size1, (int)size2);
+
+       if (size2 > size1) {
+               printf("memcache leaks memory!\n");
+               goto fail;
+       }
+
+       ret = true;
+ fail:
+       TALLOC_FREE(cache);
+       return ret;
+}
+
+static void wbclient_done(struct tevent_req *req)
+{
+       wbcErr wbc_err;
+       struct winbindd_response *wb_resp;
+       int *i = (int *)tevent_req_callback_data_void(req);
+
+       wbc_err = wb_trans_recv(req, req, &wb_resp);
+       TALLOC_FREE(req);
+       *i += 1;
+       d_printf("wb_trans_recv %d returned %s\n", *i, wbcErrorString(wbc_err));
+}
+
+static bool run_wbclient_multi_ping(int dummy)
+{
+       struct tevent_context *ev;
+       struct wb_context **wb_ctx;
+       struct winbindd_request wb_req;
+       bool result = false;
+       int i, j;
+
+       BlockSignals(True, SIGPIPE);
+
+       ev = tevent_context_init(talloc_tos());
+       if (ev == NULL) {
+               goto fail;
+       }
+
+       wb_ctx = talloc_array(ev, struct wb_context *, torture_nprocs);
+       if (wb_ctx == NULL) {
+               goto fail;
+       }
+
+       ZERO_STRUCT(wb_req);
+       wb_req.cmd = WINBINDD_PING;
+
+       d_printf("torture_nprocs=%d, numops=%d\n", (int)torture_nprocs, (int)torture_numops);
+
+       for (i=0; i<torture_nprocs; i++) {
+               wb_ctx[i] = wb_context_init(ev, NULL);
+               if (wb_ctx[i] == NULL) {
+                       goto fail;
+               }
+               for (j=0; j<torture_numops; j++) {
+                       struct tevent_req *req;
+                       req = wb_trans_send(ev, ev, wb_ctx[i],
+                                           (j % 2) == 0, &wb_req);
+                       if (req == NULL) {
+                               goto fail;
+                       }
+                       tevent_req_set_callback(req, wbclient_done, &i);
+               }
+       }
+
+       i = 0;
+
+       while (i < torture_nprocs * torture_numops) {
+               tevent_loop_once(ev);
+       }
+
+       result = true;
+ fail:
+       TALLOC_FREE(ev);
+       return result;
+}
+
+static bool dbtrans_inc(struct db_context *db)
+{
+       struct db_record *rec;
+       uint32_t val;
+       bool ret = false;
+       NTSTATUS status;
+       TDB_DATA value;
+
+       rec = dbwrap_fetch_locked(db, db, string_term_tdb_data("transtest"));
+       if (rec == NULL) {
+               printf(__location__ "fetch_lock failed\n");
                return false;
        }
 
-       TALLOC_FREE(cache);
-       TALLOC_FREE(mem_ctx);
+       value = dbwrap_record_get_value(rec);
 
-       mem_ctx = talloc_init("foo");
-       if (mem_ctx == NULL) {
-               return false;
+       if (value.dsize != sizeof(uint32_t)) {
+               printf(__location__ "value.dsize = %d\n",
+                      (int)value.dsize);
+               goto fail;
        }
 
-       cache = memcache_init(NULL, 0);
-       if (cache == NULL) {
+       memcpy(&val, value.dptr, sizeof(val));
+       val += 1;
+
+       status = dbwrap_record_store(
+               rec, make_tdb_data((uint8_t *)&val, sizeof(val)), 0);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf(__location__ "store failed: %s\n",
+                      nt_errstr(status));
+               goto fail;
+       }
+
+       ret = true;
+fail:
+       TALLOC_FREE(rec);
+       return ret;
+}
+
+static bool run_local_dbtrans(int dummy)
+{
+       struct db_context *db;
+       struct db_record *rec;
+       NTSTATUS status;
+       uint32_t initial;
+       int res;
+       TDB_DATA value;
+
+       db = db_open(talloc_tos(), "transtest.tdb", 0, TDB_DEFAULT,
+                    O_RDWR|O_CREAT, 0600, DBWRAP_LOCK_ORDER_1,
+                    DBWRAP_FLAG_NONE);
+       if (db == NULL) {
+               printf("Could not open transtest.db\n");
                return false;
        }
 
-       str1 = talloc_strdup(mem_ctx, "string1");
-       if (str1 == NULL) {
+       res = dbwrap_transaction_start(db);
+       if (res != 0) {
+               printf(__location__ "transaction_start failed\n");
                return false;
        }
-       str2 = talloc_strdup(mem_ctx, "string2");
-       if (str2 == NULL) {
+
+       rec = dbwrap_fetch_locked(db, db, string_term_tdb_data("transtest"));
+       if (rec == NULL) {
+               printf(__location__ "fetch_lock failed\n");
                return false;
        }
-       memcache_add_talloc(cache, SINGLETON_CACHE_TALLOC,
-                           data_blob_string_const("torture"), &str1);
-       size1 = talloc_total_size(cache);
 
-       memcache_add_talloc(cache, SINGLETON_CACHE_TALLOC,
-                           data_blob_string_const("torture"), &str2);
-       size2 = talloc_total_size(cache);
+       value = dbwrap_record_get_value(rec);
 
-       printf("size1=%d, size2=%d\n", (int)size1, (int)size2);
+       if (value.dptr == NULL) {
+               initial = 0;
+               status = dbwrap_record_store(
+                       rec, make_tdb_data((uint8_t *)&initial,
+                                          sizeof(initial)),
+                       0);
+               if (!NT_STATUS_IS_OK(status)) {
+                       printf(__location__ "store returned %s\n",
+                              nt_errstr(status));
+                       return false;
+               }
+       }
 
-       if (size2 > size1) {
-               printf("memcache leaks memory!\n");
-               goto fail;
+       TALLOC_FREE(rec);
+
+       res = dbwrap_transaction_commit(db);
+       if (res != 0) {
+               printf(__location__ "transaction_commit failed\n");
+               return false;
        }
 
-       ret = true;
- fail:
-       TALLOC_FREE(cache);
-       return ret;
-}
+       while (true) {
+               uint32_t val, val2;
+               int i;
 
-static void wbclient_done(struct tevent_req *req)
-{
-       wbcErr wbc_err;
-       struct winbindd_response *wb_resp;
-       int *i = (int *)tevent_req_callback_data_void(req);
+               res = dbwrap_transaction_start(db);
+               if (res != 0) {
+                       printf(__location__ "transaction_start failed\n");
+                       break;
+               }
 
-       wbc_err = wb_trans_recv(req, req, &wb_resp);
-       TALLOC_FREE(req);
-       *i += 1;
-       d_printf("wb_trans_recv %d returned %s\n", *i, wbcErrorString(wbc_err));
+               status = dbwrap_fetch_uint32_bystring(db, "transtest", &val);
+               if (!NT_STATUS_IS_OK(status)) {
+                       printf(__location__ "dbwrap_fetch_uint32 failed: %s\n",
+                              nt_errstr(status));
+                       break;
+               }
+
+               for (i=0; i<10; i++) {
+                       if (!dbtrans_inc(db)) {
+                               return false;
+                       }
+               }
+
+               status = dbwrap_fetch_uint32_bystring(db, "transtest", &val2);
+               if (!NT_STATUS_IS_OK(status)) {
+                       printf(__location__ "dbwrap_fetch_uint32 failed: %s\n",
+                              nt_errstr(status));
+                       break;
+               }
+
+               if (val2 != val + 10) {
+                       printf(__location__ "val=%d, val2=%d\n",
+                              (int)val, (int)val2);
+                       break;
+               }
+
+               printf("val2=%d\r", val2);
+
+               res = dbwrap_transaction_commit(db);
+               if (res != 0) {
+                       printf(__location__ "transaction_commit failed\n");
+                       break;
+               }
+       }
+
+       TALLOC_FREE(db);
+       return true;
 }
 
-static bool run_wbclient_multi_ping(int dummy)
+/*
+ * Just a dummy test to be run under a debugger. There's no real way
+ * to inspect the tevent_poll specific function from outside of
+ * tevent_poll.c.
+ */
+
+static bool run_local_tevent_poll(int dummy)
 {
        struct tevent_context *ev;
-       struct wb_context **wb_ctx;
-       struct winbindd_request wb_req;
+       struct tevent_fd *fd1, *fd2;
        bool result = false;
-       int i, j;
-
-       BlockSignals(True, SIGPIPE);
 
-       ev = tevent_context_init(talloc_tos());
+       ev = tevent_context_init_byname(NULL, "poll");
        if (ev == NULL) {
+               d_fprintf(stderr, "tevent_context_init_byname failed\n");
                goto fail;
        }
 
-       wb_ctx = talloc_array(ev, struct wb_context *, torture_nprocs);
-       if (wb_ctx == NULL) {
+       fd1 = tevent_add_fd(ev, ev, 2, 0, NULL, NULL);
+       if (fd1 == NULL) {
+               d_fprintf(stderr, "tevent_add_fd failed\n");
                goto fail;
        }
+       fd2 = tevent_add_fd(ev, ev, 3, 0, NULL, NULL);
+       if (fd2 == NULL) {
+               d_fprintf(stderr, "tevent_add_fd failed\n");
+               goto fail;
+       }
+       TALLOC_FREE(fd2);
+
+       fd2 = tevent_add_fd(ev, ev, 1, 0, NULL, NULL);
+       if (fd2 == NULL) {
+               d_fprintf(stderr, "tevent_add_fd failed\n");
+               goto fail;
+       }
+
+       result = true;
+fail:
+       TALLOC_FREE(ev);
+       return result;
+}
+
+static bool run_local_hex_encode_buf(int dummy)
+{
+       char buf[17];
+       uint8_t src[8];
+       size_t i;
+
+       for (i=0; i<sizeof(src); i++) {
+               src[i] = i;
+       }
+       hex_encode_buf(buf, src, sizeof(src));
+       if (strcmp(buf, "0001020304050607") != 0) {
+               return false;
+       }
+       hex_encode_buf(buf, NULL, 0);
+       if (buf[0] != '\0') {
+               return false;
+       }
+       return true;
+}
+
+static const char *remove_duplicate_addrs2_test_strings_vector[] = {
+       "0.0.0.0",
+       "::0",
+       "1.2.3.1",
+       "0.0.0.0",
+       "0.0.0.0",
+       "1.2.3.2",
+       "1.2.3.3",
+       "1.2.3.4",
+       "1.2.3.5",
+       "::0",
+       "1.2.3.6",
+       "1.2.3.7",
+       "::0",
+       "::0",
+       "::0",
+       "1.2.3.8",
+       "1.2.3.9",
+       "1.2.3.10",
+       "1.2.3.11",
+       "1.2.3.12",
+       "1.2.3.13",
+       "1001:1111:1111:1000:0:1111:1111:1111",
+       "1.2.3.1",
+       "1.2.3.2",
+       "1.2.3.3",
+       "1.2.3.12",
+       "::0",
+       "::0"
+};
+
+static const char *remove_duplicate_addrs2_test_strings_result[] = {
+       "1.2.3.1",
+       "1.2.3.2",
+       "1.2.3.3",
+       "1.2.3.4",
+       "1.2.3.5",
+       "1.2.3.6",
+       "1.2.3.7",
+       "1.2.3.8",
+       "1.2.3.9",
+       "1.2.3.10",
+       "1.2.3.11",
+       "1.2.3.12",
+       "1.2.3.13",
+       "1001:1111:1111:1000:0:1111:1111:1111"
+};
 
-       ZERO_STRUCT(wb_req);
-       wb_req.cmd = WINBINDD_PING;
+static bool run_local_remove_duplicate_addrs2(int dummy)
+{
+       struct samba_sockaddr test_vector[28];
+       size_t count, i;
 
-       d_printf("torture_nprocs=%d, numops=%d\n", (int)torture_nprocs, (int)torture_numops);
+       /* Construct the sockaddr_storage test vector. */
+       for (i = 0; i < 28; i++) {
+               struct addrinfo hints;
+               struct addrinfo *res = NULL;
+               int ret;
 
-       for (i=0; i<torture_nprocs; i++) {
-               wb_ctx[i] = wb_context_init(ev, NULL);
-               if (wb_ctx[i] == NULL) {
-                       goto fail;
-               }
-               for (j=0; j<torture_numops; j++) {
-                       struct tevent_req *req;
-                       req = wb_trans_send(ev, ev, wb_ctx[i],
-                                           (j % 2) == 0, &wb_req);
-                       if (req == NULL) {
-                               goto fail;
-                       }
-                       tevent_req_set_callback(req, wbclient_done, &i);
+               memset(&hints, '\0', sizeof(hints));
+               hints.ai_flags = AI_NUMERICHOST;
+               ret = getaddrinfo(remove_duplicate_addrs2_test_strings_vector[i],
+                               NULL,
+                               &hints,
+                               &res);
+               if (ret) {
+                       fprintf(stderr, "getaddrinfo failed on [%s]\n",
+                               remove_duplicate_addrs2_test_strings_vector[i]);
+                       return false;
                }
+               memset(&test_vector[i], '\0', sizeof(test_vector[i]));
+               memcpy(&test_vector[i].u.ss,
+                       res->ai_addr,
+                       res->ai_addrlen);
+               freeaddrinfo(res);
        }
 
-       i = 0;
-
-       while (i < torture_nprocs * torture_numops) {
-               tevent_loop_once(ev);
-       }
-
-       result = true;
- fail:
-       TALLOC_FREE(ev);
-       return result;
-}
-
-static bool dbtrans_inc(struct db_context *db)
-{
-       struct db_record *rec;
-       uint32_t val;
-       bool ret = false;
-       NTSTATUS status;
-       TDB_DATA value;
+       count = remove_duplicate_addrs2(test_vector, i);
 
-       rec = dbwrap_fetch_locked(db, db, string_term_tdb_data("transtest"));
-       if (rec == NULL) {
-               printf(__location__ "fetch_lock failed\n");
+       if (count != 14) {
+               fprintf(stderr, "count wrong (%zu) should be 14\n",
+                       count);
                return false;
        }
 
-       value = dbwrap_record_get_value(rec);
-
-       if (value.dsize != sizeof(uint32_t)) {
-               printf(__location__ "value.dsize = %d\n",
-                      (int)value.dsize);
-               goto fail;
-       }
+       for (i = 0; i < count; i++) {
+               char addr[INET6_ADDRSTRLEN];
 
-       memcpy(&val, value.dptr, sizeof(val));
-       val += 1;
+               print_sockaddr(addr, sizeof(addr), &test_vector[i].u.ss);
 
-       status = dbwrap_record_store(
-               rec, make_tdb_data((uint8_t *)&val, sizeof(val)), 0);
-       if (!NT_STATUS_IS_OK(status)) {
-               printf(__location__ "store failed: %s\n",
-                      nt_errstr(status));
-               goto fail;
+               if (strcmp(addr, remove_duplicate_addrs2_test_strings_result[i]) != 0) {
+                       fprintf(stderr, "mismatch on [%zu] [%s] [%s]\n",
+                               i,
+                               addr,
+                               remove_duplicate_addrs2_test_strings_result[i]);
+                       return false;
+               }
        }
 
-       ret = true;
-fail:
-       TALLOC_FREE(rec);
-       return ret;
+       printf("run_local_remove_duplicate_addrs2: success\n");
+       return true;
 }
 
-static bool run_local_dbtrans(int dummy)
+static bool run_local_tdb_opener(int dummy)
 {
-       struct db_context *db;
-       struct db_record *rec;
-       NTSTATUS status;
-       uint32_t initial;
-       int res;
-       TDB_DATA value;
-
-       db = db_open(talloc_tos(), "transtest.tdb", 0, TDB_DEFAULT,
-                    O_RDWR|O_CREAT, 0600, DBWRAP_LOCK_ORDER_1,
-                    DBWRAP_FLAG_NONE);
-       if (db == NULL) {
-               printf("Could not open transtest.db\n");
-               return false;
-       }
-
-       res = dbwrap_transaction_start(db);
-       if (res != 0) {
-               printf(__location__ "transaction_start failed\n");
-               return false;
-       }
-
-       rec = dbwrap_fetch_locked(db, db, string_term_tdb_data("transtest"));
-       if (rec == NULL) {
-               printf(__location__ "fetch_lock failed\n");
-               return false;
-       }
-
-       value = dbwrap_record_get_value(rec);
+       TDB_CONTEXT *t;
+       unsigned v = 0;
 
-       if (value.dptr == NULL) {
-               initial = 0;
-               status = dbwrap_record_store(
-                       rec, make_tdb_data((uint8_t *)&initial,
-                                          sizeof(initial)),
-                       0);
-               if (!NT_STATUS_IS_OK(status)) {
-                       printf(__location__ "store returned %s\n",
-                              nt_errstr(status));
+       while (1) {
+               t = tdb_open("test.tdb", 1000, TDB_CLEAR_IF_FIRST,
+                            O_RDWR|O_CREAT, 0755);
+               if (t == NULL) {
+                       perror("tdb_open failed");
                        return false;
                }
+               tdb_close(t);
+
+               v += 1;
+               printf("\r%u", v);
        }
+       return true;
+}
 
-       TALLOC_FREE(rec);
+static bool run_local_tdb_writer(int dummy)
+{
+       TDB_CONTEXT *t;
+       unsigned v = 0;
+       TDB_DATA val;
 
-       res = dbwrap_transaction_commit(db);
-       if (res != 0) {
-               printf(__location__ "transaction_commit failed\n");
-               return false;
+       t = tdb_open("test.tdb", 1000, 0, O_RDWR|O_CREAT, 0755);
+       if (t == 0) {
+               perror("tdb_open failed");
+               return 1;
        }
 
-       while (true) {
-               uint32_t val, val2;
-               int i;
+       val.dptr = (uint8_t *)&v;
+       val.dsize = sizeof(v);
 
-               res = dbwrap_transaction_start(db);
-               if (res != 0) {
-                       printf(__location__ "transaction_start failed\n");
-                       break;
+       while (1) {
+               TDB_DATA data;
+               int ret;
+
+               ret = tdb_store(t, val, val, 0);
+               if (ret != 0) {
+                       printf("%s\n", tdb_errorstr(t));
                }
+               v += 1;
+               printf("\r%u", v);
 
-               status = dbwrap_fetch_uint32_bystring(db, "transtest", &val);
-               if (!NT_STATUS_IS_OK(status)) {
-                       printf(__location__ "dbwrap_fetch_uint32 failed: %s\n",
-                              nt_errstr(status));
-                       break;
+               data = tdb_fetch(t, val);
+               if (data.dptr != NULL) {
+                       SAFE_FREE(data.dptr);
                }
+       }
+       return true;
+}
+
+static bool run_local_canonicalize_path(int dummy)
+{
+       const char *src[] = {
+                       "/foo/..",
+                       "/..",
+                       "/foo/bar/../baz",
+                       "/foo/././",
+                       "/../foo",
+                       ".././././",
+                       ".././././../../../boo",
+                       "./..",
+                       "/",
+                       "/../../",
+                       "/foo/../",
+                       "/./././",
+                       "/./././.",
+                       "/.../././.",
+                       "/./././.foo",
+                       "/./././.foo.",
+                       "/./././foo.",
+                       "/foo/bar/..",
+                       "/foo/bar/../baz/",
+                       "////////////////",
+                       "/////////./././././.",
+                       "/./.././../.boo/../baz",
+                       "/a/component/path",
+                       "/a/component/path/",
+                       "/a/component/path/..",
+                       "/a/component/../path/",
+                       "///a/./././///component/../////path/",
+                       NULL
+                       };
+       const char *dst[] = {
+                       "/",
+                       "/",
+                       "/foo/baz",
+                       "/foo",
+                       "/foo",
+                       "/",
+                       "/boo",
+                       "/",
+                       "/",
+                       "/",
+                       "/",
+                       "/",
+                       "/",
+                       "/...",
+                       "/.foo",
+                       "/.foo.",
+                       "/foo.",
+                       "/foo",
+                       "/foo/baz",
+                       "/",
+                       "/",
+                       "/baz",
+                       "/a/component/path",
+                       "/a/component/path",
+                       "/a/component",
+                       "/a/path",
+                       "/a/path",
+                       NULL
+                       };
+       unsigned int i;
 
-               for (i=0; i<10; i++) {
-                       if (!dbtrans_inc(db)) {
-                               return false;
-                       }
+       for (i = 0; src[i] != NULL; i++) {
+               char *d = canonicalize_absolute_path(talloc_tos(), src[i]);
+               if (d == NULL) {
+                       perror("talloc fail\n");
+                       return false;
                }
-
-               status = dbwrap_fetch_uint32_bystring(db, "transtest", &val2);
-               if (!NT_STATUS_IS_OK(status)) {
-                       printf(__location__ "dbwrap_fetch_uint32 failed: %s\n",
-                              nt_errstr(status));
-                       break;
+               if (strcmp(d, dst[i]) != 0) {
+                       d_fprintf(stderr,
+                               "canonicalize mismatch %s -> %s != %s",
+                               src[i], d, dst[i]);
+                       return false;
                }
+               talloc_free(d);
+       }
+       return true;
+}
+struct session_setup_nt1_truncated_state {
+       uint16_t vwv[13];
+       uint8_t bytes[20];
+};
 
-               if (val2 != val + 10) {
-                       printf(__location__ "val=%d, val2=%d\n",
-                              (int)val, (int)val2);
-                       break;
-               }
+static void smb1_session_setup_nt1_truncated_done(struct tevent_req *subreq);
 
-               printf("val2=%d\r", val2);
+static struct tevent_req *smb1_session_setup_nt1_truncated_send(
+               TALLOC_CTX *mem_ctx,
+               struct tevent_context *ev,
+               struct smbXcli_conn *conn)
+{
+       uint16_t *vwv = NULL;
+       uint8_t *bytes = NULL;
+       const char *pass = "12345678";
+       const char *uname = "z";
+       struct session_setup_nt1_truncated_state *state = NULL;
+       struct tevent_req *req = NULL;
+       struct tevent_req *subreq = NULL;
 
-               res = dbwrap_transaction_commit(db);
-               if (res != 0) {
-                       printf(__location__ "transaction_commit failed\n");
-                       break;
-               }
+       req = tevent_req_create(mem_ctx,
+                               &state,
+                               struct session_setup_nt1_truncated_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       vwv = &state->vwv[0];
+       bytes = &state->bytes[0];
+
+       SCVAL(vwv+0,  0, 0xff);
+       SCVAL(vwv+0,  1, 0);
+       SSVAL(vwv+1,  0, 0);
+       SSVAL(vwv+2,  0, 8192);
+       SSVAL(vwv+3,  0, 2);
+       SSVAL(vwv+4,  0, 1);
+       SIVAL(vwv+5,  0, 0);
+       SSVAL(vwv+7,  0, strlen(pass)); /* OEMPasswordLen */
+       SSVAL(vwv+8,  0, 0); /* UnicodePasswordLen */
+       SSVAL(vwv+9,  0, 0); /* reserved */
+       SSVAL(vwv+10, 0, 0); /* reserved */
+       SIVAL(vwv+11, 0, CAP_STATUS32);
+
+       memcpy(bytes, pass, strlen(pass));
+       bytes += strlen(pass);
+       memcpy(bytes, uname, strlen(uname)+1);
+
+       subreq = smb1cli_req_send(state, ev, conn,
+                                 SMBsesssetupX,
+                                 0, /*  additional_flags */
+                                 0, /*  clear_flags */
+                                 0, /*  additional_flags2 */
+                                 0, /*  clear_flags2 */
+                                 10000, /* timeout_msec */
+                                 getpid(),
+                                 NULL, /* tcon */
+                                 NULL, /* session */
+                                 13, /* wct */
+                                 state->vwv,
+                                 strlen(pass), /* Truncate length at password. */
+                                 state->bytes);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
        }
+       tevent_req_set_callback(subreq,
+                               smb1_session_setup_nt1_truncated_done,
+                               req);
+       return req;
+}
 
-       TALLOC_FREE(db);
-       return true;
+static void smb1_session_setup_nt1_truncated_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct session_setup_nt1_truncated_state *state =
+               tevent_req_data(req,
+               struct session_setup_nt1_truncated_state);
+       NTSTATUS status;
+       struct smb1cli_req_expected_response expected[] = {
+       {
+               .status = NT_STATUS_OK,
+               .wct    = 3,
+       },
+       };
+
+       status = smb1cli_req_recv(subreq, state,
+                                 NULL,
+                                 NULL,
+                                 NULL,
+                                 NULL,
+                                 NULL, /* pvwv_offset */
+                                 NULL,
+                                 NULL,
+                                 NULL, /* pbytes_offset */
+                                 NULL,
+                                 expected, ARRAY_SIZE(expected));
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+       tevent_req_done(req);
 }
 
-/*
- * Just a dummy test to be run under a debugger. There's no real way
- * to inspect the tevent_poll specific function from outside of
- * tevent_poll.c.
- */
+static NTSTATUS smb1_session_setup_nt1_truncated_recv(struct tevent_req *req)
+{
+       return tevent_req_simple_recv_ntstatus(req);
+}
 
-static bool run_local_tevent_poll(int dummy)
+static bool run_smb1_truncated_sesssetup(int dummy)
 {
        struct tevent_context *ev;
-       struct tevent_fd *fd1, *fd2;
-       bool result = false;
+       struct tevent_req *req;
+       struct smbXcli_conn *conn;
+       struct sockaddr_storage ss;
+       NTSTATUS status;
+       int fd;
+       bool ok;
 
-       ev = tevent_context_init_byname(NULL, "poll");
-       if (ev == NULL) {
-               d_fprintf(stderr, "tevent_context_init_byname failed\n");
-               goto fail;
-       }
+       printf("Starting send truncated SMB1 sesssetup.\n");
 
-       fd1 = tevent_add_fd(ev, ev, 2, 0, NULL, NULL);
-       if (fd1 == NULL) {
-               d_fprintf(stderr, "tevent_add_fd failed\n");
-               goto fail;
+       ok = resolve_name(host, &ss, 0x20, true);
+       if (!ok) {
+               d_fprintf(stderr, "Could not resolve name %s\n", host);
+               return false;
        }
-       fd2 = tevent_add_fd(ev, ev, 3, 0, NULL, NULL);
-       if (fd2 == NULL) {
-               d_fprintf(stderr, "tevent_add_fd failed\n");
-               goto fail;
+
+       status = open_socket_out(&ss, 445, 10000, &fd);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "open_socket_out failed: %s\n",
+                         nt_errstr(status));
+               return false;
        }
-       TALLOC_FREE(fd2);
 
-       fd2 = tevent_add_fd(ev, ev, 1, 0, NULL, NULL);
-       if (fd2 == NULL) {
-               d_fprintf(stderr, "tevent_add_fd failed\n");
-               goto fail;
+       conn = smbXcli_conn_create(talloc_tos(), fd, host, SMB_SIGNING_OFF, 0,
+                                  NULL, 0, NULL);
+       if (conn == NULL) {
+               d_fprintf(stderr, "smbXcli_conn_create failed\n");
+               return false;
        }
 
-       result = true;
-fail:
-       TALLOC_FREE(ev);
-       return result;
-}
+       status = smbXcli_negprot(conn, 0, PROTOCOL_NT1, PROTOCOL_NT1);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "smbXcli_negprot failed!\n");
+               return false;
+       }
 
-static bool run_local_hex_encode_buf(int dummy)
-{
-       char buf[17];
-       uint8_t src[8];
-       int i;
+       ev = samba_tevent_context_init(talloc_tos());
+       if (ev == NULL) {
+               d_fprintf(stderr, "samba_tevent_context_init failed\n");
+               return false;
+       }
 
-       for (i=0; i<sizeof(src); i++) {
-               src[i] = i;
+       req = smb1_session_setup_nt1_truncated_send(ev, ev, conn);
+       if (req == NULL) {
+               d_fprintf(stderr, "smb1_session_setup_nt1_truncated_send failed\n");
+               return false;
        }
-       hex_encode_buf(buf, src, sizeof(src));
-       if (strcmp(buf, "0001020304050607") != 0) {
-               return false;
+
+       ok = tevent_req_poll_ntstatus(req, ev, &status);
+       if (!ok) {
+               d_fprintf(stderr, "tevent_req_poll failed with status %s\n",
+                       nt_errstr(status));
+               return false;
        }
-       hex_encode_buf(buf, NULL, 0);
-       if (buf[0] != '\0') {
+
+       status = smb1_session_setup_nt1_truncated_recv(req);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "smb1_session_setup_nt1_truncated_recv returned "
+                         "%s, expected NT_STATUS_OK\n",
+                         nt_errstr(status));
                return false;
        }
+
+       TALLOC_FREE(conn);
        return true;
 }
 
-static const char *remove_duplicate_addrs2_test_strings_vector[] = {
-       "0.0.0.0",
-       "::0",
-       "1.2.3.1",
-       "0.0.0.0",
-       "0.0.0.0",
-       "1.2.3.2",
-       "1.2.3.3",
-       "1.2.3.4",
-       "1.2.3.5",
-       "::0",
-       "1.2.3.6",
-       "1.2.3.7",
-       "::0",
-       "::0",
-       "::0",
-       "1.2.3.8",
-       "1.2.3.9",
-       "1.2.3.10",
-       "1.2.3.11",
-       "1.2.3.12",
-       "1.2.3.13",
-       "1001:1111:1111:1000:0:1111:1111:1111",
-       "1.2.3.1",
-       "1.2.3.2",
-       "1.2.3.3",
-       "1.2.3.12",
-       "::0",
-       "::0"
+struct smb1_negotiate_exit_state {
+       int dummy;
 };
 
-static const char *remove_duplicate_addrs2_test_strings_result[] = {
-       "1.2.3.1",
-       "1.2.3.2",
-       "1.2.3.3",
-       "1.2.3.4",
-       "1.2.3.5",
-       "1.2.3.6",
-       "1.2.3.7",
-       "1.2.3.8",
-       "1.2.3.9",
-       "1.2.3.10",
-       "1.2.3.11",
-       "1.2.3.12",
-       "1.2.3.13",
-       "1001:1111:1111:1000:0:1111:1111:1111"
-};
+static void smb1_negotiate_exit_done(struct tevent_req *subreq);
 
-static bool run_local_remove_duplicate_addrs2(int dummy)
+static struct tevent_req *smb1_negotiate_exit_send(
+               TALLOC_CTX *mem_ctx,
+               struct tevent_context *ev,
+               struct smbXcli_conn *conn)
 {
-       struct ip_service test_vector[28];
-       int count, i;
-
-       /* Construct the sockaddr_storage test vector. */
-       for (i = 0; i < 28; i++) {
-               struct addrinfo hints;
-               struct addrinfo *res = NULL;
-               int ret;
+       struct smb1_negotiate_exit_state *state = NULL;
+       struct tevent_req *req = NULL;
+       struct tevent_req *subreq = NULL;
 
-               memset(&hints, '\0', sizeof(hints));
-               hints.ai_flags = AI_NUMERICHOST;
-               ret = getaddrinfo(remove_duplicate_addrs2_test_strings_vector[i],
-                               NULL,
-                               &hints,
-                               &res);
-               if (ret) {
-                       fprintf(stderr, "getaddrinfo failed on [%s]\n",
-                               remove_duplicate_addrs2_test_strings_vector[i]);
-                       return false;
-               }
-               memset(&test_vector[i], '\0', sizeof(test_vector[i]));
-               memcpy(&test_vector[i].ss,
-                       res->ai_addr,
-                       res->ai_addrlen);
-               freeaddrinfo(res);
+       req = tevent_req_create(mem_ctx,
+                               &state,
+                               struct smb1_negotiate_exit_state);
+       if (req == NULL) {
+               return NULL;
        }
-
-       count = remove_duplicate_addrs2(test_vector, i);
-
-       if (count != 14) {
-               fprintf(stderr, "count wrong (%d) should be 14\n",
-                       count);
-               return false;
+       subreq = smb1cli_req_send(state, ev, conn,
+                                 SMBexit,
+                                 0, /*  additional_flags */
+                                 0, /*  clear_flags */
+                                 0, /*  additional_flags2 */
+                                 0, /*  clear_flags2 */
+                                 10000, /* timeout_msec */
+                                 getpid(),
+                                 NULL, /* tcon */
+                                 NULL, /* session */
+                                 0, /* wct */
+                                 NULL,
+                                 0,
+                                 NULL);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
        }
+       tevent_req_set_callback(subreq,
+                               smb1_negotiate_exit_done,
+                               req);
+       return req;
+}
 
-       for (i = 0; i < count; i++) {
-               char addr[INET6_ADDRSTRLEN];
-
-               print_sockaddr(addr, sizeof(addr), &test_vector[i].ss);
+static void smb1_negotiate_exit_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct smb1_negotiate_exit_state *state =
+               tevent_req_data(req,
+               struct smb1_negotiate_exit_state);
+       NTSTATUS status;
+       struct smb1cli_req_expected_response expected[] = {
+       {
+               .status = NT_STATUS_OK,
+               .wct    = 0,
+       },
+       };
 
-               if (strcmp(addr, remove_duplicate_addrs2_test_strings_result[i]) != 0) {
-                       fprintf(stderr, "mismatch on [%d] [%s] [%s]\n",
-                               i,
-                               addr,
-                               remove_duplicate_addrs2_test_strings_result[i]);
-                       return false;
-               }
+       status = smb1cli_req_recv(subreq, state,
+                                 NULL,
+                                 NULL,
+                                 NULL,
+                                 NULL,
+                                 NULL, /* pvwv_offset */
+                                 NULL,
+                                 NULL,
+                                 NULL, /* pbytes_offset */
+                                 NULL,
+                                 expected, ARRAY_SIZE(expected));
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
        }
+       tevent_req_done(req);
+}
 
-       printf("run_local_remove_duplicate_addrs2: success\n");
-       return true;
+static NTSTATUS smb1_negotiate_exit_recv(struct tevent_req *req)
+{
+       return tevent_req_simple_recv_ntstatus(req);
 }
 
-static bool run_local_tdb_opener(int dummy)
+static bool do_smb1_exit(TALLOC_CTX *mem_ctx,
+                        struct tevent_context *ev,
+                        struct smbXcli_conn *conn)
 {
-       TDB_CONTEXT *t;
-       unsigned v = 0;
+       struct tevent_req *req;
+       bool ok;
+       NTSTATUS status;
+       NTSTATUS expected_status = NT_STATUS_DOS(ERRSRV, ERRinvnid);;
 
-       while (1) {
-               t = tdb_open("test.tdb", 1000, TDB_CLEAR_IF_FIRST,
-                            O_RDWR|O_CREAT, 0755);
-               if (t == NULL) {
-                       perror("tdb_open failed");
-                       return false;
-               }
-               tdb_close(t);
+       req = smb1_negotiate_exit_send(ev, ev, conn);
+       if (req == NULL) {
+               d_fprintf(stderr, "smb1_negotiate_exit_send failed\n");
+               return false;
+       }
 
-               v += 1;
-               printf("\r%u", v);
+       ok = tevent_req_poll_ntstatus(req, ev, &status);
+       if (!ok) {
+               d_fprintf(stderr, "tevent_req_poll failed with status %s\n",
+                       nt_errstr(status));
+               return false;
+       }
+
+       status = smb1_negotiate_exit_recv(req);
+       if (!NT_STATUS_EQUAL(status, expected_status)) {
+               d_fprintf(stderr, "smb1_negotiate_exit_recv returned "
+                         "%s, expected ERRSRV, ERRinvnid\n",
+                         nt_errstr(status));
+               return false;
        }
        return true;
 }
 
-static bool run_local_tdb_writer(int dummy)
+static bool run_smb1_negotiate_exit(int dummy)
 {
-       TDB_CONTEXT *t;
-       unsigned v = 0;
-       TDB_DATA val;
+       struct tevent_context *ev;
+       struct smbXcli_conn *conn;
+       struct sockaddr_storage ss;
+       NTSTATUS status;
+       int fd;
+       bool ok;
 
-       t = tdb_open("test.tdb", 1000, 0, O_RDWR|O_CREAT, 0755);
-       if (t == 0) {
-               perror("tdb_open failed");
-               return 1;
+       printf("Starting send SMB1 negotiate+exit.\n");
+
+       ok = resolve_name(host, &ss, 0x20, true);
+       if (!ok) {
+               d_fprintf(stderr, "Could not resolve name %s\n", host);
+               return false;
        }
 
-       val.dptr = (uint8_t *)&v;
-       val.dsize = sizeof(v);
+       status = open_socket_out(&ss, 445, 10000, &fd);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "open_socket_out failed: %s\n",
+                         nt_errstr(status));
+               return false;
+       }
 
-       while (1) {
-               TDB_DATA data;
-               int ret;
+       conn = smbXcli_conn_create(talloc_tos(), fd, host, SMB_SIGNING_OFF, 0,
+                                  NULL, 0, NULL);
+       if (conn == NULL) {
+               d_fprintf(stderr, "smbXcli_conn_create failed\n");
+               return false;
+       }
 
-               ret = tdb_store(t, val, val, 0);
-               if (ret != 0) {
-                       printf("%s\n", tdb_errorstr(t));
-               }
-               v += 1;
-               printf("\r%u", v);
+       status = smbXcli_negprot(conn, 0, PROTOCOL_NT1, PROTOCOL_NT1);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "smbXcli_negprot failed!\n");
+               return false;
+       }
 
-               data = tdb_fetch(t, val);
-               if (data.dptr != NULL) {
-                       SAFE_FREE(data.dptr);
-               }
+       ev = samba_tevent_context_init(talloc_tos());
+       if (ev == NULL) {
+               d_fprintf(stderr, "samba_tevent_context_init failed\n");
+               return false;
        }
+
+       /*
+        * Call do_smb1_exit twice to catch a server crash, the
+        * server sends the first return code then crashes.
+        */
+       ok = do_smb1_exit(ev, ev, conn);
+       if (!ok) {
+               d_fprintf(stderr, "do_smb1_exit (1) failed\n");
+               return false;
+       }
+       ok = do_smb1_exit(ev, ev, conn);
+       if (!ok) {
+               d_fprintf(stderr, "do_smb1_exit (2) failed\n");
+               return false;
+       }
+
+       TALLOC_FREE(conn);
        return true;
 }
 
-static bool run_local_canonicalize_path(int dummy)
+static bool run_smb1_negotiate_tcon(int dummy)
 {
-       const char *src[] = {
-                       "/foo/..",
-                       "/..",
-                       "/foo/bar/../baz",
-                       "/foo/././",
-                       "/../foo",
-                       ".././././",
-                       ".././././../../../boo",
-                       "./..",
-                       "/",
-                       "/../../",
-                       "/foo/../",
-                       "/./././",
-                       "/./././.",
-                       "/.../././.",
-                       "/./././.foo",
-                       "/./././.foo.",
-                       "/./././foo.",
-                       "/foo/bar/..",
-                       "/foo/bar/../baz/",
-                       "////////////////",
-                       "/////////./././././.",
-                       "/./.././../.boo/../baz",
-                       "/a/component/path",
-                       "/a/component/path/",
-                       "/a/component/path/..",
-                       "/a/component/../path/",
-                       "///a/./././///component/../////path/",
-                       NULL
-                       };
-       const char *dst[] = {
-                       "/",
-                       "/",
-                       "/foo/baz",
-                       "/foo",
-                       "/foo",
-                       "/",
-                       "/boo",
-                       "/",
-                       "/",
-                       "/",
-                       "/",
-                       "/",
-                       "/",
-                       "/...",
-                       "/.foo",
-                       "/.foo.",
-                       "/foo.",
-                       "/foo",
-                       "/foo/baz",
-                       "/",
-                       "/",
-                       "/baz",
-                       "/a/component/path",
-                       "/a/component/path",
-                       "/a/component",
-                       "/a/path",
-                       "/a/path",
-                       NULL
-                       };
-       unsigned int i;
+       struct cli_state *cli = NULL;
+       uint16_t cnum = 0;
+       uint16_t max_xmit = 0;
+       NTSTATUS status;
 
-       for (i = 0; src[i] != NULL; i++) {
-               char *d = canonicalize_absolute_path(talloc_tos(), src[i]);
-               if (d == NULL) {
-                       perror("talloc fail\n");
-                       return false;
-               }
-               if (strcmp(d, dst[i]) != 0) {
-                       d_fprintf(stderr,
-                               "canonicalize mismatch %s -> %s != %s",
-                               src[i], d, dst[i]);
-                       return false;
-               }
-               talloc_free(d);
+       printf("Starting send SMB1 negotiate+tcon.\n");
+       cli = open_nbt_connection();
+       if (cli == NULL) {
+               d_fprintf(stderr, "open_nbt_connection failed!\n");
+               return false;
+       }
+       smbXcli_conn_set_sockopt(cli->conn, sockops);
+
+       status = smbXcli_negprot(cli->conn, 0, PROTOCOL_NT1, PROTOCOL_NT1);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "smbXcli_negprot failed %s!\n",
+                       nt_errstr(status));
+               return false;
+       }
+        status = cli_raw_tcon(cli,
+                             share,
+                             "",
+                             "?????",
+                             &max_xmit,
+                             &cnum);
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+               d_fprintf(stderr, "cli_raw_tcon failed - got %s "
+                       "(should get NT_STATUS_ACCESS_DENIED)!\n",
+                       nt_errstr(status));
+               return false;
        }
        return true;
 }
@@ -14162,7 +15141,7 @@ static bool run_ign_bad_negprot(int dummy)
        }
 
        conn = smbXcli_conn_create(talloc_tos(), fd, host, SMB_SIGNING_OFF, 0,
-                                  NULL, 0);
+                                  NULL, 0, NULL);
        if (conn == NULL) {
                d_fprintf(stderr, "smbXcli_conn_create failed\n");
                return false;
@@ -14211,6 +15190,7 @@ static bool run_ign_bad_negprot(int dummy)
        return true;
 }
 
+
 static double create_procs(bool (*fn)(int), bool *result)
 {
        int i, status;
@@ -14521,10 +15501,58 @@ static struct {
                .name  = "POSIX-ACL-SHAREROOT",
                .fn    = run_posix_acl_shareroot_test,
        },
+       {
+               .name  = "POSIX-LS-WILDCARD",
+               .fn    = run_posix_ls_wildcard_test,
+       },
+       {
+               .name  = "POSIX-LS-SINGLE",
+               .fn    = run_posix_ls_single_test,
+       },
+       {
+               .name  = "POSIX-READLINK",
+               .fn    = run_posix_readlink_test,
+       },
+       {
+               .name  = "POSIX-STAT",
+               .fn    = run_posix_stat_test,
+       },
+       {
+               .name  = "POSIX-SYMLINK-PARENT",
+               .fn    = run_posix_symlink_parent_test,
+       },
+       {
+               .name  = "POSIX-SYMLINK-CHMOD",
+               .fn    = run_posix_symlink_chmod_test,
+       },
+       {
+               .name  = "POSIX-SYMLINK-RENAME",
+               .fn    = run_posix_symlink_rename_test,
+       },
+       {
+               .name  = "POSIX-DIR-DEFAULT-ACL",
+               .fn    = run_posix_dir_default_acl_test,
+       },
+       {
+               .name  = "POSIX-SYMLINK-GETPATHINFO",
+               .fn    = run_posix_symlink_getpathinfo_test,
+       },
+       {
+               .name  = "POSIX-SYMLINK-SETPATHINFO",
+               .fn    = run_posix_symlink_setpathinfo_test,
+       },
        {
                .name  = "WINDOWS-BAD-SYMLINK",
                .fn    = run_symlink_open_test,
        },
+       {
+               .name  = "SMB1-WILD-MANGLE-UNLINK",
+               .fn    = run_smb1_wild_mangle_unlink_test,
+       },
+       {
+               .name  = "SMB1-WILD-MANGLE-RENAME",
+               .fn    = run_smb1_wild_mangle_rename_test,
+       },
        {
                .name  = "CASE-INSENSITIVE-CREATE",
                .fn    = run_case_insensitive_create,
@@ -14579,10 +15607,6 @@ static struct {
                .name  = "DELETE-PRINT",
                .fn    = run_delete_print_test,
        },
-       {
-               .name  = "WILDDELETE",
-               .fn    = run_wild_deletetest,
-       },
        {
                .name  = "DELETE-LN",
                .fn    = run_deletetest_ln,
@@ -14675,6 +15699,10 @@ static struct {
                .name  = "LARGE_READX",
                .fn    = run_large_readx,
        },
+       {
+               .name  = "MSDFS-ATTRIBUTE",
+               .fn    = run_msdfs_attribute,
+       },
        {
                .name  = "NTTRANS-CREATE",
                .fn    = run_nttrans_create,
@@ -14775,6 +15803,74 @@ static struct {
                .name  = "SMB2-SACL",
                .fn    = run_smb2_sacl,
        },
+       {
+               .name  = "SMB2-QUOTA1",
+               .fn    = run_smb2_quota1,
+       },
+       {
+               .name  = "SMB2-STREAM-ACL",
+               .fn    = run_smb2_stream_acl,
+       },
+       {
+               .name  = "SMB2-LIST-DIR-ASYNC",
+               .fn    = run_list_dir_async_test,
+       },
+       {
+               .name  = "SMB2-DEL-ON-CLOSE-NONEMPTY",
+               .fn    = run_delete_on_close_non_empty,
+       },
+       {
+               .name  = "SMB2-DEL-ON-CLOSE-NONWRITE-DELETE-YES",
+               .fn    = run_delete_on_close_nonwrite_delete_yes_test,
+       },
+       {
+               .name  = "SMB2-DEL-ON-CLOSE-NONWRITE-DELETE-NO",
+               .fn    = run_delete_on_close_nonwrite_delete_no_test,
+       },
+       {
+               .name  = "SMB2-DFS-PATHS",
+               .fn    = run_smb2_dfs_paths,
+       },
+       {
+               .name  = "SMB2-NON-DFS-SHARE",
+               .fn    = run_smb2_non_dfs_share,
+       },
+       {
+               .name  = "SMB2-DFS-SHARE-NON-DFS-PATH",
+               .fn    = run_smb2_dfs_share_non_dfs_path,
+       },
+       {
+               .name  = "SMB2-DFS-FILENAME-LEADING-BACKSLASH",
+               .fn    = run_smb2_dfs_filename_leading_backslash,
+       },
+       {
+               .name  = "SMB1-TRUNCATED-SESSSETUP",
+               .fn    = run_smb1_truncated_sesssetup,
+       },
+       {
+               .name  = "SMB1-NEGOTIATE-EXIT",
+               .fn    = run_smb1_negotiate_exit,
+       },
+       {
+               .name  = "SMB1-NEGOTIATE-TCON",
+               .fn    = run_smb1_negotiate_tcon,
+       },
+       {
+               .name  = "SMB1-DFS-PATHS",
+               .fn    = run_smb1_dfs_paths,
+       },
+       {
+               .name  = "SMB1-DFS-SEARCH-PATHS",
+               .fn    = run_smb1_dfs_search_paths,
+       },
+       {
+               .name  = "SMB1-DFS-OPERATIONS",
+               .fn    = run_smb1_dfs_operations,
+       },
+       {
+               .name  = "SMB1-DFS-BADPATH",
+               .fn    = run_smb1_dfs_check_badpath,
+       },
        {
                .name  = "CLEANUP1",
                .fn    = run_cleanup1,
@@ -14875,6 +15971,14 @@ static struct {
                .name  = "LOCAL-STREAM-NAME",
                .fn    = run_local_stream_name,
        },
+       {
+               .name  = "LOCAL-STR-MATCH-MSWILD",
+               .fn    = run_str_match_mswild,
+       },
+       {
+               .name  = "LOCAL-STR-MATCH-REGEX-SUB1",
+               .fn    = run_str_match_regex_sub1,
+       },
        {
                .name  = "WBCLIENT-MULTI-PING",
                .fn    = run_wbclient_multi_ping,
@@ -14971,6 +16075,10 @@ static struct {
                .name  = "LOCAL-G-LOCK7",
                .fn    = run_g_lock7,
        },
+       {
+               .name  = "LOCAL-G-LOCK8",
+               .fn    = run_g_lock8,
+       },
        {
                .name  = "LOCAL-G-LOCK-PING-PONG",
                .fn    = run_g_lock_ping_pong,
@@ -14995,6 +16103,10 @@ static struct {
                .name  = "hide-new-files-timeout",
                .fn    = run_hidenewfiles,
        },
+       {
+               .name  = "hide-new-files-timeout-showdirs",
+               .fn    = run_hidenewfiles_showdirs,
+       },
 #ifdef CLUSTER_SUPPORT
        {
                .name  = "ctdbd-conn1",
@@ -15005,6 +16117,14 @@ static struct {
                .name  = "readdir-timestamp",
                .fn    = run_readdir_timestamp,
        },
+       {
+               .name  = "rpc-scale",
+               .fn    = run_rpc_scale,
+       },
+       {
+               .name  = "LOCAL-TDB-VALIDATE",
+               .fn    = run_tdb_validate,
+       },
        {
                .name = NULL,
        },