s4-torture: allow host-only in unc lists in smbtorture
[ira/wip.git] / source4 / torture / util_smb.c
index a4e8e198bb057ee1917d258d4d9038915d85d7c1..216927ce70dcc3c527a32d59e38061ccb47ac5d7 100644 (file)
@@ -2,10 +2,11 @@
    Unix SMB/CIFS implementation.
    SMB torture tester utility functions
    Copyright (C) Andrew Tridgell 2003
+   Copyright (C) Jelmer Vernooij 2006
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
-#include "smb.h"
 #include "lib/cmdline/popt_common.h"
 #include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
 #include "libcli/raw/ioctl.h"
 #include "libcli/libcli.h"
 #include "system/filesys.h"
 #include "system/wait.h"
 #include "system/time.h"
 #include "torture/torture.h"
+#include "../lib/util/dlinklist.h"
+#include "libcli/resolve/resolve.h"
+#include "param/param.h"
+#include "libcli/security/security.h"
+#include "libcli/util/clilsa.h"
 
 
 /**
   setup a directory ready for a test
 */
-_PUBLIC_ BOOL torture_setup_dir(struct smbcli_state *cli, const char *dname)
+_PUBLIC_ bool torture_setup_dir(struct smbcli_state *cli, const char *dname)
 {
        smb_raw_exit(cli->session);
        if (smbcli_deltree(cli->tree, dname) == -1 ||
            NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, dname))) {
                printf("Unable to setup %s - %s\n", dname, smbcli_errstr(cli->tree));
-               return False;
+               return false;
        }
-       return True;
+       return true;
 }
 
 /*
@@ -54,15 +59,15 @@ NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, in
        union smb_open io;
        TALLOC_CTX *mem_ctx;
 
-       mem_ctx = talloc_init("create_directory_handle");
+       mem_ctx = talloc_named_const(tree, 0, "create_directory_handle");
 
        io.generic.level = RAW_OPEN_NTCREATEX;
-       io.ntcreatex.in.root_fid = 0;
+       io.ntcreatex.in.root_fid.fnum = 0;
        io.ntcreatex.in.flags = 0;
        io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
        io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
        io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
-       io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+       io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
        io.ntcreatex.in.alloc_size = 0;
        io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
        io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
@@ -124,14 +129,17 @@ _PUBLIC_ int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx,
                }
        }
 
-       /* make sure all the timestamps aren't the same, and are also 
-          in different DST zones*/
-       setfile.generic.level = RAW_SFILEINFO_SETATTRE;
+       /* make sure all the timestamps aren't the same */
+       ZERO_STRUCT(setfile);
+       setfile.generic.level = RAW_SFILEINFO_BASIC_INFO;
        setfile.generic.in.file.fnum = fnum;
 
-       setfile.setattre.in.create_time = t + 9*30*24*60*60;
-       setfile.setattre.in.access_time = t + 6*30*24*60*60;
-       setfile.setattre.in.write_time  = t + 3*30*24*60*60;
+       unix_to_nt_time(&setfile.basic_info.in.create_time,
+           t + 9*30*24*60*60);
+       unix_to_nt_time(&setfile.basic_info.in.access_time,
+           t + 6*30*24*60*60);
+       unix_to_nt_time(&setfile.basic_info.in.write_time,
+           t + 3*30*24*60*60);
 
        status = smb_raw_setfileinfo(cli->tree, &setfile);
        if (!NT_STATUS_IS_OK(status)) {
@@ -139,7 +147,7 @@ _PUBLIC_ int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx,
        }
 
        /* make sure all the timestamps aren't the same */
-       fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
+       fileinfo.generic.level = RAW_FILEINFO_BASIC_INFO;
        fileinfo.generic.in.file.fnum = fnum;
 
        status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
@@ -147,13 +155,13 @@ _PUBLIC_ int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx,
                printf("Failed to query file times - %s\n", nt_errstr(status));
        }
 
-       if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
+       if (setfile.basic_info.in.create_time != fileinfo.basic_info.out.create_time) {
                printf("create_time not setup correctly\n");
        }
