root/source4/torture/util_smb.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. torture_setup_dir
  2. create_directory_handle
  3. create_complex_file
  4. create_complex_dir
  5. shm_setup
  6. wire_bad_flags
  7. dump_all_info
  8. torture_all_info
  9. torture_set_file_attribute
  10. torture_set_sparse
  11. torture_check_ea
  12. torture_open_connection_share
  13. torture_get_conn_index
  14. torture_open_connection_ev
  15. torture_open_connection
  16. torture_close_connection
  17. check_error
  18. sigcont
  19. torture_create_procs
  20. wrap_smb_multi_test
  21. torture_suite_add_smb_multi_test
  22. wrap_simple_2smb_test
  23. torture_suite_add_2smb_test
  24. wrap_simple_1smb_test
  25. torture_suite_add_1smb_test
  26. torture_second_tcon

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    SMB torture tester utility functions
   4    Copyright (C) Andrew Tridgell 2003
   5    Copyright (C) Jelmer Vernooij 2006
   6    
   7    This program is free software; you can redistribute it and/or modify
   8    it under the terms of the GNU General Public License as published by
   9    the Free Software Foundation; either version 3 of the License, or
  10    (at your option) any later version.
  11    
  12    This program is distributed in the hope that it will be useful,
  13    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15    GNU General Public License for more details.
  16    
  17    You should have received a copy of the GNU General Public License
  18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19 */
  20 
  21 #include "includes.h"
  22 #include "lib/cmdline/popt_common.h"
  23 #include "libcli/raw/libcliraw.h"
  24 #include "libcli/raw/raw_proto.h"
  25 #include "libcli/raw/ioctl.h"
  26 #include "libcli/libcli.h"
  27 #include "system/filesys.h"
  28 #include "system/shmem.h"
  29 #include "system/wait.h"
  30 #include "system/time.h"
  31 #include "torture/torture.h"
  32 #include "../lib/util/dlinklist.h"
  33 #include "auth/credentials/credentials.h"
  34 #include "libcli/resolve/resolve.h"
  35 #include "param/param.h"
  36 
  37 
  38 /**
  39   setup a directory ready for a test
  40 */
  41 _PUBLIC_ bool torture_setup_dir(struct smbcli_state *cli, const char *dname)
     /* [<][>][^][v][top][bottom][index][help] */
  42 {
  43         smb_raw_exit(cli->session);
  44         if (smbcli_deltree(cli->tree, dname) == -1 ||
  45             NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, dname))) {
  46                 printf("Unable to setup %s - %s\n", dname, smbcli_errstr(cli->tree));
  47                 return false;
  48         }
  49         return true;
  50 }
  51 
  52 /*
  53   create a directory, returning a handle to it
  54 */
  55 NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, int *fnum)
     /* [<][>][^][v][top][bottom][index][help] */
  56 {
  57         NTSTATUS status;
  58         union smb_open io;
  59         TALLOC_CTX *mem_ctx;
  60 
  61         mem_ctx = talloc_named_const(tree, 0, "create_directory_handle");
  62 
  63         io.generic.level = RAW_OPEN_NTCREATEX;
  64         io.ntcreatex.in.root_fid = 0;
  65         io.ntcreatex.in.flags = 0;
  66         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
  67         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
  68         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
  69         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
  70         io.ntcreatex.in.alloc_size = 0;
  71         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
  72         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
  73         io.ntcreatex.in.security_flags = 0;
  74         io.ntcreatex.in.fname = dname;
  75 
  76         status = smb_raw_open(tree, mem_ctx, &io);
  77         talloc_free(mem_ctx);
  78 
  79         if (NT_STATUS_IS_OK(status)) {
  80                 *fnum = io.ntcreatex.out.file.fnum;
  81         }
  82 
  83         return status;
  84 }
  85 
  86 
  87 /**
  88   sometimes we need a fairly complex file to work with, so we can test
  89   all possible attributes. 
  90 */
  91 _PUBLIC_ int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname)
     /* [<][>][^][v][top][bottom][index][help] */
  92 {
  93         int fnum;
  94         char buf[7] = "abc";
  95         union smb_setfileinfo setfile;
  96         union smb_fileinfo fileinfo;
  97         time_t t = (time(NULL) & ~1);
  98         NTSTATUS status;
  99 
 100         smbcli_unlink(cli->tree, fname);
 101         fnum = smbcli_nt_create_full(cli->tree, fname, 0, 
 102                                      SEC_RIGHTS_FILE_ALL,
 103                                      FILE_ATTRIBUTE_NORMAL,
 104                                      NTCREATEX_SHARE_ACCESS_DELETE|
 105                                      NTCREATEX_SHARE_ACCESS_READ|
 106                                      NTCREATEX_SHARE_ACCESS_WRITE, 
 107                                      NTCREATEX_DISP_OVERWRITE_IF,
 108                                      0, 0);
 109         if (fnum == -1) return -1;
 110 
 111         smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
 112 
 113         if (strchr(fname, ':') == NULL) {
 114                 /* setup some EAs */
 115                 setfile.generic.level = RAW_SFILEINFO_EA_SET;
 116                 setfile.generic.in.file.fnum = fnum;
 117                 setfile.ea_set.in.num_eas = 2;  
 118                 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
 119                 setfile.ea_set.in.eas[0].flags = 0;
 120                 setfile.ea_set.in.eas[0].name.s = "EAONE";
 121                 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
 122                 setfile.ea_set.in.eas[1].flags = 0;
 123                 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
 124                 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
 125                 status = smb_raw_setfileinfo(cli->tree, &setfile);
 126                 if (!NT_STATUS_IS_OK(status)) {
 127                         printf("Failed to setup EAs\n");
 128                 }
 129         }
 130 
 131         /* make sure all the timestamps aren't the same, and are also 
 132            in different DST zones*/
 133         setfile.generic.level = RAW_SFILEINFO_SETATTRE;
 134         setfile.generic.in.file.fnum = fnum;
 135 
 136         setfile.setattre.in.create_time = t + 9*30*24*60*60;
 137         setfile.setattre.in.access_time = t + 6*30*24*60*60;
 138         setfile.setattre.in.write_time  = t + 3*30*24*60*60;
 139 
 140         status = smb_raw_setfileinfo(cli->tree, &setfile);
 141         if (!NT_STATUS_IS_OK(status)) {
 142                 printf("Failed to setup file times - %s\n", nt_errstr(status));
 143         }
 144 
 145         /* make sure all the timestamps aren't the same */
 146         fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
 147         fileinfo.generic.in.file.fnum = fnum;
 148 
 149         status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
 150         if (!NT_STATUS_IS_OK(status)) {
 151                 printf("Failed to query file times - %s\n", nt_errstr(status));
 152         }
 153 
 154         if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
 155                 printf("create_time not setup correctly\n");
 156         }
 157         if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
 158                 printf("access_time not setup correctly\n");
 159         }
 160         if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
 161                 printf("write_time not setup correctly\n");
 162         }
 163 
 164         return fnum;
 165 }
 166 
 167 
 168 /*
 169   sometimes we need a fairly complex directory to work with, so we can test
 170   all possible attributes. 
 171 */
 172 int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *dname)
     /* [<][>][^][v][top][bottom][index][help] */
 173 {
 174         int fnum;
 175         union smb_setfileinfo setfile;
 176         union smb_fileinfo fileinfo;
 177         time_t t = (time(NULL) & ~1);
 178         NTSTATUS status;
 179 
 180         smbcli_deltree(cli->tree, dname);
 181         fnum = smbcli_nt_create_full(cli->tree, dname, 0, 
 182                                      SEC_RIGHTS_DIR_ALL,
 183                                      FILE_ATTRIBUTE_DIRECTORY,
 184                                      NTCREATEX_SHARE_ACCESS_READ|
 185                                      NTCREATEX_SHARE_ACCESS_WRITE, 
 186                                      NTCREATEX_DISP_OPEN_IF,
 187                                      NTCREATEX_OPTIONS_DIRECTORY, 0);
 188         if (fnum == -1) return -1;
 189 
 190         if (strchr(dname, ':') == NULL) {
 191                 /* setup some EAs */
 192                 setfile.generic.level = RAW_SFILEINFO_EA_SET;
 193                 setfile.generic.in.file.fnum = fnum;
 194                 setfile.ea_set.in.num_eas = 2;  
 195                 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
 196                 setfile.ea_set.in.eas[0].flags = 0;
 197                 setfile.ea_set.in.eas[0].name.s = "EAONE";
 198                 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
 199                 setfile.ea_set.in.eas[1].flags = 0;
 200                 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
 201                 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
 202                 status = smb_raw_setfileinfo(cli->tree, &setfile);
 203                 if (!NT_STATUS_IS_OK(status)) {
 204                         printf("Failed to setup EAs\n");
 205                 }
 206         }
 207 
 208         /* make sure all the timestamps aren't the same, and are also 
 209            in different DST zones*/
 210         setfile.generic.level = RAW_SFILEINFO_SETATTRE;
 211         setfile.generic.in.file.fnum = fnum;
 212 
 213         setfile.setattre.in.create_time = t + 9*30*24*60*60;
 214         setfile.setattre.in.access_time = t + 6*30*24*60*60;
 215         setfile.setattre.in.write_time  = t + 3*30*24*60*60;
 216 
 217         status = smb_raw_setfileinfo(cli->tree, &setfile);
 218         if (!NT_STATUS_IS_OK(status)) {
 219                 printf("Failed to setup file times - %s\n", nt_errstr(status));
 220         }
 221 
 222         /* make sure all the timestamps aren't the same */
 223         fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
 224         fileinfo.generic.in.file.fnum = fnum;
 225 
 226         status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
 227         if (!NT_STATUS_IS_OK(status)) {
 228                 printf("Failed to query file times - %s\n", nt_errstr(status));
 229         }
 230 
 231         if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
 232                 printf("create_time not setup correctly\n");
 233         }
 234         if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
 235                 printf("access_time not setup correctly\n");
 236         }
 237         if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
 238                 printf("write_time not setup correctly\n");
 239         }
 240 
 241         return fnum;
 242 }
 243 
 244 
 245 
 246 /* return a pointer to a anonymous shared memory segment of size "size"
 247    which will persist across fork() but will disappear when all processes
 248    exit 
 249 
 250    The memory is not zeroed 
 251 
 252    This function uses system5 shared memory. It takes advantage of a property
 253    that the memory is not destroyed if it is attached when the id is removed
 254    */
 255 void *shm_setup(int size)
     /* [<][>][^][v][top][bottom][index][help] */
 256 {
 257         int shmid;
 258         void *ret;
 259 
 260         shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
 261         if (shmid == -1) {
 262                 printf("can't get shared memory\n");
 263                 exit(1);
 264         }
 265         ret = (void *)shmat(shmid, 0, 0);
 266         if (!ret || ret == (void *)-1) {
 267                 printf("can't attach to shared memory\n");
 268                 return NULL;
 269         }
 270         /* the following releases the ipc, but note that this process
 271            and all its children will still have access to the memory, its
 272            just that the shmid is no longer valid for other shm calls. This
 273            means we don't leave behind lots of shm segments after we exit 
 274 
 275            See Stevens "advanced programming in unix env" for details
 276            */
 277         shmctl(shmid, IPC_RMID, 0);
 278         
 279         return ret;
 280 }
 281 
 282 
 283 /**
 284   check that a wire string matches the flags specified 
 285   not 100% accurate, but close enough for testing
 286 */
 287 bool wire_bad_flags(struct smb_wire_string *str, int flags, 
     /* [<][>][^][v][top][bottom][index][help] */
 288                     struct smbcli_transport *transport)
 289 {
 290         bool server_unicode;
 291         int len;
 292         if (!str || !str->s) return true;
 293         len = strlen(str->s);
 294         if (flags & STR_TERMINATE) len++;
 295 
 296         server_unicode = (transport->negotiate.capabilities&CAP_UNICODE)?true:false;
 297         if (getenv("CLI_FORCE_ASCII") || !transport->options.unicode) {
 298                 server_unicode = false;
 299         }
 300 
 301         if ((flags & STR_UNICODE) || server_unicode) {
 302                 len *= 2;
 303         } else if (flags & STR_TERMINATE_ASCII) {
 304                 len++;
 305         }
 306         if (str->private_length != len) {
 307                 printf("Expected wire_length %d but got %d for '%s'\n", 
 308                        len, str->private_length, str->s);
 309                 return true;
 310         }
 311         return false;
 312 }
 313 
 314 /*
 315   dump a all_info QFILEINFO structure
 316 */
 317 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
     /* [<][>][^][v][top][bottom][index][help] */
 318 {
 319         d_printf("\tcreate_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
 320         d_printf("\taccess_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
 321         d_printf("\twrite_time:     %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
 322         d_printf("\tchange_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
 323         d_printf("\tattrib:         0x%x\n", finfo->all_info.out.attrib);
 324         d_printf("\talloc_size:     %llu\n", (long long)finfo->all_info.out.alloc_size);
 325         d_printf("\tsize:           %llu\n", (long long)finfo->all_info.out.size);
 326         d_printf("\tnlink:          %u\n", finfo->all_info.out.nlink);
 327         d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
 328         d_printf("\tdirectory:      %u\n", finfo->all_info.out.directory);
 329         d_printf("\tea_size:        %u\n", finfo->all_info.out.ea_size);
 330         d_printf("\tfname:          '%s'\n", finfo->all_info.out.fname.s);
 331 }
 332 
 333 /*
 334   dump file infor by name
 335 */
 336 void torture_all_info(struct smbcli_tree *tree, const char *fname)
     /* [<][>][^][v][top][bottom][index][help] */
 337 {
 338         TALLOC_CTX *mem_ctx = talloc_named(tree, 0, "%s", fname);
 339         union smb_fileinfo finfo;
 340         NTSTATUS status;
 341 
 342         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
 343         finfo.generic.in.file.path = fname;
 344         status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
 345         if (!NT_STATUS_IS_OK(status)) {
 346                 d_printf("%s - %s\n", fname, nt_errstr(status));
 347                 return;
 348         }
 349 
 350         d_printf("%s:\n", fname);
 351         dump_all_info(mem_ctx, &finfo);
 352         talloc_free(mem_ctx);
 353 }
 354 
 355 
 356 /*
 357   set a attribute on a file
 358 */
 359 bool torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
     /* [<][>][^][v][top][bottom][index][help] */
 360 {
 361         union smb_setfileinfo sfinfo;
 362         NTSTATUS status;
 363 
 364         ZERO_STRUCT(sfinfo.basic_info.in);
 365         sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
 366         sfinfo.basic_info.in.file.path = fname;
 367         sfinfo.basic_info.in.attrib = attrib;
 368         status = smb_raw_setpathinfo(tree, &sfinfo);
 369         return NT_STATUS_IS_OK(status);
 370 }
 371 
 372 
 373 /*
 374   set a file descriptor as sparse
 375 */
 376 NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
     /* [<][>][^][v][top][bottom][index][help] */
 377 {
 378         union smb_ioctl nt;
 379         NTSTATUS status;
 380         TALLOC_CTX *mem_ctx;
 381 
 382         mem_ctx = talloc_named_const(tree, 0, "torture_set_sparse");
 383         if (!mem_ctx) {
 384                 return NT_STATUS_NO_MEMORY;
 385         }
 386 
 387         nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
 388         nt.ntioctl.in.function = FSCTL_SET_SPARSE;
 389         nt.ntioctl.in.file.fnum = fnum;
 390         nt.ntioctl.in.fsctl = true;
 391         nt.ntioctl.in.filter = 0;
 392         nt.ntioctl.in.max_data = 0;
 393         nt.ntioctl.in.blob = data_blob(NULL, 0);
 394 
 395         status = smb_raw_ioctl(tree, mem_ctx, &nt);
 396 
 397         talloc_free(mem_ctx);
 398 
 399         return status;
 400 }
 401 
 402 /*
 403   check that an EA has the right value 
 404 */
 405 NTSTATUS torture_check_ea(struct smbcli_state *cli, 
     /* [<][>][^][v][top][bottom][index][help] */
 406                           const char *fname, const char *eaname, const char *value)
 407 {
 408         union smb_fileinfo info;
 409         NTSTATUS status;
 410         struct ea_name ea;
 411         TALLOC_CTX *mem_ctx = talloc_new(cli);
 412 
 413         info.ea_list.level = RAW_FILEINFO_EA_LIST;
 414         info.ea_list.in.file.path = fname;
 415         info.ea_list.in.num_names = 1;
 416         info.ea_list.in.ea_names = &ea;
 417 
 418         ea.name.s = eaname;
 419 
 420         status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
 421         if (!NT_STATUS_IS_OK(status)) {
 422                 talloc_free(mem_ctx);
 423                 return status;
 424         }
 425 
 426         if (info.ea_list.out.num_eas != 1) {
 427                 printf("Expected 1 ea in ea_list\n");
 428                 talloc_free(mem_ctx);
 429                 return NT_STATUS_EA_CORRUPT_ERROR;
 430         }
 431 
 432         if (strcasecmp_m(eaname, info.ea_list.out.eas[0].name.s) != 0) {
 433                 printf("Expected ea '%s' not '%s' in ea_list\n",
 434                        eaname, info.ea_list.out.eas[0].name.s);
 435                 talloc_free(mem_ctx);
 436                 return NT_STATUS_EA_CORRUPT_ERROR;
 437         }
 438 
 439         if (value == NULL) {
 440                 if (info.ea_list.out.eas[0].value.length != 0) {
 441                         printf("Expected zero length ea for %s\n", eaname);
 442                         talloc_free(mem_ctx);
 443                         return NT_STATUS_EA_CORRUPT_ERROR;
 444                 }
 445                 talloc_free(mem_ctx);
 446                 return NT_STATUS_OK;
 447         }
 448 
 449         if (strlen(value) == info.ea_list.out.eas[0].value.length &&
 450             memcmp(value, info.ea_list.out.eas[0].value.data,
 451                    info.ea_list.out.eas[0].value.length) == 0) {
 452                 talloc_free(mem_ctx);
 453                 return NT_STATUS_OK;
 454         }
 455 
 456         printf("Expected value '%s' not '%*.*s' for ea %s\n",
 457                value, 
 458                (int)info.ea_list.out.eas[0].value.length,
 459                (int)info.ea_list.out.eas[0].value.length,
 460                info.ea_list.out.eas[0].value.data,
 461                eaname);
 462 
 463         talloc_free(mem_ctx);
 464 
 465         return NT_STATUS_EA_CORRUPT_ERROR;
 466 }
 467 
 468 _PUBLIC_ bool torture_open_connection_share(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 469                                    struct smbcli_state **c, 
 470                                    struct torture_context *tctx,
 471                                    const char *hostname, 
 472                                    const char *sharename,
 473                                    struct tevent_context *ev)
 474 {
 475         NTSTATUS status;
 476 
 477         struct smbcli_options options;
 478         struct smbcli_session_options session_options;
 479 
 480         lp_smbcli_options(tctx->lp_ctx, &options);
 481         lp_smbcli_session_options(tctx->lp_ctx, &session_options);
 482 
 483         options.use_oplocks = torture_setting_bool(tctx, "use_oplocks", true);
 484         options.use_level2_oplocks = torture_setting_bool(tctx, "use_level2_oplocks", true);
 485 
 486         status = smbcli_full_connection(mem_ctx, c, hostname, 
 487                                         lp_smb_ports(tctx->lp_ctx),
 488                                         sharename, NULL,
 489                                         lp_socket_options(tctx->lp_ctx),
 490                                         cmdline_credentials, 
 491                                         lp_resolve_context(tctx->lp_ctx),
 492                                         ev, &options, &session_options,
 493                                         lp_iconv_convenience(tctx->lp_ctx),
 494                                         lp_gensec_settings(tctx, tctx->lp_ctx));
 495         if (!NT_STATUS_IS_OK(status)) {
 496                 printf("Failed to open connection - %s\n", nt_errstr(status));
 497                 return false;
 498         }
 499 
 500         return true;
 501 }
 502 
 503 _PUBLIC_ bool torture_get_conn_index(int conn_index,
     /* [<][>][^][v][top][bottom][index][help] */
 504                                      TALLOC_CTX *mem_ctx,
 505                                      struct torture_context *tctx,
 506                                      char **host, char **share)
 507 {
 508         char **unc_list = NULL;
 509         int num_unc_names = 0;
 510         const char *p;
 511 
 512         (*host) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "host", NULL));
 513         (*share) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "share", NULL));
 514         
 515         p = torture_setting_string(tctx, "unclist", NULL);
 516         if (!p) {
 517                 return true;
 518         }
 519 
 520         unc_list = file_lines_load(p, &num_unc_names, 0, NULL);
 521         if (!unc_list || num_unc_names <= 0) {
 522                 DEBUG(0,("Failed to load unc names list from '%s'\n", p));
 523                 return false;
 524         }
 525 
 526         if (!smbcli_parse_unc(unc_list[conn_index % num_unc_names],
 527                               mem_ctx, host, share)) {
 528                 DEBUG(0, ("Failed to parse UNC name %s\n",
 529                           unc_list[conn_index % num_unc_names]));
 530                 return false;
 531         }
 532 
 533         talloc_free(unc_list);
 534         return true;
 535 }
 536 
 537 
 538 
 539 _PUBLIC_ bool torture_open_connection_ev(struct smbcli_state **c,
     /* [<][>][^][v][top][bottom][index][help] */
 540                                          int conn_index,
 541                                          struct torture_context *tctx,
 542                                          struct tevent_context *ev)
 543 {
 544         char *host, *share;
 545         bool ret;
 546 
 547         if (!torture_get_conn_index(conn_index, ev, tctx, &host, &share)) {
 548                 return false;
 549         }
 550 
 551         ret = torture_open_connection_share(NULL, c, tctx, host, share, ev);
 552         talloc_free(host);
 553         talloc_free(share);
 554 
 555         return ret;
 556 }
 557 
 558 _PUBLIC_ bool torture_open_connection(struct smbcli_state **c, struct torture_context *tctx, int conn_index)
     /* [<][>][^][v][top][bottom][index][help] */
 559 {
 560         return torture_open_connection_ev(c, conn_index, tctx, tctx->ev);
 561 }
 562 
 563 
 564 
 565 _PUBLIC_ bool torture_close_connection(struct smbcli_state *c)
     /* [<][>][^][v][top][bottom][index][help] */
 566 {
 567         bool ret = true;
 568         if (!c) return true;
 569         if (NT_STATUS_IS_ERR(smbcli_tdis(c))) {
 570                 printf("tdis failed (%s)\n", smbcli_errstr(c->tree));
 571                 ret = false;
 572         }
 573         talloc_free(c);
 574         return ret;
 575 }
 576 
 577 
 578 /* check if the server produced the expected error code */
 579 _PUBLIC_ bool check_error(const char *location, struct smbcli_state *c, 
     /* [<][>][^][v][top][bottom][index][help] */
 580                  uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
 581 {
 582         NTSTATUS status;
 583         
 584         status = smbcli_nt_error(c->tree);
 585         if (NT_STATUS_IS_DOS(status)) {
 586                 int classnum, num;
 587                 classnum = NT_STATUS_DOS_CLASS(status);
 588                 num = NT_STATUS_DOS_CODE(status);
 589                 if (eclass != classnum || ecode != num) {
 590                         printf("unexpected error code %s\n", nt_errstr(status));
 591                         printf(" expected %s or %s (at %s)\n", 
 592                                nt_errstr(NT_STATUS_DOS(eclass, ecode)), 
 593                                nt_errstr(nterr), location);
 594                         return false;
 595                 }
 596         } else {
 597                 if (!NT_STATUS_EQUAL(nterr, status)) {
 598                         printf("unexpected error code %s\n", nt_errstr(status));
 599                         printf(" expected %s (at %s)\n", nt_errstr(nterr), location);
 600                         return false;
 601                 }
 602         }
 603 
 604         return true;
 605 }
 606 
 607 static struct smbcli_state *current_cli;
 608 static int procnum; /* records process count number when forking */
 609 
 610 static void sigcont(int sig)
     /* [<][>][^][v][top][bottom][index][help] */
 611 {
 612 }
 613 
 614 double torture_create_procs(struct torture_context *tctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 615                                                         bool (*fn)(struct torture_context *, struct smbcli_state *, int), bool *result)
 616 {
 617         int i, status;
 618         volatile pid_t *child_status;
 619         volatile bool *child_status_out;
 620         int synccount;
 621         int tries = 8;
 622         int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
 623         double start_time_limit = 10 + (torture_nprocs * 1.5);
 624         struct timeval tv;
 625 
 626         *result = true;
 627 
 628         synccount = 0;
 629 
 630         signal(SIGCONT, sigcont);
 631 
 632         child_status = (volatile pid_t *)shm_setup(sizeof(pid_t)*torture_nprocs);
 633         if (!child_status) {
 634                 printf("Failed to setup shared memory\n");
 635                 return -1;
 636         }
 637 
 638         child_status_out = (volatile bool *)shm_setup(sizeof(bool)*torture_nprocs);
 639         if (!child_status_out) {
 640                 printf("Failed to setup result status shared memory\n");
 641                 return -1;
 642         }
 643 
 644         for (i = 0; i < torture_nprocs; i++) {
 645                 child_status[i] = 0;
 646                 child_status_out[i] = true;
 647         }
 648 
 649         tv = timeval_current();
 650 
 651         for (i=0;i<torture_nprocs;i++) {
 652                 procnum = i;
 653                 if (fork() == 0) {
 654                         char *myname;
 655 
 656                         pid_t mypid = getpid();
 657                         srandom(((int)mypid) ^ ((int)time(NULL)));
 658 
 659                         if (asprintf(&myname, "CLIENT%d", i) == -1) {
 660                                 printf("asprintf failed\n");
 661                                 return -1;
 662                         }
 663                         lp_set_cmdline(tctx->lp_ctx, "netbios name", myname);
 664                         free(myname);
 665 
 666 
 667                         while (1) {
 668                                 if (torture_open_connection(&current_cli, tctx, i)) {
 669                                         break;
 670                                 }
 671                                 if (tries-- == 0) {
 672                                         printf("pid %d failed to start\n", (int)getpid());
 673                                         _exit(1);
 674                                 }
 675                                 msleep(100);    
 676                         }
 677 
 678                         child_status[i] = getpid();
 679 
 680                         pause();
 681 
 682                         if (child_status[i]) {
 683                                 printf("Child %d failed to start!\n", i);
 684                                 child_status_out[i] = 1;
 685                                 _exit(1);
 686                         }
 687 
 688                         child_status_out[i] = fn(tctx, current_cli, i);
 689                         _exit(0);
 690                 }
 691         }
 692 
 693         do {
 694                 synccount = 0;
 695                 for (i=0;i<torture_nprocs;i++) {
 696                         if (child_status[i]) synccount++;
 697                 }
 698                 if (synccount == torture_nprocs) break;
 699                 msleep(100);
 700         } while (timeval_elapsed(&tv) < start_time_limit);
 701 
 702         if (synccount != torture_nprocs) {
 703                 printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs, synccount);
 704                 *result = false;
 705                 return timeval_elapsed(&tv);
 706         }
 707 
 708         printf("Starting %d clients\n", torture_nprocs);
 709 
 710         /* start the client load */
 711         tv = timeval_current();
 712         for (i=0;i<torture_nprocs;i++) {
 713                 child_status[i] = 0;
 714         }
 715 
 716         printf("%d clients started\n", torture_nprocs);
 717 
 718         kill(0, SIGCONT);
 719 
 720         for (i=0;i<torture_nprocs;i++) {
 721                 int ret;
 722                 while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
 723                 if (ret == -1 || WEXITSTATUS(status) != 0) {
 724                         *result = false;
 725                 }
 726         }
 727 
 728         printf("\n");
 729         
 730         for (i=0;i<torture_nprocs;i++) {
 731                 if (!child_status_out[i]) {
 732                         *result = false;
 733                 }
 734         }
 735         return timeval_elapsed(&tv);
 736 }
 737 
 738 static bool wrap_smb_multi_test(struct torture_context *torture,
     /* [<][>][^][v][top][bottom][index][help] */
 739                                                                 struct torture_tcase *tcase,
 740                                                                 struct torture_test *test)
 741 {
 742         bool (*fn)(struct torture_context *, struct smbcli_state *, int ) = test->fn;
 743         bool result;
 744 
 745         torture_create_procs(torture, fn, &result);
 746 
 747         return result;
 748 }
 749 
 750 _PUBLIC_ struct torture_test *torture_suite_add_smb_multi_test(
     /* [<][>][^][v][top][bottom][index][help] */
 751                                                                         struct torture_suite *suite,
 752                                                                         const char *name,
 753                                                                         bool (*run) (struct torture_context *,
 754                                                                                                  struct smbcli_state *,
 755                                                                                                 int i))
 756 {
 757         struct torture_test *test; 
 758         struct torture_tcase *tcase;
 759         
 760         tcase = torture_suite_add_tcase(suite, name);
 761 
 762         test = talloc(tcase, struct torture_test);
 763 
 764         test->name = talloc_strdup(test, name);
 765         test->description = NULL;
 766         test->run = wrap_smb_multi_test;
 767         test->fn = run;
 768         test->dangerous = false;
 769 
 770         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
 771 
 772         return test;
 773 
 774 }
 775 
 776 static bool wrap_simple_2smb_test(struct torture_context *torture_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 777                                                                         struct torture_tcase *tcase,
 778                                                                         struct torture_test *test)
 779 {
 780         bool (*fn) (struct torture_context *, struct smbcli_state *,
 781                                 struct smbcli_state *);
 782         bool ret;
 783 
 784         struct smbcli_state *cli1, *cli2;
 785 
 786         if (!torture_open_connection(&cli1, torture_ctx, 0) || 
 787                 !torture_open_connection(&cli2, torture_ctx, 1))
 788                 return false;
 789 
 790         fn = test->fn;
 791 
 792         ret = fn(torture_ctx, cli1, cli2);
 793 
 794         talloc_free(cli1);
 795         talloc_free(cli2);
 796 
 797         return ret;
 798 }
 799 
 800 
 801 
 802 _PUBLIC_ struct torture_test *torture_suite_add_2smb_test(
     /* [<][>][^][v][top][bottom][index][help] */
 803                                                                         struct torture_suite *suite,
 804                                                                         const char *name,
 805                                                                         bool (*run) (struct torture_context *,
 806                                                                                                 struct smbcli_state *,
 807                                                                                                 struct smbcli_state *))
 808 {
 809         struct torture_test *test; 
 810         struct torture_tcase *tcase;
 811         
 812         tcase = torture_suite_add_tcase(suite, name);
 813 
 814         test = talloc(tcase, struct torture_test);
 815 
 816         test->name = talloc_strdup(test, name);
 817         test->description = NULL;
 818         test->run = wrap_simple_2smb_test;
 819         test->fn = run;
 820         test->dangerous = false;
 821 
 822         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
 823 
 824         return test;
 825 
 826 }
 827 
 828 static bool wrap_simple_1smb_test(struct torture_context *torture_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 829                                                                         struct torture_tcase *tcase,
 830                                                                         struct torture_test *test)
 831 {
 832         bool (*fn) (struct torture_context *, struct smbcli_state *);
 833         bool ret;
 834 
 835         struct smbcli_state *cli1;
 836 
 837         if (!torture_open_connection(&cli1, torture_ctx, 0))
 838                 return false;
 839 
 840         fn = test->fn;
 841 
 842         ret = fn(torture_ctx, cli1);
 843 
 844         talloc_free(cli1);
 845 
 846         return ret;
 847 }
 848 
 849 _PUBLIC_ struct torture_test *torture_suite_add_1smb_test(
     /* [<][>][^][v][top][bottom][index][help] */
 850                                 struct torture_suite *suite,
 851                                 const char *name,
 852                                 bool (*run) (struct torture_context *, struct smbcli_state *))
 853 {
 854         struct torture_test *test; 
 855         struct torture_tcase *tcase;
 856         
 857         tcase = torture_suite_add_tcase(suite, name);
 858 
 859         test = talloc(tcase, struct torture_test);
 860 
 861         test->name = talloc_strdup(test, name);
 862         test->description = NULL;
 863         test->run = wrap_simple_1smb_test;
 864         test->fn = run;
 865         test->dangerous = false;
 866 
 867         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
 868 
 869         return test;
 870 }
 871 
 872 
 873 NTSTATUS torture_second_tcon(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 874                              struct smbcli_session *session,
 875                              const char *sharename,
 876                              struct smbcli_tree **res)
 877 {
 878         union smb_tcon tcon;
 879         struct smbcli_tree *result;
 880         TALLOC_CTX *tmp_ctx;
 881         NTSTATUS status;
 882 
 883         if ((tmp_ctx = talloc_new(mem_ctx)) == NULL) {
 884                 return NT_STATUS_NO_MEMORY;
 885         }
 886 
 887         result = smbcli_tree_init(session, tmp_ctx, false);
 888         if (result == NULL) {
 889                 talloc_free(tmp_ctx);
 890                 return NT_STATUS_NO_MEMORY;
 891         }
 892 
 893         tcon.generic.level = RAW_TCON_TCONX;
 894         tcon.tconx.in.flags = 0;
 895 
 896         /* Ignore share mode security here */
 897         tcon.tconx.in.password = data_blob(NULL, 0);
 898         tcon.tconx.in.path = sharename;
 899         tcon.tconx.in.device = "?????";
 900 
 901         status = smb_raw_tcon(result, tmp_ctx, &tcon);
 902         if (!NT_STATUS_IS_OK(status)) {
 903                 talloc_free(tmp_ctx);
 904                 return status;
 905         }
 906 
 907         result->tid = tcon.tconx.out.tid;
 908         *res = talloc_steal(mem_ctx, result);
 909         talloc_free(tmp_ctx);
 910         return NT_STATUS_OK;
 911 }

/* [<][>][^][v][top][bottom][index][help] */