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 193 : _PUBLIC_ bool torture_setup_dir(struct smbcli_state *cli, const char *dname)
47 : {
48 193 : smb_raw_exit(cli->session);
49 386 : if (smbcli_deltree(cli->tree, dname) == -1 ||
50 193 : 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 193 : return true;
55 : }
56 :
57 : /*
58 : create a directory, returning a handle to it
59 : */
60 10 : NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, int *fnum)
61 : {
62 : NTSTATUS status;
63 : union smb_open io;
64 : TALLOC_CTX *mem_ctx;
65 :
66 10 : mem_ctx = talloc_named_const(tree, 0, "create_directory_handle");
67 :
68 10 : io.generic.level = RAW_OPEN_NTCREATEX;
69 10 : io.ntcreatex.in.root_fid.fnum = 0;
70 10 : io.ntcreatex.in.flags = 0;
71 10 : io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
72 10 : io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
73 10 : io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
74 10 : io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
75 10 : io.ntcreatex.in.alloc_size = 0;
76 10 : io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
77 10 : io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
78 10 : io.ntcreatex.in.security_flags = 0;
79 10 : io.ntcreatex.in.fname = dname;
80 :
81 10 : status = smb_raw_open(tree, mem_ctx, &io);
82 10 : talloc_free(mem_ctx);
83 :
84 10 : if (NT_STATUS_IS_OK(status)) {
85 10 : *fnum = io.ntcreatex.out.file.fnum;
86 : }
87 :
88 10 : 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 279 : _PUBLIC_ int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname)
97 : {
98 : int fnum;
99 279 : char buf[7] = "abc";
100 : union smb_setfileinfo setfile;
101 : union smb_fileinfo fileinfo;
102 279 : time_t t = (time(NULL) & ~1);
103 : NTSTATUS status;
104 :
105 279 : smbcli_unlink(cli->tree, fname);
106 279 : 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 279 : if (fnum == -1) return -1;
115 :
116 279 : smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
117 :
118 279 : if (strchr(fname, ':') == NULL) {
119 : /* setup some EAs */
120 279 : setfile.generic.level = RAW_SFILEINFO_EA_SET;
121 279 : setfile.generic.in.file.fnum = fnum;
122 279 : setfile.ea_set.in.num_eas = 2;
123 279 : setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
124 279 : setfile.ea_set.in.eas[0].flags = 0;
125 279 : setfile.ea_set.in.eas[0].name.s = "EAONE";
126 279 : setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
127 279 : setfile.ea_set.in.eas[1].flags = 0;
128 279 : setfile.ea_set.in.eas[1].name.s = "SECONDEA";
129 279 : setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
130 279 : status = smb_raw_setfileinfo(cli->tree, &setfile);
131 279 : 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 279 : ZERO_STRUCT(setfile);
138 279 : setfile.generic.level = RAW_SFILEINFO_BASIC_INFO;
139 279 : setfile.generic.in.file.fnum = fnum;
140 :
141 279 : unix_to_nt_time(&setfile.basic_info.in.create_time,
142 : t + 9*30*24*60*60);
143 279 : unix_to_nt_time(&setfile.basic_info.in.access_time,
144 : t + 6*30*24*60*60);
145 279 : unix_to_nt_time(&setfile.basic_info.in.write_time,
146 : t + 3*30*24*60*60);
147 :
148 279 : status = smb_raw_setfileinfo(cli->tree, &setfile);
149 279 : 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 279 : fileinfo.generic.level = RAW_FILEINFO_BASIC_INFO;
155 279 : fileinfo.generic.in.file.fnum = fnum;
156 :
157 279 : status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
158 279 : if (!NT_STATUS_IS_OK(status)) {
159 0 : printf("Failed to query file times - %s\n", nt_errstr(status));
160 : }
161 :
162 279 : if (setfile.basic_info.in.create_time != fileinfo.basic_info.out.create_time) {
163 0 : printf("create_time not setup correctly\n");
164 : }
165 279 : if (setfile.basic_info.in.access_time != fileinfo.basic_info.out.access_time) {
166 0 : printf("access_time not setup correctly\n");
167 : }
168 279 : 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 279 : 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 : int fnum;
183 : union smb_setfileinfo setfile;
184 : union smb_fileinfo fileinfo;
185 0 : time_t t = (time(NULL) & ~1);
186 : 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 65 : bool wire_bad_flags(struct smb_wire_string *str, int flags,
260 : struct smbcli_transport *transport)
261 : {
262 : bool server_unicode;
263 : int len;
264 65 : if (!str || !str->s) return true;
265 65 : len = strlen(str->s);
266 65 : if (flags & STR_TERMINATE) len++;
267 :
268 65 : server_unicode = (transport->negotiate.capabilities&CAP_UNICODE)?true:false;
269 65 : if (getenv("CLI_FORCE_ASCII") || !transport->options.unicode) {
270 0 : server_unicode = false;
271 : }
272 :
273 65 : if ((flags & STR_UNICODE) || server_unicode) {
274 65 : len *= 2;
275 0 : } else if (flags & STR_TERMINATE_ASCII) {
276 0 : len++;
277 : }
278 65 : 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 65 : return false;
284 : }
285 :
286 : /*
287 : dump a all_info QFILEINFO structure
288 : */
289 0 : void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
290 : {
291 0 : d_printf("\tcreate_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
292 0 : d_printf("\taccess_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
293 0 : d_printf("\twrite_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
294 0 : d_printf("\tchange_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
295 0 : d_printf("\tattrib: 0x%x\n", finfo->all_info.out.attrib);
296 0 : d_printf("\talloc_size: %llu\n", (long long)finfo->all_info.out.alloc_size);
297 0 : d_printf("\tsize: %llu\n", (long long)finfo->all_info.out.size);
298 0 : d_printf("\tnlink: %u\n", finfo->all_info.out.nlink);
299 0 : d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
300 0 : d_printf("\tdirectory: %u\n", finfo->all_info.out.directory);
301 0 : d_printf("\tea_size: %u\n", finfo->all_info.out.ea_size);
302 0 : d_printf("\tfname: '%s'\n", finfo->all_info.out.fname.s);
303 0 : }
304 :
305 : /*
306 : dump file infor 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 : union smb_fileinfo finfo;
312 : 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 12 : bool torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
332 : {
333 : union smb_setfileinfo sfinfo;
334 : NTSTATUS status;
335 :
336 12 : ZERO_STRUCT(sfinfo.basic_info.in);
337 12 : sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
338 12 : sfinfo.basic_info.in.file.path = fname;
339 12 : sfinfo.basic_info.in.attrib = attrib;
340 12 : status = smb_raw_setpathinfo(tree, &sfinfo);
341 12 : return NT_STATUS_IS_OK(status);
342 : }
343 :
344 :
345 : /*
346 : set a file descriptor as sparse
347 : */
348 4 : NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
349 : {
350 : union smb_ioctl nt;
351 : NTSTATUS status;
352 : TALLOC_CTX *mem_ctx;
353 :
354 4 : mem_ctx = talloc_named_const(tree, 0, "torture_set_sparse");
355 4 : if (!mem_ctx) {
356 0 : return NT_STATUS_NO_MEMORY;
357 : }
358 :
359 4 : nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
360 4 : nt.ntioctl.in.function = FSCTL_SET_SPARSE;
361 4 : nt.ntioctl.in.file.fnum = fnum;
362 4 : nt.ntioctl.in.fsctl = true;
363 4 : nt.ntioctl.in.filter = 0;
364 4 : nt.ntioctl.in.max_data = 0;
365 4 : nt.ntioctl.in.blob = data_blob(NULL, 0);
366 :
367 4 : status = smb_raw_ioctl(tree, mem_ctx, &nt);
368 :
369 4 : talloc_free(mem_ctx);
370 :
371 4 : return status;
372 : }
373 :
374 : /*
375 : check that an EA has the right value
376 : */
377 7 : NTSTATUS torture_check_ea(struct smbcli_state *cli,
378 : const char *fname, const char *eaname, const char *value)
379 : {
380 : union smb_fileinfo info;
381 : NTSTATUS status;
382 : struct ea_name ea;
383 7 : TALLOC_CTX *mem_ctx = talloc_new(cli);
384 :
385 7 : info.ea_list.level = RAW_FILEINFO_EA_LIST;
386 7 : info.ea_list.in.file.path = fname;
387 7 : info.ea_list.in.num_names = 1;
388 7 : info.ea_list.in.ea_names = &ea;
389 :
390 7 : ea.name.s = eaname;
391 :
392 7 : status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
393 7 : if (!NT_STATUS_IS_OK(status)) {
394 1 : talloc_free(mem_ctx);
395 1 : return status;
396 : }
397 :
398 6 : 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 6 : 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 6 : if (value == NULL) {
412 0 : 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 0 : talloc_free(mem_ctx);
418 0 : return NT_STATUS_OK;
419 : }
420 :
421 12 : if (strlen(value) == info.ea_list.out.eas[0].value.length &&
422 6 : memcmp(value, info.ea_list.out.eas[0].value.data,
423 6 : info.ea_list.out.eas[0].value.length) == 0) {
424 6 : talloc_free(mem_ctx);
425 6 : 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 573 : _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 : NTSTATUS status;
448 :
449 : struct smbcli_options options;
450 : struct smbcli_session_options session_options;
451 :
452 573 : lpcfg_smbcli_options(tctx->lp_ctx, &options);
453 573 : lpcfg_smbcli_session_options(tctx->lp_ctx, &session_options);
454 :
455 573 : options.use_oplocks = torture_setting_bool(tctx, "use_oplocks", true);
456 573 : options.use_level2_oplocks = torture_setting_bool(tctx, "use_level2_oplocks", true);
457 :
458 573 : 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 565 : if (!NT_STATUS_IS_OK(status)) {
467 8 : printf("Failed to open connection - %s\n", nt_errstr(status));
468 8 : return false;
469 : }
470 :
471 557 : return true;
472 : }
473 :
474 569 : _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 569 : char **unc_list = NULL;
480 569 : int num_unc_names = 0;
481 : const char *p;
482 :
483 569 : (*host) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "host", NULL));
484 569 : (*share) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "share", NULL));
485 :
486 569 : p = torture_setting_string(tctx, "unclist", NULL);
487 569 : if (!p) {
488 569 : 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 569 : _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 : char *host, *share;
519 : bool ret;
520 :
521 569 : if (!torture_get_conn_index(conn_index, ev, tctx, &host, &share)) {
522 0 : return false;
523 : }
524 :
525 569 : ret = torture_open_connection_share(NULL, c, tctx, host, share, ev);
526 561 : talloc_free(host);
527 561 : talloc_free(share);
528 :
529 561 : return ret;
530 : }
531 :
532 569 : _PUBLIC_ bool torture_open_connection(struct smbcli_state **c, struct torture_context *tctx, int conn_index)
533 : {
534 569 : return torture_open_connection_ev(c, conn_index, tctx, tctx->ev);
535 : }
536 :
537 :
538 :
539 11 : _PUBLIC_ bool torture_close_connection(struct smbcli_state *c)
540 : {
541 11 : bool ret = true;
542 11 : if (!c) return true;
543 11 : 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 11 : talloc_free(c);
548 11 : return ret;
549 : }
550 :
551 :
552 : /* check if the server produced the expected error code */
553 108 : _PUBLIC_ bool check_error(const char *location, struct smbcli_state *c,
554 : uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
555 : {
556 : NTSTATUS status;
557 :
558 108 : status = smbcli_nt_error(c->tree);
559 108 : if (NT_STATUS_IS_DOS(status)) {
560 : 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 108 : 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 106 : return true;
579 : }
580 :
581 : static struct smbcli_state *current_cli;
582 : static int procnum; /* records process count number when forking */
583 :
584 2 : static void sigcont(int sig)
585 : {
586 2 : }
587 :
588 : struct child_status {
589 : pid_t pid;
590 : bool start;
591 : enum torture_result result;
592 : char reason[1024];
593 : };
594 :
595 2 : double torture_create_procs(struct torture_context *tctx,
596 : bool (*fn)(struct torture_context *, struct smbcli_state *, int),
597 : bool *result)
598 : {
599 : int status;
600 : size_t i;
601 : struct child_status *child_status;
602 : size_t synccount;
603 2 : size_t tries = 8;
604 2 : size_t torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
605 2 : double start_time_limit = 10 + (torture_nprocs * 1.5);
606 : struct timeval tv;
607 :
608 2 : *result = true;
609 :
610 2 : synccount = 0;
611 :
612 2 : signal(SIGCONT, sigcont);
613 :
614 2 : child_status = (struct child_status *)anonymous_shared_allocate(
615 : sizeof(struct child_status)*torture_nprocs);
616 2 : if (child_status == NULL) {
617 0 : printf("Failed to setup shared memory\n");
618 0 : return -1;
619 : }
620 :
621 10 : for (i = 0; i < torture_nprocs; i++) {
622 8 : ZERO_STRUCT(child_status[i]);
623 : }
624 :
625 2 : tv = timeval_current();
626 :
627 10 : for (i=0;i<torture_nprocs;i++) {
628 8 : procnum = i;
629 8 : if (fork() == 0) {
630 : char *myname;
631 : bool ok;
632 :
633 8 : pid_t mypid = getpid();
634 8 : srandom(((int)mypid) ^ ((int)time(NULL)));
635 :
636 8 : if (asprintf(&myname, "CLIENT%zu", i) == -1) {
637 0 : printf("asprintf failed\n");
638 0 : return -1;
639 : }
640 8 : lpcfg_set_cmdline(tctx->lp_ctx, "netbios name", myname);
641 8 : free(myname);
642 :
643 :
644 : while (1) {
645 8 : 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 : do {
699 15 : synccount = 0;
700 75 : for (i=0;i<torture_nprocs;i++) {
701 60 : if (child_status[i].pid != 0) {
702 14 : synccount++;
703 : }
704 : }
705 15 : if (synccount == torture_nprocs) {
706 2 : break;
707 : }
708 13 : smb_msleep(100);
709 13 : } while (timeval_elapsed(&tv) < start_time_limit);
710 :
711 2 : 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 2 : printf("Starting %zu clients\n", torture_nprocs);
726 :
727 : /* start the client load */
728 2 : tv = timeval_current();
729 10 : for (i=0;i<torture_nprocs;i++) {
730 8 : child_status[i].start = true;
731 : }
732 :
733 2 : printf("%zu clients started\n", torture_nprocs);
734 :
735 2 : kill(0, SIGCONT);
736 :
737 10 : for (i=0;i<torture_nprocs;i++) {
738 : int ret;
739 8 : while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
740 8 : if (ret == -1 || WEXITSTATUS(status) != 0) {
741 0 : *result = false;
742 : }
743 : }
744 :
745 2 : printf("\n");
746 :
747 10 : for (i=0;i<torture_nprocs;i++) {
748 8 : 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 2 : return timeval_elapsed(&tv);
756 : }
757 :
758 2 : static bool wrap_smb_multi_test(struct torture_context *torture,
759 : struct torture_tcase *tcase,
760 : struct torture_test *test)
761 : {
762 2 : bool (*fn)(struct torture_context *, struct smbcli_state *, int ) = test->fn;
763 : bool result;
764 :
765 2 : torture_create_procs(torture, fn, &result);
766 :
767 2 : return result;
768 : }
769 :
770 2892 : _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 : struct torture_test *test;
778 : struct torture_tcase *tcase;
779 :
780 2892 : tcase = torture_suite_add_tcase(suite, name);
781 :
782 2892 : test = talloc(tcase, struct torture_test);
783 :
784 2892 : test->name = talloc_strdup(test, name);
785 2892 : test->description = NULL;
786 2892 : test->run = wrap_smb_multi_test;
787 2892 : test->fn = run;
788 2892 : test->dangerous = false;
789 :
790 2892 : DLIST_ADD_END(tcase->tests, test);
791 :
792 2892 : return test;
793 :
794 : }
795 :
796 142 : static bool wrap_simple_2smb_test(struct torture_context *torture_ctx,
797 : struct torture_tcase *tcase,
798 : struct torture_test *test)
799 : {
800 : bool (*fn) (struct torture_context *, struct smbcli_state *,
801 : struct smbcli_state *);
802 142 : bool ret = true;
803 :
804 142 : struct smbcli_state *cli1 = NULL, *cli2 = NULL;
805 :
806 142 : torture_assert_goto(torture_ctx, torture_open_connection(&cli1, torture_ctx, 0), ret, fail, "Failed to open connection");
807 142 : torture_assert_goto(torture_ctx, torture_open_connection(&cli2, torture_ctx, 1), ret, fail, "Failed to open connection");
808 :
809 142 : fn = test->fn;
810 :
811 142 : ret = fn(torture_ctx, cli1, cli2);
812 142 : fail:
813 142 : talloc_free(cli1);
814 142 : talloc_free(cli2);
815 :
816 142 : return ret;
817 : }
818 :
819 :
820 :
821 102184 : _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 : struct torture_test *test;
829 : struct torture_tcase *tcase;
830 :
831 102184 : tcase = torture_suite_add_tcase(suite, name);
832 :
833 102184 : test = talloc(tcase, struct torture_test);
834 :
835 102184 : test->name = talloc_strdup(test, name);
836 102184 : test->description = NULL;
837 102184 : test->run = wrap_simple_2smb_test;
838 102184 : test->fn = run;
839 102184 : test->dangerous = false;
840 :
841 102184 : DLIST_ADD_END(tcase->tests, test);
842 :
843 102184 : return test;
844 :
845 : }
846 :
847 219 : static bool wrap_simple_1smb_test(struct torture_context *torture_ctx,
848 : struct torture_tcase *tcase,
849 : struct torture_test *test)
850 : {
851 : bool (*fn) (struct torture_context *, struct smbcli_state *);
852 219 : bool ret = true;
853 :
854 219 : struct smbcli_state *cli1 = NULL;
855 :
856 219 : torture_assert_goto(torture_ctx, torture_open_connection(&cli1, torture_ctx, 0), ret, fail, "Failed to open connection");
857 :
858 211 : fn = test->fn;
859 :
860 211 : ret = fn(torture_ctx, cli1);
861 219 : fail:
862 219 : talloc_free(cli1);
863 :
864 219 : return ret;
865 : }
866 :
867 208224 : _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 : struct torture_test *test;
873 : struct torture_tcase *tcase;
874 :
875 208224 : tcase = torture_suite_add_tcase(suite, name);
876 :
877 208224 : test = talloc(tcase, struct torture_test);
878 :
879 208224 : test->name = talloc_strdup(test, name);
880 208224 : test->description = NULL;
881 208224 : test->run = wrap_simple_1smb_test;
882 208224 : test->fn = run;
883 208224 : test->dangerous = false;
884 :
885 208224 : DLIST_ADD_END(tcase->tests, test);
886 :
887 208224 : return test;
888 : }
889 :
890 :
891 0 : NTSTATUS torture_second_tcon(TALLOC_CTX *mem_ctx,
892 : struct smbcli_session *session,
893 : const char *sharename,
894 : struct smbcli_tree **res)
895 : {
896 : union smb_tcon tcon;
897 : struct smbcli_tree *result;
898 : TALLOC_CTX *tmp_ctx;
899 : NTSTATUS status;
900 :
901 0 : if ((tmp_ctx = talloc_new(mem_ctx)) == NULL) {
902 0 : return NT_STATUS_NO_MEMORY;
903 : }
904 :
905 0 : result = smbcli_tree_init(session, tmp_ctx, false);
906 0 : if (result == NULL) {
907 0 : talloc_free(tmp_ctx);
908 0 : return NT_STATUS_NO_MEMORY;
909 : }
910 :
911 0 : tcon.generic.level = RAW_TCON_TCONX;
912 0 : tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
913 0 : tcon.tconx.in.flags |= TCONX_FLAG_EXTENDED_SIGNATURES;
914 :
915 : /* Ignore share mode security here */
916 0 : tcon.tconx.in.password = data_blob(NULL, 0);
917 0 : tcon.tconx.in.path = sharename;
918 0 : tcon.tconx.in.device = "?????";
919 :
920 0 : status = smb_raw_tcon(result, tmp_ctx, &tcon);
921 0 : if (!NT_STATUS_IS_OK(status)) {
922 0 : talloc_free(tmp_ctx);
923 0 : return status;
924 : }
925 :
926 0 : result->tid = tcon.tconx.out.tid;
927 :
928 0 : if (tcon.tconx.out.options & SMB_EXTENDED_SIGNATURES) {
929 0 : smb1cli_session_protect_session_key(result->session->smbXcli);
930 : }
931 :
932 0 : *res = talloc_steal(mem_ctx, result);
933 0 : talloc_free(tmp_ctx);
934 0 : 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 12 : NTSTATUS torture_check_privilege(struct smbcli_state *cli,
944 : const char *sid_str,
945 : const char *privilege)
946 : {
947 : struct dom_sid *sid;
948 12 : TALLOC_CTX *tmp_ctx = talloc_new(cli);
949 : uint32_t rid;
950 : NTSTATUS status;
951 :
952 12 : sid = dom_sid_parse_talloc(tmp_ctx, sid_str);
953 12 : if (sid == NULL) {
954 0 : talloc_free(tmp_ctx);
955 0 : return NT_STATUS_INVALID_SID;
956 : }
957 :
958 12 : status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
959 12 : if (!NT_STATUS_IS_OK(status)) {
960 0 : TALLOC_FREE(tmp_ctx);
961 0 : return status;
962 : }
963 :
964 12 : if (rid == DOMAIN_RID_ADMINISTRATOR) {
965 : /* assume the administrator has them all */
966 12 : return NT_STATUS_OK;
967 : }
968 :
969 0 : talloc_free(tmp_ctx);
970 :
971 0 : 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 2 : struct cli_credentials *torture_user2_credentials(struct torture_context *tctx,
982 : TALLOC_CTX *mem_ctx)
983 : {
984 2 : struct cli_credentials *credentials1 = samba_cmdline_get_creds();
985 2 : const char *user1domain = cli_credentials_get_domain(credentials1);
986 2 : const char *user2name = torture_setting_string(tctx, "user2name", NULL);
987 2 : const char *user2domain = torture_setting_string(tctx, "user2domain", user1domain);
988 2 : const char *user2password = torture_setting_string(tctx, "user2password", NULL);
989 2 : struct cli_credentials *credentials2 = NULL;
990 :
991 2 : credentials2 = cli_credentials_shallow_copy(mem_ctx, credentials1);
992 2 : if (credentials2 == NULL) {
993 0 : torture_comment(tctx,
994 : "%s: cli_credentials_shallow_copy() failed\n",
995 : __func__);
996 0 : return NULL;
997 : }
998 2 : if (user2name != NULL) {
999 0 : torture_comment(tctx,
1000 : "Using "
1001 : "'torture:user2name'='%s' "
1002 : "'torture:user2domain'='%s' "
1003 : "'torture:user2password'='REDACTED'",
1004 : user2name,
1005 : user2domain);
1006 0 : cli_credentials_set_username(credentials2, user2name, CRED_SPECIFIED);
1007 0 : cli_credentials_set_domain(credentials2, user2domain, CRED_SPECIFIED);
1008 0 : cli_credentials_set_password(credentials2, user2password, CRED_SPECIFIED);
1009 : } else {
1010 2 : torture_comment(tctx,
1011 : "Fallback to anonymous for "
1012 : "'torture:user2name'=NULL "
1013 : "'torture:user2domain'='%s' "
1014 : "'torture:user2password'='REDACTED'",
1015 : user2domain);
1016 2 : cli_credentials_set_anonymous(credentials2);
1017 : }
1018 :
1019 2 : return credentials2;
1020 : }
|