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(¤t_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 50 : synccount = 0;
701 250 : for (i=0;i<torture_nprocs;i++) {
702 200 : if (child_status[i].pid != 0) {
703 55 : synccount++;
704 : }
705 : }
706 50 : if (synccount == torture_nprocs) {
707 10 : break;
708 : }
709 40 : smb_msleep(100);
710 40 : } 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 7062 : _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 7062 : tcase = torture_suite_add_tcase(suite, name);
782 :
783 7062 : test = talloc(tcase, struct torture_test);
784 :
785 7062 : test->name = talloc_strdup(test, name);
786 7062 : test->description = NULL;
787 7062 : test->run = wrap_smb_multi_test;
788 7062 : test->fn = run;
789 7062 : test->dangerous = false;
790 :
791 7062 : DLIST_ADD_END(tcase->tests, test);
792 :
793 7062 : 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 249524 : _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 249524 : tcase = torture_suite_add_tcase(suite, name);
833 :
834 249524 : test = talloc(tcase, struct torture_test);
835 :
836 249524 : test->name = talloc_strdup(test, name);
837 249524 : test->description = NULL;
838 249524 : test->run = wrap_simple_2smb_test;
839 249524 : test->fn = run;
840 249524 : test->dangerous = false;
841 :
842 249524 : DLIST_ADD_END(tcase->tests, test);
843 :
844 249524 : 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 510818 : _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 510818 : tcase = torture_suite_add_tcase(suite, name);
877 :
878 510818 : test = talloc(tcase, struct torture_test);
879 :
880 510818 : test->name = talloc_strdup(test, name);
881 510818 : test->description = NULL;
882 510818 : test->run = wrap_simple_1smb_test;
883 510818 : test->fn = run;
884 510818 : test->dangerous = false;
885 :
886 510818 : DLIST_ADD_END(tcase->tests, test);
887 :
888 510818 : 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 : }
|