r14363: Remove credentials.h from the global includes.
[samba.git] / source4 / torture / torture.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB torture tester
4    Copyright (C) Andrew Tridgell 1997-2003
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "lib/cmdline/popt_common.h"
23 #include "libcli/raw/libcliraw.h"
24 #include "system/time.h"
25 #include "system/wait.h"
26 #include "system/filesys.h"
27 #include "libcli/raw/ioctl.h"
28 #include "libcli/libcli.h"
29 #include "lib/ldb/include/ldb.h"
30 #include "librpc/rpc/dcerpc_table.h"
31 #include "lib/events/events.h"
32 #include "libcli/resolve/resolve.h"
33 #include "auth/credentials/credentials.h"
34
35 #include "torture/basic/proto.h"
36 #include "torture/raw/proto.h"
37 #include "torture/smb2/proto.h"
38 #include "torture/rpc/proto.h"
39 #include "torture/rap/proto.h"
40 #include "torture/auth/proto.h"
41 #include "torture/local/proto.h"
42 #include "torture/nbench/proto.h"
43 #include "torture/ldap/proto.h"
44 #include "torture/com/proto.h"
45 #include "torture/nbt/proto.h"
46 #include "torture/libnet/proto.h"
47 #include "torture/torture.h"
48 #include "build.h"
49 #include "dlinklist.h"
50
51 int torture_nprocs=4;
52 int torture_numops=10;
53 int torture_entries=1000;
54 int torture_failures=1;
55 int torture_seed=0;
56 static int procnum; /* records process count number when forking */
57 static struct smbcli_state *current_cli;
58 static BOOL use_oplocks;
59 static BOOL use_level_II_oplocks;
60 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
61
62 BOOL torture_showall = False;
63
64 #define CHECK_MAX_FAILURES(label) do { if (++failures >= torture_failures) goto label; } while (0)
65
66 static struct smbcli_state *open_nbt_connection(void)
67 {
68         struct nbt_name called, calling;
69         struct smbcli_state *cli;
70         const char *host = lp_parm_string(-1, "torture", "host");
71
72         make_nbt_name_client(&calling, lp_netbios_name());
73
74         nbt_choose_called_name(NULL, &called, host, NBT_NAME_SERVER);
75
76         cli = smbcli_state_init(NULL);
77         if (!cli) {
78                 printf("Failed initialize smbcli_struct to connect with %s\n", host);
79                 goto failed;
80         }
81
82         if (!smbcli_socket_connect(cli, host)) {
83                 printf("Failed to connect with %s\n", host);
84                 goto failed;
85         }
86
87         if (!smbcli_transport_establish(cli, &calling, &called)) {
88                 printf("%s rejected the session\n",host);
89                 goto failed;
90         }
91
92         return cli;
93
94 failed:
95         talloc_free(cli);
96         return NULL;
97 }
98
99 BOOL torture_open_connection_share(TALLOC_CTX *mem_ctx,
100                                    struct smbcli_state **c, 
101                                    const char *hostname, 
102                                    const char *sharename,
103                                    struct event_context *ev)
104 {
105         NTSTATUS status;
106
107         status = smbcli_full_connection(mem_ctx, c, hostname, 
108                                         sharename, NULL,
109                                         cmdline_credentials, ev);
110         if (!NT_STATUS_IS_OK(status)) {
111                 printf("Failed to open connection - %s\n", nt_errstr(status));
112                 return False;
113         }
114
115         (*c)->transport->options.use_oplocks = use_oplocks;
116         (*c)->transport->options.use_level2_oplocks = use_level_II_oplocks;
117
118         return True;
119 }
120
121 BOOL torture_open_connection(struct smbcli_state **c)
122 {
123         const char *host = lp_parm_string(-1, "torture", "host");
124         const char *share = lp_parm_string(-1, "torture", "share");
125
126         return torture_open_connection_share(NULL, c, host, share, NULL);
127 }
128
129
130
131 BOOL torture_close_connection(struct smbcli_state *c)
132 {
133         BOOL ret = True;
134         if (!c) return True;
135         if (NT_STATUS_IS_ERR(smbcli_tdis(c))) {
136                 printf("tdis failed (%s)\n", smbcli_errstr(c->tree));
137                 ret = False;
138         }
139         talloc_free(c);
140         return ret;
141 }
142
143 /* open a rpc connection to the chosen binding string */
144 NTSTATUS torture_rpc_connection(TALLOC_CTX *parent_ctx, 
145                                 struct dcerpc_pipe **p, 
146                                 const struct dcerpc_interface_table *table)
147 {
148         NTSTATUS status;
149         const char *binding = lp_parm_string(-1, "torture", "binding");
150
151         if (!binding) {
152                 printf("You must specify a ncacn binding string\n");
153                 return NT_STATUS_INVALID_PARAMETER;
154         }
155
156         status = dcerpc_pipe_connect(parent_ctx, 
157                                      p, binding, table,
158                                      cmdline_credentials, NULL);
159  
160         return status;
161 }
162
163 /* open a rpc connection to a specific transport */
164 NTSTATUS torture_rpc_connection_transport(TALLOC_CTX *parent_ctx, 
165                                           struct dcerpc_pipe **p, 
166                                           const struct dcerpc_interface_table *table,
167                                           enum dcerpc_transport_t transport)
168 {
169         NTSTATUS status;
170         const char *binding = lp_parm_string(-1, "torture", "binding");
171         struct dcerpc_binding *b;
172         TALLOC_CTX *mem_ctx = talloc_named(parent_ctx, 0, "torture_rpc_connection_smb");
173
174         if (!binding) {
175                 printf("You must specify a ncacn binding string\n");
176                 talloc_free(mem_ctx);
177                 return NT_STATUS_INVALID_PARAMETER;
178         }
179
180         status = dcerpc_parse_binding(mem_ctx, binding, &b);
181         if (!NT_STATUS_IS_OK(status)) {
182                 DEBUG(0,("Failed to parse dcerpc binding '%s'\n", binding));
183                 talloc_free(mem_ctx);
184                 return status;
185         }
186
187         b->transport = transport;
188
189         status = dcerpc_pipe_connect_b(mem_ctx, p, b, table,
190                                        cmdline_credentials, NULL);
191                                            
192         if (NT_STATUS_IS_OK(status)) {
193                 *p = talloc_reference(parent_ctx, *p);
194         } else {
195                 *p = NULL;
196         }
197         talloc_free(mem_ctx);
198         return status;
199 }
200
201 /* check if the server produced the expected error code */
202 BOOL check_error(const char *location, struct smbcli_state *c, 
203                  uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
204 {
205         NTSTATUS status;
206         
207         status = smbcli_nt_error(c->tree);
208         if (NT_STATUS_IS_DOS(status)) {
209                 int class, num;
210                 class = NT_STATUS_DOS_CLASS(status);
211                 num = NT_STATUS_DOS_CODE(status);
212                 if (eclass != class || ecode != num) {
213                         printf("unexpected error code %s\n", nt_errstr(status));
214                         printf(" expected %s or %s (at %s)\n", 
215                                nt_errstr(NT_STATUS_DOS(eclass, ecode)), 
216                                nt_errstr(nterr), location);
217                         return False;
218                 }
219         } else {
220                 if (!NT_STATUS_EQUAL(nterr, status)) {
221                         printf("unexpected error code %s\n", nt_errstr(status));
222                         printf(" expected %s (at %s)\n", nt_errstr(nterr), location);
223                         return False;
224                 }
225         }
226
227         return True;
228 }
229
230
231 static BOOL wait_lock(struct smbcli_state *c, int fnum, uint32_t offset, uint32_t len)
232 {
233         while (NT_STATUS_IS_ERR(smbcli_lock(c->tree, fnum, offset, len, -1, WRITE_LOCK))) {
234                 if (!check_error(__location__, c, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return False;
235         }
236         return True;
237 }
238
239
240 static BOOL rw_torture(struct smbcli_state *c)
241 {
242         const char *lockfname = "\\torture.lck";
243         char *fname;
244         int fnum;
245         int fnum2;
246         pid_t pid2, pid = getpid();
247         int i, j;
248         uint8_t buf[1024];
249         BOOL correct = True;
250
251         fnum2 = smbcli_open(c->tree, lockfname, O_RDWR | O_CREAT | O_EXCL, 
252                          DENY_NONE);
253         if (fnum2 == -1)
254                 fnum2 = smbcli_open(c->tree, lockfname, O_RDWR, DENY_NONE);
255         if (fnum2 == -1) {
256                 printf("open of %s failed (%s)\n", lockfname, smbcli_errstr(c->tree));
257                 return False;
258         }
259
260
261         for (i=0;i<torture_numops;i++) {
262                 uint_t n = (uint_t)random()%10;
263                 if (i % 10 == 0) {
264                         printf("%d\r", i); fflush(stdout);
265                 }
266                 asprintf(&fname, "\\torture.%u", n);
267
268                 if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
269                         return False;
270                 }
271
272                 fnum = smbcli_open(c->tree, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
273                 if (fnum == -1) {
274                         printf("open failed (%s)\n", smbcli_errstr(c->tree));
275                         correct = False;
276                         break;
277                 }
278
279                 if (smbcli_write(c->tree, fnum, 0, &pid, 0, sizeof(pid)) != sizeof(pid)) {
280                         printf("write failed (%s)\n", smbcli_errstr(c->tree));
281                         correct = False;
282                 }
283
284                 for (j=0;j<50;j++) {
285                         if (smbcli_write(c->tree, fnum, 0, buf, 
286                                       sizeof(pid)+(j*sizeof(buf)), 
287                                       sizeof(buf)) != sizeof(buf)) {
288                                 printf("write failed (%s)\n", smbcli_errstr(c->tree));
289                                 correct = False;
290                         }
291                 }
292
293                 pid2 = 0;
294
295                 if (smbcli_read(c->tree, fnum, &pid2, 0, sizeof(pid)) != sizeof(pid)) {
296                         printf("read failed (%s)\n", smbcli_errstr(c->tree));
297                         correct = False;
298                 }
299
300                 if (pid2 != pid) {
301                         printf("data corruption!\n");
302                         correct = False;
303                 }
304
305                 if (NT_STATUS_IS_ERR(smbcli_close(c->tree, fnum))) {
306                         printf("close failed (%s)\n", smbcli_errstr(c->tree));
307                         correct = False;
308                 }
309
310                 if (NT_STATUS_IS_ERR(smbcli_unlink(c->tree, fname))) {
311                         printf("unlink failed (%s)\n", smbcli_errstr(c->tree));
312                         correct = False;
313                 }
314
315                 if (NT_STATUS_IS_ERR(smbcli_unlock(c->tree, fnum2, n*sizeof(int), sizeof(int)))) {
316                         printf("unlock failed (%s)\n", smbcli_errstr(c->tree));
317                         correct = False;
318                 }
319                 free(fname);
320         }
321
322         smbcli_close(c->tree, fnum2);
323         smbcli_unlink(c->tree, lockfname);
324
325         printf("%d\n", i);
326
327         return correct;
328 }
329
330 static BOOL run_torture(struct smbcli_state *cli, int dummy)
331 {
332         BOOL ret;
333
334         ret = rw_torture(cli);
335         
336         if (!torture_close_connection(cli)) {
337                 ret = False;
338         }
339
340         return ret;
341 }
342
343
344 static BOOL rw_torture2(struct smbcli_state *c1, struct smbcli_state *c2)
345 {
346         const char *lockfname = "\\torture2.lck";
347         int fnum1;
348         int fnum2;
349         int i;
350         uint8_t buf[131072];
351         uint8_t buf_rd[131072];
352         BOOL correct = True;
353         ssize_t bytes_read, bytes_written;
354
355         if (smbcli_deltree(c1->tree, lockfname) == -1) {
356                 printf("unlink failed (%s)\n", smbcli_errstr(c1->tree));
357         }
358
359         fnum1 = smbcli_open(c1->tree, lockfname, O_RDWR | O_CREAT | O_EXCL, 
360                          DENY_NONE);
361         if (fnum1 == -1) {
362                 printf("first open read/write of %s failed (%s)\n",
363                                 lockfname, smbcli_errstr(c1->tree));
364                 return False;
365         }
366         fnum2 = smbcli_open(c2->tree, lockfname, O_RDONLY, 
367                          DENY_NONE);
368         if (fnum2 == -1) {
369                 printf("second open read-only of %s failed (%s)\n",
370                                 lockfname, smbcli_errstr(c2->tree));
371                 smbcli_close(c1->tree, fnum1);
372                 return False;
373         }
374
375         printf("Checking data integrity over %d ops\n", torture_numops);
376
377         for (i=0;i<torture_numops;i++)
378         {
379                 size_t buf_size = ((uint_t)random()%(sizeof(buf)-1))+ 1;
380                 if (i % 10 == 0) {
381                         printf("%d\r", i); fflush(stdout);
382                 }
383
384                 generate_random_buffer(buf, buf_size);
385
386                 if ((bytes_written = smbcli_write(c1->tree, fnum1, 0, buf, 0, buf_size)) != buf_size) {
387                         printf("write failed (%s)\n", smbcli_errstr(c1->tree));
388                         printf("wrote %d, expected %d\n", (int)bytes_written, (int)buf_size); 
389                         correct = False;
390                         break;
391                 }
392
393                 if ((bytes_read = smbcli_read(c2->tree, fnum2, buf_rd, 0, buf_size)) != buf_size) {
394                         printf("read failed (%s)\n", smbcli_errstr(c2->tree));
395                         printf("read %d, expected %d\n", (int)bytes_read, (int)buf_size); 
396                         correct = False;
397                         break;
398                 }
399
400                 if (memcmp(buf_rd, buf, buf_size) != 0)
401                 {
402                         printf("read/write compare failed\n");
403                         correct = False;
404                         break;
405                 }
406         }
407
408         if (NT_STATUS_IS_ERR(smbcli_close(c2->tree, fnum2))) {
409                 printf("close failed (%s)\n", smbcli_errstr(c2->tree));
410                 correct = False;
411         }
412         if (NT_STATUS_IS_ERR(smbcli_close(c1->tree, fnum1))) {
413                 printf("close failed (%s)\n", smbcli_errstr(c1->tree));
414                 correct = False;
415         }
416
417         if (NT_STATUS_IS_ERR(smbcli_unlink(c1->tree, lockfname))) {
418                 printf("unlink failed (%s)\n", smbcli_errstr(c1->tree));
419                 correct = False;
420         }
421
422         return correct;
423 }
424
425 #define BOOLSTR(b) ((b) ? "Yes" : "No")
426
427 static BOOL run_readwritetest(void)
428 {
429         struct smbcli_state *cli1, *cli2;
430         BOOL test1, test2 = True;
431
432         if (!torture_open_connection(&cli1) || !torture_open_connection(&cli2)) {
433                 return False;
434         }
435
436         printf("starting readwritetest\n");
437
438         test1 = rw_torture2(cli1, cli2);
439         printf("Passed readwritetest v1: %s\n", BOOLSTR(test1));
440
441         if (test1) {
442                 test2 = rw_torture2(cli1, cli1);
443                 printf("Passed readwritetest v2: %s\n", BOOLSTR(test2));
444         }
445
446         if (!torture_close_connection(cli1)) {
447                 test1 = False;
448         }
449
450         if (!torture_close_connection(cli2)) {
451                 test2 = False;
452         }
453
454         return (test1 && test2);
455 }
456
457 /*
458   this checks to see if a secondary tconx can use open files from an
459   earlier tconx
460  */
461 static BOOL run_tcon_test(void)
462 {
463         struct smbcli_state *cli;
464         const char *fname = "\\tcontest.tmp";
465         int fnum1;
466         uint16_t cnum1, cnum2, cnum3;
467         uint16_t vuid1, vuid2;
468         uint8_t buf[4];
469         BOOL ret = True;
470         struct smbcli_tree *tree1;
471         const char *host = lp_parm_string(-1, "torture", "host");
472         const char *share = lp_parm_string(-1, "torture", "share");
473         const char *password = lp_parm_string(-1, "torture", "password");
474
475         if (!torture_open_connection(&cli)) {
476                 return False;
477         }
478
479         printf("starting tcontest\n");
480
481         if (smbcli_deltree(cli->tree, fname) == -1) {
482                 printf("unlink of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
483         }
484
485         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
486         if (fnum1 == -1) {
487                 printf("open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
488                 return False;
489         }
490
491         cnum1 = cli->tree->tid;
492         vuid1 = cli->session->vuid;
493
494         memset(&buf, 0, 4); /* init buf so valgrind won't complain */
495         if (smbcli_write(cli->tree, fnum1, 0, buf, 130, 4) != 4) {
496                 printf("initial write failed (%s)\n", smbcli_errstr(cli->tree));
497                 return False;
498         }
499
500         tree1 = cli->tree;      /* save old tree connection */
501         if (NT_STATUS_IS_ERR(smbcli_tconX(cli, share, "?????", password))) {
502                 printf("%s refused 2nd tree connect (%s)\n", host,
503                            smbcli_errstr(cli->tree));
504                 talloc_free(cli);
505                 return False;
506         }
507
508         cnum2 = cli->tree->tid;
509         cnum3 = MAX(cnum1, cnum2) + 1; /* any invalid number */
510         vuid2 = cli->session->vuid + 1;
511
512         /* try a write with the wrong tid */
513         cli->tree->tid = cnum2;
514
515         if (smbcli_write(cli->tree, fnum1, 0, buf, 130, 4) == 4) {
516                 printf("* server allows write with wrong TID\n");
517                 ret = False;
518         } else {
519                 printf("server fails write with wrong TID : %s\n", smbcli_errstr(cli->tree));
520         }
521
522
523         /* try a write with an invalid tid */
524         cli->tree->tid = cnum3;
525
526         if (smbcli_write(cli->tree, fnum1, 0, buf, 130, 4) == 4) {
527                 printf("* server allows write with invalid TID\n");
528                 ret = False;
529         } else {
530                 printf("server fails write with invalid TID : %s\n", smbcli_errstr(cli->tree));
531         }
532
533         /* try a write with an invalid vuid */
534         cli->session->vuid = vuid2;
535         cli->tree->tid = cnum1;
536
537         if (smbcli_write(cli->tree, fnum1, 0, buf, 130, 4) == 4) {
538                 printf("* server allows write with invalid VUID\n");
539                 ret = False;
540         } else {
541                 printf("server fails write with invalid VUID : %s\n", smbcli_errstr(cli->tree));
542         }
543
544         cli->session->vuid = vuid1;
545         cli->tree->tid = cnum1;
546
547         if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnum1))) {
548                 printf("close failed (%s)\n", smbcli_errstr(cli->tree));
549                 return False;
550         }
551
552         cli->tree->tid = cnum2;
553
554         if (NT_STATUS_IS_ERR(smbcli_tdis(cli))) {
555                 printf("secondary tdis failed (%s)\n", smbcli_errstr(cli->tree));
556                 return False;
557         }
558
559         cli->tree = tree1;  /* restore initial tree */
560         cli->tree->tid = cnum1;
561
562         smbcli_unlink(tree1, fname);
563
564         if (!torture_close_connection(cli)) {
565                 return False;
566         }
567
568         return ret;
569 }
570
571
572
573 static BOOL tcon_devtest(struct smbcli_state *cli,
574                          const char *myshare, const char *devtype,
575                          NTSTATUS expected_error)
576 {
577         BOOL status;
578         BOOL ret;
579         const char *password = lp_parm_string(-1, "torture", "password");
580
581         status = NT_STATUS_IS_OK(smbcli_tconX(cli, myshare, devtype, 
582                                                 password));
583
584         printf("Trying share %s with devtype %s\n", myshare, devtype);
585
586         if (NT_STATUS_IS_OK(expected_error)) {
587                 if (status) {
588                         ret = True;
589                 } else {
590                         printf("tconX to share %s with type %s "
591                                "should have succeeded but failed\n",
592                                myshare, devtype);
593                         ret = False;
594                 }
595                 smbcli_tdis(cli);
596         } else {
597                 if (status) {
598                         printf("tconx to share %s with type %s "
599                                "should have failed but succeeded\n",
600                                myshare, devtype);
601                         ret = False;
602                 } else {
603                         if (NT_STATUS_EQUAL(smbcli_nt_error(cli->tree),
604                                             expected_error)) {
605                                 ret = True;
606                         } else {
607                                 printf("Returned unexpected error\n");
608                                 ret = False;
609                         }
610                 }
611         }
612         return ret;
613 }
614
615 /*
616  checks for correct tconX support
617  */
618 static BOOL run_tcon_devtype_test(void)
619 {
620         struct smbcli_state *cli1 = NULL;
621         NTSTATUS status;
622         BOOL ret = True;
623         const char *host = lp_parm_string(-1, "torture", "host");
624         const char *share = lp_parm_string(-1, "torture", "share");
625         
626         status = smbcli_full_connection(NULL,
627                                         &cli1, host, 
628                                         share, NULL,
629                                         cmdline_credentials, NULL);
630
631         if (!NT_STATUS_IS_OK(status)) {
632                 printf("could not open connection\n");
633                 return False;
634         }
635
636         if (!tcon_devtest(cli1, "IPC$", "A:", NT_STATUS_BAD_DEVICE_TYPE))
637                 ret = False;
638
639         if (!tcon_devtest(cli1, "IPC$", "?????", NT_STATUS_OK))
640                 ret = False;
641
642         if (!tcon_devtest(cli1, "IPC$", "LPT:", NT_STATUS_BAD_DEVICE_TYPE))
643                 ret = False;
644
645         if (!tcon_devtest(cli1, "IPC$", "IPC", NT_STATUS_OK))
646                 ret = False;
647                         
648         if (!tcon_devtest(cli1, "IPC$", "FOOBA", NT_STATUS_BAD_DEVICE_TYPE))
649                 ret = False;
650
651         if (!tcon_devtest(cli1, share, "A:", NT_STATUS_OK))
652                 ret = False;
653
654         if (!tcon_devtest(cli1, share, "?????", NT_STATUS_OK))
655                 ret = False;
656
657         if (!tcon_devtest(cli1, share, "LPT:", NT_STATUS_BAD_DEVICE_TYPE))
658                 ret = False;
659
660         if (!tcon_devtest(cli1, share, "IPC", NT_STATUS_BAD_DEVICE_TYPE))
661                 ret = False;
662                         
663         if (!tcon_devtest(cli1, share, "FOOBA", NT_STATUS_BAD_DEVICE_TYPE))
664                 ret = False;
665
666         talloc_free(cli1);
667
668         if (ret)
669                 printf("Passed tcondevtest\n");
670
671         return ret;
672 }
673
674
675 /*
676 test whether fnums and tids open on one VC are available on another (a major
677 security hole)
678 */
679 static BOOL run_fdpasstest(void)
680 {
681         struct smbcli_state *cli1, *cli2;
682         const char *fname = "\\fdpass.tst";
683         int fnum1, oldtid;
684         uint8_t buf[1024];
685
686         if (!torture_open_connection(&cli1) || !torture_open_connection(&cli2)) {
687                 return False;
688         }
689
690         printf("starting fdpasstest\n");
691
692         smbcli_unlink(cli1->tree, fname);
693
694         printf("Opening a file on connection 1\n");
695
696         fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
697         if (fnum1 == -1) {
698                 printf("open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
699                 return False;
700         }
701
702         printf("writing to file on connection 1\n");
703
704         if (smbcli_write(cli1->tree, fnum1, 0, "hello world\n", 0, 13) != 13) {
705                 printf("write failed (%s)\n", smbcli_errstr(cli1->tree));
706                 return False;
707         }
708
709         oldtid = cli2->tree->tid;
710         cli2->session->vuid = cli1->session->vuid;
711         cli2->tree->tid = cli1->tree->tid;
712         cli2->session->pid = cli1->session->pid;
713
714         printf("reading from file on connection 2\n");
715
716         if (smbcli_read(cli2->tree, fnum1, buf, 0, 13) == 13) {
717                 printf("read succeeded! nasty security hole [%s]\n",
718                        buf);
719                 return False;
720         }
721
722         smbcli_close(cli1->tree, fnum1);
723         smbcli_unlink(cli1->tree, fname);
724
725         cli2->tree->tid = oldtid;
726
727         torture_close_connection(cli1);
728         torture_close_connection(cli2);
729
730         printf("finished fdpasstest\n");
731         return True;
732 }
733
734
735 /*
736 test the timing of deferred open requests
737 */
738 static BOOL run_deferopen(struct smbcli_state *cli, int dummy)
739 {
740         const char *fname = "\\defer_open_test.dat";
741         int retries=4;
742         int i = 0;
743         BOOL correct = True;
744
745         if (retries <= 0) {
746                 printf("failed to connect\n");
747                 return False;
748         }
749
750         printf("Testing deferred open requests.\n");
751
752         while (i < 4) {
753                 int fnum = -1;
754
755                 do {
756                         struct timeval tv;
757                         tv = timeval_current();
758                         fnum = smbcli_nt_create_full(cli->tree, fname, 0, 
759                                                      SEC_RIGHTS_FILE_ALL,
760                                                      FILE_ATTRIBUTE_NORMAL, 
761                                                      NTCREATEX_SHARE_ACCESS_NONE,
762                                                      NTCREATEX_DISP_OPEN_IF, 0, 0);
763                         if (fnum != -1) {
764                                 break;
765                         }
766                         if (NT_STATUS_EQUAL(smbcli_nt_error(cli->tree),NT_STATUS_SHARING_VIOLATION)) {
767                                 double e = timeval_elapsed(&tv);
768                                 if (e < 0.5 || e > 1.5) {
769                                         fprintf(stderr,"Timing incorrect %.2f violation\n",
770                                                 e);
771                                 }
772                         }
773                 } while (NT_STATUS_EQUAL(smbcli_nt_error(cli->tree),NT_STATUS_SHARING_VIOLATION));
774
775                 if (fnum == -1) {
776                         fprintf(stderr,"Failed to open %s, error=%s\n", fname, smbcli_errstr(cli->tree));
777                         return False;
778                 }
779
780                 printf("pid %u open %d\n", getpid(), i);
781
782                 sleep(10);
783                 i++;
784                 if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnum))) {
785                         fprintf(stderr,"Failed to close %s, error=%s\n", fname, smbcli_errstr(cli->tree));
786                         return False;
787                 }
788                 sleep(2);
789         }
790
791         if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) {
792                 /* All until the last unlink will fail with sharing violation. */
793                 if (!NT_STATUS_EQUAL(smbcli_nt_error(cli->tree),NT_STATUS_SHARING_VIOLATION)) {
794                         printf("unlink of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
795                         correct = False;
796                 }
797         }
798
799         printf("deferred test finished\n");
800         if (!torture_close_connection(cli)) {
801                 correct = False;
802         }
803         return correct;
804 }
805
806 /*
807 test how many open files this server supports on the one socket
808 */
809 static BOOL run_maxfidtest(struct smbcli_state *cli, int dummy)
810 {
811 #define MAXFID_TEMPLATE "\\maxfid\\fid%d\\maxfid.%d.%d"
812         char *fname;
813         int fnums[0x11000], i;
814         int retries=4, maxfid;
815         BOOL correct = True;
816
817         if (retries <= 0) {
818                 printf("failed to connect\n");
819                 return False;
820         }
821
822         if (smbcli_deltree(cli->tree, "\\maxfid") == -1) {
823                 printf("Failed to deltree \\maxfid - %s\n",
824                        smbcli_errstr(cli->tree));
825                 return False;
826         }
827         if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, "\\maxfid"))) {
828                 printf("Failed to mkdir \\maxfid, error=%s\n", 
829                        smbcli_errstr(cli->tree));
830                 return False;
831         }
832
833         printf("Testing maximum number of open files\n");
834
835         for (i=0; i<0x11000; i++) {
836                 if (i % 1000 == 0) {
837                         asprintf(&fname, "\\maxfid\\fid%d", i/1000);
838                         if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, fname))) {
839                                 printf("Failed to mkdir %s, error=%s\n", 
840                                        fname, smbcli_errstr(cli->tree));
841                                 return False;
842                         }
843                         free(fname);
844                 }
845                 asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid());
846                 if ((fnums[i] = smbcli_open(cli->tree, fname, 
847                                         O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) ==
848                     -1) {
849                         printf("open of %s failed (%s)\n", 
850                                fname, smbcli_errstr(cli->tree));
851                         printf("maximum fnum is %d\n", i);
852                         break;
853                 }
854                 free(fname);
855                 printf("%6d\r", i);
856         }
857         printf("%6d\n", i);
858         i--;
859
860         maxfid = i;
861
862         printf("cleaning up\n");
863         for (i=0;i<maxfid/2;i++) {
864                 asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid());
865                 if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnums[i]))) {
866                         printf("Close of fnum %d failed - %s\n", fnums[i], smbcli_errstr(cli->tree));
867                 }
868                 if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) {
869                         printf("unlink of %s failed (%s)\n", 
870                                fname, smbcli_errstr(cli->tree));
871                         correct = False;
872                 }
873                 free(fname);
874
875                 asprintf(&fname, MAXFID_TEMPLATE, (maxfid-i)/1000, maxfid-i,(int)getpid());
876                 if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnums[maxfid-i]))) {
877                         printf("Close of fnum %d failed - %s\n", fnums[maxfid-i], smbcli_errstr(cli->tree));
878                 }
879                 if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) {
880                         printf("unlink of %s failed (%s)\n", 
881                                fname, smbcli_errstr(cli->tree));
882                         correct = False;
883                 }
884                 free(fname);
885
886                 printf("%6d %6d\r", i, maxfid-i);
887         }
888         printf("%6d\n", 0);
889
890         if (smbcli_deltree(cli->tree, "\\maxfid") == -1) {
891                 printf("Failed to deltree \\maxfid - %s\n",
892                        smbcli_errstr(cli->tree));
893                 return False;
894         }
895
896         printf("maxfid test finished\n");
897         if (!torture_close_connection(cli)) {
898                 correct = False;
899         }
900         return correct;
901 #undef MAXFID_TEMPLATE
902 }
903
904 /* send smb negprot commands, not reading the response */
905 static BOOL run_negprot_nowait(void)
906 {
907         int i;
908         struct smbcli_state *cli, *cli2;
909         BOOL correct = True;
910
911         printf("starting negprot nowait test\n");
912
913         cli = open_nbt_connection();
914         if (!cli) {
915                 return False;
916         }
917
918         printf("Filling send buffer\n");
919
920         for (i=0;i<100;i++) {
921                 struct smbcli_request *req;
922                 req = smb_raw_negotiate_send(cli->transport, PROTOCOL_NT1);
923                 event_loop_once(cli->transport->socket->event.ctx);
924                 if (req->state == SMBCLI_REQUEST_ERROR) {
925                         if (i > 0) {
926                                 printf("Failed to fill pipe packet[%d] - %s (ignored)\n", i+1, nt_errstr(req->status));
927                                 break;
928                         } else {
929                                 printf("Failed to fill pipe - %s \n", nt_errstr(req->status));
930                                 torture_close_connection(cli);
931                                 return False;
932                         }
933                 }
934         }
935
936         printf("Opening secondary connection\n");
937         if (!torture_open_connection(&cli2)) {
938                 printf("Failed to open secondary connection\n");
939                 correct = False;
940         }
941
942         if (!torture_close_connection(cli2)) {
943                 printf("Failed to close secondary connection\n");
944                 correct = False;
945         }
946
947         torture_close_connection(cli);
948
949         printf("finished negprot nowait test\n");
950
951         return correct;
952 }
953
954
955 /*
956   This checks how the getatr calls works
957 */
958 static BOOL run_attrtest(void)
959 {
960         struct smbcli_state *cli;
961         int fnum;
962         time_t t, t2;
963         const char *fname = "\\attrib123456789.tst";
964         BOOL correct = True;
965
966         printf("starting attrib test\n");
967
968         if (!torture_open_connection(&cli)) {
969                 return False;
970         }
971
972         smbcli_unlink(cli->tree, fname);
973         fnum = smbcli_open(cli->tree, fname, 
974                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
975         smbcli_close(cli->tree, fnum);
976
977         if (NT_STATUS_IS_ERR(smbcli_getatr(cli->tree, fname, NULL, NULL, &t))) {
978                 printf("getatr failed (%s)\n", smbcli_errstr(cli->tree));
979                 correct = False;
980         }
981
982         printf("New file time is %s", ctime(&t));
983
984         if (abs(t - time(NULL)) > 60*60*24*10) {
985                 printf("ERROR: SMBgetatr bug. time is %s",
986                        ctime(&t));
987                 t = time(NULL);
988                 correct = False;
989         }
990
991         t2 = t-60*60*24; /* 1 day ago */
992
993         printf("Setting file time to %s", ctime(&t2));
994
995         if (NT_STATUS_IS_ERR(smbcli_setatr(cli->tree, fname, 0, t2))) {
996                 printf("setatr failed (%s)\n", smbcli_errstr(cli->tree));
997                 correct = True;
998         }
999
1000         if (NT_STATUS_IS_ERR(smbcli_getatr(cli->tree, fname, NULL, NULL, &t))) {
1001                 printf("getatr failed (%s)\n", smbcli_errstr(cli->tree));
1002                 correct = True;
1003         }
1004
1005         printf("Retrieved file time as %s", ctime(&t));
1006
1007         if (t != t2) {
1008                 printf("ERROR: getatr/setatr bug. times are\n%s",
1009                        ctime(&t));
1010                 printf("%s", ctime(&t2));
1011                 correct = True;
1012         }
1013
1014         smbcli_unlink(cli->tree, fname);
1015
1016         if (!torture_close_connection(cli)) {
1017                 correct = False;
1018         }
1019
1020         printf("attrib test finished\n");
1021
1022         return correct;
1023 }
1024
1025
1026 /*
1027   This checks a couple of trans2 calls
1028 */
1029 static BOOL run_trans2test(void)
1030 {
1031         struct smbcli_state *cli;
1032         int fnum;
1033         size_t size;
1034         time_t c_time, a_time, m_time, w_time, m_time2;
1035         const char *fname = "\\trans2.tst";
1036         const char *dname = "\\trans2";
1037         const char *fname2 = "\\trans2\\trans2.tst";
1038         const char *pname;
1039         BOOL correct = True;
1040
1041         printf("starting trans2 test\n");
1042
1043         if (!torture_open_connection(&cli)) {
1044                 return False;
1045         }
1046
1047         smbcli_unlink(cli->tree, fname);
1048
1049         printf("Testing qfileinfo\n");
1050         
1051         fnum = smbcli_open(cli->tree, fname, 
1052                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
1053         if (NT_STATUS_IS_ERR(smbcli_qfileinfo(cli->tree, fnum, NULL, &size, &c_time, &a_time, &m_time,
1054                            NULL, NULL))) {
1055                 printf("ERROR: qfileinfo failed (%s)\n", smbcli_errstr(cli->tree));
1056                 correct = False;
1057         }
1058
1059         printf("Testing NAME_INFO\n");
1060
1061         if (NT_STATUS_IS_ERR(smbcli_qfilename(cli->tree, fnum, &pname))) {
1062                 printf("ERROR: qfilename failed (%s)\n", smbcli_errstr(cli->tree));
1063                 correct = False;
1064         }
1065
1066         if (!pname || strcmp(pname, fname)) {
1067                 printf("qfilename gave different name? [%s] [%s]\n",
1068                        fname, pname);
1069                 correct = False;
1070         }
1071
1072         smbcli_close(cli->tree, fnum);
1073         smbcli_unlink(cli->tree, fname);
1074
1075         fnum = smbcli_open(cli->tree, fname, 
1076                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
1077         if (fnum == -1) {
1078                 printf("open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
1079                 return False;
1080         }
1081         smbcli_close(cli->tree, fnum);
1082
1083         printf("Checking for sticky create times\n");
1084
1085         if (NT_STATUS_IS_ERR(smbcli_qpathinfo(cli->tree, fname, &c_time, &a_time, &m_time, &size, NULL))) {
1086                 printf("ERROR: qpathinfo failed (%s)\n", smbcli_errstr(cli->tree));
1087                 correct = False;
1088         } else {
1089                 if (c_time != m_time) {
1090                         printf("create time=%s", ctime(&c_time));
1091                         printf("modify time=%s", ctime(&m_time));
1092                         printf("This system appears to have sticky create times\n");
1093                 }
1094                 if (a_time % (60*60) == 0) {
1095                         printf("access time=%s", ctime(&a_time));
1096                         printf("This system appears to set a midnight access time\n");
1097                         correct = False;
1098                 }
1099
1100                 if (abs(m_time - time(NULL)) > 60*60*24*7) {
1101                         printf("ERROR: totally incorrect times - maybe word reversed? mtime=%s", ctime(&m_time));
1102                         correct = False;
1103                 }
1104         }
1105
1106
1107         smbcli_unlink(cli->tree, fname);
1108         fnum = smbcli_open(cli->tree, fname, 
1109                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
1110         smbcli_close(cli->tree, fnum);
1111         if (NT_STATUS_IS_ERR(smbcli_qpathinfo2(cli->tree, fname, &c_time, &a_time, &m_time, &w_time, &size, NULL, NULL))) {
1112                 printf("ERROR: qpathinfo2 failed (%s)\n", smbcli_errstr(cli->tree));
1113                 correct = False;
1114         } else {
1115                 if (w_time < 60*60*24*2) {
1116                         printf("write time=%s", ctime(&w_time));
1117                         printf("This system appears to set a initial 0 write time\n");
1118                         correct = False;
1119                 }
1120         }
1121
1122         smbcli_unlink(cli->tree, fname);
1123
1124
1125         /* check if the server updates the directory modification time
1126            when creating a new file */
1127         if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, dname))) {
1128                 printf("ERROR: mkdir failed (%s)\n", smbcli_errstr(cli->tree));
1129                 correct = False;
1130         }
1131         sleep(3);
1132         if (NT_STATUS_IS_ERR(smbcli_qpathinfo2(cli->tree, "\\trans2\\", &c_time, &a_time, &m_time, &w_time, &size, NULL, NULL))) {
1133                 printf("ERROR: qpathinfo2 failed (%s)\n", smbcli_errstr(cli->tree));
1134                 correct = False;
1135         }
1136
1137         fnum = smbcli_open(cli->tree, fname2, 
1138                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
1139         smbcli_write(cli->tree, fnum,  0, &fnum, 0, sizeof(fnum));
1140         smbcli_close(cli->tree, fnum);
1141         if (NT_STATUS_IS_ERR(smbcli_qpathinfo2(cli->tree, "\\trans2\\", &c_time, &a_time, &m_time2, &w_time, &size, NULL, NULL))) {
1142                 printf("ERROR: qpathinfo2 failed (%s)\n", smbcli_errstr(cli->tree));
1143                 correct = False;
1144         } else {
1145                 if (m_time2 == m_time) {
1146                         printf("This system does not update directory modification times\n");
1147                         correct = False;
1148                 }
1149         }
1150         smbcli_unlink(cli->tree, fname2);
1151         smbcli_rmdir(cli->tree, dname);
1152
1153         if (!torture_close_connection(cli)) {
1154                 correct = False;
1155         }
1156
1157         printf("trans2 test finished\n");
1158
1159         return correct;
1160 }
1161
1162
1163
1164 /* FIRST_DESIRED_ACCESS   0xf019f */
1165 #define FIRST_DESIRED_ACCESS   SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|SEC_FILE_APPEND_DATA|\
1166                                SEC_FILE_READ_EA|                           /* 0xf */ \
1167                                SEC_FILE_WRITE_EA|SEC_FILE_READ_ATTRIBUTE|     /* 0x90 */ \
1168                                SEC_FILE_WRITE_ATTRIBUTE|                  /* 0x100 */ \
1169                                SEC_STD_DELETE|SEC_STD_READ_CONTROL|\
1170                                SEC_STD_WRITE_DAC|SEC_STD_WRITE_OWNER     /* 0xf0000 */
1171 /* SECOND_DESIRED_ACCESS  0xe0080 */
1172 #define SECOND_DESIRED_ACCESS  SEC_FILE_READ_ATTRIBUTE|                   /* 0x80 */ \
1173                                SEC_STD_READ_CONTROL|SEC_STD_WRITE_DAC|\
1174                                SEC_STD_WRITE_OWNER                      /* 0xe0000 */
1175
1176 #if 0
1177 #define THIRD_DESIRED_ACCESS   FILE_READ_ATTRIBUTE|                   /* 0x80 */ \
1178                                READ_CONTROL|WRITE_DAC|\
1179                                SEC_FILE_READ_DATA|\
1180                                WRITE_OWNER                      /* */
1181 #endif
1182
1183 /*
1184   Test ntcreate calls made by xcopy
1185  */
1186 static BOOL run_xcopy(void)
1187 {
1188         struct smbcli_state *cli1;
1189         const char *fname = "\\test.txt";
1190         BOOL correct = True;
1191         int fnum1, fnum2;
1192
1193         printf("starting xcopy test\n");
1194         
1195         if (!torture_open_connection(&cli1)) {
1196                 return False;
1197         }
1198         
1199         fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
1200                                       FIRST_DESIRED_ACCESS, 
1201                                       FILE_ATTRIBUTE_ARCHIVE,
1202                                       NTCREATEX_SHARE_ACCESS_NONE, 
1203                                       NTCREATEX_DISP_OVERWRITE_IF, 
1204                                       0x4044, 0);
1205
1206         if (fnum1 == -1) {
1207                 printf("First open failed - %s\n", smbcli_errstr(cli1->tree));
1208                 return False;
1209         }
1210
1211         fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
1212                                    SECOND_DESIRED_ACCESS, 0,
1213                                    NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, NTCREATEX_DISP_OPEN, 
1214                                    0x200000, 0);
1215         if (fnum2 == -1) {
1216                 printf("second open failed - %s\n", smbcli_errstr(cli1->tree));
1217                 return False;
1218         }
1219         
1220         if (!torture_close_connection(cli1)) {
1221                 correct = False;
1222         }
1223         
1224         return correct;
1225 }
1226
1227
1228 /*
1229   see how many RPC pipes we can open at once
1230 */
1231 static BOOL run_pipe_number(void)
1232 {
1233         struct smbcli_state *cli1;
1234         const char *pipe_name = "\\WKSSVC";
1235         int fnum;
1236         int num_pipes = 0;
1237
1238         printf("starting pipenumber test\n");
1239         if (!torture_open_connection(&cli1)) {
1240                 return False;
1241         }
1242
1243         while(1) {
1244                 fnum = smbcli_nt_create_full(cli1->tree, pipe_name, 0, SEC_FILE_READ_DATA, FILE_ATTRIBUTE_NORMAL,
1245                                    NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE, NTCREATEX_DISP_OPEN_IF, 0, 0);
1246
1247                 if (fnum == -1) {
1248                         printf("Open of pipe %s failed with error (%s)\n", pipe_name, smbcli_errstr(cli1->tree));
1249                         break;
1250                 }
1251                 num_pipes++;
1252                 printf("%d\r", num_pipes);
1253                 fflush(stdout);
1254         }
1255
1256         printf("pipe_number test - we can open %d %s pipes.\n", num_pipes, pipe_name );
1257         torture_close_connection(cli1);
1258         return True;
1259 }
1260
1261
1262
1263
1264 /*
1265   open N connections to the server and just hold them open
1266   used for testing performance when there are N idle users
1267   already connected
1268  */
1269  static BOOL torture_holdcon(void)
1270 {
1271         int i;
1272         struct smbcli_state **cli;
1273         int num_dead = 0;
1274
1275         printf("Opening %d connections\n", torture_numops);
1276         
1277         cli = malloc_array_p(struct smbcli_state *, torture_numops);
1278
1279         for (i=0;i<torture_numops;i++) {
1280                 if (!torture_open_connection(&cli[i])) {
1281                         return False;
1282                 }
1283                 printf("opened %d connections\r", i);
1284                 fflush(stdout);
1285         }
1286
1287         printf("\nStarting pings\n");
1288
1289         while (1) {
1290                 for (i=0;i<torture_numops;i++) {
1291                         NTSTATUS status;
1292                         if (cli[i]) {
1293                                 status = smbcli_chkpath(cli[i]->tree, "\\");
1294                                 if (!NT_STATUS_IS_OK(status)) {
1295                                         printf("Connection %d is dead\n", i);
1296                                         cli[i] = NULL;
1297                                         num_dead++;
1298                                 }
1299                                 usleep(100);
1300                         }
1301                 }
1302
1303                 if (num_dead == torture_numops) {
1304                         printf("All connections dead - finishing\n");
1305                         break;
1306                 }
1307
1308                 printf(".");
1309                 fflush(stdout);
1310         }
1311
1312         return True;
1313 }
1314
1315 /*
1316   Try with a wrong vuid and check error message.
1317  */
1318
1319 static BOOL run_vuidtest(void)
1320 {
1321         struct smbcli_state *cli;
1322         const char *fname = "\\vuid.tst";
1323         int fnum;
1324         size_t size;
1325         time_t c_time, a_time, m_time;
1326         BOOL correct = True;
1327
1328         uint16_t orig_vuid;
1329         NTSTATUS result;
1330
1331         printf("starting vuid test\n");
1332
1333         if (!torture_open_connection(&cli)) {
1334                 return False;
1335         }
1336
1337         smbcli_unlink(cli->tree, fname);
1338
1339         fnum = smbcli_open(cli->tree, fname, 
1340                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
1341
1342         orig_vuid = cli->session->vuid;
1343
1344         cli->session->vuid += 1234;
1345
1346         printf("Testing qfileinfo with wrong vuid\n");
1347         
1348         if (NT_STATUS_IS_OK(result = smbcli_qfileinfo(cli->tree, fnum, NULL,
1349                                                    &size, &c_time, &a_time,
1350                                                    &m_time, NULL, NULL))) {
1351                 printf("ERROR: qfileinfo passed with wrong vuid\n");
1352                 correct = False;
1353         }
1354
1355         if (!NT_STATUS_EQUAL(cli->transport->error.e.nt_status, 
1356                              NT_STATUS_DOS(ERRSRV, ERRbaduid)) &&
1357             !NT_STATUS_EQUAL(cli->transport->error.e.nt_status, 
1358                              NT_STATUS_INVALID_HANDLE)) {
1359                 printf("ERROR: qfileinfo should have returned DOS error "
1360                        "ERRSRV:ERRbaduid\n  but returned %s\n",
1361                        smbcli_errstr(cli->tree));
1362                 correct = False;
1363         }
1364
1365         cli->session->vuid -= 1234;
1366
1367         if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnum))) {
1368                 printf("close failed (%s)\n", smbcli_errstr(cli->tree));
1369                 correct = False;
1370         }
1371
1372         smbcli_unlink(cli->tree, fname);
1373
1374         if (!torture_close_connection(cli)) {
1375                 correct = False;
1376         }
1377
1378         printf("vuid test finished\n");
1379
1380         return correct;
1381 }
1382
1383 /*
1384   Test open mode returns on read-only files.
1385  */
1386  static BOOL run_opentest(void)
1387 {
1388         static struct smbcli_state *cli1;
1389         static struct smbcli_state *cli2;
1390         const char *fname = "\\readonly.file";
1391         char *control_char_fname;
1392         int fnum1, fnum2;
1393         uint8_t buf[20];
1394         size_t fsize;
1395         BOOL correct = True;
1396         char *tmp_path;
1397         int failures = 0;
1398         int i;
1399
1400         printf("starting open test\n");
1401         
1402         if (!torture_open_connection(&cli1)) {
1403                 return False;
1404         }
1405         
1406         asprintf(&control_char_fname, "\\readonly.afile");
1407         for (i = 1; i <= 0x1f; i++) {
1408                 control_char_fname[10] = i;
1409                 fnum1 = smbcli_nt_create_full(cli1->tree, control_char_fname, 0, SEC_FILE_WRITE_DATA, FILE_ATTRIBUTE_NORMAL,
1410                                    NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
1411                 
1412                 if (!check_error(__location__, cli1, ERRDOS, ERRinvalidname, 
1413                                 NT_STATUS_OBJECT_NAME_INVALID)) {
1414                         printf("Error code should be NT_STATUS_OBJECT_NAME_INVALID, was %s for file with %d char\n",
1415                                         smbcli_errstr(cli1->tree), i);
1416                         failures++;
1417                 }
1418
1419                 if (fnum1 != -1) {
1420                         smbcli_close(cli1->tree, fnum1);
1421                 }
1422                 smbcli_setatr(cli1->tree, control_char_fname, 0, 0);
1423                 smbcli_unlink(cli1->tree, control_char_fname);
1424         }
1425         free(control_char_fname);
1426
1427         if (!failures)
1428                 printf("Create file with control char names passed.\n");
1429
1430         smbcli_setatr(cli1->tree, fname, 0, 0);
1431         smbcli_unlink(cli1->tree, fname);
1432         
1433         fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
1434         if (fnum1 == -1) {
1435                 printf("open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
1436                 return False;
1437         }
1438
1439         if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
1440                 printf("close2 failed (%s)\n", smbcli_errstr(cli1->tree));
1441                 return False;
1442         }
1443         
1444         if (NT_STATUS_IS_ERR(smbcli_setatr(cli1->tree, fname, FILE_ATTRIBUTE_READONLY, 0))) {
1445                 printf("smbcli_setatr failed (%s)\n", smbcli_errstr(cli1->tree));
1446                 CHECK_MAX_FAILURES(error_test1);
1447                 return False;
1448         }
1449         
1450         fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_WRITE);
1451         if (fnum1 == -1) {
1452                 printf("open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
1453                 CHECK_MAX_FAILURES(error_test1);
1454                 return False;
1455         }
1456         
1457         /* This will fail - but the error should be ERRnoaccess, not ERRbadshare. */
1458         fnum2 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_ALL);
1459         
1460         if (check_error(__location__, cli1, ERRDOS, ERRnoaccess, 
1461                         NT_STATUS_ACCESS_DENIED)) {
1462                 printf("correct error code ERRDOS/ERRnoaccess returned\n");
1463         }
1464         
1465         printf("finished open test 1\n");
1466 error_test1:
1467         smbcli_close(cli1->tree, fnum1);
1468         
1469         /* Now try not readonly and ensure ERRbadshare is returned. */
1470         
1471         smbcli_setatr(cli1->tree, fname, 0, 0);
1472         
1473         fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_WRITE);
1474         if (fnum1 == -1) {
1475                 printf("open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
1476                 return False;
1477         }
1478         
1479         /* This will fail - but the error should be ERRshare. */
1480         fnum2 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_ALL);
1481         
1482         if (check_error(__location__, cli1, ERRDOS, ERRbadshare, 
1483                         NT_STATUS_SHARING_VIOLATION)) {
1484                 printf("correct error code ERRDOS/ERRbadshare returned\n");
1485         }
1486         
1487         if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
1488                 printf("close2 failed (%s)\n", smbcli_errstr(cli1->tree));
1489                 return False;
1490         }
1491         
1492         smbcli_unlink(cli1->tree, fname);
1493         
1494         printf("finished open test 2\n");
1495         
1496         /* Test truncate open disposition on file opened for read. */
1497         
1498         fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
1499         if (fnum1 == -1) {
1500                 printf("(3) open (1) of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
1501                 return False;
1502         }
1503         
1504         /* write 20 bytes. */
1505         
1506         memset(buf, '\0', 20);
1507
1508         if (smbcli_write(cli1->tree, fnum1, 0, buf, 0, 20) != 20) {
1509                 printf("write failed (%s)\n", smbcli_errstr(cli1->tree));
1510                 correct = False;
1511         }
1512
1513         if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
1514                 printf("(3) close1 failed (%s)\n", smbcli_errstr(cli1->tree));
1515                 return False;
1516         }
1517         
1518         /* Ensure size == 20. */
1519         if (NT_STATUS_IS_ERR(smbcli_getatr(cli1->tree, fname, NULL, &fsize, NULL))) {
1520                 printf("(3) getatr failed (%s)\n", smbcli_errstr(cli1->tree));
1521                 CHECK_MAX_FAILURES(error_test3);
1522                 return False;
1523         }
1524         
1525         if (fsize != 20) {
1526                 printf("(3) file size != 20\n");
1527                 CHECK_MAX_FAILURES(error_test3);
1528                 return False;
1529         }
1530
1531         /* Now test if we can truncate a file opened for readonly. */
1532         
1533         fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY|O_TRUNC, DENY_NONE);
1534         if (fnum1 == -1) {
1535                 printf("(3) open (2) of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
1536                 CHECK_MAX_FAILURES(error_test3);
1537                 return False;
1538         }
1539         
1540         if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
1541                 printf("close2 failed (%s)\n", smbcli_errstr(cli1->tree));
1542                 return False;
1543         }
1544
1545         /* Ensure size == 0. */
1546         if (NT_STATUS_IS_ERR(smbcli_getatr(cli1->tree, fname, NULL, &fsize, NULL))) {
1547                 printf("(3) getatr failed (%s)\n", smbcli_errstr(cli1->tree));
1548                 CHECK_MAX_FAILURES(error_test3);
1549                 return False;
1550         }
1551
1552         if (fsize != 0) {
1553                 printf("(3) file size != 0\n");
1554                 CHECK_MAX_FAILURES(error_test3);
1555                 return False;
1556         }
1557         printf("finished open test 3\n");
1558 error_test3:    
1559         smbcli_unlink(cli1->tree, fname);
1560
1561
1562         printf("testing ctemp\n");
1563         fnum1 = smbcli_ctemp(cli1->tree, "\\", &tmp_path);
1564         if (fnum1 == -1) {
1565                 printf("ctemp failed (%s)\n", smbcli_errstr(cli1->tree));
1566                 CHECK_MAX_FAILURES(error_test4);
1567                 return False;
1568         }
1569         printf("ctemp gave path %s\n", tmp_path);
1570         if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
1571                 printf("close of temp failed (%s)\n", smbcli_errstr(cli1->tree));
1572         }
1573         if (NT_STATUS_IS_ERR(smbcli_unlink(cli1->tree, tmp_path))) {
1574                 printf("unlink of temp failed (%s)\n", smbcli_errstr(cli1->tree));
1575         }
1576 error_test4:    
1577         /* Test the non-io opens... */
1578
1579         if (!torture_open_connection(&cli2)) {
1580                 return False;
1581         }
1582         
1583         smbcli_setatr(cli2->tree, fname, 0, 0);
1584         smbcli_unlink(cli2->tree, fname);
1585         
1586         printf("TEST #1 testing 2 non-io opens (no delete)\n");
1587         
1588         fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0, SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
1589                                    NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
1590
1591         if (fnum1 == -1) {
1592                 printf("test 1 open 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
1593                 CHECK_MAX_FAILURES(error_test10);
1594                 return False;
1595         }
1596
1597         fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0, SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
1598                                    NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OPEN_IF, 0, 0);
1599         if (fnum2 == -1) {
1600                 printf("test 1 open 2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree));
1601                 CHECK_MAX_FAILURES(error_test10);
1602                 return False;
1603         }
1604
1605         if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
1606                 printf("test 1 close 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
1607                 return False;
1608         }
1609         if (NT_STATUS_IS_ERR(smbcli_close(cli2->tree, fnum2))) {
1610                 printf("test 1 close 2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree));
1611                 return False;
1612         }
1613
1614         printf("non-io open test #1 passed.\n");
1615 error_test10:
1616         smbcli_unlink(cli1->tree, fname);
1617
1618         printf("TEST #2 testing 2 non-io opens (first with delete)\n");
1619         
1620         fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0, SEC_STD_DELETE|SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
1621                                    NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
1622
1623         if (fnum1 == -1) {
1624                 printf("test 2 open 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
1625                 CHECK_MAX_FAILURES(error_test20);
1626                 return False;
1627         }
1628
1629         fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0, SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
1630                                    NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OPEN_IF, 0, 0);
1631
1632         if (fnum2 == -1) {
1633                 printf("test 2 open 2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree));
1634                 CHECK_MAX_FAILURES(error_test20);
1635                 return False;
1636         }
1637
1638         if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
1639                 printf("test 1 close 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
1640                 return False;
1641         }
1642         if (NT_STATUS_IS_ERR(smbcli_close(cli2->tree, fnum2))) {
1643                 printf("test 1 close 2 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
1644                 return False;
1645         }
1646
1647         printf("non-io open test #2 passed.\n");
1648 error_test20:
1649         smbcli_unlink(cli1->tree, fname);
1650
1651         printf("TEST #3 testing 2 non-io opens (second with delete)\n");
1652         
1653         fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0, SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
1654                                    NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
1655
1656         if (fnum1 == -1) {
1657                 printf("test 3 open 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
1658                 CHECK_MAX_FAILURES(error_test30);
1659                 return False;
1660         }
1661
1662         fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0, SEC_STD_DELETE|SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
1663                                    NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OPEN_IF, 0, 0);
1664
1665         if (fnum2 == -1) {
1666                 printf("test 3 open 2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree));
1667                 CHECK_MAX_FAILURES(error_test30);
1668                 return False;
1669         }
1670
1671         if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
1672                 printf("test 3 close 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
1673                 return False;
1674         }
1675         if (NT_STATUS_IS_ERR(smbcli_close(cli2->tree, fnum2))) {
1676                 printf("test 3 close 2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree));
1677                 return False;
1678         }
1679
1680         printf("non-io open test #3 passed.\n");
1681 error_test30:
1682         smbcli_unlink(cli1->tree, fname);
1683
1684         printf("TEST #4 testing 2 non-io opens (both with delete)\n");
1685         
1686         fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0, SEC_STD_DELETE|SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
1687                                    NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
1688
1689         if (fnum1 == -1) {
1690                 printf("test 4 open 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
1691                 CHECK_MAX_FAILURES(error_test40);
1692                 return False;
1693         }
1694
1695         fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0, SEC_STD_DELETE|SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
1696                                    NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OPEN_IF, 0, 0);
1697
1698         if (fnum2 != -1) {
1699                 printf("test 4 open 2 of %s SUCCEEDED - should have failed (%s)\n", fname, smbcli_errstr(cli2->tree));
1700                 CHECK_MAX_FAILURES(error_test40);
1701                 return False;
1702         }
1703
1704         printf("test 4 open 2 of %s gave %s (correct error should be %s)\n", fname, smbcli_errstr(cli2->tree), "sharing violation");
1705
1706         if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
1707                 printf("test 4 close 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
1708                 return False;
1709         }
1710
1711         printf("non-io open test #4 passed.\n");
1712 error_test40:
1713         smbcli_unlink(cli1->tree, fname);
1714
1715         printf("TEST #5 testing 2 non-io opens (both with delete - both with file share delete)\n");
1716         
1717         fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0, SEC_STD_DELETE|SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
1718                                    NTCREATEX_SHARE_ACCESS_DELETE, NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
1719
1720         if (fnum1 == -1) {
1721                 printf("test 5 open 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
1722                 CHECK_MAX_FAILURES(error_test50);
1723                 return False;
1724         }
1725
1726         fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0, SEC_STD_DELETE|SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
1727                                    NTCREATEX_SHARE_ACCESS_DELETE, NTCREATEX_DISP_OPEN_IF, 0, 0);
1728
1729         if (fnum2 == -1) {
1730                 printf("test 5 open 2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree));
1731                 CHECK_MAX_FAILURES(error_test50);
1732                 return False;
1733         }
1734
1735         if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
1736                 printf("test 5 close 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
1737                 return False;
1738         }
1739
1740         if (NT_STATUS_IS_ERR(smbcli_close(cli2->tree, fnum2))) {
1741                 printf("test 5 close 2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree));
1742                 return False;
1743         }
1744
1745         printf("non-io open test #5 passed.\n");
1746 error_test50:
1747         printf("TEST #6 testing 1 non-io open, one io open\n");
1748         
1749         smbcli_unlink(cli1->tree, fname);
1750
1751         fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0, SEC_FILE_READ_DATA, FILE_ATTRIBUTE_NORMAL,
1752                                    NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
1753
1754         if (fnum1 == -1) {
1755                 printf("test 6 open 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
1756                 CHECK_MAX_FAILURES(error_test60);
1757                 return False;
1758         }
1759
1760         fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0, SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
1761                                    NTCREATEX_SHARE_ACCESS_READ, NTCREATEX_DISP_OPEN_IF, 0, 0);
1762
1763         if (fnum2 == -1) {
1764                 printf("test 6 open 2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree));
1765                 CHECK_MAX_FAILURES(error_test60);
1766                 return False;
1767         }
1768
1769         if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
1770                 printf("test 6 close 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
1771                 return False;
1772         }
1773
1774         if (NT_STATUS_IS_ERR(smbcli_close(cli2->tree, fnum2))) {
1775                 printf("test 6 close 2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree));
1776                 return False;
1777         }
1778
1779         printf("non-io open test #6 passed.\n");
1780 error_test60:
1781         printf("TEST #7 testing 1 non-io open, one io open with delete\n");
1782
1783         smbcli_unlink(cli1->tree, fname);
1784
1785         fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0, SEC_FILE_READ_DATA, FILE_ATTRIBUTE_NORMAL,
1786                                    NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
1787
1788         if (fnum1 == -1) {
1789                 printf("test 7 open 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
1790                 CHECK_MAX_FAILURES(error_test70);
1791                 return False;
1792         }
1793
1794         fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0, SEC_STD_DELETE|SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
1795                                    NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, NTCREATEX_DISP_OPEN_IF, 0, 0);
1796
1797         if (fnum2 != -1) {
1798                 printf("test 7 open 2 of %s SUCCEEDED - should have failed (%s)\n", fname, smbcli_errstr(cli2->tree));
1799                 CHECK_MAX_FAILURES(error_test70);
1800                 return False;
1801         }
1802
1803         printf("test 7 open 2 of %s gave %s (correct error should be %s)\n", fname, smbcli_errstr(cli2->tree), "sharing violation");
1804
1805         if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
1806                 printf("test 7 close 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
1807                 return False;
1808         }
1809
1810         printf("non-io open test #7 passed.\n");
1811
1812 error_test70:
1813
1814         printf("TEST #8 testing one normal open, followed by lock, followed by open with truncate\n");
1815
1816         smbcli_unlink(cli1->tree, fname);
1817
1818         fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1819         if (fnum1 == -1) {
1820                 printf("(8) open (1) of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
1821                 return False;
1822         }
1823         
1824         /* write 20 bytes. */
1825         
1826         memset(buf, '\0', 20);
1827
1828         if (smbcli_write(cli1->tree, fnum1, 0, buf, 0, 20) != 20) {
1829                 printf("(8) write failed (%s)\n", smbcli_errstr(cli1->tree));
1830                 correct = False;
1831         }
1832
1833         /* Ensure size == 20. */
1834         if (NT_STATUS_IS_ERR(smbcli_getatr(cli1->tree, fname, NULL, &fsize, NULL))) {
1835                 printf("(8) getatr (1) failed (%s)\n", smbcli_errstr(cli1->tree));
1836                 CHECK_MAX_FAILURES(error_test80);
1837                 return False;
1838         }
1839         
1840         if (fsize != 20) {
1841                 printf("(8) file size != 20\n");
1842                 CHECK_MAX_FAILURES(error_test80);
1843                 return False;
1844         }
1845
1846         /* Get an exclusive lock on the open file. */
1847         if (NT_STATUS_IS_ERR(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK))) {
1848                 printf("(8) lock1 failed (%s)\n", smbcli_errstr(cli1->tree));
1849                 CHECK_MAX_FAILURES(error_test80);
1850                 return False;
1851         }
1852
1853         fnum2 = smbcli_open(cli1->tree, fname, O_RDWR|O_TRUNC, DENY_NONE);
1854         if (fnum1 == -1) {
1855                 printf("(8) open (2) of %s with truncate failed (%s)\n", fname, smbcli_errstr(cli1->tree));
1856                 return False;
1857         }
1858
1859         /* Ensure size == 0. */
1860         if (NT_STATUS_IS_ERR(smbcli_getatr(cli1->tree, fname, NULL, &fsize, NULL))) {
1861                 printf("(8) getatr (2) failed (%s)\n", smbcli_errstr(cli1->tree));
1862                 CHECK_MAX_FAILURES(error_test80);
1863                 return False;
1864         }
1865         
1866         if (fsize != 0) {
1867                 printf("(8) file size != 0\n");
1868                 CHECK_MAX_FAILURES(error_test80);
1869                 return False;
1870         }
1871
1872         if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
1873                 printf("(8) close1 failed (%s)\n", smbcli_errstr(cli1->tree));
1874                 return False;
1875         }
1876         
1877         if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum2))) {
1878                 printf("(8) close1 failed (%s)\n", smbcli_errstr(cli1->tree));
1879                 return False;
1880         }
1881         
1882 error_test80:
1883
1884         printf("open test #8 passed.\n");
1885
1886         smbcli_unlink(cli1->tree, fname);
1887
1888         if (!torture_close_connection(cli1)) {
1889                 correct = False;
1890         }
1891         if (!torture_close_connection(cli2)) {
1892                 correct = False;
1893         }
1894         
1895         return correct;
1896 }
1897
1898
1899 /*
1900   sees what IOCTLs are supported
1901  */
1902 BOOL torture_ioctl_test(void)
1903 {
1904         struct smbcli_state *cli;
1905         uint16_t device, function;
1906         int fnum;
1907         const char *fname = "\\ioctl.dat";
1908         NTSTATUS status;
1909         union smb_ioctl parms;
1910         TALLOC_CTX *mem_ctx;
1911
1912         if (!torture_open_connection(&cli)) {
1913                 return False;
1914         }
1915
1916         mem_ctx = talloc_init("ioctl_test");
1917
1918         printf("starting ioctl test\n");
1919
1920         smbcli_unlink(cli->tree, fname);
1921
1922         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
1923         if (fnum == -1) {
1924                 printf("open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
1925                 return False;
1926         }
1927
1928         parms.ioctl.level = RAW_IOCTL_IOCTL;
1929         parms.ioctl.in.file.fnum = fnum;
1930         parms.ioctl.in.request = IOCTL_QUERY_JOB_INFO;
1931         status = smb_raw_ioctl(cli->tree, mem_ctx, &parms);
1932         printf("ioctl job info: %s\n", smbcli_errstr(cli->tree));
1933
1934         for (device=0;device<0x100;device++) {
1935                 printf("testing device=0x%x\n", device);
1936                 for (function=0;function<0x100;function++) {
1937                         parms.ioctl.in.request = (device << 16) | function;
1938                         status = smb_raw_ioctl(cli->tree, mem_ctx, &parms);
1939
1940                         if (NT_STATUS_IS_OK(status)) {
1941                                 printf("ioctl device=0x%x function=0x%x OK : %d bytes\n", 
1942                                         device, function, (int)parms.ioctl.out.blob.length);
1943                         }
1944                 }
1945         }
1946
1947         if (!torture_close_connection(cli)) {
1948                 return False;
1949         }
1950
1951         return True;
1952 }
1953
1954
1955 /*
1956   tries variants of chkpath
1957  */
1958 BOOL torture_chkpath_test(void)
1959 {
1960         struct smbcli_state *cli;
1961         int fnum;
1962         BOOL ret;
1963
1964         if (!torture_open_connection(&cli)) {
1965                 return False;
1966         }
1967
1968         printf("starting chkpath test\n");
1969
1970         printf("Testing valid and invalid paths\n");
1971
1972         /* cleanup from an old run */
1973         smbcli_rmdir(cli->tree, "\\chkpath.dir\\dir2");
1974         smbcli_unlink(cli->tree, "\\chkpath.dir\\*");
1975         smbcli_rmdir(cli->tree, "\\chkpath.dir");
1976
1977         if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, "\\chkpath.dir"))) {
1978                 printf("mkdir1 failed : %s\n", smbcli_errstr(cli->tree));
1979                 return False;
1980         }
1981
1982         if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, "\\chkpath.dir\\dir2"))) {
1983                 printf("mkdir2 failed : %s\n", smbcli_errstr(cli->tree));
1984                 return False;
1985         }
1986
1987         fnum = smbcli_open(cli->tree, "\\chkpath.dir\\foo.txt", O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
1988         if (fnum == -1) {
1989                 printf("open1 failed (%s)\n", smbcli_errstr(cli->tree));
1990                 return False;
1991         }
1992         smbcli_close(cli->tree, fnum);
1993
1994         if (NT_STATUS_IS_ERR(smbcli_chkpath(cli->tree, "\\chkpath.dir"))) {
1995                 printf("chkpath1 failed: %s\n", smbcli_errstr(cli->tree));
1996                 ret = False;
1997         }
1998
1999         if (NT_STATUS_IS_ERR(smbcli_chkpath(cli->tree, "\\chkpath.dir\\dir2"))) {
2000                 printf("chkpath2 failed: %s\n", smbcli_errstr(cli->tree));
2001                 ret = False;
2002         }
2003
2004         if (NT_STATUS_IS_ERR(smbcli_chkpath(cli->tree, "\\chkpath.dir\\foo.txt"))) {
2005                 ret = check_error(__location__, cli, ERRDOS, ERRbadpath, 
2006                                   NT_STATUS_NOT_A_DIRECTORY);
2007         } else {
2008                 printf("* chkpath on a file should fail\n");
2009                 ret = False;
2010         }
2011
2012         if (NT_STATUS_IS_ERR(smbcli_chkpath(cli->tree, "\\chkpath.dir\\bar.txt"))) {
2013                 ret = check_error(__location__, cli, ERRDOS, ERRbadpath, 
2014                                   NT_STATUS_OBJECT_NAME_NOT_FOUND);
2015         } else {
2016                 printf("* chkpath on a non existent file should fail\n");
2017                 ret = False;
2018         }
2019
2020         if (NT_STATUS_IS_ERR(smbcli_chkpath(cli->tree, "\\chkpath.dir\\dirxx\\bar.txt"))) {
2021                 ret = check_error(__location__, cli, ERRDOS, ERRbadpath, 
2022                                   NT_STATUS_OBJECT_PATH_NOT_FOUND);
2023         } else {
2024                 printf("* chkpath on a non existent component should fail\n");
2025                 ret = False;
2026         }
2027
2028         smbcli_rmdir(cli->tree, "\\chkpath.dir\\dir2");
2029         smbcli_unlink(cli->tree, "\\chkpath.dir\\*");
2030         smbcli_rmdir(cli->tree, "\\chkpath.dir");
2031
2032         if (!torture_close_connection(cli)) {
2033                 return False;
2034         }
2035
2036         return ret;
2037 }
2038
2039
2040 static void sigcont(int sig)
2041 {
2042 }
2043
2044 double torture_create_procs(BOOL (*fn)(struct smbcli_state *, int), BOOL *result)
2045 {
2046         int i, status;
2047         volatile pid_t *child_status;
2048         volatile BOOL *child_status_out;
2049         int synccount;
2050         int tries = 8;
2051         double start_time_limit = 10 + (torture_nprocs * 1.5);
2052         char **unc_list = NULL;
2053         const char *p;
2054         int num_unc_names = 0;
2055         struct timeval tv;
2056
2057         *result = True;
2058
2059         synccount = 0;
2060
2061         signal(SIGCONT, sigcont);
2062
2063         child_status = (volatile pid_t *)shm_setup(sizeof(pid_t)*torture_nprocs);
2064         if (!child_status) {
2065                 printf("Failed to setup shared memory\n");
2066                 return -1;
2067         }
2068
2069         child_status_out = (volatile BOOL *)shm_setup(sizeof(BOOL)*torture_nprocs);
2070         if (!child_status_out) {
2071                 printf("Failed to setup result status shared memory\n");
2072                 return -1;
2073         }
2074
2075         p = lp_parm_string(-1, "torture", "unclist");
2076         if (p) {
2077                 unc_list = file_lines_load(p, &num_unc_names, NULL);
2078                 if (!unc_list || num_unc_names <= 0) {
2079                         printf("Failed to load unc names list from '%s'\n", p);
2080                         exit(1);
2081                 }
2082         }
2083
2084         for (i = 0; i < torture_nprocs; i++) {
2085                 child_status[i] = 0;
2086                 child_status_out[i] = True;
2087         }
2088
2089         tv = timeval_current();
2090
2091         for (i=0;i<torture_nprocs;i++) {
2092                 procnum = i;
2093                 if (fork() == 0) {
2094                         char *myname;
2095                         const char *hostname=NULL, *sharename;
2096
2097                         pid_t mypid = getpid();
2098                         srandom(((int)mypid) ^ ((int)time(NULL)));
2099
2100                         asprintf(&myname, "CLIENT%d", i);
2101                         lp_set_cmdline("netbios name", myname);
2102                         free(myname);
2103
2104
2105                         if (unc_list) {
2106                                 if (!smbcli_parse_unc(unc_list[i % num_unc_names],
2107                                                       NULL, &hostname, &sharename)) {
2108                                         printf("Failed to parse UNC name %s\n",
2109                                                unc_list[i % num_unc_names]);
2110                                         exit(1);
2111                                 }
2112                         }
2113
2114                         while (1) {
2115                                 if (hostname) {
2116                                         if (torture_open_connection_share(NULL,
2117                                                                           &current_cli,
2118                                                                           hostname, 
2119                                                                           sharename,
2120                                                                           NULL)) {
2121                                                 break;
2122                                         }
2123                                 } else if (torture_open_connection(&current_cli)) {
2124                                                 break;
2125                                 }
2126                                 if (tries-- == 0) {
2127                                         printf("pid %d failed to start\n", (int)getpid());
2128                                         _exit(1);
2129                                 }
2130                                 msleep(100);    
2131                         }
2132
2133                         child_status[i] = getpid();
2134
2135                         pause();
2136
2137                         if (child_status[i]) {
2138                                 printf("Child %d failed to start!\n", i);
2139                                 child_status_out[i] = 1;
2140                                 _exit(1);
2141                         }
2142
2143                         child_status_out[i] = fn(current_cli, i);
2144                         _exit(0);
2145                 }
2146         }
2147
2148         do {
2149                 synccount = 0;
2150                 for (i=0;i<torture_nprocs;i++) {
2151                         if (child_status[i]) synccount++;
2152                 }
2153                 if (synccount == torture_nprocs) break;
2154                 msleep(100);
2155         } while (timeval_elapsed(&tv) < start_time_limit);
2156
2157         if (synccount != torture_nprocs) {
2158                 printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs, synccount);
2159                 *result = False;
2160                 return timeval_elapsed(&tv);
2161         }
2162
2163         printf("Starting %d clients\n", torture_nprocs);
2164
2165         /* start the client load */
2166         tv = timeval_current();
2167         for (i=0;i<torture_nprocs;i++) {
2168                 child_status[i] = 0;
2169         }
2170
2171         printf("%d clients started\n", torture_nprocs);
2172
2173         kill(0, SIGCONT);
2174
2175         for (i=0;i<torture_nprocs;i++) {
2176                 int ret;
2177                 while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
2178                 if (ret == -1 || WEXITSTATUS(status) != 0) {
2179                         *result = False;
2180                 }
2181         }
2182
2183         printf("\n");
2184         
2185         for (i=0;i<torture_nprocs;i++) {
2186                 if (!child_status_out[i]) {
2187                         *result = False;
2188                 }
2189         }
2190         return timeval_elapsed(&tv);
2191 }
2192
2193 #define FLAG_MULTIPROC 1
2194
2195 static struct {
2196         const char *name;
2197         BOOL (*fn)(void);
2198         BOOL (*multi_fn)(struct smbcli_state *, int );
2199 } builtin_torture_ops[] = {
2200         /* base tests */
2201         {"BASE-FDPASS", run_fdpasstest, 0},
2202         {"BASE-LOCK1",  torture_locktest1,  0},
2203         {"BASE-LOCK2",  torture_locktest2,  0},
2204         {"BASE-LOCK3",  torture_locktest3,  0},
2205         {"BASE-LOCK4",  torture_locktest4,  0},
2206         {"BASE-LOCK5",  torture_locktest5,  0},
2207         {"BASE-LOCK6",  torture_locktest6,  0},
2208         {"BASE-LOCK7",  torture_locktest7,  0},
2209         {"BASE-UNLINK", torture_unlinktest, 0},
2210         {"BASE-ATTR",   run_attrtest,   0},
2211         {"BASE-TRANS2", run_trans2test, 0},
2212         {"BASE-NEGNOWAIT", run_negprot_nowait, 0},
2213         {"BASE-DIR1",  torture_dirtest1, 0},
2214         {"BASE-DIR2",  torture_dirtest2, 0},
2215         {"BASE-DENY1",  torture_denytest1, 0},
2216         {"BASE-DENY2",  torture_denytest2, 0},
2217         {"BASE-DENY3",  torture_denytest3, 0},
2218         {"BASE-DENYDOS",  torture_denydos_sharing, 0},
2219         {"BASE-NTDENY1",  NULL, torture_ntdenytest1},
2220         {"BASE-NTDENY2",  torture_ntdenytest2, 0},
2221         {"BASE-TCON",  run_tcon_test, 0},
2222         {"BASE-TCONDEV",  run_tcon_devtype_test, 0},
2223         {"BASE-VUID", run_vuidtest, 0},
2224         {"BASE-RW1",  run_readwritetest, 0},
2225         {"BASE-OPEN", run_opentest, 0},
2226         {"BASE-DEFER_OPEN", NULL, run_deferopen},
2227         {"BASE-XCOPY", run_xcopy, 0},
2228         {"BASE-RENAME", torture_test_rename, 0},
2229         {"BASE-DELETE", torture_test_delete, 0},
2230         {"BASE-PROPERTIES", torture_test_properties, 0},
2231         {"BASE-MANGLE", torture_mangle, 0},
2232         {"BASE-OPENATTR", torture_openattrtest, 0},
2233         {"BASE-CHARSET", torture_charset, 0},
2234         {"BASE-CHKPATH",  torture_chkpath_test, 0},
2235         {"BASE-SECLEAK",  torture_sec_leak, 0},
2236         {"BASE-DISCONNECT",  torture_disconnect, 0},
2237         {"BASE-DELAYWRITE", torture_delay_write, 0},
2238
2239         /* benchmarking tests */
2240         {"BENCH-HOLDCON",  torture_holdcon, 0},
2241         {"BENCH-NBENCH",  torture_nbench, 0},
2242         {"BENCH-TORTURE", NULL, run_torture},
2243         {"BENCH-NBT",     torture_bench_nbt, 0},
2244         {"BENCH-WINS",    torture_bench_wins, 0},
2245         {"BENCH-RPC",     torture_bench_rpc, 0},
2246         {"BENCH-CLDAP",   torture_bench_cldap, 0},
2247
2248         /* RAW smb tests */
2249         {"RAW-QFSINFO", torture_raw_qfsinfo, 0},
2250         {"RAW-QFILEINFO", torture_raw_qfileinfo, 0},
2251         {"RAW-SFILEINFO", torture_raw_sfileinfo, 0},
2252         {"RAW-SFILEINFO-BUG", torture_raw_sfileinfo_bug, 0},
2253         {"RAW-SEARCH", torture_raw_search, 0},
2254         {"RAW-CLOSE", torture_raw_close, 0},
2255         {"RAW-OPEN", torture_raw_open, 0},
2256         {"RAW-MKDIR", torture_raw_mkdir, 0},
2257         {"RAW-OPLOCK", torture_raw_oplock, 0},
2258         {"RAW-NOTIFY", torture_raw_notify, 0},
2259         {"RAW-MUX", torture_raw_mux, 0},
2260         {"RAW-IOCTL", torture_raw_ioctl, 0},
2261         {"RAW-CHKPATH", torture_raw_chkpath, 0},
2262         {"RAW-UNLINK", torture_raw_unlink, 0},
2263         {"RAW-READ", torture_raw_read, 0},
2264         {"RAW-WRITE", torture_raw_write, 0},
2265         {"RAW-LOCK", torture_raw_lock, 0},
2266         {"RAW-CONTEXT", torture_raw_context, 0},
2267         {"RAW-RENAME", torture_raw_rename, 0},
2268         {"RAW-SEEK", torture_raw_seek, 0},
2269         {"RAW-EAS", torture_raw_eas, 0},
2270         {"RAW-EAMAX", torture_max_eas, 0},
2271         {"RAW-STREAMS", torture_raw_streams, 0},
2272         {"RAW-ACLS", torture_raw_acls, 0},
2273         {"RAW-RAP", torture_raw_rap, 0},
2274         {"RAW-COMPOSITE", torture_raw_composite, 0},
2275
2276         /* SMB2 tests */
2277         {"SMB2-CONNECT", torture_smb2_connect, 0},
2278         {"SMB2-SCAN", torture_smb2_scan, 0},
2279         {"SMB2-SCANGETINFO", torture_smb2_getinfo_scan, 0},
2280         {"SMB2-SCANSETINFO", torture_smb2_setinfo_scan, 0},
2281         {"SMB2-SCANFIND", torture_smb2_find_scan, 0},
2282         {"SMB2-GETINFO", torture_smb2_getinfo, 0},
2283         {"SMB2-SETINFO", torture_smb2_setinfo, 0},
2284         {"SMB2-FIND", torture_smb2_find, 0},
2285
2286         /* protocol scanners */
2287         {"SCAN-TRANS2", torture_trans2_scan, 0},
2288         {"SCAN-NTTRANS", torture_nttrans_scan, 0},
2289         {"SCAN-ALIASES", torture_trans2_aliases, 0},
2290         {"SCAN-SMB", torture_smb_scan, 0},
2291         {"SCAN-MAXFID", NULL, run_maxfidtest},
2292         {"SCAN-UTABLE", torture_utable, 0},
2293         {"SCAN-CASETABLE", torture_casetable, 0},
2294         {"SCAN-PIPE_NUMBER", run_pipe_number, 0},
2295         {"SCAN-IOCTL",  torture_ioctl_test, 0},
2296         {"SCAN-RAP",  torture_rap_scan, 0},
2297
2298         /* rpc testers */
2299         {"RPC-LSA", torture_rpc_lsa, 0},
2300         {"RPC-LSALOOKUP", torture_rpc_lsa_lookup, 0},
2301         {"RPC-SECRETS", torture_rpc_lsa_secrets, 0},
2302         {"RPC-ECHO", torture_rpc_echo, 0},
2303         {"RPC-DFS", torture_rpc_dfs, 0},
2304         {"RPC-SPOOLSS", torture_rpc_spoolss, 0},
2305         {"RPC-SAMR", torture_rpc_samr, 0},
2306         {"RPC-UNIXINFO", torture_rpc_unixinfo, 0},
2307         {"RPC-NETLOGON", torture_rpc_netlogon, 0},
2308         {"RPC-SAMLOGON", torture_rpc_samlogon, 0},
2309         {"RPC-SAMSYNC", torture_rpc_samsync, 0},
2310         {"RPC-SCHANNEL", torture_rpc_schannel, 0},
2311         {"RPC-WKSSVC", torture_rpc_wkssvc, 0},
2312         {"RPC-SRVSVC", torture_rpc_srvsvc, 0},
2313         {"RPC-SVCCTL", torture_rpc_svcctl, 0},
2314         {"RPC-ATSVC", torture_rpc_atsvc, 0},
2315         {"RPC-EVENTLOG", torture_rpc_eventlog, 0},
2316         {"RPC-EPMAPPER", torture_rpc_epmapper, 0},
2317         {"RPC-WINREG", torture_rpc_winreg, 0},
2318         {"RPC-INITSHUTDOWN", torture_rpc_initshutdown, 0},
2319         {"RPC-OXIDRESOLVE", torture_rpc_oxidresolve, 0},
2320         {"RPC-REMACT", torture_rpc_remact, 0},
2321         {"RPC-MGMT", torture_rpc_mgmt, 0},
2322         {"RPC-SCANNER", torture_rpc_scanner, 0},
2323         {"RPC-AUTOIDL", torture_rpc_autoidl, 0},
2324         {"RPC-COUNTCALLS", torture_rpc_countcalls, 0},
2325         {"RPC-MULTIBIND", torture_multi_bind, 0},
2326         {"RPC-DRSUAPI", torture_rpc_drsuapi, 0},
2327         {"RPC-CRACKNAMES", torture_rpc_drsuapi_cracknames, 0},
2328         {"RPC-ROT", torture_rpc_rot, 0},
2329         {"RPC-DSSETUP", torture_rpc_dssetup, 0},
2330         {"RPC-ALTERCONTEXT", torture_rpc_alter_context, 0},
2331         {"RPC-JOIN", torture_rpc_join, 0},
2332         {"RPC-DSSYNC", torture_rpc_dssync, 0},
2333
2334         /* local (no server) testers */
2335         {"LOCAL-NTLMSSP", torture_ntlmssp_self_check, 0},
2336         {"LOCAL-ICONV", torture_local_iconv, 0},
2337         {"LOCAL-TALLOC", torture_local_talloc, 0},
2338         {"LOCAL-MESSAGING", torture_local_messaging, 0},
2339         {"LOCAL-IRPC",  torture_local_irpc, 0},
2340         {"LOCAL-BINDING", torture_local_binding_string, 0},
2341         {"LOCAL-STRLIST", torture_local_util_strlist, 0},
2342         {"LOCAL-FILE", torture_local_util_file, 0},
2343         {"LOCAL-IDTREE", torture_local_idtree, 0},
2344         {"LOCAL-SOCKET", torture_local_socket, 0},
2345         {"LOCAL-PAC", torture_pac, 0},
2346         {"LOCAL-REGISTRY", torture_registry, 0},
2347         {"LOCAL-RESOLVE", torture_local_resolve, 0},
2348         {"LOCAL-SDDL", torture_local_sddl, 0},
2349         {"LOCAL-NDR", torture_local_ndr, 0},
2350
2351         /* ldap testers */
2352         {"LDAP-BASIC", torture_ldap_basic, 0},
2353         {"LDAP-CLDAP", torture_cldap, 0},
2354
2355         /* nbt tests */
2356         {"NBT-REGISTER", torture_nbt_register, 0},
2357         {"NBT-WINS", torture_nbt_wins, 0},
2358         {"NBT-DGRAM", torture_nbt_dgram, 0},
2359         {"NBT-BROWSE", torture_nbt_browse, 0},
2360         {"NBT-WINSREPLICATION-SIMPLE", torture_nbt_winsreplication_simple, 0},
2361         {"NBT-WINSREPLICATION-REPLICA", torture_nbt_winsreplication_replica, 0},
2362         {"NBT-WINSREPLICATION-OWNED", torture_nbt_winsreplication_owned, 0},
2363         
2364         /* libnet tests */
2365         {"NET-USERINFO", torture_userinfo, 0},
2366         {"NET-USERADD", torture_useradd, 0},
2367         {"NET-USERDEL", torture_userdel, 0},
2368         {"NET-USERMOD", torture_usermod, 0},
2369         {"NET-DOMOPEN", torture_domainopen, 0},
2370         {"NET-API-LOOKUP", torture_lookup, 0},
2371         {"NET-API-LOOKUPHOST", torture_lookup_host, 0},
2372         {"NET-API-LOOKUPPDC", torture_lookup_pdc, 0},
2373         {"NET-API-CREATEUSER", torture_createuser, 0},
2374         {"NET-API-RPCCONNECT", torture_rpc_connect, 0},
2375         {"NET-API-LISTSHARES", torture_listshares, 0},
2376         {"NET-API-DELSHARE", torture_delshare, 0},
2377
2378         {NULL, NULL, 0}};
2379
2380 static void register_builtin_ops(void)
2381 {
2382         int i;
2383         for (i = 0; builtin_torture_ops[i].name; i++) {
2384                 register_torture_op(builtin_torture_ops[i].name, 
2385                                                         builtin_torture_ops[i].fn, 
2386                                                         builtin_torture_ops[i].multi_fn);
2387         }
2388 }
2389
2390
2391 static struct torture_op {
2392         const char *name;
2393         BOOL (*fn)(void);
2394         BOOL (*multi_fn)(struct smbcli_state *, int );
2395         struct torture_op *prev, *next;
2396 }* torture_ops = NULL;;
2397
2398 static struct torture_op *find_torture_op(const char *name)
2399 {
2400         struct torture_op *o;
2401         for (o = torture_ops; o; o = o->next) {
2402                 if (strcmp(name, o->name) == 0)
2403                         return o;
2404         }
2405
2406         return NULL;
2407 }
2408
2409 NTSTATUS register_torture_op(const char *name, BOOL (*fn)(void), BOOL (*multi_fn)(struct smbcli_state *, int ))
2410 {
2411         struct torture_op *op;
2412         
2413         /* Check for duplicates */
2414         if (find_torture_op(name) != NULL) {
2415                 DEBUG(0,("There already is a torture op registered with the name %s!\n", name));
2416                 return NT_STATUS_OBJECT_NAME_COLLISION;
2417         }
2418
2419         op = talloc(talloc_autofree_context(), struct torture_op);
2420
2421         op->name = talloc_strdup(op, name);
2422         op->fn = fn;
2423         op->multi_fn = multi_fn;
2424
2425         DLIST_ADD(torture_ops, op);
2426         
2427         return NT_STATUS_OK;
2428 }
2429
2430 /****************************************************************************
2431 run a specified test or "ALL"
2432 ****************************************************************************/
2433 static BOOL run_test(const char *name)
2434 {
2435         BOOL ret = True;
2436         struct torture_op *o;
2437         BOOL matched = False;
2438
2439         if (strequal(name,"ALL")) {
2440                 for (o = torture_ops; o; o = o->next) {
2441                         if (!run_test(o->name)) {
2442                                 ret = False;
2443                         }
2444                 }
2445                 return ret;
2446         }
2447
2448         for (o = torture_ops; o; o = o->next) {
2449                 if (gen_fnmatch(name, o->name) == 0) {
2450                         double t;
2451                         matched = True;
2452                         init_iconv();
2453                         printf("Running %s\n", o->name);
2454                         if (o->multi_fn) {
2455                                 BOOL result = False;
2456                                 t = torture_create_procs(o->multi_fn, 
2457                                                          &result);
2458                                 if (!result) { 
2459                                         ret = False;
2460                                         printf("TEST %s FAILED!\n", o->name);
2461                                 }
2462                                          
2463                         } else {
2464                                 struct timeval tv = timeval_current();
2465                                 if (!o->fn()) {
2466                                         ret = False;
2467                                         printf("TEST %s FAILED!\n", o->name);
2468                                 }
2469                                 t = timeval_elapsed(&tv);
2470                         }
2471                         printf("%s took %g secs\n\n", o->name, t);
2472                 }
2473         }
2474
2475         if (!matched) {
2476                 printf("Unknown torture operation '%s'\n", name);
2477         }
2478
2479         return ret;
2480 }
2481
2482
2483 static void parse_dns(const char *dns)
2484 {
2485         char *userdn, *basedn, *secret;
2486         char *p, *d;
2487
2488         /* retrievieng the userdn */
2489         p = strchr_m(dns, '#');
2490         if (!p) {
2491                 lp_set_cmdline("torture:ldap_userdn", "");
2492                 lp_set_cmdline("torture:ldap_basedn", "");
2493                 lp_set_cmdline("torture:ldap_secret", "");
2494                 return;
2495         }
2496         userdn = strndup(dns, p - dns);
2497         lp_set_cmdline("torture:ldap_userdn", userdn);
2498
2499         /* retrieve the basedn */
2500         d = p + 1;
2501         p = strchr_m(d, '#');
2502         if (!p) {
2503                 lp_set_cmdline("torture:ldap_basedn", "");
2504                 lp_set_cmdline("torture:ldap_secret", "");
2505                 return;
2506         }
2507         basedn = strndup(d, p - d);
2508         lp_set_cmdline("torture:ldap_basedn", basedn);
2509
2510         /* retrieve the secret */
2511         p = p + 1;
2512         if (!p) {
2513                 lp_set_cmdline("torture:ldap_secret", "");
2514                 return;
2515         }
2516         secret = strdup(p);
2517         lp_set_cmdline("torture:ldap_secret", secret);
2518
2519         printf ("%s - %s - %s\n", userdn, basedn, secret);
2520
2521 }
2522
2523 static void usage(poptContext pc)
2524 {
2525         struct torture_op *o;
2526         int i;
2527
2528         poptPrintUsage(pc, stdout, 0);
2529         printf("\n");
2530
2531         printf("The binding format is:\n\n");
2532
2533         printf("  TRANSPORT:host[flags]\n\n");
2534
2535         printf("  where TRANSPORT is either ncacn_np for SMB or ncacn_ip_tcp for RPC/TCP\n\n");
2536
2537         printf("  'host' is an IP or hostname or netbios name. If the binding string\n");
2538         printf("  identifies the server side of an endpoint, 'host' may be an empty\n");
2539         printf("  string.\n\n");
2540
2541         printf("  'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
2542         printf("  a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
2543         printf("  will be auto-determined.\n\n");
2544
2545         printf("  other recognised flags are:\n\n");
2546
2547         printf("    sign : enable ntlmssp signing\n");
2548         printf("    seal : enable ntlmssp sealing\n");
2549         printf("    connect : enable rpc connect level auth (auth, but no sign or seal)\n");
2550         printf("    validate: enable the NDR validator\n");
2551         printf("    print: enable debugging of the packets\n");
2552         printf("    bigendian: use bigendian RPC\n");
2553         printf("    padcheck: check reply data for non-zero pad bytes\n\n");
2554
2555         printf("  For example, these all connect to the samr pipe:\n\n");
2556
2557         printf("    ncacn_np:myserver\n");
2558         printf("    ncacn_np:myserver[samr]\n");
2559         printf("    ncacn_np:myserver[\\pipe\\samr]\n");
2560         printf("    ncacn_np:myserver[/pipe/samr]\n");
2561         printf("    ncacn_np:myserver[samr,sign,print]\n");
2562         printf("    ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
2563         printf("    ncacn_np:myserver[/pipe/samr,seal,validate]\n");
2564         printf("    ncacn_np:\n");
2565         printf("    ncacn_np:[/pipe/samr]\n\n");
2566
2567         printf("    ncacn_ip_tcp:myserver\n");
2568         printf("    ncacn_ip_tcp:myserver[1024]\n");
2569         printf("    ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
2570
2571         printf("The unc format is:\n\n");
2572
2573         printf("    //server/share\n\n");
2574
2575         printf("tests are:\n");
2576
2577         i = 0;
2578         for (o = torture_ops; o; o = o->next) {
2579                 if (i + strlen(o->name) >= MAX_COLS) {
2580                         printf("\n");
2581                         i = 0;
2582                 }
2583                 i+=printf("%s ", o->name);
2584         }
2585         printf("\n\n");
2586
2587         printf("default test is ALL\n");
2588
2589         exit(1);
2590 }
2591
2592 static BOOL is_binding_string(const char *binding_string)
2593 {
2594         TALLOC_CTX *mem_ctx = talloc_init("is_binding_string");
2595         struct dcerpc_binding *binding_struct;
2596         NTSTATUS status;
2597         
2598         status = dcerpc_parse_binding(mem_ctx, binding_string, &binding_struct);
2599
2600         talloc_free(mem_ctx);
2601         return NT_STATUS_IS_OK(status);
2602 }
2603
2604 static void max_runtime_handler(int sig)
2605 {
2606         DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
2607         exit(1);
2608 }
2609
2610 /****************************************************************************
2611   main program
2612 ****************************************************************************/
2613  int main(int argc,char *argv[])
2614 {
2615         int opt, i;
2616         char *p;
2617         BOOL correct = True;
2618         int max_runtime=0;
2619         int argc_new;
2620         char **argv_new;
2621         poptContext pc;
2622         enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS,
2623             OPT_DANGEROUS,OPT_SMB_PORTS};
2624         init_module_fn static_init[] = STATIC_smbtorture_MODULES;
2625         init_module_fn *shared_init = load_samba_modules(NULL, "torture");
2626         
2627         struct poptOption long_options[] = {
2628                 POPT_AUTOHELP
2629                 {"smb-ports",   'p', POPT_ARG_STRING, NULL,     OPT_SMB_PORTS,  "SMB ports",    NULL},
2630                 {"seed",          0, POPT_ARG_INT,  &torture_seed,      0,      "seed",         NULL},
2631                 {"num-progs",     0, POPT_ARG_INT,  &torture_nprocs,    0,      "num progs",    NULL},
2632                 {"num-ops",       0, POPT_ARG_INT,  &torture_numops,    0,      "num ops",      NULL},
2633                 {"entries",       0, POPT_ARG_INT,  &torture_entries,   0,      "entries",      NULL},
2634                 {"use-oplocks", 'L', POPT_ARG_NONE, &use_oplocks,       0,      "use oplocks",  NULL},
2635                 {"show-all",      0, POPT_ARG_NONE, &torture_showall,   0,      "show all",     NULL},
2636                 {"loadfile",      0, POPT_ARG_STRING,   NULL,   OPT_LOADFILE,   "loadfile",     NULL},
2637                 {"unclist",       0, POPT_ARG_STRING,   NULL,   OPT_UNCLIST,    "unclist",      NULL},
2638                 {"timelimit",   't', POPT_ARG_STRING,   NULL,   OPT_TIMELIMIT,  "timelimit",    NULL},
2639                 {"failures",    'f', POPT_ARG_INT,  &torture_failures,  0,      "failures",     NULL},
2640                 {"parse-dns",   'D', POPT_ARG_STRING,   NULL,   OPT_DNS,        "parse-dns",    NULL},
2641                 {"dangerous",   'X', POPT_ARG_NONE,     NULL,   OPT_DANGEROUS,  "dangerous",    NULL},
2642                 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0, 
2643                  "set maximum time for smbtorture to live", "seconds"},
2644                 POPT_COMMON_SAMBA
2645                 POPT_COMMON_CONNECTION
2646                 POPT_COMMON_CREDENTIALS
2647                 POPT_COMMON_VERSION
2648                 POPT_TABLEEND
2649         };
2650
2651 #ifdef HAVE_SETBUFFER
2652         setbuffer(stdout, NULL, 0);
2653 #endif
2654
2655         register_builtin_ops();
2656
2657         run_init_functions(static_init);
2658         run_init_functions(shared_init);
2659
2660         talloc_free(shared_init);
2661
2662         /* we are never interested in SIGPIPE */
2663         BlockSignals(True,SIGPIPE);
2664
2665         pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options, 
2666                             POPT_CONTEXT_KEEP_FIRST);
2667
2668         poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
2669
2670         while((opt = poptGetNextOpt(pc)) != -1) {
2671                 switch (opt) {
2672                 case OPT_LOADFILE:
2673                         lp_set_cmdline("torture:loadfile", poptGetOptArg(pc));
2674                         break;
2675                 case OPT_UNCLIST:
2676                         lp_set_cmdline("torture:unclist", poptGetOptArg(pc));
2677                         break;
2678                 case OPT_TIMELIMIT:
2679                         lp_set_cmdline("torture:timelimit", poptGetOptArg(pc));
2680                         break;
2681                 case OPT_DNS:
2682                         parse_dns(poptGetOptArg(pc));
2683                         break;
2684                 case OPT_DANGEROUS:
2685                         lp_set_cmdline("torture:dangerous", "Yes");
2686                         break;
2687                 case OPT_SMB_PORTS:
2688                         lp_set_cmdline("smb ports", poptGetOptArg(pc));
2689                         break;
2690                 default:
2691                         d_printf("Invalid option %s: %s\n", 
2692                                  poptBadOption(pc, 0), poptStrerror(opt));
2693                         usage(pc);
2694                         exit(1);
2695                 }
2696         }
2697
2698         if (max_runtime) {
2699                 /* this will only work if nobody else uses alarm(),
2700                    which means it won't work for some tests, but we
2701                    can't use the event context method we use for smbd
2702                    as so many tests create their own event
2703                    context. This will at least catch most cases. */
2704                 signal(SIGALRM, max_runtime_handler);
2705                 alarm(max_runtime);
2706         }
2707
2708         ldb_global_init();
2709
2710         dcerpc_init();
2711
2712         dcerpc_table_init();
2713
2714         if (torture_seed == 0) {
2715                 torture_seed = time(NULL);
2716         } 
2717         printf("Using seed %d\n", torture_seed);
2718         srandom(torture_seed);
2719
2720         argv_new = discard_const_p(char *, poptGetArgs(pc));
2721
2722         argc_new = argc;
2723         for (i=0; i<argc; i++) {
2724                 if (argv_new[i] == NULL) {
2725                         argc_new = i;
2726                         break;
2727                 }
2728         }
2729
2730         if (argc_new < 3) {
2731                 usage(pc);
2732                 exit(1);
2733         }
2734
2735         for(p = argv_new[1]; *p; p++) {
2736                 if(*p == '\\')
2737                         *p = '/';
2738         }
2739
2740         /* see if its a RPC transport specifier */
2741         if (is_binding_string(argv_new[1])) {
2742                 lp_set_cmdline("torture:binding", argv_new[1]);
2743         } else {
2744                 char *binding = NULL;
2745                 const char *host = NULL, *share = NULL;
2746
2747                 if (!smbcli_parse_unc(argv_new[1], NULL, &host, &share)) {
2748                         d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", argv_new[1]);
2749                         usage(pc);
2750                 }
2751
2752                 lp_set_cmdline("torture:host", host);
2753                 lp_set_cmdline("torture:share", share);
2754                 asprintf(&binding, "ncacn_np:%s", host);
2755                 lp_set_cmdline("torture:binding", binding);
2756         }
2757
2758         if (argc_new == 0) {
2759                 printf("You must specify a test to run, or 'ALL'\n");
2760         } else {
2761                 for (i=2;i<argc_new;i++) {
2762                         if (!run_test(argv_new[i])) {
2763                                 correct = False;
2764                         }
2765                 }
2766         }
2767
2768         if (correct) {
2769                 return(0);
2770         } else {
2771                 return(1);
2772         }
2773 }