-       if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
+       if (setfile.basic_info.in.access_time != fileinfo.basic_info.out.access_time) {
                printf("access_time not setup correctly\n");
        }
-       if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
+       if (setfile.basic_info.in.write_time != fileinfo.basic_info.out.write_time) {
                printf("write_time not setup correctly\n");
        }
 
@@ -201,14 +209,17 @@ int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char
                }
        }
 
-       /* make sure all the timestamps aren't the same, and are also 
-          in different DST zones*/
-       setfile.generic.level = RAW_SFILEINFO_SETATTRE;
+       /* make sure all the timestamps aren't the same */
+       ZERO_STRUCT(setfile);
+       setfile.generic.level = RAW_SFILEINFO_BASIC_INFO;
        setfile.generic.in.file.fnum = fnum;
 
-       setfile.setattre.in.create_time = t + 9*30*24*60*60;
-       setfile.setattre.in.access_time = t + 6*30*24*60*60;
-       setfile.setattre.in.write_time  = t + 3*30*24*60*60;
+       unix_to_nt_time(&setfile.basic_info.in.create_time,
+           t + 9*30*24*60*60);
+       unix_to_nt_time(&setfile.basic_info.in.access_time,
+           t + 6*30*24*60*60);
+       unix_to_nt_time(&setfile.basic_info.in.write_time,
+           t + 3*30*24*60*60);
 
        status = smb_raw_setfileinfo(cli->tree, &setfile);
        if (!NT_STATUS_IS_OK(status)) {
@@ -216,7 +227,7 @@ int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char
        }
 
        /* make sure all the timestamps aren't the same */
-       fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
+       fileinfo.generic.level = RAW_FILEINFO_BASIC_INFO;
        fileinfo.generic.in.file.fnum = fnum;
 
        status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
@@ -224,13 +235,13 @@ int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char
                printf("Failed to query file times - %s\n", nt_errstr(status));
        }
 
-       if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
+       if (setfile.basic_info.in.create_time != fileinfo.basic_info.out.create_time) {
                printf("create_time not setup correctly\n");
        }
-       if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
+       if (setfile.basic_info.in.access_time != fileinfo.basic_info.out.access_time) {
                printf("access_time not setup correctly\n");
        }
-       if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
+       if (setfile.basic_info.in.write_time != fileinfo.basic_info.out.write_time) {
                printf("write_time not setup correctly\n");
        }
 
@@ -253,6 +264,23 @@ void *shm_setup(int size)
        int shmid;
        void *ret;
 
+#ifdef __QNXNTO__
+       shmid = shm_open("private", O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+       if (shmid == -1) {
+               printf("can't get shared memory\n");
+               exit(1);
+       }
+       shm_unlink("private");
+       if (ftruncate(shmid, size) == -1) {
+               printf("can't set shared memory size\n");
+               exit(1);
+       }
+       ret = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, shmid, 0);
+       if (ret == MAP_FAILED) {
+               printf("can't map shared memory\n");
+               exit(1);
+       }
+#else
        shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
        if (shmid == -1) {
                printf("can't get shared memory\n");
@@ -271,26 +299,28 @@ void *shm_setup(int size)
           See Stevens "advanced programming in unix env" for details
           */
        shmctl(shmid, IPC_RMID, 0);
+#endif
        
        return ret;
 }
 
 
-/*
+/**
   check that a wire string matches the flags specified 
   not 100% accurate, but close enough for testing
 */
