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

Generated by: LCOV version 1.14