s4-torture: allow host-only in unc lists in smbtorture
[ira/wip.git] / source4 / torture / util_smb.c
index 8b944e33a09f8eed640194c35673e9ba35bdfd78..216927ce70dcc3c527a32d59e38061ccb47ac5d7 100644 (file)
 #include "includes.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/shmem.h"
 #include "system/wait.h"
 #include "system/time.h"
-#include "torture/ui.h"
 #include "torture/torture.h"
-#include "util/dlinklist.h"
-#include "auth/credentials/credentials.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"
 
 
 /**
@@ -43,9 +45,9 @@ _PUBLIC_ bool torture_setup_dir(struct smbcli_state *cli, const char *dname)
        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;
 }
 
 /*
@@ -60,12 +62,12 @@ NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, in
        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;
@@ -127,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)) {
@@ -142,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);
@@ -150,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");
        }
 
@@ -204,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)) {
@@ -219,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);
@@ -227,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");
        }
 
@@ -256,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");
@@ -274,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_transport *transport)
+bool wire_bad_flags(struct smb_wire_string *str, int flags, 
+                   struct smbcli_transport *transport)
 {
        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 = (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) {
@@ -304,9 +331,9 @@ bool wire_bad_flags(struct smb_wire_string *str, int flags, struct smbcli_transp
        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;
 }
 
 /*
@@ -385,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);
@@ -465,96 +492,111 @@ NTSTATUS torture_check_ea(struct smbcli_state *cli,
 
 _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 = lp_parm_bool(NULL, "torture", 
-                                                                                                               "use_oplocks", false);
-       (*c)->transport->options.use_level2_oplocks = lp_parm_bool(NULL, "torture", 
-                                                                                               "use_level2_oplocks", false);
-
-       return True;
+       return true;
 }
 
 _PUBLIC_ bool torture_get_conn_index(int conn_index,
                                     TALLOC_CTX *mem_ctx,
+                                    struct torture_context *tctx,
                                     char **host, char **share)
 {
        char **unc_list = NULL;
        int num_unc_names = 0;
        const char *p;
 
-       (*host) = talloc_strdup(mem_ctx, lp_parm_string(NULL, "torture", "host"));
-       (*share) = talloc_strdup(mem_ctx, lp_parm_string(NULL, "torture", "share"));
+       (*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(NULL, "torture", "unclist");
+       p = torture_setting_string(tctx, "unclist", NULL);
        if (!p) {
-               return True;
+               return true;
        }
 
-       unc_list = file_lines_load(p, &num_unc_names, NULL);
+       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 false;
        }
 
-       if (!smbcli_parse_unc(unc_list[conn_index % num_unc_names],
-                             mem_ctx, host, share)) {
+       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;
+               return false;
        }
 
        talloc_free(unc_list);
-       return True;
+       return true;
 }
 
 
 
 _PUBLIC_ bool torture_open_connection_ev(struct smbcli_state **c,
                                         int conn_index,
-                                        struct event_context *ev)
+                                        struct torture_context *tctx,
+                                        struct tevent_context *ev)
 {
        char *host, *share;
        bool ret;
 
-       if (!torture_get_conn_index(conn_index, ev, &host, &share)) {
-               return False;
+       if (!torture_get_conn_index(conn_index, ev, tctx, &host, &share)) {
+               return false;
        }
 
-       ret = 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, int conn_index)
+_PUBLIC_ bool torture_open_connection(struct smbcli_state **c, struct torture_context *tctx, int conn_index)
 {
-       return torture_open_connection_ev(c, conn_index, 
-                                         cli_credentials_get_event_context(cmdline_credentials));
+       return torture_open_connection_ev(c, conn_index, tctx, tctx->ev);
 }
 
 
 
 _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;
@@ -569,25 +611,25 @@ _PUBLIC_ bool check_error(const char *location, struct smbcli_state *c,
        
        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;
@@ -609,7 +651,7 @@ double torture_create_procs(struct torture_context *tctx,
        double start_time_limit = 10 + (torture_nprocs * 1.5);
        struct timeval tv;
 
-       *result = True;
+       *result = true;
 
        synccount = 0;
 
@@ -629,7 +671,7 @@ double torture_create_procs(struct torture_context *tctx,
 
        for (i = 0; i < torture_nprocs; i++) {
                child_status[i] = 0;
-               child_status_out[i] = True;
+               child_status_out[i] = true;
        }
 
        tv = timeval_current();
@@ -642,13 +684,16 @@ double torture_create_procs(struct torture_context *tctx,
                        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) {
@@ -684,7 +729,7 @@ double torture_create_procs(struct torture_context *tctx,
 
        if (synccount != torture_nprocs) {
                printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs, synccount);
-               *result = False;
+               *result = false;
                return timeval_elapsed(&tv);
        }
 
@@ -704,7 +749,7 @@ double torture_create_procs(struct torture_context *tctx,
                int ret;
                while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
                if (ret == -1 || WEXITSTATUS(status) != 0) {
-                       *result = False;
+                       *result = false;
                }
        }
 
@@ -712,7 +757,7 @@ double torture_create_procs(struct torture_context *tctx,
        
        for (i=0;i<torture_nprocs;i++) {
                if (!child_status_out[i]) {
-                       *result = False;
+                       *result = false;
                }
        }
        return timeval_elapsed(&tv);
@@ -766,8 +811,8 @@ static bool wrap_simple_2smb_test(struct torture_context *torture_ctx,
 
        struct smbcli_state *cli1, *cli2;
 
-       if (!torture_open_connection(&cli1, 0) || 
-               !torture_open_connection(&cli2, 1))
+       if (!torture_open_connection(&cli1, torture_ctx, 0) || 
+               !torture_open_connection(&cli2, torture_ctx, 1))
                return false;
 
        fn = test->fn;
@@ -817,7 +862,7 @@ static bool wrap_simple_1smb_test(struct torture_context *torture_ctx,
 
        struct smbcli_state *cli1;
 
-       if (!torture_open_connection(&cli1, 0))
+       if (!torture_open_connection(&cli1, torture_ctx, 0))
                return false;
 
        fn = test->fn;
@@ -853,3 +898,76 @@ _PUBLIC_ struct torture_test *torture_suite_add_1smb_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);
+}