LCOV - code coverage report
Current view: top level - source4/torture - util_smb.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 335 519 64.5 %
Date: 2024-02-28 12:06:22 Functions: 25 27 92.6 %

          Line data    Source code
       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/cmdline.h"
      23             : #include "libcli/raw/libcliraw.h"
      24             : #include "libcli/raw/raw_proto.h"
      25             : #include "../libcli/smb/smb_constants.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 "libcli/resolve/resolve.h"
      34             : #include "param/param.h"
      35             : #include "libcli/security/security.h"
      36             : #include "libcli/smb2/smb2.h"
      37             : #include "libcli/util/clilsa.h"
      38             : #include "torture/util.h"
      39             : #include "libcli/smb/smbXcli_base.h"
      40             : #include "auth/credentials/credentials.h"
      41             : #include "auth/credentials/credentials_krb5.h"
      42             : 
      43             : /**
      44             :   setup a directory ready for a test
      45             : */
      46         982 : _PUBLIC_ bool torture_setup_dir(struct smbcli_state *cli, const char *dname)
      47             : {
      48         982 :         smb_raw_exit(cli->session);
      49         982 :         if (smbcli_deltree(cli->tree, dname) == -1 ||
      50         982 :             NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, dname))) {
      51           0 :                 printf("Unable to setup %s - %s\n", dname, smbcli_errstr(cli->tree));
      52           0 :                 return false;
      53             :         }
      54         945 :         return true;
      55             : }
      56             : 
      57             : /*
      58             :   create a directory, returning a handle to it
      59             : */
      60          39 : NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, int *fnum)
      61             : {
      62           1 :         NTSTATUS status;
      63           1 :         union smb_open io;
      64           1 :         TALLOC_CTX *mem_ctx;
      65             : 
      66          39 :         mem_ctx = talloc_named_const(tree, 0, "create_directory_handle");
      67             : 
      68          39 :         io.generic.level = RAW_OPEN_NTCREATEX;
      69          39 :         io.ntcreatex.in.root_fid.fnum = 0;
      70          39 :         io.ntcreatex.in.flags = 0;
      71          39 :         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
      72          39 :         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
      73          39 :         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
      74          39 :         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
      75          39 :         io.ntcreatex.in.alloc_size = 0;
      76          39 :         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
      77          39 :         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
      78          39 :         io.ntcreatex.in.security_flags = 0;
      79          39 :         io.ntcreatex.in.fname = dname;
      80             : 
      81          39 :         status = smb_raw_open(tree, mem_ctx, &io);
      82          39 :         talloc_free(mem_ctx);
      83             : 
      84          39 :         if (NT_STATUS_IS_OK(status)) {
      85          39 :                 *fnum = io.ntcreatex.out.file.fnum;
      86             :         }
      87             : 
      88          39 :         return status;
      89             : }
      90             : 
      91             : 
      92             : /**
      93             :   sometimes we need a fairly complex file to work with, so we can test
      94             :   all possible attributes. 
      95             : */
      96         832 : _PUBLIC_ int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname)
      97             : {
      98          21 :         int fnum;
      99         832 :         char buf[7] = "abc";
     100          21 :         union smb_setfileinfo setfile;
     101          21 :         union smb_fileinfo fileinfo;
     102         832 :         time_t t = (time(NULL) & ~1);
     103          21 :         NTSTATUS status;
     104             : 
     105         832 :         smbcli_unlink(cli->tree, fname);
     106         832 :         fnum = smbcli_nt_create_full(cli->tree, fname, 0, 
     107             :                                      SEC_RIGHTS_FILE_ALL,
     108             :                                      FILE_ATTRIBUTE_NORMAL,
     109             :                                      NTCREATEX_SHARE_ACCESS_DELETE|
     110             :                                      NTCREATEX_SHARE_ACCESS_READ|
     111             :                                      NTCREATEX_SHARE_ACCESS_WRITE, 
     112             :                                      NTCREATEX_DISP_OVERWRITE_IF,
     113             :                                      0, 0);
     114         832 :         if (fnum == -1) return -1;
     115             : 
     116         832 :         smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
     117             : 
     118         832 :         if (strchr(fname, ':') == NULL) {
     119             :                 /* setup some EAs */
     120         832 :                 setfile.generic.level = RAW_SFILEINFO_EA_SET;
     121         832 :                 setfile.generic.in.file.fnum = fnum;
     122         832 :                 setfile.ea_set.in.num_eas = 2;  
     123         832 :                 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
     124         832 :                 setfile.ea_set.in.eas[0].flags = 0;
     125         832 :                 setfile.ea_set.in.eas[0].name.s = "EAONE";
     126         832 :                 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
     127         832 :                 setfile.ea_set.in.eas[1].flags = 0;
     128         832 :                 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
     129         832 :                 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
     130         832 :                 status = smb_raw_setfileinfo(cli->tree, &setfile);
     131         832 :                 if (!NT_STATUS_IS_OK(status)) {
     132           0 :                         printf("Failed to setup EAs\n");
     133             :                 }
     134             :         }
     135             : 
     136             :         /* make sure all the timestamps aren't the same */
     137         832 :         ZERO_STRUCT(setfile);
     138         832 :         setfile.generic.level = RAW_SFILEINFO_BASIC_INFO;
     139         832 :         setfile.generic.in.file.fnum = fnum;
     140             : 
     141         832 :         unix_to_nt_time(&setfile.basic_info.in.create_time,
     142             :             t + 9*30*24*60*60);
     143         832 :         unix_to_nt_time(&setfile.basic_info.in.access_time,
     144             :             t + 6*30*24*60*60);
     145         832 :         unix_to_nt_time(&setfile.basic_info.in.write_time,
     146             :             t + 3*30*24*60*60);
     147             : 
     148         832 :         status = smb_raw_setfileinfo(cli->tree, &setfile);
     149         832 :         if (!NT_STATUS_IS_OK(status)) {
     150           0 :                 printf("Failed to setup file times - %s\n", nt_errstr(status));
     151             :         }
     152             : 
     153             :         /* make sure all the timestamps aren't the same */
     154         832 :         fileinfo.generic.level = RAW_FILEINFO_BASIC_INFO;
     155         832 :         fileinfo.generic.in.file.fnum = fnum;
     156             : 
     157         832 :         status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
     158         832 :         if (!NT_STATUS_IS_OK(status)) {
     159           0 :                 printf("Failed to query file times - %s\n", nt_errstr(status));
     160             :         }
     161             : 
     162         832 :         if (setfile.basic_info.in.create_time != fileinfo.basic_info.out.create_time) {
     163           0 :                 printf("create_time not setup correctly\n");
     164             :         }
     165         832 :         if (setfile.basic_info.in.access_time != fileinfo.basic_info.out.access_time) {
     166           0 :                 printf("access_time not setup correctly\n");
     167             :         }
     168         832 :         if (setfile.basic_info.in.write_time != fileinfo.basic_info.out.write_time) {
     169           0 :                 printf("write_time not setup correctly\n");
     170             :         }
     171             : 
     172         811 :         return fnum;
     173             : }
     174             : 
     175             : 
     176             : /*
     177             :   sometimes we need a fairly complex directory to work with, so we can test
     178             :   all possible attributes. 
     179             : */
     180           0 : int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *dname)
     181             : {
     182           0 :         int fnum;
     183           0 :         union smb_setfileinfo setfile;
     184           0 :         union smb_fileinfo fileinfo;
     185           0 :         time_t t = (time(NULL) & ~1);
     186           0 :         NTSTATUS status;
     187             : 
     188           0 :         smbcli_deltree(cli->tree, dname);
     189           0 :         fnum = smbcli_nt_create_full(cli->tree, dname, 0, 
     190             :                                      SEC_RIGHTS_DIR_ALL,
     191             :                                      FILE_ATTRIBUTE_DIRECTORY,
     192             :                                      NTCREATEX_SHARE_ACCESS_READ|
     193             :                                      NTCREATEX_SHARE_ACCESS_WRITE, 
     194             :                                      NTCREATEX_DISP_OPEN_IF,
     195             :                                      NTCREATEX_OPTIONS_DIRECTORY, 0);
     196           0 :         if (fnum == -1) return -1;
     197             : 
     198           0 :         if (strchr(dname, ':') == NULL) {
     199             :                 /* setup some EAs */
     200           0 :                 setfile.generic.level = RAW_SFILEINFO_EA_SET;
     201           0 :                 setfile.generic.in.file.fnum = fnum;
     202           0 :                 setfile.ea_set.in.num_eas = 2;  
     203           0 :                 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
     204           0 :                 setfile.ea_set.in.eas[0].flags = 0;
     205           0 :                 setfile.ea_set.in.eas[0].name.s = "EAONE";
     206           0 :                 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
     207           0 :                 setfile.ea_set.in.eas[1].flags = 0;
     208           0 :                 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
     209           0 :                 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
     210           0 :                 status = smb_raw_setfileinfo(cli->tree, &setfile);
     211           0 :                 if (!NT_STATUS_IS_OK(status)) {
     212           0 :                         printf("Failed to setup EAs\n");
     213             :                 }
     214             :         }
     215             : 
     216             :         /* make sure all the timestamps aren't the same */
     217           0 :         ZERO_STRUCT(setfile);
     218           0 :         setfile.generic.level = RAW_SFILEINFO_BASIC_INFO;
     219           0 :         setfile.generic.in.file.fnum = fnum;
     220             : 
     221           0 :         unix_to_nt_time(&setfile.basic_info.in.create_time,
     222             :             t + 9*30*24*60*60);
     223           0 :         unix_to_nt_time(&setfile.basic_info.in.access_time,
     224             :             t + 6*30*24*60*60);
     225           0 :         unix_to_nt_time(&setfile.basic_info.in.write_time,
     226             :             t + 3*30*24*60*60);
     227             : 
     228           0 :         status = smb_raw_setfileinfo(cli->tree, &setfile);
     229           0 :         if (!NT_STATUS_IS_OK(status)) {
     230           0 :                 printf("Failed to setup file times - %s\n", nt_errstr(status));
     231             :         }
     232             : 
     233             :         /* make sure all the timestamps aren't the same */
     234           0 :         fileinfo.generic.level = RAW_FILEINFO_BASIC_INFO;
     235           0 :         fileinfo.generic.in.file.fnum = fnum;
     236             : 
     237           0 :         status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
     238           0 :         if (!NT_STATUS_IS_OK(status)) {
     239           0 :                 printf("Failed to query file times - %s\n", nt_errstr(status));
     240             :         }
     241             : 
     242           0 :         if (setfile.basic_info.in.create_time != fileinfo.basic_info.out.create_time) {
     243           0 :                 printf("create_time not setup correctly\n");
     244             :         }
     245           0 :         if (setfile.basic_info.in.access_time != fileinfo.basic_info.out.access_time) {
     246           0 :                 printf("access_time not setup correctly\n");
     247             :         }
     248           0 :         if (setfile.basic_info.in.write_time != fileinfo.basic_info.out.write_time) {
     249           0 :                 printf("write_time not setup correctly\n");
     250             :         }
     251             : 
     252           0 :         return fnum;
     253             : }
     254             : 
     255             : /**
     256             :   check that a wire string matches the flags specified 
     257             :   not 100% accurate, but close enough for testing
     258             : */
     259         189 : bool wire_bad_flags(struct smb_wire_string *str, int flags, 
     260             :                     struct smbcli_transport *transport)
     261             : {
     262           0 :         bool server_unicode;
     263           0 :         int len;
     264         189 :         if (!str || !str->s) return true;
     265         189 :         len = strlen(str->s);
     266         189 :         if (flags & STR_TERMINATE) len++;
     267             : 
     268         189 :         server_unicode = (transport->negotiate.capabilities&CAP_UNICODE)?true:false;
     269         189 :         if (getenv("CLI_FORCE_ASCII") || !transport->options.unicode) {
     270           0 :                 server_unicode = false;
     271             :         }
     272             : 
     273         189 :         if ((flags & STR_UNICODE) || server_unicode) {
     274         189 :                 len *= 2;
     275           0 :         } else if (flags & STR_TERMINATE_ASCII) {
     276           0 :                 len++;
     277             :         }
     278         189 :         if (str->private_length != len) {
     279           0 :                 printf("Expected wire_length %d but got %d for '%s'\n", 
     280             :                        len, str->private_length, str->s);
     281           0 :                 return true;
     282             :         }
     283         189 :         return false;
     284             : }
     285             : 
     286             : /*
     287             :   dump a all_info QFILEINFO structure
     288             : */
     289           5 : void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
     290             : {
     291           5 :         d_printf("\tcreate_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
     292           5 :         d_printf("\taccess_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
     293           5 :         d_printf("\twrite_time:     %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
     294           5 :         d_printf("\tchange_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
     295           5 :         d_printf("\tattrib:         0x%x\n", finfo->all_info.out.attrib);
     296           5 :         d_printf("\talloc_size:     %llu\n", (long long)finfo->all_info.out.alloc_size);
     297           5 :         d_printf("\tsize:           %llu\n", (long long)finfo->all_info.out.size);
     298           5 :         d_printf("\tnlink:          %u\n", finfo->all_info.out.nlink);
     299           5 :         d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
     300           5 :         d_printf("\tdirectory:      %u\n", finfo->all_info.out.directory);
     301           5 :         d_printf("\tea_size:        %u\n", finfo->all_info.out.ea_size);
     302           5 :         d_printf("\tfname:          '%s'\n", finfo->all_info.out.fname.s);
     303           5 : }
     304             : 
     305             : /*
     306             :   dump file info by name
     307             : */
     308           0 : void torture_all_info(struct smbcli_tree *tree, const char *fname)
     309             : {
     310           0 :         TALLOC_CTX *mem_ctx = talloc_named(tree, 0, "%s", fname);
     311           0 :         union smb_fileinfo finfo;
     312           0 :         NTSTATUS status;
     313             : 
     314           0 :         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
     315           0 :         finfo.generic.in.file.path = fname;
     316           0 :         status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
     317           0 :         if (!NT_STATUS_IS_OK(status)) {
     318           0 :                 d_printf("%s - %s\n", fname, nt_errstr(status));
     319           0 :                 return;
     320             :         }
     321             : 
     322           0 :         d_printf("%s:\n", fname);
     323           0 :         dump_all_info(mem_ctx, &finfo);
     324           0 :         talloc_free(mem_ctx);
     325             : }
     326             : 
     327             : 
     328             : /*
     329             :   set a attribute on a file
     330             : */
     331          74 : bool torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
     332             : {
     333           6 :         union smb_setfileinfo sfinfo;
     334           6 :         NTSTATUS status;
     335             : 
     336          74 :         ZERO_STRUCT(sfinfo.basic_info.in);
     337          74 :         sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
     338          74 :         sfinfo.basic_info.in.file.path = fname;
     339          74 :         sfinfo.basic_info.in.attrib = attrib;
     340          74 :         status = smb_raw_setpathinfo(tree, &sfinfo);
     341          74 :         return NT_STATUS_IS_OK(status);
     342             : }
     343             : 
     344             : 
     345             : /*
     346             :   set a file descriptor as sparse
     347             : */
     348          24 : NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
     349             : {
     350           4 :         union smb_ioctl nt;
     351           4 :         NTSTATUS status;
     352           4 :         TALLOC_CTX *mem_ctx;
     353             : 
     354          24 :         mem_ctx = talloc_named_const(tree, 0, "torture_set_sparse");
     355          24 :         if (!mem_ctx) {
     356           0 :                 return NT_STATUS_NO_MEMORY;
     357             :         }
     358             : 
     359          24 :         nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
     360          24 :         nt.ntioctl.in.function = FSCTL_SET_SPARSE;
     361          24 :         nt.ntioctl.in.file.fnum = fnum;
     362          24 :         nt.ntioctl.in.fsctl = true;
     363          24 :         nt.ntioctl.in.filter = 0;
     364          24 :         nt.ntioctl.in.max_data = 0;
     365          24 :         nt.ntioctl.in.blob = data_blob(NULL, 0);
     366             : 
     367          24 :         status = smb_raw_ioctl(tree, mem_ctx, &nt);
     368             : 
     369          24 :         talloc_free(mem_ctx);
     370             : 
     371          24 :         return status;
     372             : }
     373             : 
     374             : /*
     375             :   check that an EA has the right value 
     376             : */
     377         151 : NTSTATUS torture_check_ea(struct smbcli_state *cli, 
     378             :                           const char *fname, const char *eaname, const char *value)
     379             : {
     380          28 :         union smb_fileinfo info;
     381          28 :         NTSTATUS status;
     382          28 :         struct ea_name ea;
     383         151 :         TALLOC_CTX *mem_ctx = talloc_new(cli);
     384             : 
     385         151 :         info.ea_list.level = RAW_FILEINFO_EA_LIST;
     386         151 :         info.ea_list.in.file.path = fname;
     387         151 :         info.ea_list.in.num_names = 1;
     388         151 :         info.ea_list.in.ea_names = &ea;
     389             : 
     390         151 :         ea.name.s = eaname;
     391             : 
     392         151 :         status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
     393         151 :         if (!NT_STATUS_IS_OK(status)) {
     394           5 :                 talloc_free(mem_ctx);
     395           5 :                 return status;
     396             :         }
     397             : 
     398         146 :         if (info.ea_list.out.num_eas != 1) {
     399           0 :                 printf("Expected 1 ea in ea_list\n");
     400           0 :                 talloc_free(mem_ctx);
     401           0 :                 return NT_STATUS_EA_CORRUPT_ERROR;
     402             :         }
     403             : 
     404         146 :         if (strcasecmp_m(eaname, info.ea_list.out.eas[0].name.s) != 0) {
     405           0 :                 printf("Expected ea '%s' not '%s' in ea_list\n",
     406           0 :                        eaname, info.ea_list.out.eas[0].name.s);
     407           0 :                 talloc_free(mem_ctx);
     408           0 :                 return NT_STATUS_EA_CORRUPT_ERROR;
     409             :         }
     410             : 
     411         146 :         if (value == NULL) {
     412          45 :                 if (info.ea_list.out.eas[0].value.length != 0) {
     413           0 :                         printf("Expected zero length ea for %s\n", eaname);
     414           0 :                         talloc_free(mem_ctx);
     415           0 :                         return NT_STATUS_EA_CORRUPT_ERROR;
     416             :                 }
     417          45 :                 talloc_free(mem_ctx);
     418          45 :                 return NT_STATUS_OK;
     419             :         }
     420             : 
     421         101 :         if (strlen(value) == info.ea_list.out.eas[0].value.length &&
     422         101 :             memcmp(value, info.ea_list.out.eas[0].value.data,
     423          82 :                    info.ea_list.out.eas[0].value.length) == 0) {
     424         101 :                 talloc_free(mem_ctx);
     425         101 :                 return NT_STATUS_OK;
     426             :         }
     427             : 
     428           0 :         printf("Expected value '%s' not '%*.*s' for ea %s\n",
     429             :                value, 
     430           0 :                (int)info.ea_list.out.eas[0].value.length,
     431           0 :                (int)info.ea_list.out.eas[0].value.length,
     432           0 :                info.ea_list.out.eas[0].value.data,
     433             :                eaname);
     434             : 
     435           0 :         talloc_free(mem_ctx);
     436             : 
     437           0 :         return NT_STATUS_EA_CORRUPT_ERROR;
     438             : }
     439             : 
     440        2302 : _PUBLIC_ bool torture_open_connection_share(TALLOC_CTX *mem_ctx,
     441             :                                    struct smbcli_state **c, 
     442             :                                    struct torture_context *tctx,
     443             :                                    const char *hostname, 
     444             :                                    const char *sharename,
     445             :                                    struct tevent_context *ev)
     446             : {
     447         133 :         NTSTATUS status;
     448             : 
     449         133 :         struct smbcli_options options;
     450         133 :         struct smbcli_session_options session_options;
     451             : 
     452        2302 :         lpcfg_smbcli_options(tctx->lp_ctx, &options);
     453        2302 :         lpcfg_smbcli_session_options(tctx->lp_ctx, &session_options);
     454             : 
     455        2302 :         options.use_oplocks = torture_setting_bool(tctx, "use_oplocks", true);
     456        2302 :         options.use_level2_oplocks = torture_setting_bool(tctx, "use_level2_oplocks", true);
     457             : 
     458        2302 :         status = smbcli_full_connection(mem_ctx, c, hostname, 
     459             :                                         lpcfg_smb_ports(tctx->lp_ctx),
     460             :                                         sharename, NULL,
     461             :                                         lpcfg_socket_options(tctx->lp_ctx),
     462             :                                         samba_cmdline_get_creds(),
     463             :                                         lpcfg_resolve_context(tctx->lp_ctx),
     464             :                                         ev, &options, &session_options,
     465             :                                         lpcfg_gensec_settings(tctx, tctx->lp_ctx));
     466        2302 :         if (!NT_STATUS_IS_OK(status)) {
     467          80 :                 printf("Failed to open connection - %s\n", nt_errstr(status));
     468          80 :                 return false;
     469             :         }
     470             : 
     471        2097 :         return true;
     472             : }
     473             : 
     474        2266 : _PUBLIC_ bool torture_get_conn_index(int conn_index,
     475             :                                      TALLOC_CTX *mem_ctx,
     476             :                                      struct torture_context *tctx,
     477             :                                      char **host, char **share)
     478             : {
     479        2266 :         char **unc_list = NULL;
     480        2266 :         int num_unc_names = 0;
     481         129 :         const char *p;
     482             : 
     483        2266 :         (*host) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "host", NULL));
     484        2266 :         (*share) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "share", NULL));
     485             :         
     486        2266 :         p = torture_setting_string(tctx, "unclist", NULL);
     487        2266 :         if (!p) {
     488        2137 :                 return true;
     489             :         }
     490             : 
     491           0 :         unc_list = file_lines_load(p, &num_unc_names, 0, NULL);
     492           0 :         if (!unc_list || num_unc_names <= 0) {
     493           0 :                 DEBUG(0,("Failed to load unc names list from '%s'\n", p));
     494           0 :                 return false;
     495             :         }
     496             : 
     497           0 :         p = unc_list[conn_index % num_unc_names];
     498           0 :         if (p[0] != '/' && p[0] != '\\') {
     499             :                 /* allow UNC lists of hosts */
     500           0 :                 (*host) = talloc_strdup(mem_ctx, p);
     501           0 :         } else if (!smbcli_parse_unc(p, mem_ctx, host, share)) {
     502           0 :                 DEBUG(0, ("Failed to parse UNC name %s\n",
     503             :                           unc_list[conn_index % num_unc_names]));
     504           0 :                 return false;
     505             :         }
     506             : 
     507           0 :         talloc_free(unc_list);
     508           0 :         return true;
     509             : }
     510             : 
     511             : 
     512             : 
     513        2266 : _PUBLIC_ bool torture_open_connection_ev(struct smbcli_state **c,
     514             :                                          int conn_index,
     515             :                                          struct torture_context *tctx,
     516             :                                          struct tevent_context *ev)
     517             : {
     518         129 :         char *host, *share;
     519         129 :         bool ret;
     520             : 
     521        2266 :         if (!torture_get_conn_index(conn_index, ev, tctx, &host, &share)) {
     522           0 :                 return false;
     523             :         }
     524             : 
     525        2266 :         ret = torture_open_connection_share(NULL, c, tctx, host, share, ev);
     526        2266 :         talloc_free(host);
     527        2266 :         talloc_free(share);
     528             : 
     529        2266 :         return ret;
     530             : }
     531             : 
     532        2266 : _PUBLIC_ bool torture_open_connection(struct smbcli_state **c, struct torture_context *tctx, int conn_index)
     533             : {
     534        2266 :         return torture_open_connection_ev(c, conn_index, tctx, tctx->ev);
     535             : }
     536             : 
     537             : 
     538             : 
     539          62 : _PUBLIC_ bool torture_close_connection(struct smbcli_state *c)
     540             : {
     541          62 :         bool ret = true;
     542          62 :         if (!c) return true;
     543          62 :         if (NT_STATUS_IS_ERR(smbcli_tdis(c))) {
     544           0 :                 printf("tdis failed (%s)\n", smbcli_errstr(c->tree));
     545           0 :                 ret = false;
     546             :         }
     547          62 :         talloc_free(c);
     548          62 :         return ret;
     549             : }
     550             : 
     551             : 
     552             : /* check if the server produced the expected error code */
     553         324 : _PUBLIC_ bool check_error(const char *location, struct smbcli_state *c, 
     554             :                  uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
     555             : {
     556          38 :         NTSTATUS status;
     557             :         
     558         324 :         status = smbcli_nt_error(c->tree);
     559         324 :         if (NT_STATUS_IS_DOS(status)) {
     560           0 :                 int classnum, num;
     561           0 :                 classnum = NT_STATUS_DOS_CLASS(status);
     562           0 :                 num = NT_STATUS_DOS_CODE(status);
     563           0 :                 if (eclass != classnum || ecode != num) {
     564           0 :                         printf("unexpected error code %s\n", nt_errstr(status));
     565           0 :                         printf(" expected %s or %s (at %s)\n", 
     566           0 :                                nt_errstr(NT_STATUS_DOS(eclass, ecode)), 
     567             :                                nt_errstr(nterr), location);
     568           0 :                         return false;
     569             :                 }
     570             :         } else {
     571         324 :                 if (!NT_STATUS_EQUAL(nterr, status)) {
     572           2 :                         printf("unexpected error code %s\n", nt_errstr(status));
     573           2 :                         printf(" expected %s (at %s)\n", nt_errstr(nterr), location);
     574           2 :                         return false;
     575             :                 }
     576             :         }
     577             : 
     578         284 :         return true;
     579             : }
     580             : 
     581             : static struct smbcli_state *current_cli;
     582             : static int procnum; /* records process count number when forking */
     583             : 
     584          10 : static void sigcont(int sig)
     585             : {
     586          10 : }
     587             : 
     588             : struct child_status {
     589             :         pid_t pid;
     590             :         bool start;
     591             :         enum torture_result result;
     592             :         char reason[1024];
     593             : };
     594             : 
     595          10 : double torture_create_procs(struct torture_context *tctx,
     596             :         bool (*fn)(struct torture_context *, struct smbcli_state *, int),
     597             :         bool *result)
     598             : {
     599           0 :         int status;
     600           0 :         size_t i;
     601           0 :         struct child_status *child_status;
     602           0 :         size_t synccount;
     603          10 :         size_t tries = 8;
     604          10 :         size_t torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
     605          10 :         double start_time_limit = 10 + (torture_nprocs * 1.5);
     606           0 :         struct timeval tv;
     607             : 
     608          10 :         *result = true;
     609             : 
     610          10 :         synccount = 0;
     611             : 
     612          10 :         signal(SIGCONT, sigcont);
     613             : 
     614          10 :         child_status = (struct child_status *)anonymous_shared_allocate(
     615             :                                 sizeof(struct child_status)*torture_nprocs);
     616          10 :         if (child_status == NULL) {
     617           0 :                 printf("Failed to setup shared memory\n");
     618           0 :                 return -1;
     619             :         }
     620             : 
     621          50 :         for (i = 0; i < torture_nprocs; i++) {
     622          40 :                 ZERO_STRUCT(child_status[i]);
     623             :         }
     624             : 
     625          10 :         tv = timeval_current();
     626             : 
     627          50 :         for (i=0;i<torture_nprocs;i++) {
     628          40 :                 procnum = i;
     629          40 :                 if (fork() == 0) {
     630           0 :                         char *myname;
     631           0 :                         bool ok;
     632             : 
     633           0 :                         pid_t mypid = getpid();
     634           0 :                         srandom(((int)mypid) ^ ((int)time(NULL)));
     635             : 
     636           0 :                         if (asprintf(&myname, "CLIENT%zu", i) == -1) {
     637           0 :                                 printf("asprintf failed\n");
     638           0 :                                 return -1;
     639             :                         }
     640           0 :                         lpcfg_set_cmdline(tctx->lp_ctx, "netbios name", myname);
     641           0 :                         free(myname);
     642             : 
     643             : 
     644           0 :                         while (1) {
     645           0 :                                 if (torture_open_connection(&current_cli, tctx, i)) {
     646           0 :                                         break;
     647             :                                 }
     648           0 :                                 if (tries-- == 0) {
     649           0 :                                         printf("pid %d failed to start\n", (int)getpid());
     650           0 :                                         _exit(1);
     651             :                                 }
     652           0 :                                 smb_msleep(100);        
     653             :                         }
     654             : 
     655           0 :                         child_status[i].pid = getpid();
     656             : 
     657           0 :                         pause();
     658             : 
     659           0 :                         if (!child_status[i].start) {
     660           0 :                                 child_status[i].result = TORTURE_ERROR;
     661           0 :                                 printf("Child %zu failed to start!\n", i);
     662           0 :                                 _exit(1);
     663             :                         }
     664             : 
     665           0 :                         ok = fn(tctx, current_cli, i);
     666           0 :                         if (!ok) {
     667           0 :                                 if (tctx->last_result == TORTURE_OK) {
     668           0 :                                         torture_result(tctx, TORTURE_ERROR,
     669             :                                                 "unknown error: missing "
     670             :                                                 "torture_result call?\n");
     671             :                                 }
     672             : 
     673           0 :                                 child_status[i].result = tctx->last_result;
     674             : 
     675           0 :                                 if (strlen(tctx->last_reason) > 1023) {
     676             :                                         /* note: reason already contains \n */
     677           0 :                                         torture_comment(tctx,
     678             :                                                 "child %zu (pid %u) failed: %s",
     679             :                                                 i,
     680           0 :                                                 (unsigned)child_status[i].pid,
     681             :                                                 tctx->last_reason);
     682             :                                 }
     683             : 
     684           0 :                                 snprintf(child_status[i].reason,
     685             :                                          1024, "child %zu (pid %u) failed: %s",
     686           0 :                                          i, (unsigned)child_status[i].pid,
     687             :                                          tctx->last_reason);
     688             :                                 /* ensure proper "\n\0" termination: */
     689           0 :                                 if (child_status[i].reason[1022] != '\0') {
     690           0 :                                         child_status[i].reason[1022] = '\n';
     691           0 :                                         child_status[i].reason[1023] = '\0';
     692             :                                 }
     693             :                         }
     694           0 :                         _exit(0);
     695             :                 }
     696             :         }
     697             : 
     698           0 :         do {
     699          50 :                 synccount = 0;
     700         250 :                 for (i=0;i<torture_nprocs;i++) {
     701         200 :                         if (child_status[i].pid != 0) {
     702          52 :                                 synccount++;
     703             :                         }
     704             :                 }
     705          50 :                 if (synccount == torture_nprocs) {
     706          10 :                         break;
     707             :                 }
     708          40 :                 smb_msleep(100);
     709          40 :         } while (timeval_elapsed(&tv) < start_time_limit);
     710             : 
     711          10 :         if (synccount != torture_nprocs) {
     712           0 :                 printf("FAILED TO START %zu CLIENTS (started %zu)\n", torture_nprocs, synccount);
     713             : 
     714             :                 /* cleanup child processes */
     715           0 :                 for (i = 0; i < torture_nprocs; i++) {
     716           0 :                         if (child_status[i].pid != 0) {
     717           0 :                                 kill(child_status[i].pid, SIGTERM);
     718             :                         }
     719             :                 }
     720             : 
     721           0 :                 *result = false;
     722           0 :                 return timeval_elapsed(&tv);
     723             :         }
     724             : 
     725          10 :         printf("Starting %zu clients\n", torture_nprocs);
     726             : 
     727             :         /* start the client load */
     728          10 :         tv = timeval_current();
     729          50 :         for (i=0;i<torture_nprocs;i++) {
     730          40 :                 child_status[i].start = true;
     731             :         }
     732             : 
     733          10 :         printf("%zu clients started\n", torture_nprocs);
     734             : 
     735          10 :         kill(0, SIGCONT);
     736             : 
     737          50 :         for (i=0;i<torture_nprocs;i++) {
     738             :                 int ret;
     739          40 :                 while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
     740          40 :                 if (ret == -1 || WEXITSTATUS(status) != 0) {
     741           0 :                         *result = false;
     742             :                 }
     743             :         }
     744             : 
     745          10 :         printf("\n");
     746             : 
     747          50 :         for (i=0;i<torture_nprocs;i++) {
     748          40 :                 if (child_status[i].result != TORTURE_OK) {
     749           0 :                         *result = false;
     750           0 :                         torture_result(tctx, child_status[i].result,
     751           0 :                                        "%s", child_status[i].reason);
     752             :                 }
     753             :         }
     754             : 
     755          10 :         return timeval_elapsed(&tv);
     756             : }
     757             : 
     758          10 : static bool wrap_smb_multi_test(struct torture_context *torture,
     759             :                                                                 struct torture_tcase *tcase,
     760             :                                                                 struct torture_test *test)
     761             : {
     762          10 :         bool (*fn)(struct torture_context *, struct smbcli_state *, int ) = test->fn;
     763           0 :         bool result;
     764             : 
     765          10 :         torture_create_procs(torture, fn, &result);
     766             : 
     767          10 :         return result;
     768             : }
     769             : 
     770        7137 : _PUBLIC_ struct torture_test *torture_suite_add_smb_multi_test(
     771             :                                                                         struct torture_suite *suite,
     772             :                                                                         const char *name,
     773             :                                                                         bool (*run) (struct torture_context *,
     774             :                                                                                                  struct smbcli_state *,
     775             :                                                                                                 int i))
     776             : {
     777         375 :         struct torture_test *test; 
     778         375 :         struct torture_tcase *tcase;
     779             :         
     780        7137 :         tcase = torture_suite_add_tcase(suite, name);
     781             : 
     782        7137 :         test = talloc(tcase, struct torture_test);
     783             : 
     784        7137 :         test->name = talloc_strdup(test, name);
     785        7137 :         test->description = NULL;
     786        7137 :         test->run = wrap_smb_multi_test;
     787        7137 :         test->fn = run;
     788        7137 :         test->dangerous = false;
     789             : 
     790        7137 :         DLIST_ADD_END(tcase->tests, test);
     791             : 
     792        7137 :         return test;
     793             : 
     794             : }
     795             : 
     796         476 : static bool wrap_simple_2smb_test(struct torture_context *torture_ctx,
     797             :                                                                         struct torture_tcase *tcase,
     798             :                                                                         struct torture_test *test)
     799             : {
     800          36 :         bool (*fn) (struct torture_context *, struct smbcli_state *,
     801             :                                 struct smbcli_state *);
     802         476 :         bool ret = true;
     803             : 
     804         476 :         struct smbcli_state *cli1 = NULL, *cli2 = NULL;
     805             : 
     806         476 :         torture_assert_goto(torture_ctx, torture_open_connection(&cli1, torture_ctx, 0), ret, fail, "Failed to open connection");
     807         476 :         torture_assert_goto(torture_ctx, torture_open_connection(&cli2, torture_ctx, 1), ret, fail, "Failed to open connection");
     808             : 
     809         476 :         fn = test->fn;
     810             : 
     811         476 :         ret = fn(torture_ctx, cli1, cli2);
     812         476 : fail:
     813         476 :         talloc_free(cli1);
     814         476 :         talloc_free(cli2);
     815             : 
     816         476 :         return ret;
     817             : }
     818             : 
     819             : 
     820             : 
     821      252174 : _PUBLIC_ struct torture_test *torture_suite_add_2smb_test(
     822             :                                                                         struct torture_suite *suite,
     823             :                                                                         const char *name,
     824             :                                                                         bool (*run) (struct torture_context *,
     825             :                                                                                                 struct smbcli_state *,
     826             :                                                                                                 struct smbcli_state *))
     827             : {
     828       13250 :         struct torture_test *test; 
     829       13250 :         struct torture_tcase *tcase;
     830             :         
     831      252174 :         tcase = torture_suite_add_tcase(suite, name);
     832             : 
     833      252174 :         test = talloc(tcase, struct torture_test);
     834             : 
     835      252174 :         test->name = talloc_strdup(test, name);
     836      252174 :         test->description = NULL;
     837      252174 :         test->run = wrap_simple_2smb_test;
     838      252174 :         test->fn = run;
     839      252174 :         test->dangerous = false;
     840             : 
     841      252174 :         DLIST_ADD_END(tcase->tests, test);
     842             : 
     843      252174 :         return test;
     844             : 
     845             : }
     846             : 
     847        1119 : static bool wrap_simple_1smb_test(struct torture_context *torture_ctx,
     848             :                                                                         struct torture_tcase *tcase,
     849             :                                                                         struct torture_test *test)
     850             : {
     851          52 :         bool (*fn) (struct torture_context *, struct smbcli_state *);
     852        1119 :         bool ret = true;
     853             : 
     854        1119 :         struct smbcli_state *cli1 = NULL;
     855             : 
     856        1119 :         torture_assert_goto(torture_ctx, torture_open_connection(&cli1, torture_ctx, 0), ret, fail, "Failed to open connection");
     857             : 
     858        1039 :         fn = test->fn;
     859             : 
     860        1039 :         ret = fn(torture_ctx, cli1);
     861        1119 : fail:
     862        1119 :         talloc_free(cli1);
     863             : 
     864        1119 :         return ret;
     865             : }
     866             : 
     867      516243 : _PUBLIC_ struct torture_test *torture_suite_add_1smb_test(
     868             :                                 struct torture_suite *suite,
     869             :                                 const char *name,
     870             :                                 bool (*run) (struct torture_context *, struct smbcli_state *))
     871             : {
     872       27125 :         struct torture_test *test; 
     873       27125 :         struct torture_tcase *tcase;
     874             :         
     875      516243 :         tcase = torture_suite_add_tcase(suite, name);
     876             : 
     877      516243 :         test = talloc(tcase, struct torture_test);
     878             : 
     879      516243 :         test->name = talloc_strdup(test, name);
     880      516243 :         test->description = NULL;
     881      516243 :         test->run = wrap_simple_1smb_test;
     882      516243 :         test->fn = run;
     883      516243 :         test->dangerous = false;
     884             : 
     885      516243 :         DLIST_ADD_END(tcase->tests, test);
     886             : 
     887      516243 :         return test;
     888             : }
     889             : 
     890             : 
     891          14 : NTSTATUS torture_second_tcon(TALLOC_CTX *mem_ctx,
     892             :                              struct smbcli_session *session,
     893             :                              const char *sharename,
     894             :                              struct smbcli_tree **res)
     895             : {
     896           0 :         union smb_tcon tcon;
     897           0 :         struct smbcli_tree *result;
     898           0 :         TALLOC_CTX *tmp_ctx;
     899           0 :         NTSTATUS status;
     900             : 
     901          14 :         if ((tmp_ctx = talloc_new(mem_ctx)) == NULL) {
     902           0 :                 return NT_STATUS_NO_MEMORY;
     903             :         }
     904             : 
     905          14 :         result = smbcli_tree_init(session, tmp_ctx, false);
     906          14 :         if (result == NULL) {
     907           0 :                 talloc_free(tmp_ctx);
     908           0 :                 return NT_STATUS_NO_MEMORY;
     909             :         }
     910             : 
     911          14 :         tcon.generic.level = RAW_TCON_TCONX;
     912          14 :         tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
     913          14 :         tcon.tconx.in.flags |= TCONX_FLAG_EXTENDED_SIGNATURES;
     914             : 
     915             :         /* Ignore share mode security here */
     916          14 :         tcon.tconx.in.password = data_blob(NULL, 0);
     917          14 :         tcon.tconx.in.path = sharename;
     918          14 :         tcon.tconx.in.device = "?????";
     919             : 
     920          14 :         status = smb_raw_tcon(result, tmp_ctx, &tcon);
     921          14 :         if (!NT_STATUS_IS_OK(status)) {
     922           2 :                 talloc_free(tmp_ctx);
     923           2 :                 return status;
     924             :         }
     925             : 
     926          12 :         result->tid = tcon.tconx.out.tid;
     927             : 
     928          12 :         if (tcon.tconx.out.options & SMB_EXTENDED_SIGNATURES) {
     929           0 :                 smb1cli_session_protect_session_key(result->session->smbXcli);
     930             :         }
     931             : 
     932          12 :         *res = talloc_steal(mem_ctx, result);
     933          12 :         talloc_free(tmp_ctx);
     934          12 :         return NT_STATUS_OK;
     935             : }
     936             : 
     937             : /* 
     938             :    a wrapper around smblsa_sid_check_privilege, that tries to take
     939             :    account of the fact that the lsa privileges calls don't expand
     940             :    group memberships, using an explicit check for administrator. There
     941             :    must be a better way ...
     942             :  */
     943         120 : NTSTATUS torture_check_privilege(struct smbcli_state *cli, 
     944             :                                  const char *sid_str,
     945             :                                  const char *privilege)
     946             : {
     947           0 :         struct dom_sid *sid;
     948         120 :         TALLOC_CTX *tmp_ctx = talloc_new(cli);
     949           0 :         uint32_t rid;
     950           0 :         NTSTATUS status;
     951             : 
     952         120 :         sid = dom_sid_parse_talloc(tmp_ctx, sid_str);
     953         120 :         if (sid == NULL) {
     954           0 :                 talloc_free(tmp_ctx);
     955           0 :                 return NT_STATUS_INVALID_SID;
     956             :         }
     957             : 
     958         120 :         status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
     959         120 :         if (!NT_STATUS_IS_OK(status)) {
     960           0 :                 TALLOC_FREE(tmp_ctx);
     961           0 :                 return status;
     962             :         }
     963             : 
     964         120 :         if (rid == DOMAIN_RID_ADMINISTRATOR) {
     965             :                 /* assume the administrator has them all */
     966          12 :                 return NT_STATUS_OK;
     967             :         }
     968             : 
     969         108 :         talloc_free(tmp_ctx);
     970             : 
     971         108 :         return smblsa_sid_check_privilege(cli, sid_str, privilege);
     972             : }
     973             : 
     974             : /*
     975             :  * Use this to pass a 2nd user:
     976             :  *
     977             :  * --option='torture:user2name=user2'
     978             :  * --option='torture:user2domain=domain2'
     979             :  * --option='torture:user2password=password2'
     980             :  */
     981          12 : struct cli_credentials *torture_user2_credentials(struct torture_context *tctx,
     982             :                                                   TALLOC_CTX *mem_ctx)
     983             : {
     984          12 :         struct cli_credentials *credentials1 = samba_cmdline_get_creds();
     985          12 :         const char *user1domain = cli_credentials_get_domain(credentials1);
     986          12 :         const char *user2name = torture_setting_string(tctx, "user2name", NULL);
     987          12 :         const char *user2domain = torture_setting_string(tctx, "user2domain", user1domain);
     988          12 :         const char *user2password = torture_setting_string(tctx, "user2password", NULL);
     989          12 :         struct cli_credentials *credentials2 = NULL;
     990             : 
     991          12 :         credentials2 = cli_credentials_shallow_copy(mem_ctx, credentials1);
     992          12 :         if (credentials2 == NULL) {
     993           0 :                 torture_comment(tctx,
     994             :                                 "%s: cli_credentials_shallow_copy() failed\n",
     995             :                                 __func__);
     996           0 :                 return NULL;
     997             :         }
     998          12 :         if (user2name != NULL) {
     999           6 :                 torture_comment(tctx,
    1000             :                                 "Using "
    1001             :                                 "'torture:user2name'='%s' "
    1002             :                                 "'torture:user2domain'='%s' "
    1003             :                                 "'torture:user2password'='REDACTED'",
    1004             :                                 user2name,
    1005             :                                 user2domain);
    1006           6 :                 cli_credentials_set_username(credentials2, user2name, CRED_SPECIFIED);
    1007           6 :                 cli_credentials_set_domain(credentials2, user2domain, CRED_SPECIFIED);
    1008           6 :                 cli_credentials_set_password(credentials2, user2password, CRED_SPECIFIED);
    1009             :         } else {
    1010           6 :                 torture_comment(tctx,
    1011             :                                 "Fallback to anonymous for "
    1012             :                                 "'torture:user2name'=NULL "
    1013             :                                 "'torture:user2domain'='%s' "
    1014             :                                 "'torture:user2password'='REDACTED'",
    1015             :                                 user2domain);
    1016           6 :                 cli_credentials_set_anonymous(credentials2);
    1017             :         }
    1018             : 
    1019          10 :         return credentials2;
    1020             : }

Generated by: LCOV version 1.14