2 Unix SMB/Netbios implementation.
5 Copyright (C) Andrew Tridgell 1997-1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 static fstring host, workgroup, share, password, username, myname;
27 static int max_protocol = PROTOCOL_NT1;
28 static char *sockops="";
31 static struct timeval tp1,tp2;
33 static void start_timer(void)
35 gettimeofday(&tp1,NULL);
38 static double end_timer(void)
40 gettimeofday(&tp2,NULL);
41 return((tp2.tv_sec - tp1.tv_sec) +
42 (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
46 static BOOL open_connection(struct cli_state *c)
48 struct nmb_name called, calling;
52 make_nmb_name(&calling, myname, 0x0, "");
53 make_nmb_name(&called , host, 0x20, "");
55 if (!cli_initialise(c) || !cli_connect(c, host, NULL)) {
56 printf("Failed to connect with %s\n", host);
60 if (!cli_session_request(c, &calling, &called)) {
62 printf("%s rejected the session\n",host);
66 if (!cli_negprot(c)) {
67 printf("%s rejected the negprot (%s)\n",host, cli_errstr(c));
72 if (!cli_session_setup(c, username,
73 password, strlen(password),
74 password, strlen(password),
77 printf("%s rejected the sessionsetup (%s)\n", host, cli_errstr(c));
81 if (!cli_send_tconX(c, share, "?????",
82 password, strlen(password)+1)) {
83 printf("%s refused tree connect (%s)\n", host, cli_errstr(c));
93 static void close_connection(struct cli_state *c)
96 printf("tdis failed (%s)\n", cli_errstr(c));
103 /* check if the server produced the expected error code */
104 static BOOL check_error(struct cli_state *c,
105 uint8 eclass, uint32 ecode, uint32 nterr)
110 eno = cli_error(c, &class, &num);
111 if ((eclass != class || ecode != num) &&
112 num != (nterr&0xFFFFFF)) {
113 printf("unexpected error code class=%d code=%d\n",
114 (int)class, (int)num);
115 printf(" expected %d/%d %d\n",
116 (int)eclass, (int)ecode, (int)nterr);
123 static BOOL wait_lock(struct cli_state *c, int fnum, uint32 offset, uint32 len)
125 while (!cli_lock(c, fnum, offset, len, -1)) {
126 if (!check_error(c, ERRDOS, ERRlock, 0)) return False;
132 static BOOL rw_torture(struct cli_state *c, int numops)
134 char *lockfname = "\\torture.lck";
138 int pid2, pid = getpid();
142 fnum2 = cli_open(c, lockfname, O_RDWR | O_CREAT | O_EXCL,
145 fnum2 = cli_open(c, lockfname, O_RDWR, DENY_NONE);
147 printf("open of %s failed (%s)\n", lockfname, cli_errstr(c));
152 for (i=0;i<numops;i++) {
153 unsigned n = (unsigned)sys_random()%10;
155 printf("%d\r", i); fflush(stdout);
157 slprintf(fname, sizeof(fstring) - 1, "\\torture.%u", n);
159 if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
163 fnum = cli_open(c, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
165 printf("open failed (%s)\n", cli_errstr(c));
169 if (cli_write(c, fnum, 0, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
170 printf("write failed (%s)\n", cli_errstr(c));
174 if (cli_write(c, fnum, 0, (char *)buf,
175 sizeof(pid)+(j*sizeof(buf)),
176 sizeof(buf)) != sizeof(buf)) {
177 printf("write failed (%s)\n", cli_errstr(c));
183 if (cli_read(c, fnum, (char *)&pid2, 0, sizeof(pid)) != sizeof(pid)) {
184 printf("read failed (%s)\n", cli_errstr(c));
188 printf("data corruption!\n");
191 if (!cli_close(c, fnum)) {
192 printf("close failed (%s)\n", cli_errstr(c));
195 if (!cli_unlink(c, fname)) {
196 printf("unlink failed (%s)\n", cli_errstr(c));
199 if (!cli_unlock(c, fnum2, n*sizeof(int), sizeof(int), -1)) {
200 printf("unlock failed (%s)\n", cli_errstr(c));
205 cli_unlink(c, lockfname);
212 static void usage(void)
214 printf("Usage: smbtorture //server/share <options>\n");
216 printf("\t-U user%%pass\n");
217 printf("\t-N numprocs\n");
218 printf("\t-n my_netbios_name\n");
219 printf("\t-W workgroup\n");
220 printf("\t-o num_operations\n");
221 printf("\t-O socket_options\n");
222 printf("\t-m maximum protocol\n");
230 static void run_torture(int numops)
232 static struct cli_state cli;
234 if (open_connection(&cli)) {
235 cli_sockopt(&cli, sockops);
237 printf("pid %d OK\n", getpid());
239 rw_torture(&cli, numops);
241 close_connection(&cli);
246 This test checks for two things:
248 1) correct support for retaining locks over a close (ie. the server
249 must not use posix semantics)
250 2) support for lock timeouts
252 static void run_locktest1(void)
254 static struct cli_state cli1, cli2;
255 char *fname = "\\lockt1.lck";
256 int fnum1, fnum2, fnum3;
259 if (!open_connection(&cli1) || !open_connection(&cli2)) {
262 cli_sockopt(&cli1, sockops);
263 cli_sockopt(&cli2, sockops);
265 printf("starting locktest1\n");
267 cli_unlink(&cli1, fname);
269 fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
271 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
274 fnum2 = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
276 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli1));
279 fnum3 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
281 printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli2));
285 if (!cli_lock(&cli1, fnum1, 0, 4, 0)) {
286 printf("lock1 failed (%s)\n", cli_errstr(&cli1));
291 if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
292 printf("lock2 succeeded! This is a locking bug\n");
295 if (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
299 printf("Testing lock timeouts\n");
301 if (cli_lock(&cli2, fnum3, 0, 4, 10*1000)) {
302 printf("lock3 succeeded! This is a locking bug\n");
305 if (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
310 printf("error: This server appears not to support timed lock requests\n");
313 if (!cli_close(&cli1, fnum2)) {
314 printf("close1 failed (%s)\n", cli_errstr(&cli1));
318 if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
319 printf("lock4 succeeded! This is a locking bug\n");
322 if (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
325 if (!cli_close(&cli1, fnum1)) {
326 printf("close2 failed (%s)\n", cli_errstr(&cli1));
330 if (!cli_close(&cli2, fnum3)) {
331 printf("close3 failed (%s)\n", cli_errstr(&cli2));
335 if (!cli_unlink(&cli1, fname)) {
336 printf("unlink failed (%s)\n", cli_errstr(&cli1));
341 close_connection(&cli1);
342 close_connection(&cli2);
344 printf("Passed locktest1\n");
349 This test checks that
351 1) the server supports multiple locking contexts on the one SMB
352 connection, distinguished by PID.
354 2) the server correctly fails overlapping locks made by the same PID (this
355 goes against POSIX behaviour, which is why it is tricky to implement)
357 3) the server denies unlock requests by an incorrect client PID
359 static void run_locktest2(void)
361 static struct cli_state cli;
362 char *fname = "\\lockt2.lck";
363 int fnum1, fnum2, fnum3;
365 if (!open_connection(&cli)) {
369 cli_sockopt(&cli, sockops);
371 printf("starting locktest2\n");
373 cli_unlink(&cli, fname);
377 fnum1 = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
379 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
383 fnum2 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
385 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli));
391 fnum3 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
393 printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli));
399 if (!cli_lock(&cli, fnum1, 0, 4, 0)) {
400 printf("lock1 failed (%s)\n", cli_errstr(&cli));
404 if (cli_lock(&cli, fnum2, 0, 4, 0)) {
405 printf("lock2 succeeded! This is a locking bug\n");
407 if (!check_error(&cli, ERRDOS, ERRlock, 0)) return;
412 if (cli_unlock(&cli, fnum1, 0, 4, 0)) {
413 printf("unlock1 succeeded! This is a locking bug\n");
416 if (cli_lock(&cli, fnum3, 0, 4, 0)) {
417 printf("lock3 succeeded! This is a locking bug\n");
419 if (!check_error(&cli, ERRDOS, ERRlock, 0)) return;
424 if (!cli_close(&cli, fnum1)) {
425 printf("close1 failed (%s)\n", cli_errstr(&cli));
429 if (!cli_close(&cli, fnum2)) {
430 printf("close2 failed (%s)\n", cli_errstr(&cli));
434 if (!cli_close(&cli, fnum3)) {
435 printf("close3 failed (%s)\n", cli_errstr(&cli));
439 close_connection(&cli);
441 printf("locktest2 finished\n");
446 This test checks that
448 1) the server supports the full offset range in lock requests
450 static void run_locktest3(int numops)
452 static struct cli_state cli1, cli2;
453 char *fname = "\\lockt3.lck";
457 #define NEXT_OFFSET offset += (~(uint32)0) / numops
459 if (!open_connection(&cli1) || !open_connection(&cli2)) {
462 cli_sockopt(&cli1, sockops);
463 cli_sockopt(&cli2, sockops);
465 printf("starting locktest3\n");
467 cli_unlink(&cli1, fname);
469 fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
471 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
474 fnum2 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
476 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli2));
480 for (offset=i=0;i<numops;i++) {
482 if (!cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
483 printf("lock1 %d failed (%s)\n",
489 if (!cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
490 printf("lock2 %d failed (%s)\n",
497 for (offset=i=0;i<numops;i++) {
500 if (cli_lock(&cli1, fnum1, offset-2, 1, 0)) {
501 printf("error: lock1 %d succeeded!\n", i);
505 if (cli_lock(&cli2, fnum2, offset-1, 1, 0)) {
506 printf("error: lock2 %d succeeded!\n", i);
510 if (cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
511 printf("error: lock3 %d succeeded!\n", i);
515 if (cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
516 printf("error: lock4 %d succeeded!\n", i);
521 for (offset=i=0;i<numops;i++) {
524 if (!cli_unlock(&cli1, fnum1, offset-1, 1, 0)) {
525 printf("unlock1 %d failed (%s)\n",
531 if (!cli_unlock(&cli2, fnum2, offset-2, 1, 0)) {
532 printf("unlock2 %d failed (%s)\n",
539 if (!cli_close(&cli1, fnum1)) {
540 printf("close1 failed (%s)\n", cli_errstr(&cli1));
543 if (!cli_close(&cli2, fnum2)) {
544 printf("close2 failed (%s)\n", cli_errstr(&cli2));
547 if (!cli_unlink(&cli1, fname)) {
548 printf("unlink failed (%s)\n", cli_errstr(&cli1));
552 close_connection(&cli1);
553 close_connection(&cli2);
555 printf("finished locktest3\n");
560 test whether fnums and tids open on one VC are available on another (a major
563 static void run_fdpasstest(void)
565 static struct cli_state cli1, cli2;
566 char *fname = "\\fdpass.tst";
570 if (!open_connection(&cli1) || !open_connection(&cli2)) {
573 cli_sockopt(&cli1, sockops);
574 cli_sockopt(&cli2, sockops);
576 printf("starting fdpasstest\n");
578 cli_unlink(&cli1, fname);
580 fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
582 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
586 if (cli_write(&cli1, fnum1, 0, "hello world\n", 0, 13) != 13) {
587 printf("write failed (%s)\n", cli_errstr(&cli1));
591 cli2.vuid = cli1.vuid;
592 cli2.cnum = cli1.cnum;
596 if (cli_read(&cli2, fnum1, buf, 0, 13) == 13) {
597 printf("read succeeded! nasty security hole [%s]\n",
602 cli_close(&cli1, fnum1);
603 cli_unlink(&cli1, fname);
605 close_connection(&cli1);
606 close_connection(&cli2);
608 printf("finished fdpasstest\n");
613 This test checks that
615 1) the server does not allow an unlink on a file that is open
617 static void run_unlinktest(void)
619 static struct cli_state cli;
620 char *fname = "\\unlink.tst";
623 if (!open_connection(&cli)) {
627 cli_sockopt(&cli, sockops);
629 printf("starting unlink test\n");
631 cli_unlink(&cli, fname);
635 fnum = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
637 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
641 if (cli_unlink(&cli, fname)) {
642 printf("error: server allowed unlink on an open file\n");
645 cli_close(&cli, fnum);
646 cli_unlink(&cli, fname);
648 close_connection(&cli);
650 printf("unlink test finished\n");
655 test how many open files this server supports on the one socket
657 static void run_maxfidtest(int n)
659 static struct cli_state cli;
660 char *template = "\\maxfid.%d.%d";
667 while (!open_connection(&cli) && retries--) msleep(random() % 2000);
670 printf("failed to connect\n");
674 cli_sockopt(&cli, sockops);
676 printf("starting maxfid test\n");
680 slprintf(fname,sizeof(fname)-1,template, fnum,getpid());
681 if (cli_open(&cli, fname,
682 O_RDWR|O_CREAT|O_TRUNC, DENY_NONE) ==
684 printf("open of %s failed (%s)\n",
685 fname, cli_errstr(&cli));
686 printf("maximum fnum is %d\n", fnum);
692 printf("cleaning up\n");
695 slprintf(fname,sizeof(fname)-1,template, fnum,getpid());
696 if (cli_unlink(&cli, fname)) {
697 printf("unlink of %s failed (%s)\n",
698 fname, cli_errstr(&cli));
702 printf("maxfid test finished\n");
703 close_connection(&cli);
706 /* generate a random buffer */
707 static void rand_buf(char *buf, int len)
715 /* send random IPC commands */
716 static void run_randomipc(void)
722 int api, param_len, i;
723 static struct cli_state cli;
725 printf("starting random ipc test\n");
727 if (!open_connection(&cli)) {
731 for (i=0;i<50000;i++) {
732 api = sys_random() % 500;
733 param_len = (sys_random() % 64);
735 rand_buf(param, param_len);
741 NULL, 0, BUFFER_SIZE,
746 close_connection(&cli);
748 printf("finished random ipc test\n");
753 static void browse_callback(const char *sname, uint32 stype,
756 printf("\t%20.20s %08x %s\n", sname, stype, comment);
762 This test checks the browse list code
765 static void run_browsetest(void)
767 static struct cli_state cli;
769 printf("starting browse test\n");
771 if (!open_connection(&cli)) {
775 printf("domain list:\n");
776 cli_NetServerEnum(&cli, workgroup,
780 printf("machine list:\n");
781 cli_NetServerEnum(&cli, workgroup,
785 close_connection(&cli);
787 printf("browse test finished\n");
792 This checks how the getatr calls works
794 static void run_attrtest(void)
796 static struct cli_state cli;
799 char *fname = "\\attrib.tst";
801 printf("starting attrib test\n");
803 if (!open_connection(&cli)) {
807 cli_unlink(&cli, fname);
808 fnum = cli_open(&cli, fname,
809 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
810 cli_close(&cli, fnum);
811 if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
812 printf("getatr failed (%s)\n", cli_errstr(&cli));
815 if (abs(t - time(NULL)) > 2) {
816 printf("ERROR: SMBgetatr bug. time is %s",
821 t2 = t-60*60*24; /* 1 day ago */
823 if (!cli_setatr(&cli, fname, 0, t2)) {
824 printf("setatr failed (%s)\n", cli_errstr(&cli));
827 if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
828 printf("getatr failed (%s)\n", cli_errstr(&cli));
832 printf("ERROR: getatr/setatr bug. times are\n%s",
834 printf("%s", ctime(&t2));
837 cli_unlink(&cli, fname);
839 close_connection(&cli);
841 printf("attrib test finished\n");
846 This checks a couple of trans2 calls
848 static void run_trans2test(void)
850 static struct cli_state cli;
853 time_t c_time, a_time, m_time, w_time, m_time2;
854 char *fname = "\\trans2.tst";
855 char *dname = "\\trans2";
856 char *fname2 = "\\trans2\\trans2.tst";
858 printf("starting trans2 test\n");
860 if (!open_connection(&cli)) {
864 cli_unlink(&cli, fname);
865 fnum = cli_open(&cli, fname,
866 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
867 if (!cli_qfileinfo(&cli, fnum, NULL, &size, &c_time, &a_time, &m_time)) {
868 printf("ERROR: qfileinfo failed (%s)\n", cli_errstr(&cli));
870 cli_close(&cli, fnum);
874 cli_unlink(&cli, fname);
875 fnum = cli_open(&cli, fname,
876 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
877 cli_close(&cli, fnum);
879 if (!cli_qpathinfo(&cli, fname, &c_time, &a_time, &m_time, &size, NULL)) {
880 printf("ERROR: qpathinfo failed (%s)\n", cli_errstr(&cli));
882 if (c_time != m_time) {
883 printf("create time=%s", ctime(&c_time));
884 printf("modify time=%s", ctime(&m_time));
885 printf("This system appears to have sticky create times\n");
887 if (a_time % (60*60) == 0) {
888 printf("access time=%s", ctime(&a_time));
889 printf("This system appears to set a midnight access time\n");
892 if (abs(m_time - time(NULL)) > 60*60*24*7) {
893 printf("ERROR: totally incorrect times - maybe word reversed?\n");
898 cli_unlink(&cli, fname);
899 fnum = cli_open(&cli, fname,
900 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
901 cli_close(&cli, fnum);
902 if (!cli_qpathinfo2(&cli, fname, &c_time, &a_time, &m_time,
903 &w_time, &size, NULL)) {
904 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
906 if (w_time < 60*60*24*2) {
907 printf("write time=%s", ctime(&w_time));
908 printf("This system appears to set a initial 0 write time\n");
912 cli_unlink(&cli, fname);
915 /* check if the server updates the directory modification time
916 when creating a new file */
917 if (!cli_mkdir(&cli, dname)) {
918 printf("ERROR: mkdir failed (%s)\n", cli_errstr(&cli));
921 if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time,
922 &w_time, &size, NULL)) {
923 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
926 fnum = cli_open(&cli, fname2,
927 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
928 cli_write(&cli, fnum, 0, (char *)&fnum, 0, sizeof(fnum));
929 cli_close(&cli, fnum);
930 if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time2,
931 &w_time, &size, NULL)) {
932 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
934 if (m_time2 == m_time)
935 printf("This system does not update directory modification times\n");
937 cli_unlink(&cli, fname2);
938 cli_rmdir(&cli, dname);
941 close_connection(&cli);
943 printf("trans2 test finished\n");
947 static void create_procs(int nprocs, int numops, void (*fn)(int ))
951 for (i=0;i<nprocs;i++) {
953 int mypid = getpid();
954 sys_srandom(mypid ^ time(NULL));
960 for (i=0;i<nprocs;i++)
961 waitpid(0, &status, 0);
966 /****************************************************************************
968 ****************************************************************************/
969 int main(int argc,char *argv[])
971 int nprocs=1, numops=100;
981 charset_initialise();
987 for(p = argv[1]; *p; p++)
991 if (strncmp(argv[1], "//", 2)) {
995 fstrcpy(host, &argv[1][2]);
996 p = strchr(&host[2],'/');
1001 fstrcpy(share, p+1);
1003 get_myname(myname,NULL);
1005 if (*username == 0 && getenv("LOGNAME")) {
1006 pstrcpy(username,getenv("LOGNAME"));
1013 while ((opt = getopt(argc, argv, "hW:U:n:N:O:o:m:")) != EOF) {
1016 fstrcpy(workgroup,optarg);
1019 max_protocol = interpret_protocol(optarg, max_protocol);
1022 nprocs = atoi(optarg);
1025 numops = atoi(optarg);
1031 fstrcpy(myname, optarg);
1034 pstrcpy(username,optarg);
1035 p = strchr(username,'%');
1038 pstrcpy(password, p+1);
1043 printf("Unknown option %c (%d)\n", (char)opt, opt);
1050 p = getpass("Password:");
1052 pstrcpy(password, p);
1057 printf("host=%s share=%s user=%s myname=%s\n",
1058 host, share, username, myname);
1063 run_locktest3(numops);
1069 create_procs(nprocs, numops, run_maxfidtest);
1072 create_procs(nprocs, numops, run_torture);
1073 printf("rw_torture: %g secs\n", end_timer());