1/* 2 Unix SMB/CIFS implementation. 3 4 generic testing tool - version with both SMB and SMB2 support 5 6 Copyright (C) Andrew Tridgell 2003-2008 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. 20*/ 21 22#include "includes.h" 23#include "lib/cmdline/popt_common.h" 24#include "lib/events/events.h" 25#include "system/time.h" 26#include "system/filesys.h" 27#include "libcli/raw/request.h" 28#include "libcli/libcli.h" 29#include "libcli/raw/libcliraw.h" 30#include "libcli/smb2/smb2.h" 31#include "libcli/smb2/smb2_calls.h" 32#include "librpc/gen_ndr/security.h" 33#include "librpc/gen_ndr/ndr_security.h" 34#include "auth/credentials/credentials.h" 35#include "libcli/resolve/resolve.h" 36#include "auth/gensec/gensec.h" 37#include "param/param.h" 38#include "dynconfig/dynconfig.h" 39#include "libcli/security/security.h" 40#include "libcli/raw/raw_proto.h" 41 42#define NSERVERS 2 43#define NINSTANCES 2 44 45/* global options */ 46static struct gentest_options { 47 int showall; 48 int analyze; 49 int analyze_always; 50 int analyze_continuous; 51 uint_t max_open_handles; 52 uint_t seed; 53 uint_t numops; 54 int use_oplocks; 55 char **ignore_patterns; 56 const char *seeds_file; 57 int use_preset_seeds; 58 int fast_reconnect; 59 int mask_indexing; 60 int no_eas; 61 int no_acls; 62 int skip_cleanup; 63 int valid; 64 int smb2; 65} options; 66 67/* mapping between open handles on the server and local handles */ 68static struct { 69 bool active; 70 uint_t instance; 71 struct smb2_handle smb2_handle[NSERVERS]; /* SMB2 */ 72 uint16_t smb_handle[NSERVERS]; /* SMB */ 73 const char *name; 74} *open_handles; 75static uint_t num_open_handles; 76 77/* state information for the servers. We open NINSTANCES connections to 78 each server */ 79static struct { 80 struct smb2_tree *smb2_tree[NINSTANCES]; 81 struct smbcli_tree *smb_tree[NINSTANCES]; 82 char *server_name; 83 char *share_name; 84 struct cli_credentials *credentials; 85} servers[NSERVERS]; 86 87/* the seeds and flags for each operation */ 88static struct { 89 uint_t seed; 90 bool disabled; 91} *op_parms; 92 93 94/* oplock break info */ 95static struct { 96 bool got_break; 97 struct smb2_handle smb2_handle; 98 uint16_t smb_handle; 99 uint16_t handle; 100 uint8_t level; 101 bool do_close; 102} oplocks[NSERVERS][NINSTANCES]; 103 104/* change notify reply info */ 105static struct { 106 int notify_count; 107 NTSTATUS status; 108 union smb_notify notify; 109} notifies[NSERVERS][NINSTANCES]; 110 111/* info relevant to the current operation */ 112static struct { 113 const char *name; 114 uint_t seed; 115 NTSTATUS status; 116 uint_t opnum; 117 TALLOC_CTX *mem_ctx; 118 const char *mismatch; 119} current_op; 120 121static struct smb2_handle bad_smb2_handle; 122 123 124#define BAD_HANDLE 0xFFFE 125 126static bool oplock_handler_smb2(struct smb2_transport *transport, const struct smb2_handle *handle, 127 uint8_t level, void *private_data); 128static void idle_func_smb2(struct smb2_transport *transport, void *private_data); 129static bool oplock_handler_smb(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private_data); 130static void idle_func_smb(struct smbcli_transport *transport, void *private_data); 131 132/* 133 check if a string should be ignored. This is used as the basis 134 for all error ignore settings 135*/ 136static bool ignore_pattern(const char *str) 137{ 138 int i; 139 if (!options.ignore_patterns) return false; 140 141 for (i=0;options.ignore_patterns[i];i++) { 142 if (strcmp(options.ignore_patterns[i], str) == 0 || 143 gen_fnmatch(options.ignore_patterns[i], str) == 0) { 144 DEBUG(2,("Ignoring '%s'\n", str)); 145 return true; 146 } 147 } 148 return false; 149} 150 151/***************************************************** 152connect to the servers 153*******************************************************/ 154static bool connect_servers_fast(void) 155{ 156 int h, i; 157 158 /* close all open files */ 159 for (h=0;h<options.max_open_handles;h++) { 160 if (!open_handles[h].active) continue; 161 for (i=0;i<NSERVERS;i++) { 162 NTSTATUS status; 163 if (options.smb2) { 164 status = smb2_util_close(servers[i].smb2_tree[open_handles[h].instance], 165 open_handles[h].smb2_handle[i]); 166 } else { 167 status = smbcli_close(servers[i].smb_tree[open_handles[h].instance], 168 open_handles[h].smb_handle[i]); 169 } 170 if (NT_STATUS_IS_ERR(status)) { 171 return false; 172 } 173 open_handles[h].active = false; 174 } 175 } 176 177 return true; 178} 179 180 181 182 183/***************************************************** 184connect to the servers 185*******************************************************/ 186static bool connect_servers(struct tevent_context *ev, 187 struct loadparm_context *lp_ctx) 188{ 189 int i, j; 190 191 if (options.fast_reconnect && servers[0].smb2_tree[0]) { 192 if (connect_servers_fast()) { 193 return true; 194 } 195 } 196 197 /* close any existing connections */ 198 for (i=0;i<NSERVERS;i++) { 199 for (j=0;j<NINSTANCES;j++) { 200 if (servers[i].smb2_tree[j]) { 201 smb2_tdis(servers[i].smb2_tree[j]); 202 talloc_free(servers[i].smb2_tree[j]); 203 servers[i].smb2_tree[j] = NULL; 204 } 205 if (servers[i].smb_tree[j]) { 206 smb_tree_disconnect(servers[i].smb_tree[j]); 207 talloc_free(servers[i].smb_tree[j]); 208 servers[i].smb_tree[j] = NULL; 209 } 210 } 211 } 212 213 for (i=0;i<NSERVERS;i++) { 214 for (j=0;j<NINSTANCES;j++) { 215 NTSTATUS status; 216 struct smbcli_options smb_options; 217 struct smbcli_session_options smb_session_options; 218 lp_smbcli_options(lp_ctx, &smb_options); 219 lp_smbcli_session_options(lp_ctx, &smb_session_options); 220 221 printf("Connecting to \\\\%s\\%s as %s - instance %d\n", 222 servers[i].server_name, servers[i].share_name, 223 servers[i].credentials->username, j); 224 225 cli_credentials_set_workstation(servers[i].credentials, 226 "gentest", CRED_SPECIFIED); 227 228 if (options.smb2) { 229 status = smb2_connect(NULL, servers[i].server_name, 230 lp_smb_ports(lp_ctx), 231 servers[i].share_name, 232 lp_resolve_context(lp_ctx), 233 servers[i].credentials, 234 &servers[i].smb2_tree[j], 235 ev, &smb_options, 236 lp_socket_options(lp_ctx), 237 lp_gensec_settings(lp_ctx, lp_ctx) 238 ); 239 } else { 240 status = smbcli_tree_full_connection(NULL, 241 &servers[i].smb_tree[j], 242 servers[i].server_name, 243 lp_smb_ports(lp_ctx), 244 servers[i].share_name, "A:", 245 lp_socket_options(lp_ctx), 246 servers[i].credentials, 247 lp_resolve_context(lp_ctx), ev, 248 &smb_options, 249 &smb_session_options, 250 lp_iconv_convenience(lp_ctx), 251 lp_gensec_settings(lp_ctx, lp_ctx)); 252 } 253 if (!NT_STATUS_IS_OK(status)) { 254 printf("Failed to connect to \\\\%s\\%s - %s\n", 255 servers[i].server_name, servers[i].share_name, 256 nt_errstr(status)); 257 return false; 258 } 259 260 if (options.smb2) { 261 servers[i].smb2_tree[j]->session->transport->oplock.handler = oplock_handler_smb2; 262 servers[i].smb2_tree[j]->session->transport->oplock.private_data = (void *)(uintptr_t)((i<<8)|j); 263 smb2_transport_idle_handler(servers[i].smb2_tree[j]->session->transport, 264 idle_func_smb2, 50000, NULL); 265 } else { 266 smbcli_oplock_handler(servers[i].smb_tree[j]->session->transport, oplock_handler_smb, 267 (void *)(uintptr_t)((i<<8)|j)); 268 smbcli_transport_idle_handler(servers[i].smb_tree[j]->session->transport, idle_func_smb, 269 50000, (void *)(uintptr_t)((i<<8)|j)); 270 } 271 } 272 } 273 274 return true; 275} 276 277/* 278 work out the time skew between the servers - be conservative 279*/ 280static uint_t time_skew(void) 281{ 282 uint_t ret; 283 if (options.smb2) { 284 ret = labs(servers[0].smb2_tree[0]->session->transport->negotiate.system_time - 285 servers[1].smb2_tree[0]->session->transport->negotiate.system_time); 286 } else { 287 ret = labs(servers[0].smb_tree[0]->session->transport->negotiate.server_time - 288 servers[1].smb_tree[0]->session->transport->negotiate.server_time); 289 } 290 return ret + 300; 291} 292 293 294static bool smb2_handle_equal(const struct smb2_handle *h1, const struct smb2_handle *h2) 295{ 296 return memcmp(h1, h2, sizeof(struct smb2_handle)) == 0; 297} 298 299/* 300 turn a server handle into a local handle 301*/ 302static uint_t fnum_to_handle_smb2(int server, int instance, struct smb2_handle server_handle) 303{ 304 uint_t i; 305 for (i=0;i<options.max_open_handles;i++) { 306 if (!open_handles[i].active || 307 instance != open_handles[i].instance) continue; 308 if (smb2_handle_equal(&open_handles[i].smb2_handle[server], &server_handle)) { 309 return i; 310 } 311 } 312 printf("Invalid server handle in fnum_to_handle on server %d instance %d\n", 313 server, instance); 314 return BAD_HANDLE; 315} 316 317/* 318 turn a server handle into a local handle 319*/ 320static uint_t fnum_to_handle_smb(int server, int instance, uint16_t server_handle) 321{ 322 uint_t i; 323 for (i=0;i<options.max_open_handles;i++) { 324 if (!open_handles[i].active || 325 instance != open_handles[i].instance) continue; 326 if (open_handles[i].smb_handle[server] == server_handle) { 327 return i; 328 } 329 } 330 printf("Invalid server handle in fnum_to_handle on server %d instance %d\n", 331 server, instance); 332 return BAD_HANDLE; 333} 334 335/* 336 add some newly opened handles 337*/ 338static void gen_add_handle_smb2(int instance, const char *name, struct smb2_handle handles[NSERVERS]) 339{ 340 int i, h; 341 for (h=0;h<options.max_open_handles;h++) { 342 if (!open_handles[h].active) break; 343 } 344 if (h == options.max_open_handles) { 345 /* we have to force close a random handle */ 346 h = random() % options.max_open_handles; 347 for (i=0;i<NSERVERS;i++) { 348 NTSTATUS status; 349 status = smb2_util_close(servers[i].smb2_tree[open_handles[h].instance], 350 open_handles[h].smb2_handle[i]); 351 if (NT_STATUS_IS_ERR(status)) { 352 printf("INTERNAL ERROR: Close failed when recovering handle! - %s\n", 353 nt_errstr(status)); 354 } 355 } 356 printf("Recovered handle %d\n", h); 357 num_open_handles--; 358 } 359 for (i=0;i<NSERVERS;i++) { 360 open_handles[h].smb2_handle[i] = handles[i]; 361 open_handles[h].instance = instance; 362 open_handles[h].active = true; 363 open_handles[h].name = name; 364 } 365 num_open_handles++; 366 367 printf("OPEN num_open_handles=%d h=%d (%s)\n", 368 num_open_handles, h, name); 369} 370 371/* 372 add some newly opened handles 373*/ 374static void gen_add_handle_smb(int instance, const char *name, uint16_t handles[NSERVERS]) 375{ 376 int i, h; 377 for (h=0;h<options.max_open_handles;h++) { 378 if (!open_handles[h].active) break; 379 } 380 if (h == options.max_open_handles) { 381 /* we have to force close a random handle */ 382 h = random() % options.max_open_handles; 383 for (i=0;i<NSERVERS;i++) { 384 NTSTATUS status; 385 status = smbcli_close(servers[i].smb_tree[open_handles[h].instance], 386 open_handles[h].smb_handle[i]); 387 if (NT_STATUS_IS_ERR(status)) { 388 printf("INTERNAL ERROR: Close failed when recovering handle! - %s\n", 389 nt_errstr(status)); 390 } 391 } 392 printf("Recovered handle %d\n", h); 393 num_open_handles--; 394 } 395 for (i=0;i<NSERVERS;i++) { 396 open_handles[h].smb_handle[i] = handles[i]; 397 open_handles[h].instance = instance; 398 open_handles[h].active = true; 399 open_handles[h].name = name; 400 } 401 num_open_handles++; 402 403 printf("OPEN num_open_handles=%d h=%d (%s)\n", 404 num_open_handles, h, name); 405} 406 407 408/* 409 remove a closed handle 410*/ 411static void gen_remove_handle_smb2(int instance, struct smb2_handle handles[NSERVERS]) 412{ 413 int h; 414 for (h=0;h<options.max_open_handles;h++) { 415 if (instance == open_handles[h].instance && 416 smb2_handle_equal(&open_handles[h].smb2_handle[0], &handles[0])) { 417 open_handles[h].active = false; 418 num_open_handles--; 419 printf("CLOSE num_open_handles=%d h=%d (%s)\n", 420 num_open_handles, h, 421 open_handles[h].name); 422 return; 423 } 424 } 425 printf("Removing invalid handle!?\n"); 426 exit(1); 427} 428 429/* 430 remove a closed handle 431*/ 432static void gen_remove_handle_smb(int instance, uint16_t handles[NSERVERS]) 433{ 434 int h; 435 for (h=0;h<options.max_open_handles;h++) { 436 if (instance == open_handles[h].instance && 437 open_handles[h].smb_handle[0] == handles[0]) { 438 open_handles[h].active = false; 439 num_open_handles--; 440 printf("CLOSE num_open_handles=%d h=%d (%s)\n", 441 num_open_handles, h, 442 open_handles[h].name); 443 return; 444 } 445 } 446 printf("Removing invalid handle!?\n"); 447 exit(1); 448} 449 450/* 451 return true with 'chance' probability as a percentage 452*/ 453static bool gen_chance(uint_t chance) 454{ 455 return ((random() % 100) <= chance); 456} 457 458/* 459 map an internal handle number to a server handle 460*/ 461static struct smb2_handle gen_lookup_handle_smb2(int server, uint16_t handle) 462{ 463 if (handle == BAD_HANDLE) return bad_smb2_handle; 464 return open_handles[handle].smb2_handle[server]; 465} 466 467/* 468 map an internal handle number to a server handle 469*/ 470static uint16_t gen_lookup_handle_smb(int server, uint16_t handle) 471{ 472 if (handle == BAD_HANDLE) return BAD_HANDLE; 473 return open_handles[handle].smb_handle[server]; 474} 475 476/* 477 return a file handle 478*/ 479static uint16_t gen_fnum(int instance) 480{ 481 uint16_t h; 482 int count = 0; 483 484 if (gen_chance(20)) return BAD_HANDLE; 485 486 while (num_open_handles > 0 && count++ < 10*options.max_open_handles) { 487 h = random() % options.max_open_handles; 488 if (open_handles[h].active && 489 open_handles[h].instance == instance) { 490 return h; 491 } 492 } 493 return BAD_HANDLE; 494} 495 496/* 497 return a file handle, but skewed so we don't close the last 498 couple of handles too readily 499*/ 500static uint16_t gen_fnum_close(int instance) 501{ 502 if (num_open_handles < 5) { 503 if (gen_chance(90)) return BAD_HANDLE; 504 } 505 506 return gen_fnum(instance); 507} 508 509/* 510 generate an integer in a specified range 511*/ 512static int gen_int_range(uint64_t min, uint64_t max) 513{ 514 uint_t r = random(); 515 return min + (r % (1+max-min)); 516} 517 518/* 519 return a fnum for use as a root fid 520 be careful to call GEN_SET_FNUM() when you use this! 521*/ 522static uint16_t gen_root_fid(int instance) 523{ 524 if (gen_chance(5)) return gen_fnum(instance); 525 return 0; 526} 527 528/* 529 generate a file offset 530*/ 531static int gen_offset(void) 532{ 533 if (gen_chance(20)) return 0; 534// if (gen_chance(5)) return gen_int_range(0, 0xFFFFFFFF); 535 return gen_int_range(0, 1024*1024); 536} 537 538/* 539 generate a io count 540*/ 541static int gen_io_count(void) 542{ 543 if (gen_chance(20)) return 0; 544// if (gen_chance(5)) return gen_int_range(0, 0xFFFFFFFF); 545 return gen_int_range(0, 4096); 546} 547 548/* 549 generate a filename 550*/ 551static const char *gen_fname(void) 552{ 553 const char *names[] = {"gentest\\gentest.dat", 554 "gentest\\foo", 555 "gentest\\foo2.sym", 556 "gentest\\foo3.dll", 557 "gentest\\foo4", 558 "gentest\\foo4:teststream1", 559 "gentest\\foo4:teststream2", 560 "gentest\\foo5.exe", 561 "gentest\\foo5.exe:teststream3", 562 "gentest\\foo5.exe:teststream4", 563 "gentest\\foo6.com", 564 "gentest\\blah", 565 "gentest\\blah\\blergh.txt", 566 "gentest\\blah\\blergh2", 567 "gentest\\blah\\blergh3.txt", 568 "gentest\\blah\\blergh4", 569 "gentest\\blah\\blergh5.txt", 570 "gentest\\blah\\blergh5", 571 "gentest\\blah\\.", 572 "gentest\\blah\\..", 573 "gentest\\a_very_long_name.bin", 574 "gentest\\x.y", 575 "gentest\\blah"}; 576 int i; 577 578 do { 579 i = gen_int_range(0, ARRAY_SIZE(names)-1); 580 } while (ignore_pattern(names[i])); 581 582 return names[i]; 583} 584 585/* 586 generate a filename with a higher chance of choosing an already 587 open file 588*/ 589static const char *gen_fname_open(int instance) 590{ 591 uint16_t h; 592 h = gen_fnum(instance); 593 if (h == BAD_HANDLE) { 594 return gen_fname(); 595 } 596 return open_handles[h].name; 597} 598 599/* 600 generate a wildcard pattern 601*/ 602static const char *gen_pattern(void) 603{ 604 int i; 605 const char *names[] = {"gentest\\*.dat", 606 "gentest\\*", 607 "gentest\\*.*", 608 "gentest\\blah\\*.*", 609 "gentest\\blah\\*", 610 "gentest\\?"}; 611 612 if (gen_chance(50)) return gen_fname(); 613 614 do { 615 i = gen_int_range(0, ARRAY_SIZE(names)-1); 616 } while (ignore_pattern(names[i])); 617 618 return names[i]; 619} 620 621static uint32_t gen_bits_levels(int nlevels, ...) 622{ 623 va_list ap; 624 uint32_t pct; 625 uint32_t mask; 626 int i; 627 va_start(ap, nlevels); 628 for (i=0;i<nlevels;i++) { 629 pct = va_arg(ap, uint32_t); 630 mask = va_arg(ap, uint32_t); 631 if (pct == 100 || gen_chance(pct)) { 632 va_end(ap); 633 return mask & random(); 634 } 635 } 636 va_end(ap); 637 return 0; 638} 639 640/* 641 generate a bitmask 642*/ 643static uint32_t gen_bits_mask(uint_t mask) 644{ 645 uint_t ret = random(); 646 return ret & mask; 647} 648 649/* 650 generate a bitmask with high probability of the first mask 651 and low of the second 652*/ 653static uint32_t gen_bits_mask2(uint32_t mask1, uint32_t mask2) 654{ 655 if (!options.valid && gen_chance(10)) return gen_bits_mask(mask2); 656 return gen_bits_mask(mask1); 657} 658 659/* 660 generate reserved values 661 */ 662static uint64_t gen_reserved8(void) 663{ 664 if (options.valid) return 0; 665 return gen_bits_mask(0xFF); 666} 667 668static uint64_t gen_reserved16(void) 669{ 670 if (options.valid) return 0; 671 return gen_bits_mask(0xFFFF); 672} 673 674static uint64_t gen_reserved32(void) 675{ 676 if (options.valid) return 0; 677 return gen_bits_mask(0xFFFFFFFF); 678} 679 680static uint64_t gen_reserved64(void) 681{ 682 if (options.valid) return 0; 683 return gen_bits_mask(0xFFFFFFFF) | (((uint64_t)gen_bits_mask(0xFFFFFFFF))<<32); 684} 685 686 687 688/* 689 generate a boolean 690*/ 691static bool gen_bool(void) 692{ 693 return gen_bits_mask2(0x1, 0xFF); 694} 695 696/* 697 generate ntrename flags 698*/ 699static uint16_t gen_rename_flags(void) 700{ 701 if (gen_chance(30)) return RENAME_FLAG_RENAME; 702 if (gen_chance(30)) return RENAME_FLAG_HARD_LINK; 703 if (gen_chance(30)) return RENAME_FLAG_COPY; 704 return gen_bits_mask(0xFFFF); 705} 706 707/* 708 generate a pid 709*/ 710static uint16_t gen_pid(void) 711{ 712 if (gen_chance(10)) return gen_bits_mask(0xFFFF); 713 return getpid(); 714} 715 716/* 717 return a set of lock flags 718*/ 719static uint16_t gen_lock_flags_smb2(void) 720{ 721 if (!options.valid && gen_chance(5)) return gen_bits_mask(0xFFFF); 722 if (gen_chance(20)) return gen_bits_mask(0x1F); 723 if (gen_chance(50)) return SMB2_LOCK_FLAG_UNLOCK; 724 return gen_bits_mask(SMB2_LOCK_FLAG_SHARED | 725 SMB2_LOCK_FLAG_EXCLUSIVE | 726 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY); 727} 728 729/* 730 generate a lock count 731*/ 732static off_t gen_lock_count(void) 733{ 734 return gen_int_range(0, 3); 735} 736 737/* 738 generate a NT access mask 739*/ 740static uint32_t gen_access_mask(void) 741{ 742 uint32_t ret; 743 if (gen_chance(70)) return SEC_FLAG_MAXIMUM_ALLOWED; 744 if (gen_chance(70)) return SEC_FILE_ALL; 745 ret = gen_bits_mask(0xFFFFFFFF); 746 if (options.valid) ret &= ~SEC_MASK_INVALID; 747 return ret; 748} 749 750/* 751 return a lockingx lock mode 752*/ 753static uint16_t gen_lock_mode(void) 754{ 755 if (!options.valid && gen_chance(5)) return gen_bits_mask(0xFFFF); 756 if (gen_chance(20)) return gen_bits_mask(0x1F); 757 return gen_bits_mask(LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES); 758} 759 760/* 761 generate a ntcreatex flags field 762*/ 763static uint32_t gen_ntcreatex_flags(void) 764{ 765 if (gen_chance(70)) return NTCREATEX_FLAGS_EXTENDED; 766 return gen_bits_mask2(0x1F, 0xFFFFFFFF); 767} 768 769/* 770 generate a ntcreatex create options bitfield 771*/ 772static uint32_t gen_create_options(void) 773{ 774 if (!options.valid && gen_chance(20)) return gen_bits_mask(0xFFFFFFFF); 775 if (gen_chance(50)) return 0; 776 return gen_bits_mask(NTCREATEX_OPTIONS_DELETE_ON_CLOSE | NTCREATEX_OPTIONS_DIRECTORY); 777} 778 779/* 780 generate a ntcreatex open disposition 781*/ 782static uint32_t gen_open_disp(void) 783{ 784 if (gen_chance(50)) return NTCREATEX_DISP_OPEN_IF; 785 if (!options.valid && gen_chance(10)) return gen_bits_mask(0xFFFFFFFF); 786 return gen_int_range(0, 5); 787} 788 789/* 790 generate an openx open mode 791*/ 792static uint16_t gen_openx_mode(void) 793{ 794 if (!options.valid && gen_chance(20)) return gen_bits_mask(0xFFFF); 795 if (gen_chance(20)) return gen_bits_mask(0xFF); 796 return OPENX_MODE_DENY_NONE | gen_bits_mask(0x3); 797} 798 799/* 800 generate an openx flags field 801*/ 802static uint16_t gen_openx_flags(void) 803{ 804 if (!options.valid && gen_chance(20)) return gen_bits_mask(0xFFFF); 805 return gen_bits_mask(0x7); 806} 807 808/* 809 generate an openx open function 810*/ 811static uint16_t gen_openx_func(void) 812{ 813 if (!options.valid && gen_chance(20)) return gen_bits_mask(0xFFFF); 814 return gen_bits_mask(0x13); 815} 816 817/* 818 generate a file attrib combination 819*/ 820static uint32_t gen_attrib(void) 821{ 822 uint32_t ret; 823 if (gen_chance(20)) { 824 ret = gen_bits_mask(0xFFFFFFFF); 825 if (options.valid) ret &= FILE_ATTRIBUTE_ALL_MASK; 826 return ret; 827 } 828 return gen_bits_mask(FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY); 829} 830 831/* 832 generate a unix timestamp 833*/ 834static time_t gen_timet(void) 835{ 836 if (gen_chance(30)) return 0; 837 return (time_t)random(); 838} 839 840/* 841 generate a milliseconds protocol timeout 842*/ 843static uint32_t gen_timeout(void) 844{ 845 if (gen_chance(98)) return 0; 846 return random() % 50; 847} 848 849/* 850 generate a timestamp 851*/ 852static NTTIME gen_nttime(void) 853{ 854 NTTIME ret; 855 unix_to_nt_time(&ret, gen_timet()); 856 return ret; 857} 858 859/* 860 generate a timewarp value 861*/ 862static NTTIME gen_timewarp(void) 863{ 864 NTTIME ret = gen_nttime(); 865 if (gen_chance(98)) ret = 0; 866 return ret; 867} 868 869/* 870 generate a file allocation size 871*/ 872static uint_t gen_alloc_size(void) 873{ 874 uint_t ret; 875 876 if (gen_chance(30)) return 0; 877 878 ret = random() % 4*1024*1024; 879 /* give a high chance of a round number */ 880 if (gen_chance(60)) { 881 ret &= ~(1024*1024 - 1); 882 } 883 return ret; 884} 885 886/* 887 generate an ea_struct 888*/ 889static struct ea_struct gen_ea_struct(void) 890{ 891 struct ea_struct ea; 892 const char *names[] = {"EAONE", 893 "", 894 "FOO!", 895 " WITH SPACES ", 896 ".", 897 "AVERYLONGATTRIBUTENAME"}; 898 const char *values[] = {"VALUE1", 899 "", 900 "NOT MUCH FOO", 901 " LEADING SPACES ", 902 ":", 903 "ASOMEWHATLONGERATTRIBUTEVALUE"}; 904 int i; 905 906 ZERO_STRUCT(ea); 907 908 do { 909 i = gen_int_range(0, ARRAY_SIZE(names)-1); 910 } while (ignore_pattern(names[i])); 911 912 ea.name.s = names[i]; 913 914 do { 915 i = gen_int_range(0, ARRAY_SIZE(values)-1); 916 } while (ignore_pattern(values[i])); 917 918 ea.value = data_blob(values[i], strlen(values[i])); 919 920 if (gen_chance(10)) ea.flags = gen_bits_mask(0xFF); 921 ea.flags = 0; 922 923 return ea; 924} 925 926/* 927 generate an ea_struct 928*/ 929static struct smb_ea_list gen_ea_list(void) 930{ 931 struct smb_ea_list eas; 932 int i; 933 if (options.no_eas) { 934 ZERO_STRUCT(eas); 935 return eas; 936 } 937 eas.num_eas = gen_int_range(0, 3); 938 eas.eas = talloc_array(current_op.mem_ctx, struct ea_struct, eas.num_eas); 939 for (i=0;i<eas.num_eas;i++) { 940 eas.eas[i] = gen_ea_struct(); 941 } 942 return eas; 943} 944 945/* generate a security descriptor */ 946static struct security_descriptor *gen_sec_desc(void) 947{ 948 struct security_descriptor *sd; 949 if (options.no_acls || gen_chance(90)) return NULL; 950 951 sd = security_descriptor_dacl_create(current_op.mem_ctx, 952 0, NULL, NULL, 953 NULL, 954 SEC_ACE_TYPE_ACCESS_ALLOWED, 955 SEC_FILE_WRITE_DATA | SEC_STD_WRITE_DAC, 956 SEC_ACE_FLAG_OBJECT_INHERIT, 957 SID_WORLD, 958 SEC_ACE_TYPE_ACCESS_ALLOWED, 959 SEC_FILE_ALL | SEC_STD_ALL, 960 0, 961 NULL); 962 return sd; 963} 964 965 966static void oplock_handler_close_recv_smb(struct smbcli_request *req) 967{ 968 NTSTATUS status; 969 status = smbcli_request_simple_recv(req); 970 if (!NT_STATUS_IS_OK(status)) { 971 printf("close failed in oplock_handler\n"); 972 smb_panic("close failed in oplock_handler"); 973 } 974} 975 976/* 977 the oplock handler will either ack the break or close the file 978*/ 979static bool oplock_handler_smb(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private_data) 980{ 981 union smb_close io; 982 int i, j; 983 bool do_close; 984 struct smbcli_tree *tree = NULL; 985 struct smbcli_request *req; 986 987 srandom(current_op.seed); 988 do_close = gen_chance(50); 989 990 for (i=0;i<NSERVERS;i++) { 991 for (j=0;j<NINSTANCES;j++) { 992 if (transport == servers[i].smb_tree[j]->session->transport && 993 tid == servers[i].smb_tree[j]->tid) { 994 oplocks[i][j].got_break = true; 995 oplocks[i][j].smb_handle = fnum; 996 oplocks[i][j].handle = fnum_to_handle_smb(i, j, fnum); 997 oplocks[i][j].level = level; 998 oplocks[i][j].do_close = do_close; 999 tree = servers[i].smb_tree[j]; 1000 } 1001 } 1002 } 1003 1004 if (!tree) { 1005 printf("Oplock break not for one of our trees!?\n"); 1006 return false; 1007 } 1008 1009 if (!do_close) { 1010 printf("oplock ack fnum=%d\n", fnum); 1011 return smbcli_oplock_ack(tree, fnum, level); 1012 } 1013 1014 printf("oplock close fnum=%d\n", fnum); 1015 1016 io.close.level = RAW_CLOSE_CLOSE; 1017 io.close.in.file.fnum = fnum; 1018 io.close.in.write_time = 0; 1019 req = smb_raw_close_send(tree, &io); 1020 1021 if (req == NULL) { 1022 printf("WARNING: close failed in oplock_handler_close\n"); 1023 return false; 1024 } 1025 1026 req->async.fn = oplock_handler_close_recv_smb; 1027 req->async.private_data = NULL; 1028 1029 return true; 1030} 1031 1032 1033/* 1034 the idle function tries to cope with getting an oplock break on a connection, and 1035 an operation on another connection blocking until that break is acked 1036 we check for operations on all transports in the idle function 1037*/ 1038static void idle_func_smb(struct smbcli_transport *transport, void *private_data) 1039{ 1040 int i, j; 1041 for (i=0;i<NSERVERS;i++) { 1042 for (j=0;j<NINSTANCES;j++) { 1043 if (servers[i].smb_tree[j] && 1044 transport != servers[i].smb_tree[j]->session->transport) { 1045 smbcli_transport_process(servers[i].smb_tree[j]->session->transport); 1046 } 1047 } 1048 } 1049 1050} 1051 1052static void oplock_handler_close_recv_smb2(struct smb2_request *req) 1053{ 1054 NTSTATUS status; 1055 struct smb2_close io; 1056 status = smb2_close_recv(req, &io); 1057 if (!NT_STATUS_IS_OK(status)) { 1058 printf("close failed in oplock_handler\n"); 1059 smb_panic("close failed in oplock_handler"); 1060 } 1061} 1062 1063static void oplock_handler_ack_callback_smb2(struct smb2_request *req) 1064{ 1065 NTSTATUS status; 1066 struct smb2_break br; 1067 1068 status = smb2_break_recv(req, &br); 1069 if (!NT_STATUS_IS_OK(status)) { 1070 printf("oplock break ack failed in oplock_handler\n"); 1071 smb_panic("oplock break ack failed in oplock_handler"); 1072 } 1073} 1074 1075static bool send_oplock_ack_smb2(struct smb2_tree *tree, struct smb2_handle handle, 1076 uint8_t level) 1077{ 1078 struct smb2_break br; 1079 struct smb2_request *req; 1080 1081 ZERO_STRUCT(br); 1082 br.in.file.handle = handle; 1083 br.in.oplock_level = level; 1084 br.in.reserved = gen_reserved8(); 1085 br.in.reserved2 = gen_reserved32(); 1086 1087 req = smb2_break_send(tree, &br); 1088 if (req == NULL) return false; 1089 req->async.fn = oplock_handler_ack_callback_smb2; 1090 req->async.private_data = NULL; 1091 return true; 1092} 1093 1094/* 1095 the oplock handler will either ack the break or close the file 1096*/ 1097static bool oplock_handler_smb2(struct smb2_transport *transport, const struct smb2_handle *handle, 1098 uint8_t level, void *private_data) 1099{ 1100 struct smb2_close io; 1101 unsigned i, j; 1102 bool do_close; 1103 struct smb2_tree *tree = NULL; 1104 struct smb2_request *req; 1105 1106 srandom(current_op.seed); 1107 do_close = gen_chance(50); 1108 1109 i = ((uintptr_t)private_data) >> 8; 1110 j = ((uintptr_t)private_data) & 0xFF; 1111 1112 if (i >= NSERVERS || j >= NINSTANCES) { 1113 printf("Bad private_data in oplock_handler\n"); 1114 return false; 1115 } 1116 1117 oplocks[i][j].got_break = true; 1118 oplocks[i][j].smb2_handle = *handle; 1119 oplocks[i][j].handle = fnum_to_handle_smb2(i, j, *handle); 1120 oplocks[i][j].level = level; 1121 oplocks[i][j].do_close = do_close; 1122 tree = talloc_get_type(servers[i].smb2_tree[j], struct smb2_tree); 1123 1124 if (!tree) { 1125 printf("Oplock break not for one of our trees!?\n"); 1126 return false; 1127 } 1128 1129 if (!do_close) { 1130 printf("oplock ack handle=%d\n", oplocks[i][j].handle); 1131 return send_oplock_ack_smb2(tree, *handle, level); 1132 } 1133 1134 printf("oplock close fnum=%d\n", oplocks[i][j].handle); 1135 1136 ZERO_STRUCT(io); 1137 io.in.file.handle = *handle; 1138 io.in.flags = 0; 1139 req = smb2_close_send(tree, &io); 1140 1141 if (req == NULL) { 1142 printf("WARNING: close failed in oplock_handler_close\n"); 1143 return false; 1144 } 1145 1146 req->async.fn = oplock_handler_close_recv_smb2; 1147 req->async.private_data = NULL; 1148 1149 return true; 1150} 1151 1152 1153/* 1154 the idle function tries to cope with getting an oplock break on a connection, and 1155 an operation on another connection blocking until that break is acked 1156 we check for operations on all transports in the idle function 1157*/ 1158static void idle_func_smb2(struct smb2_transport *transport, void *private_data) 1159{ 1160 int i, j; 1161 for (i=0;i<NSERVERS;i++) { 1162 for (j=0;j<NINSTANCES;j++) { 1163 if (servers[i].smb2_tree[j] && 1164 transport != servers[i].smb2_tree[j]->session->transport) { 1165 // smb2_transport_process(servers[i].smb2_tree[j]->session->transport); 1166 } 1167 } 1168 } 1169 1170} 1171 1172 1173/* 1174 compare NTSTATUS, using checking ignored patterns 1175*/ 1176static bool compare_status(NTSTATUS status1, NTSTATUS status2) 1177{ 1178 char *s; 1179 1180 if (NT_STATUS_EQUAL(status1, status2)) return true; 1181 1182 /* one code being an error and the other OK is always an error */ 1183 if (NT_STATUS_IS_OK(status1) || NT_STATUS_IS_OK(status2)) { 1184 current_op.mismatch = nt_errstr(status1); 1185 return false; 1186 } 1187 1188 /* if we are ignoring one of the status codes then consider this a match */ 1189 if (ignore_pattern(nt_errstr(status1)) || 1190 ignore_pattern(nt_errstr(status2))) { 1191 return true; 1192 } 1193 1194 /* also support ignore patterns of the form NT_STATUS_XX:NT_STATUS_YY 1195 meaning that the first server returns NT_STATUS_XX and the 2nd 1196 returns NT_STATUS_YY */ 1197 s = talloc_asprintf(current_op.mem_ctx, "%s:%s", 1198 nt_errstr(status1), 1199 nt_errstr(status2)); 1200 if (ignore_pattern(s)) { 1201 return true; 1202 } 1203 1204 current_op.mismatch = nt_errstr(status1); 1205 return false; 1206} 1207 1208/* 1209 check for pending packets on all connections 1210*/ 1211static void check_pending(void) 1212{ 1213 int i, j; 1214 1215 msleep(20); 1216 1217 for (j=0;j<NINSTANCES;j++) { 1218 for (i=0;i<NSERVERS;i++) { 1219 // smb2_transport_process(servers[i].smb2_tree[j]->session->transport); 1220 } 1221 } 1222} 1223 1224/* 1225 check that the same oplock breaks have been received by all instances 1226*/ 1227static bool check_oplocks(const char *call) 1228{ 1229 int i, j; 1230 int tries = 0; 1231 1232 if (!options.use_oplocks || options.smb2) { 1233 /* no smb2 oplocks in gentest yet */ 1234 return true; 1235 } 1236 1237again: 1238 check_pending(); 1239 1240 for (j=0;j<NINSTANCES;j++) { 1241 for (i=1;i<NSERVERS;i++) { 1242 if (oplocks[0][j].got_break != oplocks[i][j].got_break || 1243 oplocks[0][j].handle != oplocks[i][j].handle || 1244 oplocks[0][j].level != oplocks[i][j].level) { 1245 if (tries++ < 10) goto again; 1246 printf("oplock break inconsistent - %d/%d/%d vs %d/%d/%d\n", 1247 oplocks[0][j].got_break, 1248 oplocks[0][j].handle, 1249 oplocks[0][j].level, 1250 oplocks[i][j].got_break, 1251 oplocks[i][j].handle, 1252 oplocks[i][j].level); 1253 current_op.mismatch = "oplock break"; 1254 return false; 1255 } 1256 } 1257 } 1258 1259 /* if we got a break and closed then remove the handle */ 1260 for (j=0;j<NINSTANCES;j++) { 1261 if (oplocks[0][j].got_break && 1262 oplocks[0][j].do_close) { 1263 uint16_t fnums[NSERVERS]; 1264 for (i=0;i<NSERVERS;i++) { 1265 fnums[i] = oplocks[i][j].smb_handle; 1266 } 1267 gen_remove_handle_smb(j, fnums); 1268 break; 1269 } 1270 } 1271 return true; 1272} 1273 1274 1275/* 1276 check that the same change notify info has been received by all instances 1277*/ 1278static bool check_notifies(const char *call) 1279{ 1280 int i, j; 1281 int tries = 0; 1282 1283 if (options.smb2) { 1284 /* no smb2 notifies in gentest yet */ 1285 return true; 1286 } 1287 1288again: 1289 check_pending(); 1290 1291 for (j=0;j<NINSTANCES;j++) { 1292 for (i=1;i<NSERVERS;i++) { 1293 int n; 1294 union smb_notify not1, not2; 1295 1296 if (notifies[0][j].notify_count != notifies[i][j].notify_count) { 1297 if (tries++ < 10) goto again; 1298 printf("Notify count inconsistent %d %d\n", 1299 notifies[0][j].notify_count, 1300 notifies[i][j].notify_count); 1301 current_op.mismatch = "notify count"; 1302 return false; 1303 } 1304 1305 if (notifies[0][j].notify_count == 0) continue; 1306 1307 if (!NT_STATUS_EQUAL(notifies[0][j].status, 1308 notifies[i][j].status)) { 1309 printf("Notify status mismatch - %s - %s\n", 1310 nt_errstr(notifies[0][j].status), 1311 nt_errstr(notifies[i][j].status)); 1312 current_op.mismatch = "Notify status"; 1313 return false; 1314 } 1315 1316 if (!NT_STATUS_IS_OK(notifies[0][j].status)) { 1317 continue; 1318 } 1319 1320 not1 = notifies[0][j].notify; 1321 not2 = notifies[i][j].notify; 1322 1323 for (n=0;n<not1.nttrans.out.num_changes;n++) { 1324 if (not1.nttrans.out.changes[n].action != 1325 not2.nttrans.out.changes[n].action) { 1326 printf("Notify action %d inconsistent %d %d\n", n, 1327 not1.nttrans.out.changes[n].action, 1328 not2.nttrans.out.changes[n].action); 1329 current_op.mismatch = "notify action"; 1330 return false; 1331 } 1332 if (strcmp(not1.nttrans.out.changes[n].name.s, 1333 not2.nttrans.out.changes[n].name.s)) { 1334 printf("Notify name %d inconsistent %s %s\n", n, 1335 not1.nttrans.out.changes[n].name.s, 1336 not2.nttrans.out.changes[n].name.s); 1337 current_op.mismatch = "notify name"; 1338 return false; 1339 } 1340 if (not1.nttrans.out.changes[n].name.private_length != 1341 not2.nttrans.out.changes[n].name.private_length) { 1342 printf("Notify name length %d inconsistent %d %d\n", n, 1343 not1.nttrans.out.changes[n].name.private_length, 1344 not2.nttrans.out.changes[n].name.private_length); 1345 current_op.mismatch = "notify name length"; 1346 return false; 1347 } 1348 } 1349 } 1350 } 1351 1352 ZERO_STRUCT(notifies); 1353 1354 return true; 1355} 1356 1357#define GEN_COPY_PARM do { \ 1358 int i; \ 1359 for (i=1;i<NSERVERS;i++) { \ 1360 parm[i] = parm[0]; \ 1361 } \ 1362} while (0) 1363 1364#define GEN_CALL(call, treetype, treefield) do { \ 1365 int i; \ 1366 ZERO_STRUCT(oplocks); \ 1367 ZERO_STRUCT(notifies); \ 1368 for (i=0;i<NSERVERS;i++) { \ 1369 struct treetype *tree = servers[i].treefield[instance]; \ 1370 status[i] = call; \ 1371 } \ 1372 current_op.status = status[0]; \ 1373 for (i=1;i<NSERVERS;i++) { \ 1374 if (!compare_status(status[0], status[1])) { \ 1375 printf("status different in %s - %s %s\n", #call, \ 1376 nt_errstr(status[0]), nt_errstr(status[i])); \ 1377 current_op.mismatch = nt_errstr(status[0]); \ 1378 return false; \ 1379 } \ 1380 } \ 1381 if (!check_oplocks(#call)) return false; \ 1382 if (!check_notifies(#call)) return false; \ 1383 if (!NT_STATUS_IS_OK(status[0])) { \ 1384 return true; \ 1385 } \ 1386} while(0) 1387 1388#define GEN_CALL_SMB(call) GEN_CALL(call, smbcli_tree, smb_tree) 1389#define GEN_CALL_SMB2(call) GEN_CALL(call, smb2_tree, smb2_tree) 1390 1391#define ADD_HANDLE_SMB2(name, field) do { \ 1392 struct smb2_handle handles[NSERVERS]; \ 1393 int i; \ 1394 for (i=0;i<NSERVERS;i++) { \ 1395 handles[i] = parm[i].field; \ 1396 } \ 1397 gen_add_handle_smb2(instance, name, handles); \ 1398} while(0) 1399 1400#define REMOVE_HANDLE_SMB2(field) do { \ 1401 struct smb2_handle handles[NSERVERS]; \ 1402 int i; \ 1403 for (i=0;i<NSERVERS;i++) { \ 1404 handles[i] = parm[i].field; \ 1405 } \ 1406 gen_remove_handle_smb2(instance, handles); \ 1407} while(0) 1408 1409#define ADD_HANDLE_SMB(name, field) do { \ 1410 uint16_t handles[NSERVERS]; \ 1411 int i; \ 1412 for (i=0;i<NSERVERS;i++) { \ 1413 handles[i] = parm[i].field; \ 1414 } \ 1415 gen_add_handle_smb(instance, name, handles); \ 1416} while(0) 1417 1418#define REMOVE_HANDLE_SMB(field) do { \ 1419 uint16_t handles[NSERVERS]; \ 1420 int i; \ 1421 for (i=0;i<NSERVERS;i++) { \ 1422 handles[i] = parm[i].field; \ 1423 } \ 1424 gen_remove_handle_smb(instance, handles); \ 1425} while(0) 1426 1427#define GEN_SET_FNUM_SMB2(field) do { \ 1428 int i; \ 1429 for (i=0;i<NSERVERS;i++) { \ 1430 parm[i].field = gen_lookup_handle_smb2(i, parm[i].field.data[0]); \ 1431 } \ 1432} while(0) 1433 1434#define GEN_SET_FNUM_SMB(field) do { \ 1435 int i; \ 1436 for (i=0;i<NSERVERS;i++) { \ 1437 parm[i].field = gen_lookup_handle_smb(i, parm[i].field); \ 1438 } \ 1439} while(0) 1440 1441#define CHECK_EQUAL(field) do { \ 1442 if (parm[0].field != parm[1].field && !ignore_pattern(#field)) { \ 1443 current_op.mismatch = #field; \ 1444 printf("Mismatch in %s - 0x%llx 0x%llx\n", #field, \ 1445 (unsigned long long)parm[0].field, (unsigned long long)parm[1].field); \ 1446 return false; \ 1447 } \ 1448} while(0) 1449 1450#define CHECK_SECDESC(field) do { \ 1451 if (!security_acl_equal(parm[0].field->dacl, parm[1].field->dacl) && !ignore_pattern(#field)) { \ 1452 current_op.mismatch = #field; \ 1453 printf("Mismatch in %s\n", #field); \ 1454 return false; \ 1455 } \ 1456} while(0) 1457 1458#define CHECK_ATTRIB(field) do { \ 1459 if (!options.mask_indexing) { \ 1460 CHECK_EQUAL(field); \ 1461 } else if ((~FILE_ATTRIBUTE_NONINDEXED & parm[0].field) != (~FILE_ATTRIBUTE_NONINDEXED & parm[1].field) && !ignore_pattern(#field)) { \ 1462 current_op.mismatch = #field; \ 1463 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \ 1464 (int)parm[0].field, (int)parm[1].field); \ 1465 return false; \ 1466 } \ 1467} while(0) 1468 1469#define CHECK_WSTR_EQUAL(field) do { \ 1470 if ((!parm[0].field.s && parm[1].field.s) || (parm[0].field.s && !parm[1].field.s)) { \ 1471 current_op.mismatch = #field; \ 1472 printf("%s is NULL!\n", #field); \ 1473 return false; \ 1474 } \ 1475 if (parm[0].field.s && strcmp(parm[0].field.s, parm[1].field.s) != 0 && !ignore_pattern(#field)) { \ 1476 current_op.mismatch = #field; \ 1477 printf("Mismatch in %s - %s %s\n", #field, \ 1478 parm[0].field.s, parm[1].field.s); \ 1479 return false; \ 1480 } \ 1481 CHECK_EQUAL(field.private_length); \ 1482} while(0) 1483 1484#define CHECK_BLOB_EQUAL(field) do { \ 1485 if (((parm[0].field.data == NULL && parm[1].field.data != NULL) || \ 1486 (parm[1].field.data == NULL && parm[0].field.data != NULL) || \ 1487 (memcmp(parm[0].field.data, parm[1].field.data, parm[0].field.length) != 0)) && !ignore_pattern(#field)) { \ 1488 current_op.mismatch = #field; \ 1489 printf("Mismatch in %s\n", #field); \ 1490 return false; \ 1491 } \ 1492 CHECK_EQUAL(field.length); \ 1493} while(0) 1494 1495#define CHECK_TIMES_EQUAL(field) do { \ 1496 if (labs(parm[0].field - parm[1].field) > time_skew() && \ 1497 !ignore_pattern(#field)) { \ 1498 current_op.mismatch = #field; \ 1499 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \ 1500 (int)parm[0].field, (int)parm[1].field); \ 1501 return false; \ 1502 } \ 1503} while(0) 1504 1505#define CHECK_NTTIMES_EQUAL(field) do { \ 1506 if (labs(nt_time_to_unix(parm[0].field) - \ 1507 nt_time_to_unix(parm[1].field)) > time_skew() && \ 1508 !ignore_pattern(#field)) { \ 1509 current_op.mismatch = #field; \ 1510 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \ 1511 (int)nt_time_to_unix(parm[0].field), \ 1512 (int)nt_time_to_unix(parm[1].field)); \ 1513 return false; \ 1514 } \ 1515} while(0) 1516 1517 1518/* 1519 compare returned fileinfo structures 1520*/ 1521static bool cmp_fileinfo(int instance, 1522 union smb_fileinfo parm[NSERVERS], 1523 NTSTATUS status[NSERVERS]) 1524{ 1525 int i; 1526 enum smb_fileinfo_level level = parm[0].generic.level; 1527 1528 if (level == RAW_FILEINFO_ALL_INFORMATION && 1529 options.smb2) { 1530 level = RAW_FILEINFO_SMB2_ALL_INFORMATION; 1531 } 1532 1533 switch (level) { 1534 case RAW_FILEINFO_GENERIC: 1535 return false; 1536 1537 case RAW_FILEINFO_GETATTR: 1538 CHECK_ATTRIB(getattr.out.attrib); 1539 CHECK_EQUAL(getattr.out.size); 1540 CHECK_TIMES_EQUAL(getattr.out.write_time); 1541 break; 1542 1543 case RAW_FILEINFO_GETATTRE: 1544 CHECK_TIMES_EQUAL(getattre.out.create_time); 1545 CHECK_TIMES_EQUAL(getattre.out.access_time); 1546 CHECK_TIMES_EQUAL(getattre.out.write_time); 1547 CHECK_EQUAL(getattre.out.size); 1548 CHECK_EQUAL(getattre.out.alloc_size); 1549 CHECK_ATTRIB(getattre.out.attrib); 1550 break; 1551 1552 case RAW_FILEINFO_STANDARD: 1553 CHECK_TIMES_EQUAL(standard.out.create_time); 1554 CHECK_TIMES_EQUAL(standard.out.access_time); 1555 CHECK_TIMES_EQUAL(standard.out.write_time); 1556 CHECK_EQUAL(standard.out.size); 1557 CHECK_EQUAL(standard.out.alloc_size); 1558 CHECK_ATTRIB(standard.out.attrib); 1559 break; 1560 1561 case RAW_FILEINFO_EA_SIZE: 1562 CHECK_TIMES_EQUAL(ea_size.out.create_time); 1563 CHECK_TIMES_EQUAL(ea_size.out.access_time); 1564 CHECK_TIMES_EQUAL(ea_size.out.write_time); 1565 CHECK_EQUAL(ea_size.out.size); 1566 CHECK_EQUAL(ea_size.out.alloc_size); 1567 CHECK_ATTRIB(ea_size.out.attrib); 1568 CHECK_EQUAL(ea_size.out.ea_size); 1569 break; 1570 1571 case RAW_FILEINFO_ALL_EAS: 1572 CHECK_EQUAL(all_eas.out.num_eas); 1573 for (i=0;i<parm[0].all_eas.out.num_eas;i++) { 1574 CHECK_EQUAL(all_eas.out.eas[i].flags); 1575 CHECK_WSTR_EQUAL(all_eas.out.eas[i].name); 1576 CHECK_BLOB_EQUAL(all_eas.out.eas[i].value); 1577 } 1578 break; 1579 1580 case RAW_FILEINFO_IS_NAME_VALID: 1581 break; 1582 1583 case RAW_FILEINFO_BASIC_INFO: 1584 case RAW_FILEINFO_BASIC_INFORMATION: 1585 CHECK_NTTIMES_EQUAL(basic_info.out.create_time); 1586 CHECK_NTTIMES_EQUAL(basic_info.out.access_time); 1587 CHECK_NTTIMES_EQUAL(basic_info.out.write_time); 1588 CHECK_NTTIMES_EQUAL(basic_info.out.change_time); 1589 CHECK_ATTRIB(basic_info.out.attrib); 1590 break; 1591 1592 case RAW_FILEINFO_STANDARD_INFO: 1593 case RAW_FILEINFO_STANDARD_INFORMATION: 1594 CHECK_EQUAL(standard_info.out.alloc_size); 1595 CHECK_EQUAL(standard_info.out.size); 1596 CHECK_EQUAL(standard_info.out.nlink); 1597 CHECK_EQUAL(standard_info.out.delete_pending); 1598 CHECK_EQUAL(standard_info.out.directory); 1599 break; 1600 1601 case RAW_FILEINFO_EA_INFO: 1602 case RAW_FILEINFO_EA_INFORMATION: 1603 CHECK_EQUAL(ea_info.out.ea_size); 1604 break; 1605 1606 case RAW_FILEINFO_NAME_INFO: 1607 case RAW_FILEINFO_NAME_INFORMATION: 1608 CHECK_WSTR_EQUAL(name_info.out.fname); 1609 break; 1610 1611 case RAW_FILEINFO_ALL_INFO: 1612 case RAW_FILEINFO_ALL_INFORMATION: 1613 CHECK_NTTIMES_EQUAL(all_info.out.create_time); 1614 CHECK_NTTIMES_EQUAL(all_info.out.access_time); 1615 CHECK_NTTIMES_EQUAL(all_info.out.write_time); 1616 CHECK_NTTIMES_EQUAL(all_info.out.change_time); 1617 CHECK_ATTRIB(all_info.out.attrib); 1618 CHECK_EQUAL(all_info.out.alloc_size); 1619 CHECK_EQUAL(all_info.out.size); 1620 CHECK_EQUAL(all_info.out.nlink); 1621 CHECK_EQUAL(all_info.out.delete_pending); 1622 CHECK_EQUAL(all_info.out.directory); 1623 CHECK_EQUAL(all_info.out.ea_size); 1624 CHECK_WSTR_EQUAL(all_info.out.fname); 1625 break; 1626 1627 case RAW_FILEINFO_ALT_NAME_INFO: 1628 case RAW_FILEINFO_ALT_NAME_INFORMATION: 1629 CHECK_WSTR_EQUAL(alt_name_info.out.fname); 1630 break; 1631 1632 case RAW_FILEINFO_STREAM_INFO: 1633 case RAW_FILEINFO_STREAM_INFORMATION: 1634 CHECK_EQUAL(stream_info.out.num_streams); 1635 for (i=0;i<parm[0].stream_info.out.num_streams;i++) { 1636 CHECK_EQUAL(stream_info.out.streams[i].size); 1637 CHECK_EQUAL(stream_info.out.streams[i].alloc_size); 1638 CHECK_WSTR_EQUAL(stream_info.out.streams[i].stream_name); 1639 } 1640 break; 1641 1642 case RAW_FILEINFO_COMPRESSION_INFO: 1643 case RAW_FILEINFO_COMPRESSION_INFORMATION: 1644 CHECK_EQUAL(compression_info.out.compressed_size); 1645 CHECK_EQUAL(compression_info.out.format); 1646 CHECK_EQUAL(compression_info.out.unit_shift); 1647 CHECK_EQUAL(compression_info.out.chunk_shift); 1648 CHECK_EQUAL(compression_info.out.cluster_shift); 1649 break; 1650 1651 case RAW_FILEINFO_INTERNAL_INFORMATION: 1652 CHECK_EQUAL(internal_information.out.file_id); 1653 break; 1654 1655 case RAW_FILEINFO_ACCESS_INFORMATION: 1656 CHECK_EQUAL(access_information.out.access_flags); 1657 break; 1658 1659 case RAW_FILEINFO_POSITION_INFORMATION: 1660 CHECK_EQUAL(position_information.out.position); 1661 break; 1662 1663 case RAW_FILEINFO_MODE_INFORMATION: 1664 CHECK_EQUAL(mode_information.out.mode); 1665 break; 1666 1667 case RAW_FILEINFO_ALIGNMENT_INFORMATION: 1668 CHECK_EQUAL(alignment_information.out.alignment_requirement); 1669 break; 1670 1671 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION: 1672 CHECK_NTTIMES_EQUAL(network_open_information.out.create_time); 1673 CHECK_NTTIMES_EQUAL(network_open_information.out.access_time); 1674 CHECK_NTTIMES_EQUAL(network_open_information.out.write_time); 1675 CHECK_NTTIMES_EQUAL(network_open_information.out.change_time); 1676 CHECK_EQUAL(network_open_information.out.alloc_size); 1677 CHECK_EQUAL(network_open_information.out.size); 1678 CHECK_ATTRIB(network_open_information.out.attrib); 1679 break; 1680 1681 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION: 1682 CHECK_ATTRIB(attribute_tag_information.out.attrib); 1683 CHECK_EQUAL(attribute_tag_information.out.reparse_tag); 1684 break; 1685 1686 case RAW_FILEINFO_SMB2_ALL_INFORMATION: 1687 CHECK_NTTIMES_EQUAL(all_info2.out.create_time); 1688 CHECK_NTTIMES_EQUAL(all_info2.out.access_time); 1689 CHECK_NTTIMES_EQUAL(all_info2.out.write_time); 1690 CHECK_NTTIMES_EQUAL(all_info2.out.change_time); 1691 CHECK_ATTRIB(all_info2.out.attrib); 1692 CHECK_EQUAL(all_info2.out.unknown1); 1693 CHECK_EQUAL(all_info2.out.alloc_size); 1694 CHECK_EQUAL(all_info2.out.size); 1695 CHECK_EQUAL(all_info2.out.nlink); 1696 CHECK_EQUAL(all_info2.out.delete_pending); 1697 CHECK_EQUAL(all_info2.out.directory); 1698 CHECK_EQUAL(all_info2.out.file_id); 1699 CHECK_EQUAL(all_info2.out.ea_size); 1700 CHECK_EQUAL(all_info2.out.access_mask); 1701 CHECK_EQUAL(all_info2.out.position); 1702 CHECK_EQUAL(all_info2.out.mode); 1703 CHECK_EQUAL(all_info2.out.alignment_requirement); 1704 CHECK_WSTR_EQUAL(all_info2.out.fname); 1705 break; 1706 1707 case RAW_FILEINFO_SMB2_ALL_EAS: 1708 CHECK_EQUAL(all_eas.out.num_eas); 1709 for (i=0;i<parm[0].all_eas.out.num_eas;i++) { 1710 CHECK_EQUAL(all_eas.out.eas[i].flags); 1711 CHECK_WSTR_EQUAL(all_eas.out.eas[i].name); 1712 CHECK_BLOB_EQUAL(all_eas.out.eas[i].value); 1713 } 1714 break; 1715 1716 case RAW_FILEINFO_SEC_DESC: 1717 CHECK_SECDESC(query_secdesc.out.sd); 1718 break; 1719 1720 /* Unhandled levels */ 1721 case RAW_FILEINFO_EA_LIST: 1722 case RAW_FILEINFO_UNIX_BASIC: 1723 case RAW_FILEINFO_UNIX_LINK: 1724 case RAW_FILEINFO_UNIX_INFO2: 1725 break; 1726 } 1727 1728 return true; 1729} 1730 1731 1732 1733/* 1734 generate openx operations 1735*/ 1736static bool handler_smb_openx(int instance) 1737{ 1738 union smb_open parm[NSERVERS]; 1739 NTSTATUS status[NSERVERS]; 1740 1741 parm[0].openx.level = RAW_OPEN_OPENX; 1742 parm[0].openx.in.flags = gen_openx_flags(); 1743 parm[0].openx.in.open_mode = gen_openx_mode(); 1744 parm[0].openx.in.search_attrs = gen_attrib(); 1745 parm[0].openx.in.file_attrs = gen_attrib(); 1746 parm[0].openx.in.write_time = gen_timet(); 1747 parm[0].openx.in.open_func = gen_openx_func(); 1748 parm[0].openx.in.size = gen_io_count(); 1749 parm[0].openx.in.timeout = gen_timeout(); 1750 parm[0].openx.in.fname = gen_fname_open(instance); 1751 1752 if (!options.use_oplocks) { 1753 /* mask out oplocks */ 1754 parm[0].openx.in.flags &= ~(OPENX_FLAGS_REQUEST_OPLOCK| 1755 OPENX_FLAGS_REQUEST_BATCH_OPLOCK); 1756 } 1757 1758 GEN_COPY_PARM; 1759 GEN_CALL_SMB(smb_raw_open(tree, current_op.mem_ctx, &parm[i])); 1760 1761 CHECK_ATTRIB(openx.out.attrib); 1762 CHECK_EQUAL(openx.out.size); 1763 CHECK_EQUAL(openx.out.access); 1764 CHECK_EQUAL(openx.out.ftype); 1765 CHECK_EQUAL(openx.out.devstate); 1766 CHECK_EQUAL(openx.out.action); 1767 CHECK_EQUAL(openx.out.access_mask); 1768 CHECK_EQUAL(openx.out.unknown); 1769 CHECK_TIMES_EQUAL(openx.out.write_time); 1770 1771 /* open creates a new file handle */ 1772 ADD_HANDLE_SMB(parm[0].openx.in.fname, openx.out.file.fnum); 1773 1774 return true; 1775} 1776 1777 1778/* 1779 generate open operations 1780*/ 1781static bool handler_smb_open(int instance) 1782{ 1783 union smb_open parm[NSERVERS]; 1784 NTSTATUS status[NSERVERS]; 1785 1786 parm[0].openold.level = RAW_OPEN_OPEN; 1787 parm[0].openold.in.open_mode = gen_bits_mask2(0xF, 0xFFFF); 1788 parm[0].openold.in.search_attrs = gen_attrib(); 1789 parm[0].openold.in.fname = gen_fname_open(instance); 1790 1791 if (!options.use_oplocks) { 1792 /* mask out oplocks */ 1793 parm[0].openold.in.open_mode &= ~(OPENX_FLAGS_REQUEST_OPLOCK| 1794 OPENX_FLAGS_REQUEST_BATCH_OPLOCK); 1795 } 1796 1797 GEN_COPY_PARM; 1798 GEN_CALL_SMB(smb_raw_open(tree, current_op.mem_ctx, &parm[i])); 1799 1800 CHECK_ATTRIB(openold.out.attrib); 1801 CHECK_TIMES_EQUAL(openold.out.write_time); 1802 CHECK_EQUAL(openold.out.size); 1803 CHECK_EQUAL(openold.out.rmode); 1804 1805 /* open creates a new file handle */ 1806 ADD_HANDLE_SMB(parm[0].openold.in.fname, openold.out.file.fnum); 1807 1808 return true; 1809} 1810 1811 1812/* 1813 generate ntcreatex operations 1814*/ 1815static bool handler_smb_ntcreatex(int instance) 1816{ 1817 union smb_open parm[NSERVERS]; 1818 NTSTATUS status[NSERVERS]; 1819 1820 parm[0].ntcreatex.level = RAW_OPEN_NTCREATEX; 1821 parm[0].ntcreatex.in.flags = gen_ntcreatex_flags(); 1822 parm[0].ntcreatex.in.root_fid = gen_root_fid(instance); 1823 parm[0].ntcreatex.in.access_mask = gen_access_mask(); 1824 parm[0].ntcreatex.in.alloc_size = gen_alloc_size(); 1825 parm[0].ntcreatex.in.file_attr = gen_attrib(); 1826 parm[0].ntcreatex.in.share_access = gen_bits_mask2(0x7, 0xFFFFFFFF); 1827 parm[0].ntcreatex.in.open_disposition = gen_open_disp(); 1828 parm[0].ntcreatex.in.create_options = gen_create_options(); 1829 parm[0].ntcreatex.in.impersonation = gen_bits_mask2(0, 0xFFFFFFFF); 1830 parm[0].ntcreatex.in.security_flags = gen_bits_mask2(0, 0xFF); 1831 parm[0].ntcreatex.in.fname = gen_fname_open(instance); 1832 1833 if (!options.use_oplocks) { 1834 /* mask out oplocks */ 1835 parm[0].ntcreatex.in.flags &= ~(NTCREATEX_FLAGS_REQUEST_OPLOCK| 1836 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK); 1837 } 1838 1839 GEN_COPY_PARM; 1840 if (parm[0].ntcreatex.in.root_fid != 0) { 1841 GEN_SET_FNUM_SMB(ntcreatex.in.root_fid); 1842 } 1843 GEN_CALL_SMB(smb_raw_open(tree, current_op.mem_ctx, &parm[i])); 1844 1845 CHECK_EQUAL(ntcreatex.out.oplock_level); 1846 CHECK_EQUAL(ntcreatex.out.create_action); 1847 CHECK_NTTIMES_EQUAL(ntcreatex.out.create_time); 1848 CHECK_NTTIMES_EQUAL(ntcreatex.out.access_time); 1849 CHECK_NTTIMES_EQUAL(ntcreatex.out.write_time); 1850 CHECK_NTTIMES_EQUAL(ntcreatex.out.change_time); 1851 CHECK_ATTRIB(ntcreatex.out.attrib); 1852 CHECK_EQUAL(ntcreatex.out.alloc_size); 1853 CHECK_EQUAL(ntcreatex.out.size); 1854 CHECK_EQUAL(ntcreatex.out.file_type); 1855 CHECK_EQUAL(ntcreatex.out.ipc_state); 1856 CHECK_EQUAL(ntcreatex.out.is_directory); 1857 1858 /* ntcreatex creates a new file handle */ 1859 ADD_HANDLE_SMB(parm[0].ntcreatex.in.fname, ntcreatex.out.file.fnum); 1860 1861 return true; 1862} 1863 1864/* 1865 generate close operations 1866*/ 1867static bool handler_smb_close(int instance) 1868{ 1869 union smb_close parm[NSERVERS]; 1870 NTSTATUS status[NSERVERS]; 1871 1872 parm[0].close.level = RAW_CLOSE_CLOSE; 1873 parm[0].close.in.file.fnum = gen_fnum_close(instance); 1874 parm[0].close.in.write_time = gen_timet(); 1875 1876 GEN_COPY_PARM; 1877 GEN_SET_FNUM_SMB(close.in.file.fnum); 1878 GEN_CALL_SMB(smb_raw_close(tree, &parm[i])); 1879 1880 REMOVE_HANDLE_SMB(close.in.file.fnum); 1881 1882 return true; 1883} 1884 1885/* 1886 generate unlink operations 1887*/ 1888static bool handler_smb_unlink(int instance) 1889{ 1890 union smb_unlink parm[NSERVERS]; 1891 NTSTATUS status[NSERVERS]; 1892 1893 parm[0].unlink.in.pattern = gen_pattern(); 1894 parm[0].unlink.in.attrib = gen_attrib(); 1895 1896 GEN_COPY_PARM; 1897 GEN_CALL_SMB(smb_raw_unlink(tree, &parm[i])); 1898 1899 return true; 1900} 1901 1902/* 1903 generate chkpath operations 1904*/ 1905static bool handler_smb_chkpath(int instance) 1906{ 1907 union smb_chkpath parm[NSERVERS]; 1908 NTSTATUS status[NSERVERS]; 1909 1910 parm[0].chkpath.in.path = gen_fname_open(instance); 1911 1912 GEN_COPY_PARM; 1913 GEN_CALL_SMB(smb_raw_chkpath(tree, &parm[i])); 1914 1915 return true; 1916} 1917 1918/* 1919 generate mkdir operations 1920*/ 1921static bool handler_smb_mkdir(int instance) 1922{ 1923 union smb_mkdir parm[NSERVERS]; 1924 NTSTATUS status[NSERVERS]; 1925 1926 parm[0].mkdir.level = RAW_MKDIR_MKDIR; 1927 parm[0].mkdir.in.path = gen_fname_open(instance); 1928 1929 GEN_COPY_PARM; 1930 GEN_CALL_SMB(smb_raw_mkdir(tree, &parm[i])); 1931 1932 return true; 1933} 1934 1935/* 1936 generate rmdir operations 1937*/ 1938static bool handler_smb_rmdir(int instance) 1939{ 1940 struct smb_rmdir parm[NSERVERS]; 1941 NTSTATUS status[NSERVERS]; 1942 1943 parm[0].in.path = gen_fname_open(instance); 1944 1945 GEN_COPY_PARM; 1946 GEN_CALL_SMB(smb_raw_rmdir(tree, &parm[i])); 1947 1948 return true; 1949} 1950 1951/* 1952 generate rename operations 1953*/ 1954static bool handler_smb_rename(int instance) 1955{ 1956 union smb_rename parm[NSERVERS]; 1957 NTSTATUS status[NSERVERS]; 1958 1959 parm[0].generic.level = RAW_RENAME_RENAME; 1960 parm[0].rename.in.pattern1 = gen_pattern(); 1961 parm[0].rename.in.pattern2 = gen_pattern(); 1962 parm[0].rename.in.attrib = gen_attrib(); 1963 1964 GEN_COPY_PARM; 1965 GEN_CALL_SMB(smb_raw_rename(tree, &parm[i])); 1966 1967 return true; 1968} 1969 1970/* 1971 generate ntrename operations 1972*/ 1973static bool handler_smb_ntrename(int instance) 1974{ 1975 union smb_rename parm[NSERVERS]; 1976 NTSTATUS status[NSERVERS]; 1977 1978 parm[0].generic.level = RAW_RENAME_NTRENAME; 1979 parm[0].ntrename.in.old_name = gen_fname(); 1980 parm[0].ntrename.in.new_name = gen_fname(); 1981 parm[0].ntrename.in.attrib = gen_attrib(); 1982 parm[0].ntrename.in.cluster_size = gen_bits_mask2(0, 0xFFFFFFF); 1983 parm[0].ntrename.in.flags = gen_rename_flags(); 1984 1985 GEN_COPY_PARM; 1986 GEN_CALL_SMB(smb_raw_rename(tree, &parm[i])); 1987 1988 return true; 1989} 1990 1991 1992/* 1993 generate seek operations 1994*/ 1995static bool handler_smb_seek(int instance) 1996{ 1997 union smb_seek parm[NSERVERS]; 1998 NTSTATUS status[NSERVERS]; 1999 2000 parm[0].lseek.in.file.fnum = gen_fnum(instance); 2001 parm[0].lseek.in.mode = gen_bits_mask2(0x3, 0xFFFF); 2002 parm[0].lseek.in.offset = gen_offset(); 2003 2004 GEN_COPY_PARM; 2005 GEN_SET_FNUM_SMB(lseek.in.file.fnum); 2006 GEN_CALL_SMB(smb_raw_seek(tree, &parm[i])); 2007 2008 CHECK_EQUAL(lseek.out.offset); 2009 2010 return true; 2011} 2012 2013 2014/* 2015 generate readx operations 2016*/ 2017static bool handler_smb_readx(int instance) 2018{ 2019 union smb_read parm[NSERVERS]; 2020 NTSTATUS status[NSERVERS]; 2021 2022 parm[0].readx.level = RAW_READ_READX; 2023 parm[0].readx.in.file.fnum = gen_fnum(instance); 2024 parm[0].readx.in.offset = gen_offset(); 2025 parm[0].readx.in.mincnt = gen_io_count(); 2026 parm[0].readx.in.maxcnt = gen_io_count(); 2027 parm[0].readx.in.remaining = gen_io_count(); 2028 parm[0].readx.in.read_for_execute = gen_bool(); 2029 parm[0].readx.out.data = talloc_array(current_op.mem_ctx, uint8_t, 2030 MAX(parm[0].readx.in.mincnt, parm[0].readx.in.maxcnt)); 2031 2032 GEN_COPY_PARM; 2033 GEN_SET_FNUM_SMB(readx.in.file.fnum); 2034 GEN_CALL_SMB(smb_raw_read(tree, &parm[i])); 2035 2036 CHECK_EQUAL(readx.out.remaining); 2037 CHECK_EQUAL(readx.out.compaction_mode); 2038 CHECK_EQUAL(readx.out.nread); 2039 2040 return true; 2041} 2042 2043/* 2044 generate writex operations 2045*/ 2046static bool handler_smb_writex(int instance) 2047{ 2048 union smb_write parm[NSERVERS]; 2049 NTSTATUS status[NSERVERS]; 2050 2051 parm[0].writex.level = RAW_WRITE_WRITEX; 2052 parm[0].writex.in.file.fnum = gen_fnum(instance); 2053 parm[0].writex.in.offset = gen_offset(); 2054 parm[0].writex.in.wmode = gen_bits_mask(0xFFFF); 2055 parm[0].writex.in.remaining = gen_io_count(); 2056 parm[0].writex.in.count = gen_io_count(); 2057 parm[0].writex.in.data = talloc_zero_array(current_op.mem_ctx, uint8_t, parm[0].writex.in.count); 2058 2059 GEN_COPY_PARM; 2060 GEN_SET_FNUM_SMB(writex.in.file.fnum); 2061 GEN_CALL_SMB(smb_raw_write(tree, &parm[i])); 2062 2063 CHECK_EQUAL(writex.out.nwritten); 2064 CHECK_EQUAL(writex.out.remaining); 2065 2066 return true; 2067} 2068 2069/* 2070 generate lockingx operations 2071*/ 2072static bool handler_smb_lockingx(int instance) 2073{ 2074 union smb_lock parm[NSERVERS]; 2075 NTSTATUS status[NSERVERS]; 2076 int n, nlocks; 2077 2078 parm[0].lockx.level = RAW_LOCK_LOCKX; 2079 parm[0].lockx.in.file.fnum = gen_fnum(instance); 2080 parm[0].lockx.in.mode = gen_lock_mode(); 2081 parm[0].lockx.in.timeout = gen_timeout(); 2082 do { 2083 /* make sure we don't accidentially generate an oplock 2084 break ack - otherwise the server can just block forever */ 2085 parm[0].lockx.in.ulock_cnt = gen_lock_count(); 2086 parm[0].lockx.in.lock_cnt = gen_lock_count(); 2087 nlocks = parm[0].lockx.in.ulock_cnt + parm[0].lockx.in.lock_cnt; 2088 } while (nlocks == 0); 2089 2090 if (nlocks > 0) { 2091 parm[0].lockx.in.locks = talloc_array(current_op.mem_ctx, 2092 struct smb_lock_entry, 2093 nlocks); 2094 for (n=0;n<nlocks;n++) { 2095 parm[0].lockx.in.locks[n].pid = gen_pid(); 2096 parm[0].lockx.in.locks[n].offset = gen_offset(); 2097 parm[0].lockx.in.locks[n].count = gen_io_count(); 2098 } 2099 } 2100 2101 GEN_COPY_PARM; 2102 GEN_SET_FNUM_SMB(lockx.in.file.fnum); 2103 GEN_CALL_SMB(smb_raw_lock(tree, &parm[i])); 2104 2105 return true; 2106} 2107 2108#if 0 2109/* 2110 generate a fileinfo query structure 2111*/ 2112static void gen_setfileinfo(int instance, union smb_setfileinfo *info) 2113{ 2114 int i; 2115 #undef LVL 2116 #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v} 2117 struct { 2118 enum smb_setfileinfo_level level; 2119 const char *name; 2120 } levels[] = { 2121#if 0 2122 /* disabled until win2003 can handle them ... */ 2123 LVL(EA_SET), LVL(BASIC_INFO), LVL(DISPOSITION_INFO), 2124 LVL(STANDARD), LVL(ALLOCATION_INFO), LVL(END_OF_FILE_INFO), 2125#endif 2126 LVL(SETATTR), LVL(SETATTRE), LVL(BASIC_INFORMATION), 2127 LVL(RENAME_INFORMATION), LVL(DISPOSITION_INFORMATION), 2128 LVL(POSITION_INFORMATION), LVL(MODE_INFORMATION), 2129 LVL(ALLOCATION_INFORMATION), LVL(END_OF_FILE_INFORMATION), 2130 LVL(1023), LVL(1025), LVL(1029), LVL(1032), LVL(1039), LVL(1040) 2131 }; 2132 do { 2133 i = gen_int_range(0, ARRAY_SIZE(levels)-1); 2134 } while (ignore_pattern(levels[i].name)); 2135 2136 info->generic.level = levels[i].level; 2137 2138 switch (info->generic.level) { 2139 case RAW_SFILEINFO_SETATTR: 2140 info->setattr.in.attrib = gen_attrib(); 2141 info->setattr.in.write_time = gen_timet(); 2142 break; 2143 case RAW_SFILEINFO_SETATTRE: 2144 info->setattre.in.create_time = gen_timet(); 2145 info->setattre.in.access_time = gen_timet(); 2146 info->setattre.in.write_time = gen_timet(); 2147 break; 2148 case RAW_SFILEINFO_STANDARD: 2149 info->standard.in.create_time = gen_timet(); 2150 info->standard.in.access_time = gen_timet(); 2151 info->standard.in.write_time = gen_timet(); 2152 break; 2153 case RAW_SFILEINFO_EA_SET: { 2154 static struct ea_struct ea; 2155 info->ea_set.in.num_eas = 1; 2156 info->ea_set.in.eas = &ea; 2157 info->ea_set.in.eas[0] = gen_ea_struct(); 2158 } 2159 break; 2160 case RAW_SFILEINFO_BASIC_INFO: 2161 case RAW_SFILEINFO_BASIC_INFORMATION: 2162 info->basic_info.in.create_time = gen_nttime(); 2163 info->basic_info.in.access_time = gen_nttime(); 2164 info->basic_info.in.write_time = gen_nttime(); 2165 info->basic_info.in.change_time = gen_nttime(); 2166 info->basic_info.in.attrib = gen_attrib(); 2167 break; 2168 case RAW_SFILEINFO_DISPOSITION_INFO: 2169 case RAW_SFILEINFO_DISPOSITION_INFORMATION: 2170 info->disposition_info.in.delete_on_close = gen_bool(); 2171 break; 2172 case RAW_SFILEINFO_ALLOCATION_INFO: 2173 case RAW_SFILEINFO_ALLOCATION_INFORMATION: 2174 info->allocation_info.in.alloc_size = gen_alloc_size(); 2175 break; 2176 case RAW_SFILEINFO_END_OF_FILE_INFO: 2177 case RAW_SFILEINFO_END_OF_FILE_INFORMATION: 2178 info->end_of_file_info.in.size = gen_offset(); 2179 break; 2180 case RAW_SFILEINFO_RENAME_INFORMATION: 2181 case RAW_SFILEINFO_RENAME_INFORMATION_SMB2: 2182 info->rename_information.in.overwrite = gen_bool(); 2183 info->rename_information.in.root_fid = gen_root_fid(instance); 2184 info->rename_information.in.new_name = gen_fname_open(instance); 2185 break; 2186 case RAW_SFILEINFO_POSITION_INFORMATION: 2187 info->position_information.in.position = gen_offset(); 2188 break; 2189 case RAW_SFILEINFO_MODE_INFORMATION: 2190 info->mode_information.in.mode = gen_bits_mask(0xFFFFFFFF); 2191 break; 2192 case RAW_SFILEINFO_FULL_EA_INFORMATION: 2193 info->full_ea_information.in.eas = gen_ea_list(); 2194 break; 2195 case RAW_SFILEINFO_GENERIC: 2196 case RAW_SFILEINFO_SEC_DESC: 2197 case RAW_SFILEINFO_UNIX_BASIC: 2198 case RAW_SFILEINFO_UNIX_LINK: 2199 case RAW_SFILEINFO_UNIX_HLINK: 2200 case RAW_SFILEINFO_1023: 2201 case RAW_SFILEINFO_1025: 2202 case RAW_SFILEINFO_1029: 2203 case RAW_SFILEINFO_1032: 2204 case RAW_SFILEINFO_1039: 2205 case RAW_SFILEINFO_1040: 2206 case RAW_SFILEINFO_UNIX_INFO2: 2207 /* Untested */ 2208 break; 2209 } 2210} 2211#endif 2212 2213/* 2214 generate a fileinfo query structure 2215*/ 2216static void gen_setfileinfo(int instance, union smb_setfileinfo *info) 2217{ 2218 int i; 2219 #undef LVL 2220 #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v} 2221 struct levels { 2222 enum smb_setfileinfo_level level; 2223 const char *name; 2224 }; 2225 struct levels smb_levels[] = { 2226 LVL(EA_SET), LVL(BASIC_INFO), LVL(DISPOSITION_INFO), 2227 LVL(STANDARD), LVL(ALLOCATION_INFO), LVL(END_OF_FILE_INFO), 2228 LVL(SETATTR), LVL(SETATTRE), LVL(BASIC_INFORMATION), 2229 LVL(RENAME_INFORMATION), LVL(DISPOSITION_INFORMATION), 2230 LVL(POSITION_INFORMATION), LVL(FULL_EA_INFORMATION), LVL(MODE_INFORMATION), 2231 LVL(ALLOCATION_INFORMATION), LVL(END_OF_FILE_INFORMATION), 2232 LVL(PIPE_INFORMATION), LVL(VALID_DATA_INFORMATION), LVL(SHORT_NAME_INFORMATION), 2233 LVL(1025), LVL(1027), LVL(1029), LVL(1030), LVL(1031), LVL(1032), LVL(1036), 2234 LVL(1041), LVL(1042), LVL(1043), LVL(1044), 2235 }; 2236 struct levels smb2_levels[] = { 2237 LVL(BASIC_INFORMATION), 2238 LVL(RENAME_INFORMATION), LVL(DISPOSITION_INFORMATION), 2239 LVL(POSITION_INFORMATION), LVL(FULL_EA_INFORMATION), LVL(MODE_INFORMATION), 2240 LVL(ALLOCATION_INFORMATION), LVL(END_OF_FILE_INFORMATION), 2241 LVL(PIPE_INFORMATION), LVL(VALID_DATA_INFORMATION), LVL(SHORT_NAME_INFORMATION), 2242 LVL(1025), LVL(1027), LVL(1029), LVL(1030), LVL(1031), LVL(1032), LVL(1036), 2243 LVL(1041), LVL(1042), LVL(1043), LVL(1044), 2244 }; 2245 struct levels *levels = options.smb2?smb2_levels:smb_levels; 2246 uint32_t num_levels = options.smb2?ARRAY_SIZE(smb2_levels):ARRAY_SIZE(smb_levels); 2247 2248 do { 2249 i = gen_int_range(0, num_levels-1); 2250 } while (ignore_pattern(levels[i].name)); 2251 2252 ZERO_STRUCTP(info); 2253 info->generic.level = levels[i].level; 2254 2255 switch (info->generic.level) { 2256 case RAW_SFILEINFO_SETATTR: 2257 info->setattr.in.attrib = gen_attrib(); 2258 info->setattr.in.write_time = gen_timet(); 2259 break; 2260 case RAW_SFILEINFO_SETATTRE: 2261 info->setattre.in.create_time = gen_timet(); 2262 info->setattre.in.access_time = gen_timet(); 2263 info->setattre.in.write_time = gen_timet(); 2264 break; 2265 case RAW_SFILEINFO_STANDARD: 2266 info->standard.in.create_time = gen_timet(); 2267 info->standard.in.access_time = gen_timet(); 2268 info->standard.in.write_time = gen_timet(); 2269 break; 2270 case RAW_SFILEINFO_EA_SET: { 2271 static struct ea_struct ea; 2272 info->ea_set.in.num_eas = 1; 2273 info->ea_set.in.eas = &ea; 2274 info->ea_set.in.eas[0] = gen_ea_struct(); 2275 break; 2276 } 2277 case RAW_SFILEINFO_BASIC_INFO: 2278 case RAW_SFILEINFO_BASIC_INFORMATION: 2279 info->basic_info.in.create_time = gen_nttime(); 2280 info->basic_info.in.access_time = gen_nttime(); 2281 info->basic_info.in.write_time = gen_nttime(); 2282 info->basic_info.in.change_time = gen_nttime(); 2283 info->basic_info.in.attrib = gen_attrib(); 2284 break; 2285 case RAW_SFILEINFO_DISPOSITION_INFO: 2286 case RAW_SFILEINFO_DISPOSITION_INFORMATION: 2287 info->disposition_info.in.delete_on_close = gen_bool(); 2288 break; 2289 case RAW_SFILEINFO_ALLOCATION_INFO: 2290 case RAW_SFILEINFO_ALLOCATION_INFORMATION: 2291 info->allocation_info.in.alloc_size = gen_alloc_size(); 2292 break; 2293 case RAW_SFILEINFO_END_OF_FILE_INFO: 2294 case RAW_SFILEINFO_END_OF_FILE_INFORMATION: 2295 info->end_of_file_info.in.size = gen_offset(); 2296 break; 2297 case RAW_SFILEINFO_RENAME_INFORMATION: 2298 case RAW_SFILEINFO_RENAME_INFORMATION_SMB2: 2299 info->rename_information.in.overwrite = gen_bool(); 2300 info->rename_information.in.root_fid = gen_root_fid(instance); 2301 info->rename_information.in.new_name = gen_fname_open(instance); 2302 break; 2303 case RAW_SFILEINFO_POSITION_INFORMATION: 2304 info->position_information.in.position = gen_offset(); 2305 break; 2306 case RAW_SFILEINFO_MODE_INFORMATION: 2307 info->mode_information.in.mode = gen_bits_mask(0xFFFFFFFF); 2308 break; 2309 case RAW_SFILEINFO_FULL_EA_INFORMATION: 2310 info->full_ea_information.in.eas = gen_ea_list(); 2311 break; 2312 2313 case RAW_SFILEINFO_GENERIC: 2314 case RAW_SFILEINFO_SEC_DESC: 2315 case RAW_SFILEINFO_1025: 2316 case RAW_SFILEINFO_1029: 2317 case RAW_SFILEINFO_1032: 2318 case RAW_SFILEINFO_UNIX_BASIC: 2319 case RAW_SFILEINFO_UNIX_INFO2: 2320 case RAW_SFILEINFO_UNIX_LINK: 2321 case RAW_SFILEINFO_UNIX_HLINK: 2322 /* Untested */ 2323 break; 2324 } 2325} 2326 2327 2328 2329/* 2330 generate a fileinfo query structure 2331*/ 2332static void gen_fileinfo_smb(int instance, union smb_fileinfo *info) 2333{ 2334 int i; 2335 #undef LVL 2336 #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v} 2337 struct { 2338 enum smb_fileinfo_level level; 2339 const char *name; 2340 } levels[] = { 2341 LVL(GETATTR), LVL(GETATTRE), LVL(STANDARD), 2342 LVL(EA_SIZE), LVL(ALL_EAS), LVL(IS_NAME_VALID), 2343 LVL(BASIC_INFO), LVL(STANDARD_INFO), LVL(EA_INFO), 2344 LVL(NAME_INFO), LVL(ALL_INFO), LVL(ALT_NAME_INFO), 2345 LVL(STREAM_INFO), LVL(COMPRESSION_INFO), LVL(BASIC_INFORMATION), 2346 LVL(STANDARD_INFORMATION), LVL(INTERNAL_INFORMATION), LVL(EA_INFORMATION), 2347 LVL(ACCESS_INFORMATION), LVL(NAME_INFORMATION), LVL(POSITION_INFORMATION), 2348 LVL(MODE_INFORMATION), LVL(ALIGNMENT_INFORMATION), LVL(ALL_INFORMATION), 2349 LVL(ALT_NAME_INFORMATION), LVL(STREAM_INFORMATION), LVL(COMPRESSION_INFORMATION), 2350 LVL(NETWORK_OPEN_INFORMATION), LVL(ATTRIBUTE_TAG_INFORMATION) 2351 }; 2352 do { 2353 i = gen_int_range(0, ARRAY_SIZE(levels)-1); 2354 } while (ignore_pattern(levels[i].name)); 2355 2356 info->generic.level = levels[i].level; 2357} 2358 2359/* 2360 generate qpathinfo operations 2361*/ 2362static bool handler_smb_qpathinfo(int instance) 2363{ 2364 union smb_fileinfo parm[NSERVERS]; 2365 NTSTATUS status[NSERVERS]; 2366 2367 parm[0].generic.in.file.path = gen_fname_open(instance); 2368 2369 gen_fileinfo_smb(instance, &parm[0]); 2370 2371 GEN_COPY_PARM; 2372 GEN_CALL_SMB(smb_raw_pathinfo(tree, current_op.mem_ctx, &parm[i])); 2373 2374 return cmp_fileinfo(instance, parm, status); 2375} 2376 2377/* 2378 generate qfileinfo operations 2379*/ 2380static bool handler_smb_qfileinfo(int instance) 2381{ 2382 union smb_fileinfo parm[NSERVERS]; 2383 NTSTATUS status[NSERVERS]; 2384 2385 parm[0].generic.in.file.fnum = gen_fnum(instance); 2386 2387 gen_fileinfo_smb(instance, &parm[0]); 2388 2389 GEN_COPY_PARM; 2390 GEN_SET_FNUM_SMB(generic.in.file.fnum); 2391 GEN_CALL_SMB(smb_raw_fileinfo(tree, current_op.mem_ctx, &parm[i])); 2392 2393 return cmp_fileinfo(instance, parm, status); 2394} 2395 2396 2397/* 2398 generate setpathinfo operations 2399*/ 2400static bool handler_smb_spathinfo(int instance) 2401{ 2402 union smb_setfileinfo parm[NSERVERS]; 2403 NTSTATUS status[NSERVERS]; 2404 2405 gen_setfileinfo(instance, &parm[0]); 2406 parm[0].generic.in.file.path = gen_fname_open(instance); 2407 2408 GEN_COPY_PARM; 2409 2410 /* a special case for the fid in a RENAME */ 2411 if (parm[0].generic.level == RAW_SFILEINFO_RENAME_INFORMATION && 2412 parm[0].rename_information.in.root_fid != 0) { 2413 GEN_SET_FNUM_SMB(rename_information.in.root_fid); 2414 } 2415 2416 GEN_CALL_SMB(smb_raw_setpathinfo(tree, &parm[i])); 2417 2418 return true; 2419} 2420 2421 2422/* 2423 generate setfileinfo operations 2424*/ 2425static bool handler_smb_sfileinfo(int instance) 2426{ 2427 union smb_setfileinfo parm[NSERVERS]; 2428 NTSTATUS status[NSERVERS]; 2429 2430 parm[0].generic.in.file.fnum = gen_fnum(instance); 2431 2432 gen_setfileinfo(instance, &parm[0]); 2433 2434 GEN_COPY_PARM; 2435 GEN_SET_FNUM_SMB(generic.in.file.fnum); 2436 GEN_CALL_SMB(smb_raw_setfileinfo(tree, &parm[i])); 2437 2438 return true; 2439} 2440 2441 2442/* 2443 this is called when a change notify reply comes in 2444*/ 2445static void async_notify_smb(struct smbcli_request *req) 2446{ 2447 union smb_notify notify; 2448 NTSTATUS status; 2449 int i, j; 2450 uint16_t tid; 2451 struct smbcli_transport *transport = req->transport; 2452 2453 tid = SVAL(req->in.hdr, HDR_TID); 2454 2455 notify.nttrans.level = RAW_NOTIFY_NTTRANS; 2456 status = smb_raw_changenotify_recv(req, current_op.mem_ctx, ¬ify); 2457 if (NT_STATUS_IS_OK(status) && notify.nttrans.out.num_changes > 0) { 2458 printf("notify tid=%d num_changes=%d action=%d name=%s\n", 2459 tid, 2460 notify.nttrans.out.num_changes, 2461 notify.nttrans.out.changes[0].action, 2462 notify.nttrans.out.changes[0].name.s); 2463 } 2464 2465 for (i=0;i<NSERVERS;i++) { 2466 for (j=0;j<NINSTANCES;j++) { 2467 if (transport == servers[i].smb_tree[j]->session->transport && 2468 tid == servers[i].smb_tree[j]->tid) { 2469 notifies[i][j].notify_count++; 2470 notifies[i][j].status = status; 2471 notifies[i][j].notify = notify; 2472 } 2473 } 2474 } 2475} 2476 2477/* 2478 generate change notify operations 2479*/ 2480static bool handler_smb_notify(int instance) 2481{ 2482 union smb_notify parm[NSERVERS]; 2483 int n; 2484 2485 ZERO_STRUCT(parm[0]); 2486 parm[0].nttrans.level = RAW_NOTIFY_NTTRANS; 2487 parm[0].nttrans.in.buffer_size = gen_io_count(); 2488 parm[0].nttrans.in.completion_filter = gen_bits_mask(0xFF); 2489 parm[0].nttrans.in.file.fnum = gen_fnum(instance); 2490 parm[0].nttrans.in.recursive = gen_bool(); 2491 2492 GEN_COPY_PARM; 2493 GEN_SET_FNUM_SMB(nttrans.in.file.fnum); 2494 2495 for (n=0;n<NSERVERS;n++) { 2496 struct smbcli_request *req; 2497 req = smb_raw_changenotify_send(servers[n].smb_tree[instance], &parm[n]); 2498 req->async.fn = async_notify_smb; 2499 } 2500 2501 return true; 2502} 2503 2504 2505/* 2506 generate ntcreatex operations 2507*/ 2508static bool handler_smb2_create(int instance) 2509{ 2510 struct smb2_create parm[NSERVERS]; 2511 NTSTATUS status[NSERVERS]; 2512 2513 ZERO_STRUCT(parm[0]); 2514 parm[0].in.security_flags = gen_bits_levels(3, 90, 0x0, 70, 0x3, 100, 0xFF); 2515 parm[0].in.oplock_level = gen_bits_levels(3, 90, 0x0, 70, 0x9, 100, 0xFF); 2516 parm[0].in.impersonation_level = gen_bits_levels(3, 90, 0x0, 70, 0x3, 100, 0xFFFFFFFF); 2517 parm[0].in.create_flags = gen_reserved64(); 2518 parm[0].in.reserved = gen_reserved64(); 2519 parm[0].in.desired_access = gen_access_mask(); 2520 parm[0].in.file_attributes = gen_attrib(); 2521 parm[0].in.share_access = gen_bits_mask2(0x7, 0xFFFFFFFF); 2522 parm[0].in.create_disposition = gen_open_disp(); 2523 parm[0].in.create_options = gen_create_options(); 2524 parm[0].in.fname = gen_fname_open(instance); 2525 parm[0].in.eas = gen_ea_list(); 2526 parm[0].in.alloc_size = gen_alloc_size(); 2527 parm[0].in.durable_open = gen_bool(); 2528 parm[0].in.query_maximal_access = gen_bool(); 2529 parm[0].in.timewarp = gen_timewarp(); 2530 parm[0].in.query_on_disk_id = gen_bool(); 2531 parm[0].in.sec_desc = gen_sec_desc(); 2532 2533 if (!options.use_oplocks) { 2534 /* mask out oplocks */ 2535 parm[0].in.oplock_level = 0; 2536 } 2537 2538 if (options.valid) { 2539 parm[0].in.security_flags &= 3; 2540 parm[0].in.oplock_level &= 9; 2541 parm[0].in.impersonation_level &= 3; 2542 } 2543 2544 GEN_COPY_PARM; 2545 GEN_CALL_SMB2(smb2_create(tree, current_op.mem_ctx, &parm[i])); 2546 2547 CHECK_EQUAL(out.oplock_level); 2548 CHECK_EQUAL(out.reserved); 2549 CHECK_EQUAL(out.create_action); 2550 CHECK_NTTIMES_EQUAL(out.create_time); 2551 CHECK_NTTIMES_EQUAL(out.access_time); 2552 CHECK_NTTIMES_EQUAL(out.write_time); 2553 CHECK_NTTIMES_EQUAL(out.change_time); 2554 CHECK_EQUAL(out.alloc_size); 2555 CHECK_EQUAL(out.size); 2556 CHECK_ATTRIB(out.file_attr); 2557 CHECK_EQUAL(out.reserved2); 2558 CHECK_EQUAL(out.maximal_access); 2559 2560 /* ntcreatex creates a new file handle */ 2561 ADD_HANDLE_SMB2(parm[0].in.fname, out.file.handle); 2562 2563 return true; 2564} 2565 2566/* 2567 generate close operations 2568*/ 2569static bool handler_smb2_close(int instance) 2570{ 2571 struct smb2_close parm[NSERVERS]; 2572 NTSTATUS status[NSERVERS]; 2573 2574 ZERO_STRUCT(parm[0]); 2575 parm[0].in.file.handle.data[0] = gen_fnum_close(instance); 2576 parm[0].in.flags = gen_bits_mask2(0x1, 0xFFFF); 2577 2578 GEN_COPY_PARM; 2579 GEN_SET_FNUM_SMB2(in.file.handle); 2580 GEN_CALL_SMB2(smb2_close(tree, &parm[i])); 2581 2582 CHECK_EQUAL(out.flags); 2583 CHECK_EQUAL(out._pad); 2584 CHECK_NTTIMES_EQUAL(out.create_time); 2585 CHECK_NTTIMES_EQUAL(out.access_time); 2586 CHECK_NTTIMES_EQUAL(out.write_time); 2587 CHECK_NTTIMES_EQUAL(out.change_time); 2588 CHECK_EQUAL(out.alloc_size); 2589 CHECK_EQUAL(out.size); 2590 CHECK_ATTRIB(out.file_attr); 2591 2592 REMOVE_HANDLE_SMB2(in.file.handle); 2593 2594 return true; 2595} 2596 2597/* 2598 generate read operations 2599*/ 2600static bool handler_smb2_read(int instance) 2601{ 2602 struct smb2_read parm[NSERVERS]; 2603 NTSTATUS status[NSERVERS]; 2604 2605 parm[0].in.file.handle.data[0] = gen_fnum(instance); 2606 parm[0].in.reserved = gen_reserved8(); 2607 parm[0].in.length = gen_io_count(); 2608 parm[0].in.offset = gen_offset(); 2609 parm[0].in.min_count = gen_io_count(); 2610 parm[0].in.channel = gen_bits_mask2(0x0, 0xFFFFFFFF); 2611 parm[0].in.remaining = gen_bits_mask2(0x0, 0xFFFFFFFF); 2612 parm[0].in.channel_offset = gen_bits_mask2(0x0, 0xFFFF); 2613 parm[0].in.channel_length = gen_bits_mask2(0x0, 0xFFFF); 2614 2615 GEN_COPY_PARM; 2616 GEN_SET_FNUM_SMB2(in.file.handle); 2617 GEN_CALL_SMB2(smb2_read(tree, current_op.mem_ctx, &parm[i])); 2618 2619 CHECK_EQUAL(out.remaining); 2620 CHECK_EQUAL(out.reserved); 2621 CHECK_EQUAL(out.data.length); 2622 2623 return true; 2624} 2625 2626/* 2627 generate write operations 2628*/ 2629static bool handler_smb2_write(int instance) 2630{ 2631 struct smb2_write parm[NSERVERS]; 2632 NTSTATUS status[NSERVERS]; 2633 2634 parm[0].in.file.handle.data[0] = gen_fnum(instance); 2635 parm[0].in.offset = gen_offset(); 2636 parm[0].in.unknown1 = gen_bits_mask2(0, 0xFFFFFFFF); 2637 parm[0].in.unknown2 = gen_bits_mask2(0, 0xFFFFFFFF); 2638 parm[0].in.data = data_blob_talloc(current_op.mem_ctx, NULL, 2639 gen_io_count()); 2640 2641 GEN_COPY_PARM; 2642 GEN_SET_FNUM_SMB2(in.file.handle); 2643 GEN_CALL_SMB2(smb2_write(tree, &parm[i])); 2644 2645 CHECK_EQUAL(out._pad); 2646 CHECK_EQUAL(out.nwritten); 2647 CHECK_EQUAL(out.unknown1); 2648 2649 return true; 2650} 2651 2652/* 2653 generate lockingx operations 2654*/ 2655static bool handler_smb2_lock(int instance) 2656{ 2657 struct smb2_lock parm[NSERVERS]; 2658 NTSTATUS status[NSERVERS]; 2659 int n; 2660 2661 parm[0].level = RAW_LOCK_LOCKX; 2662 parm[0].in.file.handle.data[0] = gen_fnum(instance); 2663 parm[0].in.lock_count = gen_lock_count(); 2664 parm[0].in.reserved = gen_reserved32(); 2665 2666 parm[0].in.locks = talloc_array(current_op.mem_ctx, 2667 struct smb2_lock_element, 2668 parm[0].in.lock_count); 2669 for (n=0;n<parm[0].in.lock_count;n++) { 2670 parm[0].in.locks[n].offset = gen_offset(); 2671 parm[0].in.locks[n].length = gen_io_count(); 2672 /* don't yet cope with async replies */ 2673 parm[0].in.locks[n].flags = gen_lock_flags_smb2() | 2674 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY; 2675 parm[0].in.locks[n].reserved = gen_bits_mask2(0x0, 0xFFFFFFFF); 2676 } 2677 2678 GEN_COPY_PARM; 2679 GEN_SET_FNUM_SMB2(in.file.handle); 2680 GEN_CALL_SMB2(smb2_lock(tree, &parm[i])); 2681 2682 return true; 2683} 2684 2685/* 2686 generate flush operations 2687*/ 2688static bool handler_smb2_flush(int instance) 2689{ 2690 struct smb2_flush parm[NSERVERS]; 2691 NTSTATUS status[NSERVERS]; 2692 2693 ZERO_STRUCT(parm[0]); 2694 parm[0].in.file.handle.data[0] = gen_fnum(instance); 2695 parm[0].in.reserved1 = gen_reserved16(); 2696 parm[0].in.reserved2 = gen_reserved32(); 2697 2698 GEN_COPY_PARM; 2699 GEN_SET_FNUM_SMB2(in.file.handle); 2700 GEN_CALL_SMB2(smb2_flush(tree, &parm[i])); 2701 2702 CHECK_EQUAL(out.reserved); 2703 2704 return true; 2705} 2706 2707/* 2708 generate echo operations 2709*/ 2710static bool handler_smb2_echo(int instance) 2711{ 2712 NTSTATUS status[NSERVERS]; 2713 2714 GEN_CALL_SMB2(smb2_keepalive(tree->session->transport)); 2715 2716 return true; 2717} 2718 2719 2720 2721/* 2722 generate a fileinfo query structure 2723*/ 2724static void gen_fileinfo_smb2(int instance, union smb_fileinfo *info) 2725{ 2726 int i; 2727 #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v} 2728 struct { 2729 enum smb_fileinfo_level level; 2730 const char *name; 2731 } levels[] = { 2732 LVL(BASIC_INFORMATION), 2733 LVL(STANDARD_INFORMATION), LVL(INTERNAL_INFORMATION), LVL(EA_INFORMATION), 2734 LVL(ACCESS_INFORMATION), LVL(NAME_INFORMATION), LVL(POSITION_INFORMATION), 2735 LVL(MODE_INFORMATION), LVL(ALIGNMENT_INFORMATION), LVL(SMB2_ALL_INFORMATION), 2736 LVL(ALT_NAME_INFORMATION), LVL(STREAM_INFORMATION), LVL(COMPRESSION_INFORMATION), 2737 LVL(NETWORK_OPEN_INFORMATION), LVL(ATTRIBUTE_TAG_INFORMATION), 2738 LVL(SMB2_ALL_EAS), LVL(SMB2_ALL_INFORMATION), LVL(SEC_DESC), 2739 }; 2740 do { 2741 i = gen_int_range(0, ARRAY_SIZE(levels)-1); 2742 } while (ignore_pattern(levels[i].name)); 2743 2744 info->generic.level = levels[i].level; 2745} 2746 2747/* 2748 generate qfileinfo operations 2749*/ 2750static bool handler_smb2_qfileinfo(int instance) 2751{ 2752 union smb_fileinfo parm[NSERVERS]; 2753 NTSTATUS status[NSERVERS]; 2754 2755 parm[0].generic.in.file.handle.data[0] = gen_fnum(instance); 2756 2757 gen_fileinfo_smb2(instance, &parm[0]); 2758 2759 GEN_COPY_PARM; 2760 GEN_SET_FNUM_SMB2(generic.in.file.handle); 2761 GEN_CALL_SMB2(smb2_getinfo_file(tree, current_op.mem_ctx, &parm[i])); 2762 2763 return cmp_fileinfo(instance, parm, status); 2764} 2765 2766 2767/* 2768 generate setfileinfo operations 2769*/ 2770static bool handler_smb2_sfileinfo(int instance) 2771{ 2772 union smb_setfileinfo parm[NSERVERS]; 2773 NTSTATUS status[NSERVERS]; 2774 2775 gen_setfileinfo(instance, &parm[0]); 2776 parm[0].generic.in.file.fnum = gen_fnum(instance); 2777 2778 GEN_COPY_PARM; 2779 GEN_SET_FNUM_SMB2(generic.in.file.handle); 2780 GEN_CALL_SMB2(smb2_setinfo_file(tree, &parm[i])); 2781 2782 return true; 2783} 2784 2785/* 2786 wipe any relevant files 2787*/ 2788static void wipe_files(void) 2789{ 2790 int i; 2791 NTSTATUS status; 2792 2793 if (options.skip_cleanup) { 2794 return; 2795 } 2796 2797 for (i=0;i<NSERVERS;i++) { 2798 int n; 2799 if (options.smb2) { 2800 n = smb2_deltree(servers[i].smb2_tree[0], "gentest"); 2801 } else { 2802 n = smbcli_deltree(servers[i].smb_tree[0], "gentest"); 2803 } 2804 if (n == -1) { 2805 printf("Failed to wipe tree on server %d\n", i); 2806 exit(1); 2807 } 2808 if (options.smb2) { 2809 status = smb2_util_mkdir(servers[i].smb2_tree[0], "gentest"); 2810 } else { 2811 status = smbcli_mkdir(servers[i].smb_tree[0], "gentest"); 2812 } 2813 if (NT_STATUS_IS_ERR(status)) { 2814 printf("Failed to create gentest on server %d - %s\n", i, nt_errstr(status)); 2815 exit(1); 2816 } 2817 if (n > 0) { 2818 printf("Deleted %d files on server %d\n", n, i); 2819 } 2820 } 2821} 2822 2823/* 2824 dump the current seeds - useful for continuing a backtrack 2825*/ 2826static void dump_seeds(void) 2827{ 2828 int i; 2829 FILE *f; 2830 2831 if (!options.seeds_file) { 2832 return; 2833 } 2834 f = fopen("seeds.tmp", "w"); 2835 if (!f) return; 2836 2837 for (i=0;i<options.numops;i++) { 2838 fprintf(f, "%u\n", op_parms[i].seed); 2839 } 2840 fclose(f); 2841 rename("seeds.tmp", options.seeds_file); 2842} 2843 2844 2845 2846/* 2847 the list of top-level operations that we will generate 2848*/ 2849static struct { 2850 const char *name; 2851 bool (*handler)(int instance); 2852 bool smb2; 2853 int count, success_count; 2854} gen_ops[] = { 2855 {"CREATE", handler_smb2_create, true}, 2856 {"CLOSE", handler_smb2_close, true}, 2857 {"READ", handler_smb2_read, true}, 2858 {"WRITE", handler_smb2_write, true}, 2859 {"LOCK", handler_smb2_lock, true}, 2860 {"FLUSH", handler_smb2_flush, true}, 2861 {"ECHO", handler_smb2_echo, true}, 2862 {"QFILEINFO", handler_smb2_qfileinfo, true}, 2863 {"SFILEINFO", handler_smb2_sfileinfo, true}, 2864 2865 {"OPEN", handler_smb_open, false}, 2866 {"OPENX", handler_smb_openx, false}, 2867 {"NTCREATEX", handler_smb_ntcreatex, false}, 2868 {"CLOSE", handler_smb_close, false}, 2869 {"UNLINK", handler_smb_unlink, false}, 2870 {"MKDIR", handler_smb_mkdir, false}, 2871 {"RMDIR", handler_smb_rmdir, false}, 2872 {"RENAME", handler_smb_rename, false}, 2873 {"NTRENAME", handler_smb_ntrename, false}, 2874 {"READX", handler_smb_readx, false}, 2875 {"WRITEX", handler_smb_writex, false}, 2876 {"CHKPATH", handler_smb_chkpath, false}, 2877 {"SEEK", handler_smb_seek, false}, 2878 {"LOCKINGX", handler_smb_lockingx, false}, 2879 {"QPATHINFO", handler_smb_qpathinfo, false}, 2880 {"QFILEINFO", handler_smb_qfileinfo, false}, 2881 {"SPATHINFO", handler_smb_spathinfo, false}, 2882 {"SFILEINFO", handler_smb_sfileinfo, false}, 2883 {"NOTIFY", handler_smb_notify, false}, 2884 {"SEEK", handler_smb_seek, false}, 2885}; 2886 2887 2888/* 2889 run the test with the current set of op_parms parameters 2890 return the number of operations that completed successfully 2891*/ 2892static int run_test(struct tevent_context *ev, struct loadparm_context *lp_ctx) 2893{ 2894 int op, i; 2895 2896 if (!connect_servers(ev, lp_ctx)) { 2897 printf("Failed to connect to servers\n"); 2898 exit(1); 2899 } 2900 2901 dump_seeds(); 2902 2903 /* wipe any leftover files from old runs */ 2904 wipe_files(); 2905 2906 /* reset the open handles array */ 2907 memset(open_handles, 0, options.max_open_handles * sizeof(open_handles[0])); 2908 num_open_handles = 0; 2909 2910 for (i=0;i<ARRAY_SIZE(gen_ops);i++) { 2911 gen_ops[i].count = 0; 2912 gen_ops[i].success_count = 0; 2913 } 2914 2915 for (op=0; op<options.numops; op++) { 2916 int instance, which_op; 2917 bool ret; 2918 2919 if (op_parms[op].disabled) continue; 2920 2921 srandom(op_parms[op].seed); 2922 2923 instance = gen_int_range(0, NINSTANCES-1); 2924 2925 /* generate a non-ignored operation */ 2926 do { 2927 which_op = gen_int_range(0, ARRAY_SIZE(gen_ops)-1); 2928 } while (ignore_pattern(gen_ops[which_op].name) || 2929 gen_ops[which_op].smb2 != options.smb2); 2930 2931 DEBUG(3,("Generating op %s on instance %d\n", 2932 gen_ops[which_op].name, instance)); 2933 2934 current_op.seed = op_parms[op].seed; 2935 current_op.opnum = op; 2936 current_op.name = gen_ops[which_op].name; 2937 current_op.status = NT_STATUS_OK; 2938 talloc_free(current_op.mem_ctx); 2939 current_op.mem_ctx = talloc_named(NULL, 0, "%s", current_op.name); 2940 2941 ret = gen_ops[which_op].handler(instance); 2942 2943 gen_ops[which_op].count++; 2944 if (NT_STATUS_IS_OK(current_op.status)) { 2945 gen_ops[which_op].success_count++; 2946 } 2947 2948 if (!ret) { 2949 printf("Failed at operation %d - %s\n", 2950 op, gen_ops[which_op].name); 2951 return op; 2952 } 2953 2954 if (op % 100 == 0) { 2955 printf("%d\n", op); 2956 } 2957 } 2958 2959 for (i=0;i<ARRAY_SIZE(gen_ops);i++) { 2960 printf("Op %-10s got %d/%d success\n", 2961 gen_ops[i].name, 2962 gen_ops[i].success_count, 2963 gen_ops[i].count); 2964 } 2965 2966 return op; 2967} 2968 2969/* 2970 perform a backtracking analysis of the minimal set of operations 2971 to generate an error 2972*/ 2973static void backtrack_analyze(struct tevent_context *ev, 2974 struct loadparm_context *lp_ctx) 2975{ 2976 int chunk, ret; 2977 const char *mismatch = current_op.mismatch; 2978 2979 chunk = options.numops / 2; 2980 2981 do { 2982 int base; 2983 for (base=0; 2984 chunk > 0 && base+chunk < options.numops && options.numops > 1; ) { 2985 int i, max; 2986 2987 chunk = MIN(chunk, options.numops / 2); 2988 2989 /* mark this range as disabled */ 2990 max = MIN(options.numops, base+chunk); 2991 for (i=base;i<max; i++) { 2992 op_parms[i].disabled = true; 2993 } 2994 printf("Testing %d ops with %d-%d disabled\n", 2995 options.numops, base, max-1); 2996 ret = run_test(ev, lp_ctx); 2997 printf("Completed %d of %d ops\n", ret, options.numops); 2998 for (i=base;i<max; i++) { 2999 op_parms[i].disabled = false; 3000 } 3001 if (ret == options.numops) { 3002 /* this chunk is needed */ 3003 base += chunk; 3004 } else if (mismatch != current_op.mismatch && 3005 strcmp(mismatch, current_op.mismatch)) { 3006 base += chunk; 3007 printf("Different error in backtracking\n"); 3008 } else if (ret < base) { 3009 printf("damn - inconsistent errors! found early error\n"); 3010 options.numops = ret+1; 3011 base = 0; 3012 } else { 3013 /* it failed - this chunk isn't needed for a failure */ 3014 memmove(&op_parms[base], &op_parms[max], 3015 sizeof(op_parms[0]) * (options.numops - max)); 3016 options.numops = (ret+1) - (max - base); 3017 } 3018 } 3019 3020 if (chunk == 2) { 3021 chunk = 1; 3022 } else { 3023 chunk *= 0.4; 3024 } 3025 3026 if (options.analyze_continuous && chunk == 0 && options.numops != 1) { 3027 chunk = 1; 3028 } 3029 } while (chunk > 0); 3030 3031 printf("Reduced to %d ops\n", options.numops); 3032 ret = run_test(ev, lp_ctx); 3033 if (ret != options.numops - 1) { 3034 printf("Inconsistent result? ret=%d numops=%d\n", ret, options.numops); 3035 } 3036} 3037 3038/* 3039 start the main gentest process 3040*/ 3041static bool start_gentest(struct tevent_context *ev, 3042 struct loadparm_context *lp_ctx) 3043{ 3044 int op; 3045 int ret; 3046 3047 /* allocate the open_handles array */ 3048 open_handles = calloc(options.max_open_handles, sizeof(open_handles[0])); 3049 3050 srandom(options.seed); 3051 op_parms = calloc(options.numops, sizeof(op_parms[0])); 3052 3053 /* generate the seeds - after this everything is deterministic */ 3054 if (options.use_preset_seeds) { 3055 int numops; 3056 char **preset = file_lines_load(options.seeds_file, &numops, 0, NULL); 3057 if (!preset) { 3058 printf("Failed to load %s - %s\n", options.seeds_file, strerror(errno)); 3059 exit(1); 3060 } 3061 if (numops < options.numops) { 3062 options.numops = numops; 3063 } 3064 for (op=0;op<options.numops;op++) { 3065 if (!preset[op]) { 3066 printf("Not enough seeds in %s\n", options.seeds_file); 3067 exit(1); 3068 } 3069 op_parms[op].seed = atoi(preset[op]); 3070 } 3071 printf("Loaded %d seeds from %s\n", options.numops, options.seeds_file); 3072 } else { 3073 for (op=0; op<options.numops; op++) { 3074 op_parms[op].seed = random(); 3075 } 3076 } 3077 3078 ret = run_test(ev, lp_ctx); 3079 3080 if (ret != options.numops && options.analyze) { 3081 options.numops = ret+1; 3082 backtrack_analyze(ev, lp_ctx); 3083 } else if (options.analyze_always) { 3084 backtrack_analyze(ev, lp_ctx); 3085 } else if (options.analyze_continuous) { 3086 while (run_test(ev, lp_ctx) == options.numops) ; 3087 } 3088 3089 return ret == options.numops; 3090} 3091 3092 3093static void usage(poptContext pc) 3094{ 3095 printf( 3096"Usage:\n\ 3097 gentest //server1/share1 //server2/share2 [options..]\n\ 3098"); 3099 poptPrintUsage(pc, stdout, 0); 3100} 3101 3102/** 3103 split a UNC name into server and share names 3104*/ 3105static bool split_unc_name(const char *unc, char **server, char **share) 3106{ 3107 char *p = strdup(unc); 3108 if (!p) return false; 3109 all_string_sub(p, "\\", "/", 0); 3110 if (strncmp(p, "//", 2) != 0) return false; 3111 3112 (*server) = p+2; 3113 p = strchr(*server, '/'); 3114 if (!p) return false; 3115 3116 *p = 0; 3117 (*share) = p+1; 3118 3119 return true; 3120} 3121 3122 3123 3124/**************************************************************************** 3125 main program 3126****************************************************************************/ 3127 int main(int argc, char *argv[]) 3128{ 3129 int opt; 3130 int i, username_count=0; 3131 bool ret; 3132 char *ignore_file=NULL; 3133 struct tevent_context *ev; 3134 struct loadparm_context *lp_ctx; 3135 poptContext pc; 3136 int argc_new; 3137 char **argv_new; 3138 enum {OPT_UNCLIST=1000}; 3139 struct poptOption long_options[] = { 3140 POPT_AUTOHELP 3141 {"smb2", 0, POPT_ARG_NONE, &options.smb2, 0, "use SMB2 protocol", NULL}, 3142 {"seed", 0, POPT_ARG_INT, &options.seed, 0, "Seed to use for randomizer", NULL}, 3143 {"num-ops", 0, POPT_ARG_INT, &options.numops, 0, "num ops", NULL}, 3144 {"oplocks", 0, POPT_ARG_NONE, &options.use_oplocks,0, "use oplocks", NULL}, 3145 {"showall", 0, POPT_ARG_NONE, &options.showall, 0, "display all operations", NULL}, 3146 {"analyse", 0, POPT_ARG_NONE, &options.analyze, 0, "do backtrack analysis", NULL}, 3147 {"analysealways", 0, POPT_ARG_NONE, &options.analyze_always, 0, "analysis always", NULL}, 3148 {"analysecontinuous", 0, POPT_ARG_NONE, &options.analyze_continuous, 0, "analysis continuous", NULL}, 3149 {"ignore", 0, POPT_ARG_STRING, &ignore_file, 0, "ignore from file", NULL}, 3150 {"preset", 0, POPT_ARG_NONE, &options.use_preset_seeds, 0, "use preset seeds", NULL}, 3151 {"fast", 0, POPT_ARG_NONE, &options.fast_reconnect, 0, "use fast reconnect", NULL}, 3152 {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL}, 3153 {"seedsfile", 0, POPT_ARG_STRING, &options.seeds_file, 0, "seed file", NULL}, 3154 { "user", 'U', POPT_ARG_STRING, NULL, 'U', "Set the network username", "[DOMAIN/]USERNAME[%PASSWORD]" }, 3155 {"maskindexing", 0, POPT_ARG_NONE, &options.mask_indexing, 0, "mask out the indexed file attrib", NULL}, 3156 {"noeas", 0, POPT_ARG_NONE, &options.no_eas, 0, "don't use extended attributes", NULL}, 3157 {"noacls", 0, POPT_ARG_NONE, &options.no_acls, 0, "don't use ACLs", NULL}, 3158 {"skip-cleanup", 0, POPT_ARG_NONE, &options.skip_cleanup, 0, "don't delete files at start", NULL}, 3159 {"valid", 0, POPT_ARG_NONE, &options.valid, 0, "generate only valid fields", NULL}, 3160 POPT_COMMON_SAMBA 3161 POPT_COMMON_CONNECTION 3162 POPT_COMMON_CREDENTIALS 3163 POPT_COMMON_VERSION 3164 { NULL } 3165 }; 3166 3167 memset(&bad_smb2_handle, 0xFF, sizeof(bad_smb2_handle)); 3168 3169 setlinebuf(stdout); 3170 options.seed = time(NULL); 3171 options.numops = 1000; 3172 options.max_open_handles = 20; 3173 options.seeds_file = "gentest_seeds.dat"; 3174 3175 pc = poptGetContext("gentest", argc, (const char **) argv, long_options, 3176 POPT_CONTEXT_KEEP_FIRST); 3177 3178 poptSetOtherOptionHelp(pc, "<unc1> <unc2>"); 3179 3180 lp_ctx = cmdline_lp_ctx; 3181 servers[0].credentials = cli_credentials_init(talloc_autofree_context()); 3182 servers[1].credentials = cli_credentials_init(talloc_autofree_context()); 3183 cli_credentials_guess(servers[0].credentials, lp_ctx); 3184 cli_credentials_guess(servers[1].credentials, lp_ctx); 3185 3186 while((opt = poptGetNextOpt(pc)) != -1) { 3187 switch (opt) { 3188 case OPT_UNCLIST: 3189 lp_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc)); 3190 break; 3191 case 'U': 3192 if (username_count == 2) { 3193 usage(pc); 3194 exit(1); 3195 } 3196 cli_credentials_parse_string(servers[username_count].credentials, poptGetOptArg(pc), CRED_SPECIFIED); 3197 username_count++; 3198 break; 3199 } 3200 } 3201 3202 if (ignore_file) { 3203 options.ignore_patterns = file_lines_load(ignore_file, NULL, 0, NULL); 3204 } 3205 3206 argv_new = discard_const_p(char *, poptGetArgs(pc)); 3207 argc_new = argc; 3208 for (i=0; i<argc; i++) { 3209 if (argv_new[i] == NULL) { 3210 argc_new = i; 3211 break; 3212 } 3213 } 3214 3215 if (!(argc_new >= 3)) { 3216 usage(pc); 3217 exit(1); 3218 } 3219 3220 setlinebuf(stdout); 3221 3222 setup_logging("gentest", DEBUG_STDOUT); 3223 3224 if (argc < 3 || argv[1][0] == '-') { 3225 usage(pc); 3226 exit(1); 3227 } 3228 3229 setup_logging(argv[0], DEBUG_STDOUT); 3230 3231 for (i=0;i<NSERVERS;i++) { 3232 const char *share = argv[1+i]; 3233 if (!split_unc_name(share, &servers[i].server_name, &servers[i].share_name)) { 3234 printf("Invalid share name '%s'\n", share); 3235 return -1; 3236 } 3237 } 3238 3239 if (username_count == 0) { 3240 usage(pc); 3241 return -1; 3242 } 3243 if (username_count == 1) { 3244 servers[1].credentials = servers[0].credentials; 3245 } 3246 3247 printf("seed=%u\n", options.seed); 3248 3249 ev = s4_event_context_init(talloc_autofree_context()); 3250 3251 gensec_init(lp_ctx); 3252 3253 ret = start_gentest(ev, lp_ctx); 3254 3255 if (ret) { 3256 printf("gentest completed - no errors\n"); 3257 } else { 3258 printf("gentest failed\n"); 3259 } 3260 3261 return ret?0:-1; 3262} 3263