-BOOL wire_bad_flags(struct smb_wire_string *str, int flags, struct smbcli_state *cli)
+bool wire_bad_flags(struct smb_wire_string *str, int flags, 
+                   struct smbcli_transport *transport)
 {
-       BOOL server_unicode;
+       bool server_unicode;
        int len;
-       if (!str || !str->s) return True;
+       if (!str || !str->s) return true;
        len = strlen(str->s);
        if (flags & STR_TERMINATE) len++;
 
-       server_unicode = (cli->transport->negotiate.capabilities&CAP_UNICODE)?True:False;
-       if (getenv("CLI_FORCE_ASCII") || !lp_unicode()) {
-               server_unicode = False;
+       server_unicode = (transport->negotiate.capabilities&CAP_UNICODE)?true:false;
+       if (getenv("CLI_FORCE_ASCII") || !transport->options.unicode) {
+               server_unicode = false;
        }
 
        if ((flags & STR_UNICODE) || server_unicode) {
@@ -301,9 +331,9 @@ BOOL wire_bad_flags(struct smb_wire_string *str, int flags, struct smbcli_state
        if (str->private_length != len) {
                printf("Expected wire_length %d but got %d for '%s'\n", 
                       len, str->private_length, str->s);
-               return True;
+               return true;
        }
-       return False;
+       return false;
 }
 
 /*
@@ -330,7 +360,7 @@ void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
 */
 void torture_all_info(struct smbcli_tree *tree, const char *fname)
 {
-       TALLOC_CTX *mem_ctx = talloc_init("%s", fname);
+       TALLOC_CTX *mem_ctx = talloc_named(tree, 0, "%s", fname);
        union smb_fileinfo finfo;
        NTSTATUS status;
 
@@ -351,7 +381,7 @@ void torture_all_info(struct smbcli_tree *tree, const char *fname)
 /*
   set a attribute on a file
 */
-BOOL torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
+bool torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
 {
        union smb_setfileinfo sfinfo;
        NTSTATUS status;
@@ -374,7 +404,7 @@ NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
        NTSTATUS status;
        TALLOC_CTX *mem_ctx;
 
-       mem_ctx = talloc_init("torture_set_sparse");
+       mem_ctx = talloc_named_const(tree, 0, "torture_set_sparse");
        if (!mem_ctx) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -382,7 +412,7 @@ NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
        nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
        nt.ntioctl.in.function = FSCTL_SET_SPARSE;
        nt.ntioctl.in.file.fnum = fnum;
-       nt.ntioctl.in.fsctl = True;
+       nt.ntioctl.in.fsctl = true;
        nt.ntioctl.in.filter = 0;
        nt.ntioctl.in.max_data = 0;
        nt.ntioctl.in.blob = data_blob(NULL, 0);
@@ -460,76 +490,113 @@ NTSTATUS torture_check_ea(struct smbcli_state *cli,
        return NT_STATUS_EA_CORRUPT_ERROR;
 }
 
-BOOL torture_open_connection_share(TALLOC_CTX *mem_ctx,
+_PUBLIC_ bool torture_open_connection_share(TALLOC_CTX *mem_ctx,
                                   struct smbcli_state **c, 
+                                  struct torture_context *tctx,
                                   const char *hostname, 
                                   const char *sharename,
-                                  struct event_context *ev)
+                                  struct tevent_context *ev)
 {
        NTSTATUS status;
 
+       struct smbcli_options options;
+       struct smbcli_session_options session_options;
+
+       lp_smbcli_options(tctx->lp_ctx, &options);
+       lp_smbcli_session_options(tctx->lp_ctx, &session_options);
+
+       options.use_oplocks = torture_setting_bool(tctx, "use_oplocks", true);
+       options.use_level2_oplocks = torture_setting_bool(tctx, "use_level2_oplocks", true);
+
        status = smbcli_full_connection(mem_ctx, c, hostname, 
+                                       lp_smb_ports(tctx->lp_ctx),
                                        sharename, NULL,
-                                       cmdline_credentials, ev);
+                                       lp_socket_options(tctx->lp_ctx),
+                                       cmdline_credentials, 
+                                       lp_resolve_context(tctx->lp_ctx),
+                                       ev, &options, &session_options,
+                                       lp_iconv_convenience(tctx->lp_ctx),
+                                       lp_gensec_settings(tctx, tctx->lp_ctx));
        if (!NT_STATUS_IS_OK(status)) {
                printf("Failed to open connection - %s\n", nt_errstr(status));
-               return False;
+               return false;
        }
 
-       (*c)->transport->options.use_oplocks = use_oplocks;
-       (*c)->transport->options.use_level2_oplocks = use_level_II_oplocks;
-
-       return True;
+       return true;
 }
 
-_PUBLIC_ BOOL torture_open_connection(struct smbcli_state **c, int conn_index)
+_PUBLIC_ bool torture_get_conn_index(int conn_index,
+                                    TALLOC_CTX *mem_ctx,
+                                    struct torture_context *tctx,
+                                    char **host, char **share)
 {
-       const char *host = lp_parm_string(-1, "torture", "host");
-       const char *share = lp_parm_string(-1, "torture", "share");
        char **unc_list = NULL;
        int num_unc_names = 0;
        const char *p;
+
+       (*host) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "host", NULL));
+       (*share) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "share", NULL));
        
-       p = lp_parm_string(-1, "torture", "unclist");
-       if (p) {
-               char *h, *s;
-               unc_list = file_lines_load(p, &num_unc_names, NULL);
-               if (!unc_list || num_unc_names <= 0) {
-                       printf("Failed to load unc names list from '%s'\n", p);
-                       exit(1);
-               }
+       p = torture_setting_string(tctx, "unclist", NULL);
+       if (!p) {
+               return true;
+       }
 
-               if (!smbcli_parse_unc(unc_list[conn_index % num_unc_names],
-                                     NULL, &h, &s)) {
-                       printf("Failed to parse UNC name %s\n",
-                              unc_list[conn_index % num_unc_names]);
-                       exit(1);
-               }
-               host = h;
-               share = s;
+       unc_list = file_lines_load(p, &num_unc_names, 0, NULL);
+       if (!unc_list || num_unc_names <= 0) {
+               DEBUG(0,("Failed to load unc names list from '%s'\n", p));
+               return false;
        }
 
-       return torture_open_connection_share(NULL, c, host, share, NULL);
+       p = unc_list[conn_index % num_unc_names];
+       if (p[0] != '/' && p[0] != '\\') {
+               /* allow UNC lists of hosts */
+               (*host) = talloc_strdup(mem_ctx, p);
+       } else if (!smbcli_parse_unc(p, mem_ctx, host, share)) {
+               DEBUG(0, ("Failed to parse UNC name %s\n",
+                         unc_list[conn_index % num_unc_names]));
+               return false;
+       }
+
+       talloc_free(unc_list);
+       return true;
 }
 
-_PUBLIC_ BOOL torture_open_connection_ev(struct smbcli_state **c, 
-                                        struct event_context *ev)
+
+
+_PUBLIC_ bool torture_open_connection_ev(struct smbcli_state **c,
+                                        int conn_index,
+                                        struct torture_context *tctx,
+                                        struct tevent_context *ev)
 {
-       const char *host = lp_parm_string(-1, "torture", "host");
-       const char *share = lp_parm_string(-1, "torture", "share");
+       char *host, *share;
+       bool ret;
+
+       if (!torture_get_conn_index(conn_index, ev, tctx, &host, &share)) {
+               return false;
+       }
 
-       return torture_open_connection_share(NULL, c, host, share, ev);
+       ret = torture_open_connection_share(NULL, c, tctx, host, share, ev);
+       talloc_free(host);
+       talloc_free(share);
+
+       return ret;
 }
 
+_PUBLIC_ bool torture_open_connection(struct smbcli_state **c, struct torture_context *tctx, int conn_index)
+{
+       return torture_open_connection_ev(c, conn_index, tctx, tctx->ev);
+}
 
 
-_PUBLIC_ BOOL torture_close_connection(struct smbcli_state *c)
+
+_PUBLIC_ bool torture_close_connection(struct smbcli_state *c)
 {
-       BOOL ret = True;
-       if (!c) return True;
+       bool ret = true;
+       if (!c) return true;
        if (NT_STATUS_IS_ERR(smbcli_tdis(c))) {
                printf("tdis failed (%s)\n", smbcli_errstr(c->tree));
-               ret = False;
+               ret = false;
        }
        talloc_free(c);
        return ret;
@@ -537,32 +604,32 @@ _PUBLIC_ BOOL torture_close_connection(struct smbcli_state *c)
 
 
 /* check if the server produced the expected error code */
-_PUBLIC_ BOOL check_error(const char *location, struct smbcli_state *c, 
+_PUBLIC_ bool check_error(const char *location, struct smbcli_state *c, 
                 uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
 {
        NTSTATUS status;
        
        status = smbcli_nt_error(c->tree);
        if (NT_STATUS_IS_DOS(status)) {
-               int class, num;
-               class = NT_STATUS_DOS_CLASS(status);
+               int classnum, num;
+               classnum = NT_STATUS_DOS_CLASS(status);
                num = NT_STATUS_DOS_CODE(status);
-                if (eclass != class || ecode != num) {
+                if (eclass != classnum || ecode != num) {
                         printf("unexpected error code %s\n", nt_errstr(status));
                         printf(" expected %s or %s (at %s)\n", 
                               nt_errstr(NT_STATUS_DOS(eclass, ecode)), 
                                nt_errstr(nterr), location);
-                        return False;
+                        return false;
                 }
         } else {
                 if (!NT_STATUS_EQUAL(nterr, status)) {
                         printf("unexpected error code %s\n", nt_errstr(status));
                         printf(" expected %s (at %s)\n", nt_errstr(nterr), location);
-                        return False;
+                        return false;
                 }
         }
 
-       return True;
+       return true;
 }
 
 static struct smbcli_state *current_cli;
@@ -572,17 +639,19 @@ static void sigcont(int sig)
 {
 }
 
-double torture_create_procs(BOOL (*fn)(struct smbcli_state *, int), BOOL *result)
+double torture_create_procs(struct torture_context *tctx, 
+                                                       bool (*fn)(struct torture_context *, struct smbcli_state *, int), bool *result)
 {
        int i, status;
        volatile pid_t *child_status;
-       volatile BOOL *child_status_out;
+       volatile bool *child_status_out;
        int synccount;
        int tries = 8;
+       int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
        double start_time_limit = 10 + (torture_nprocs * 1.5);
        struct timeval tv;
 
-       *result = True;
+       *result = true;
 
        synccount = 0;
 
@@ -594,7 +663,7 @@ double torture_create_procs(BOOL (*fn)(struct smbcli_state *, int), BOOL *result
                return -1;
        }
 
-       child_status_out = (volatile BOOL *)shm_setup(sizeof(BOOL)*torture_nprocs);
+       child_status_out = (volatile bool *)shm_setup(sizeof(bool)*torture_nprocs);
        if (!child_status_out) {
                printf("Failed to setup result status shared memory\n");
                return -1;
@@ -602,7 +671,7 @@ double torture_create_procs(BOOL (*fn)(struct smbcli_state *, int), BOOL *result
 
        for (i = 0; i < torture_nprocs; i++) {
                child_status[i] = 0;
-               child_status_out[i] = True;
+               child_status_out[i] = true;
        }
 
        tv = timeval_current();
@@ -615,13 +684,16 @@ double torture_create_procs(BOOL (*fn)(struct smbcli_state *, int), BOOL *result
                        pid_t mypid = getpid();
                        srandom(((int)mypid) ^ ((int)time(NULL)));
 
-                       asprintf(&myname, "CLIENT%d", i);
-                       lp_set_cmdline("netbios name", myname);
+                       if (asprintf(&myname, "CLIENT%d", i) == -1) {
+                               printf("asprintf failed\n");
+                               return -1;
+                       }
+                       lp_set_cmdline(tctx->lp_ctx, "netbios name", myname);
                        free(myname);
 
 
                        while (1) {
-                               if (torture_open_connection(&current_cli, i)) {
+                               if (torture_open_connection(&current_cli, tctx, i)) {
                                        break;
                                }
                                if (tries-- == 0) {
@@ -641,7 +713,7 @@ double torture_create_procs(BOOL (*fn)(struct smbcli_state *, int), BOOL *result
                                _exit(1);
                        }
 
-                       child_status_out[i] = fn(current_cli, i);
+                       child_status_out[i] = fn(tctx, current_cli, i);
                        _exit(0);
                }
        }
@@ -657,7 +729,7 @@ double torture_create_procs(BOOL (*fn)(struct smbcli_state *, int), BOOL *result
 
        if (synccount != torture_nprocs) {
                printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs, synccount);
-               *result = False;
+               *result = false;
                return timeval_elapsed(&tv);
        }
 
@@ -677,7 +749,7 @@ double torture_create_procs(BOOL (*fn)(struct smbcli_state *, int), BOOL *result
                int ret;
                while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
                if (ret == -1 || WEXITSTATUS(status) != 0) {
-                       *result = False;
+                       *result = false;
                }
        }
 
@@ -685,36 +757,217 @@ double torture_create_procs(BOOL (*fn)(struct smbcli_state *, int), BOOL *result
        
        for (i=0;i<torture_nprocs;i++) {
                if (!child_status_out[i]) {
-                       *result = False;
+                       *result = false;
                }
        }
        return timeval_elapsed(&tv);
 }
 
-static BOOL wrap_old_torture_multifn(struct torture_context *torture,
-                                                               const void *_fn)
+static bool wrap_smb_multi_test(struct torture_context *torture,
+                                                               struct torture_tcase *tcase,
+                                                               struct torture_test *test)
 {
-       BOOL (*fn)(struct smbcli_state *, int ) = _fn;
-       BOOL result;
+       bool (*fn)(struct torture_context *, struct smbcli_state *, int ) = test->fn;
+       bool result;
 
-       torture_create_procs(fn, &result);
+       torture_create_procs(torture, fn, &result);
 
        return result;
 }
 
-_PUBLIC_ NTSTATUS register_torture_multi_op(const char *name, 
-                                                                                       BOOL (*multi_fn)(struct smbcli_state *, int ))
+_PUBLIC_ struct torture_test *torture_suite_add_smb_multi_test(
+                                                                       struct torture_suite *suite,
+                                                                       const char *name,
+                                                                       bool (*run) (struct torture_context *,
+                                                                                                struct smbcli_state *,
+                                                                                               int i))
+{
+       struct torture_test *test; 
+       struct torture_tcase *tcase;
+       
+       tcase = torture_suite_add_tcase(suite, name);
+
+       test = talloc(tcase, struct torture_test);
+
+       test->name = talloc_strdup(test, name);
+       test->description = NULL;
+       test->run = wrap_smb_multi_test;
+       test->fn = run;
+       test->dangerous = false;
+
+       DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+
+       return test;
+
+}
+
+static bool wrap_simple_2smb_test(struct torture_context *torture_ctx,
+                                                                       struct torture_tcase *tcase,
+                                                                       struct torture_test *test)
 {
-       struct torture_suite *suite;
+       bool (*fn) (struct torture_context *, struct smbcli_state *,
+                               struct smbcli_state *);
+       bool ret;
+
+       struct smbcli_state *cli1, *cli2;
+
+       if (!torture_open_connection(&cli1, torture_ctx, 0) || 
+               !torture_open_connection(&cli2, torture_ctx, 1))
+               return false;
 
-       suite = torture_suite_create(talloc_autofree_context(), name);
+       fn = test->fn;
 
-       torture_suite_add_simple_tcase(suite, name, 
-                                                                  wrap_old_torture_multifn,
-                                                                  multi_fn);
-       torture_register_suite(suite);
+       ret = fn(torture_ctx, cli1, cli2);
+
+       talloc_free(cli1);
+       talloc_free(cli2);
+
+       return ret;
+}
+
+
+
+_PUBLIC_ struct torture_test *torture_suite_add_2smb_test(
+                                                                       struct torture_suite *suite,
+                                                                       const char *name,
+                                                                       bool (*run) (struct torture_context *,
+                                                                                               struct smbcli_state *,
+                                                                                               struct smbcli_state *))
+{
+       struct torture_test *test; 
+       struct torture_tcase *tcase;
+       
+       tcase = torture_suite_add_tcase(suite, name);
 
+       test = talloc(tcase, struct torture_test);
+
+       test->name = talloc_strdup(test, name);
+       test->description = NULL;
+       test->run = wrap_simple_2smb_test;
+       test->fn = run;
+       test->dangerous = false;
+
+       DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+
+       return test;
+
+}
+
+static bool wrap_simple_1smb_test(struct torture_context *torture_ctx,
+                                                                       struct torture_tcase *tcase,
+                                                                       struct torture_test *test)
+{
+       bool (*fn) (struct torture_context *, struct smbcli_state *);
+       bool ret;
+
+       struct smbcli_state *cli1;
+
+       if (!torture_open_connection(&cli1, torture_ctx, 0))
+               return false;
+
+       fn = test->fn;
+
+       ret = fn(torture_ctx, cli1);
+
+       talloc_free(cli1);
+
+       return ret;
+}
+
+_PUBLIC_ struct torture_test *torture_suite_add_1smb_test(
+                               struct torture_suite *suite,
+                               const char *name,
+                               bool (*run) (struct torture_context *, struct smbcli_state *))
+{
+       struct torture_test *test; 
+       struct torture_tcase *tcase;
+       
+       tcase = torture_suite_add_tcase(suite, name);
+
+       test = talloc(tcase, struct torture_test);
+
+       test->name = talloc_strdup(test, name);
+       test->description = NULL;
+       test->run = wrap_simple_1smb_test;
+       test->fn = run;
+       test->dangerous = false;
+
+       DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+
+       return test;
+}
+
+
+NTSTATUS torture_second_tcon(TALLOC_CTX *mem_ctx,
+                            struct smbcli_session *session,
+                            const char *sharename,
+                            struct smbcli_tree **res)
+{
+       union smb_tcon tcon;
+       struct smbcli_tree *result;
+       TALLOC_CTX *tmp_ctx;
+       NTSTATUS status;
+
+       if ((tmp_ctx = talloc_new(mem_ctx)) == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       result = smbcli_tree_init(session, tmp_ctx, false);
+       if (result == NULL) {
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       tcon.generic.level = RAW_TCON_TCONX;
+       tcon.tconx.in.flags = 0;
+
+       /* Ignore share mode security here */
+       tcon.tconx.in.password = data_blob(NULL, 0);
+       tcon.tconx.in.path = sharename;
+       tcon.tconx.in.device = "?????";
+
+       status = smb_raw_tcon(result, tmp_ctx, &tcon);
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(tmp_ctx);
+               return status;
+       }
+
+       result->tid = tcon.tconx.out.tid;
+       *res = talloc_steal(mem_ctx, result);
+       talloc_free(tmp_ctx);
        return NT_STATUS_OK;
 }
 
+/* 
+   a wrapper around smblsa_sid_check_privilege, that tries to take
+   account of the fact that the lsa privileges calls don't expand
+   group memberships, using an explicit check for administrator. There
+   must be a better way ...
+ */
+NTSTATUS torture_check_privilege(struct smbcli_state *cli, 
+                                const char *sid_str,
+                                const char *privilege)
+{
+       struct dom_sid *sid;
+       TALLOC_CTX *tmp_ctx = talloc_new(cli);
+       uint32_t rid;
+       NTSTATUS status;
+
+       sid = dom_sid_parse_talloc(tmp_ctx, sid_str);
+       if (sid == NULL) {
+               talloc_free(tmp_ctx);
+               return NT_STATUS_INVALID_SID;
+       }
+
+       status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
+       NT_STATUS_NOT_OK_RETURN_AND_FREE(status, tmp_ctx);
+
+       if (rid == DOMAIN_RID_ADMINISTRATOR) {
+               /* assume the administrator has them all */
+               return NT_STATUS_OK;
+       }
+
+       talloc_free(tmp_ctx);
 
+       return smblsa_sid_check_privilege(cli, sid_str, privilege);
+}