s4: popt: Global replace of cmdline_credentials -> popt_get_cmdline_credentials().
[gd/samba-autobuild/.git] / source4 / torture / util_smb.c
index 513070500ed78de38960259e746065e9807bb8ca..fcbdc7a86ed2699725c1ab502306828a1ba531cb 100644 (file)
 #include "lib/cmdline/popt_common.h"
 #include "libcli/raw/libcliraw.h"
 #include "libcli/raw/raw_proto.h"
-#include "libcli/raw/ioctl.h"
+#include "../libcli/smb/smb_constants.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"
+#include "torture/util.h"
+#include "libcli/smb/smbXcli_base.h"
 
 /**
   setup a directory ready for a test
@@ -62,12 +63,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;
@@ -129,14 +130,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)) {
@@ -144,7 +148,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);
@@ -152,13 +156,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");
        }
 
@@ -206,14 +210,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)) {
@@ -221,7 +228,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);
@@ -229,58 +236,19 @@ 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");
        }
 
        return fnum;
 }
 
-
-
-/* return a pointer to a anonymous shared memory segment of size "size"
-   which will persist across fork() but will disappear when all processes
-   exit 
-
-   The memory is not zeroed 
-
-   This function uses system5 shared memory. It takes advantage of a property
-   that the memory is not destroyed if it is attached when the id is removed
-   */
-void *shm_setup(int size)
-{
-       int shmid;
-       void *ret;
-
-       shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
-       if (shmid == -1) {
-               printf("can't get shared memory\n");
-               exit(1);
-       }
-       ret = (void *)shmat(shmid, 0, 0);
-       if (!ret || ret == (void *)-1) {
-               printf("can't attach to shared memory\n");
-               return NULL;
-       }
-       /* the following releases the ipc, but note that this process
-          and all its children will still have access to the memory, its
-          just that the shmid is no longer valid for other shm calls. This
-          means we don't leave behind lots of shm segments after we exit 
-
-          See Stevens "advanced programming in unix env" for details
-          */
-       shmctl(shmid, IPC_RMID, 0);
-       
-       return ret;
-}
-
-
 /**
   check that a wire string matches the flags specified 
   not 100% accurate, but close enough for testing
@@ -471,23 +439,27 @@ _PUBLIC_ bool torture_open_connection_share(TALLOC_CTX *mem_ctx,
                                   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);
+       lpcfg_smbcli_options(tctx->lp_ctx, &options);
+       lpcfg_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),
+                                       lpcfg_smb_ports(tctx->lp_ctx),
                                        sharename, NULL,
-                                       cmdline_credentials, 
-                                       lp_resolve_context(tctx->lp_ctx),
-                                       ev, &options);
+                                       lpcfg_socket_options(tctx->lp_ctx),
+                                       popt_get_cmdline_credentials(),
+                                       lpcfg_resolve_context(tctx->lp_ctx),
+                                       ev, &options, &session_options,
+                                       lpcfg_gensec_settings(tctx, tctx->lp_ctx));
        if (!NT_STATUS_IS_OK(status)) {
                printf("Failed to open connection - %s\n", nt_errstr(status));
                return false;
@@ -513,14 +485,17 @@ _PUBLIC_ bool torture_get_conn_index(int conn_index,
                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;
        }
 
-       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;
@@ -535,7 +510,7 @@ _PUBLIC_ bool torture_get_conn_index(int conn_index,
 _PUBLIC_ bool torture_open_connection_ev(struct smbcli_state **c,
                                         int conn_index,
                                         struct torture_context *tctx,
-                                        struct event_context *ev)
+                                        struct tevent_context *ev)
 {
        char *host, *share;
        bool ret;
@@ -553,8 +528,7 @@ _PUBLIC_ bool torture_open_connection_ev(struct smbcli_state **c,
 
 _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,
-                                         cli_credentials_get_event_context(cmdline_credentials));
+       return torture_open_connection_ev(c, conn_index, tctx, tctx->ev);
 }
 
 
@@ -580,10 +554,10 @@ _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)), 
@@ -608,12 +582,19 @@ static void sigcont(int sig)
 {
 }
 
-double torture_create_procs(struct torture_context *tctx, 
-                                                       bool (*fn)(struct torture_context *, struct smbcli_state *, int), bool *result)
+struct child_status {
+       pid_t pid;
+       bool start;
+       enum torture_result result;
+       char reason[1024];
+};
+
+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;
+       struct child_status *child_status;
        int synccount;
        int tries = 8;
        int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
@@ -626,21 +607,15 @@ double torture_create_procs(struct torture_context *tctx,
 
        signal(SIGCONT, sigcont);
 
-       child_status = (volatile pid_t *)shm_setup(sizeof(pid_t)*torture_nprocs);
-       if (!child_status) {
+       child_status = (struct child_status *)anonymous_shared_allocate(
+                               sizeof(struct child_status)*torture_nprocs);
+       if (child_status == NULL) {
                printf("Failed to setup shared memory\n");
                return -1;
        }
 
-       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;
-       }
-
        for (i = 0; i < torture_nprocs; i++) {
-               child_status[i] = 0;
-               child_status_out[i] = true;
+               ZERO_STRUCT(child_status[i]);
        }
 
        tv = timeval_current();
@@ -649,12 +624,16 @@ double torture_create_procs(struct torture_context *tctx,
                procnum = i;
                if (fork() == 0) {
                        char *myname;
+                       bool ok;
 
                        pid_t mypid = getpid();
                        srandom(((int)mypid) ^ ((int)time(NULL)));
 
-                       asprintf(&myname, "CLIENT%d", i);
-                       lp_set_cmdline(tctx->lp_ctx, "netbios name", myname);
+                       if (asprintf(&myname, "CLIENT%d", i) == -1) {
+                               printf("asprintf failed\n");
+                               return -1;
+                       }
+                       lpcfg_set_cmdline(tctx->lp_ctx, "netbios name", myname);
                        free(myname);
 
 
@@ -666,20 +645,48 @@ double torture_create_procs(struct torture_context *tctx,
                                        printf("pid %d failed to start\n", (int)getpid());
                                        _exit(1);
                                }
-                               msleep(100);    
+                               smb_msleep(100);        
                        }
 
-                       child_status[i] = getpid();
+                       child_status[i].pid = getpid();
 
                        pause();
 
-                       if (child_status[i]) {
+                       if (!child_status[i].start) {
+                               child_status[i].result = TORTURE_ERROR;
                                printf("Child %d failed to start!\n", i);
-                               child_status_out[i] = 1;
                                _exit(1);
                        }
 
-                       child_status_out[i] = fn(tctx, current_cli, i);
+                       ok = fn(tctx, current_cli, i);
+                       if (!ok) {
+                               if (tctx->last_result == TORTURE_OK) {
+                                       torture_result(tctx, TORTURE_ERROR,
+                                               "unknown error: missing "
+                                               "torture_result call?\n");
+                               }
+
+                               child_status[i].result = tctx->last_result;
+
+                               if (strlen(tctx->last_reason) > 1023) {
+                                       /* note: reason already contains \n */
+                                       torture_comment(tctx,
+                                               "child %d (pid %u) failed: %s",
+                                               i,
+                                               (unsigned)child_status[i].pid,
+                                               tctx->last_reason);
+                               }
+
+                               snprintf(child_status[i].reason,
+                                        1024, "child %d (pid %u) failed: %s",
+                                        i, (unsigned)child_status[i].pid,
+                                        tctx->last_reason);
+                               /* ensure proper "\n\0" termination: */
+                               if (child_status[i].reason[1022] != '\0') {
+                                       child_status[i].reason[1022] = '\n';
+                                       child_status[i].reason[1023] = '\0';
+                               }
+                       }
                        _exit(0);
                }
        }
