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(¤t_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 51 : 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 7074 : _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 7074 : tcase = torture_suite_add_tcase(suite, name);
781 :
782 7074 : test = talloc(tcase, struct torture_test);
783 :
784 7074 : test->name = talloc_strdup(test, name);
785 7074 : test->description = NULL;
786 7074 : test->run = wrap_smb_multi_test;
787 7074 : test->fn = run;
788 7074 : test->dangerous = false;
789 :
790 7074 : DLIST_ADD_END(tcase->tests, test);
791 :
792 7074 : 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 249948 : _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 249948 : tcase = torture_suite_add_tcase(suite, name);
832 :
833 249948 : test = talloc(tcase, struct torture_test);
834 :
835 249948 : test->name = talloc_strdup(test, name);
836 249948 : test->description = NULL;
837 249948 : test->run = wrap_simple_2smb_test;
838 249948 : test->fn = run;
839 249948 : test->dangerous = false;
840 :
841 249948 : DLIST_ADD_END(tcase->tests, test);
842 :
843 249948 : 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 511686 : _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 511686 : tcase = torture_suite_add_tcase(suite, name);
876 :
877 511686 : test = talloc(tcase, struct torture_test);
878 :
879 511686 : test->name = talloc_strdup(test, name);
880 511686 : test->description = NULL;
881 511686 : test->run = wrap_simple_1smb_test;
882 511686 : test->fn = run;
883 511686 : test->dangerous = false;
884 :
885 511686 : DLIST_ADD_END(tcase->tests, test);
886 :
887 511686 : 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 : }
|