@@ -687,14 +694,26 @@ double torture_create_procs(struct torture_context *tctx,
        do {
                synccount = 0;
                for (i=0;i<torture_nprocs;i++) {
-                       if (child_status[i]) synccount++;
+                       if (child_status[i].pid != 0) {
+                               synccount++;
+                       }
                }
-               if (synccount == torture_nprocs) break;
-               msleep(100);
+               if (synccount == torture_nprocs) {
+                       break;
+               }
+               smb_msleep(100);
        } while (timeval_elapsed(&tv) < start_time_limit);
 
        if (synccount != torture_nprocs) {
                printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs, synccount);
+
+               /* cleanup child processes */
+               for (i = 0; i < torture_nprocs; i++) {
+                       if (child_status[i].pid != 0) {
+                               kill(child_status[i].pid, SIGTERM);
+                       }
+               }
+
                *result = false;
                return timeval_elapsed(&tv);
        }
@@ -704,7 +723,7 @@ double torture_create_procs(struct torture_context *tctx,
        /* start the client load */
        tv = timeval_current();
        for (i=0;i<torture_nprocs;i++) {
-               child_status[i] = 0;
+               child_status[i].start = true;
        }
 
        printf("%d clients started\n", torture_nprocs);
@@ -720,12 +739,15 @@ double torture_create_procs(struct torture_context *tctx,
        }
 
        printf("\n");
-       
+
        for (i=0;i<torture_nprocs;i++) {
-               if (!child_status_out[i]) {
+               if (child_status[i].result != TORTURE_OK) {
                        *result = false;
+                       torture_result(tctx, child_status[i].result,
+                                      "%s", child_status[i].reason);
                }
        }
+
        return timeval_elapsed(&tv);
 }
 
@@ -761,7 +783,7 @@ _PUBLIC_ struct torture_test *torture_suite_add_smb_multi_test(
        test->fn = run;
        test->dangerous = false;
 
-       DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+       DLIST_ADD_END(tcase->tests, test);
 
        return test;
 
@@ -773,18 +795,17 @@ static bool wrap_simple_2smb_test(struct torture_context *torture_ctx,
 {
        bool (*fn) (struct torture_context *, struct smbcli_state *,
                                struct smbcli_state *);
-       bool ret;
+       bool ret = true;
 
-       struct smbcli_state *cli1, *cli2;
+       struct smbcli_state *cli1 = NULL, *cli2 = NULL;
 
-       if (!torture_open_connection(&cli1, torture_ctx, 0) || 
-               !torture_open_connection(&cli2, torture_ctx, 1))
-               return false;
+       torture_assert_goto(torture_ctx, torture_open_connection(&cli1, torture_ctx, 0), ret, fail, "Failed to open connection");
+       torture_assert_goto(torture_ctx, torture_open_connection(&cli2, torture_ctx, 1), ret, fail, "Failed to open connection");
 
        fn = test->fn;
 
        ret = fn(torture_ctx, cli1, cli2);
-
+fail:
        talloc_free(cli1);
        talloc_free(cli2);
 
@@ -813,7 +834,7 @@ _PUBLIC_ struct torture_test *torture_suite_add_2smb_test(
        test->fn = run;
        test->dangerous = false;
 
-       DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+       DLIST_ADD_END(tcase->tests, test);
 
        return test;
 
@@ -824,17 +845,16 @@ static bool wrap_simple_1smb_test(struct torture_context *torture_ctx,
                                                                        struct torture_test *test)
 {
        bool (*fn) (struct torture_context *, struct smbcli_state *);
-       bool ret;
+       bool ret = true;
 
-       struct smbcli_state *cli1;
+       struct smbcli_state *cli1 = NULL;
 
-       if (!torture_open_connection(&cli1, torture_ctx, 0))
-               return false;
+       torture_assert_goto(torture_ctx, torture_open_connection(&cli1, torture_ctx, 0), ret, fail, "Failed to open connection");
 
        fn = test->fn;
 
        ret = fn(torture_ctx, cli1);
-
+fail:
        talloc_free(cli1);
 
        return ret;
@@ -858,7 +878,7 @@ _PUBLIC_ struct torture_test *torture_suite_add_1smb_test(
        test->fn = run;
        test->dangerous = false;
 
-       DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+       DLIST_ADD_END(tcase->tests, test);
 
        return test;
 }
@@ -885,7 +905,8 @@ NTSTATUS torture_second_tcon(TALLOC_CTX *mem_ctx,
        }
 
        tcon.generic.level = RAW_TCON_TCONX;
-       tcon.tconx.in.flags = 0;
+       tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
+       tcon.tconx.in.flags |= TCONX_FLAG_EXTENDED_SIGNATURES;
 
        /* Ignore share mode security here */
        tcon.tconx.in.password = data_blob(NULL, 0);
@@ -899,7 +920,49 @@ NTSTATUS torture_second_tcon(TALLOC_CTX *mem_ctx,
        }
 
        result->tid = tcon.tconx.out.tid;
+
+       if (tcon.tconx.out.options & SMB_EXTENDED_SIGNATURES) {
+               smb1cli_session_protect_session_key(result->session->smbXcli);
+       }
+
        *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);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(tmp_ctx);
+               return status;
+       }
+
+       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);
+}