s4:torture: Migrate smbtorture to new cmdline option parser
[samba.git] / source4 / torture / raw / context.c
1 /* 
2    Unix SMB/CIFS implementation.
3    test suite for session setup operations
4    Copyright (C) Andrew Tridgell 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 3 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, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "libcli/raw/libcliraw.h"
22 #include "libcli/raw/raw_proto.h"
23 #include "libcli/smb_composite/smb_composite.h"
24 #include "lib/cmdline/cmdline.h"
25 #include "libcli/libcli.h"
26 #include "torture/util.h"
27 #include "auth/credentials/credentials.h"
28 #include "param/param.h"
29 #include "torture/raw/proto.h"
30
31 #define BASEDIR "\\rawcontext"
32
33 #define CHECK_STATUS(status, correct) \
34         torture_assert_ntstatus_equal_goto(tctx, status, correct, ret, done, __location__)
35
36 #define CHECK_VALUE(v, correct) \
37         torture_assert_int_equal_goto(tctx, v, correct, ret, done, __location__)
38
39 #define CHECK_NOT_VALUE(v, correct) \
40         torture_assert_goto(tctx, ((v) != (correct)), ret, done, \
41                 talloc_asprintf(tctx, "(%s) Incorrect value %s=%d - should not be %d\n", \
42                        __location__, #v, v, correct));
43
44
45 /*
46   test session ops
47 */
48 static bool test_session(struct torture_context *tctx,
49                          struct smbcli_state *cli)
50 {
51         NTSTATUS status;
52         bool ret = true;
53         struct smbcli_session *session;
54         struct smbcli_session *session2;
55         uint16_t vuid3;
56         struct smbcli_session *session3;
57         struct smbcli_session *session4;
58         struct cli_credentials *anon_creds;
59         struct smbcli_session *sessions[15];
60         struct composite_context *composite_contexts[15];
61         struct smbcli_tree *tree;
62         struct smb_composite_sesssetup setup;
63         struct smb_composite_sesssetup setups[15];
64         struct gensec_settings *gensec_settings;
65         union smb_open io;
66         union smb_write wr;
67         union smb_close cl;
68         int fnum;
69         const char *fname = BASEDIR "\\test.txt";
70         uint8_t c = 1;
71         int i;
72         struct smbcli_session_options options;
73
74         torture_comment(tctx, "TESTING SESSION HANDLING\n");
75
76         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
77
78         torture_comment(tctx, "create a second security context on the same transport\n");
79
80         lpcfg_smbcli_session_options(tctx->lp_ctx, &options);
81         gensec_settings = lpcfg_gensec_settings(tctx, tctx->lp_ctx);
82
83         session = smbcli_session_init(cli->transport, tctx, false, options);
84
85         setup.in.sesskey = cli->transport->negotiate.sesskey;
86         setup.in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
87         setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
88
89         setup.in.credentials = samba_cmdline_get_creds();
90         setup.in.gensec_settings = gensec_settings;
91
92         status = smb_composite_sesssetup(session, &setup);
93         CHECK_STATUS(status, NT_STATUS_OK);
94         
95         session->vuid = setup.out.vuid;
96
97         torture_comment(tctx, "create a third security context on the same transport, with given vuid\n");
98         session2 = smbcli_session_init(cli->transport, tctx, false, options);
99
100         if (cli->transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) {
101                 vuid3 = session->vuid+1;
102                 if (vuid3 == cli->session->vuid) {
103                         vuid3 += 1;
104                 }
105                 if (vuid3 == UINT16_MAX) {
106                         vuid3 += 2;
107                 }
108         } else {
109                 vuid3 = session->vuid;
110         }
111         session2->vuid = vuid3;
112
113         setup.in.sesskey = cli->transport->negotiate.sesskey;
114         setup.in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
115         setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
116
117         setup.in.credentials = samba_cmdline_get_creds();
118
119         torture_comment(tctx, "vuid1=%d vuid2=%d vuid3=%d\n", cli->session->vuid, session->vuid, vuid3);
120
121         status = smb_composite_sesssetup(session2, &setup);
122         if (cli->transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) {
123                 CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV, ERRbaduid));
124         } else {
125                 CHECK_STATUS(status, NT_STATUS_OK);
126                 session2->vuid = setup.out.vuid;
127                 CHECK_NOT_VALUE(session2->vuid, vuid3);
128         }
129
130         torture_comment(tctx, "vuid1=%d vuid2=%d vuid3=%d=>%d (%s)\n",
131                         cli->session->vuid, session->vuid,
132                         vuid3, session2->vuid, nt_errstr(status));
133
134         talloc_free(session2);
135
136         if (cli->transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) {
137                 torture_comment(tctx, "create a fourth security context on the same transport, without extended security\n");
138                 session3 = smbcli_session_init(cli->transport, tctx, false, options);
139
140                 session3->vuid = vuid3;
141                 setup.in.sesskey = cli->transport->negotiate.sesskey;
142                 setup.in.capabilities &= ~CAP_EXTENDED_SECURITY; /* force a non extended security login (should fail) */
143                 setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
144         
145                 setup.in.credentials = samba_cmdline_get_creds();
146
147                 status = smb_composite_sesssetup(session3, &setup);
148                 if (!NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)) {
149                         /*
150                          * Windows 2008 R2 returns INVALID_PARAMETER
151                          * while Windows 2000 sp4 returns LOGON_FAILURE...
152                          */
153                         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
154                 }
155
156                 torture_comment(tctx, "create a fouth anonymous security context on the same transport, without extended security\n");
157                 session4 = smbcli_session_init(cli->transport, tctx, false, options);
158
159                 session4->vuid = vuid3;
160                 setup.in.sesskey = cli->transport->negotiate.sesskey;
161                 setup.in.capabilities &= ~CAP_EXTENDED_SECURITY; /* force a non extended security login (should fail) */
162                 setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
163                 
164                 anon_creds = cli_credentials_init(tctx);
165                 cli_credentials_set_conf(anon_creds, tctx->lp_ctx);
166                 cli_credentials_set_anonymous(anon_creds);
167
168                 setup.in.credentials = anon_creds;
169         
170                 status = smb_composite_sesssetup(session3, &setup);
171                 CHECK_STATUS(status, NT_STATUS_OK);
172
173                 talloc_free(session4);
174         }
175                 
176         torture_comment(tctx, "use the same tree as the existing connection\n");
177         tree = smbcli_tree_init(session, tctx, false);
178         tree->tid = cli->tree->tid;
179
180         torture_comment(tctx, "create a file using the new vuid\n");
181         io.generic.level = RAW_OPEN_NTCREATEX;
182         io.ntcreatex.in.root_fid.fnum = 0;
183         io.ntcreatex.in.flags = 0;
184         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
185         io.ntcreatex.in.create_options = 0;
186         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
187         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
188         io.ntcreatex.in.alloc_size = 0;
189         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
190         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
191         io.ntcreatex.in.security_flags = 0;
192         io.ntcreatex.in.fname = fname;
193         status = smb_raw_open(tree, tctx, &io);
194         CHECK_STATUS(status, NT_STATUS_OK);
195         fnum = io.ntcreatex.out.file.fnum;
196
197         torture_comment(tctx, "write using the old vuid\n");
198         wr.generic.level = RAW_WRITE_WRITEX;
199         wr.writex.in.file.fnum = fnum;
200         wr.writex.in.offset = 0;
201         wr.writex.in.wmode = 0;
202         wr.writex.in.remaining = 0;
203         wr.writex.in.count = 1;
204         wr.writex.in.data = &c;
205
206         status = smb_raw_write(cli->tree, &wr);
207         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
208
209         torture_comment(tctx, "write with the new vuid\n");
210         status = smb_raw_write(tree, &wr);
211         CHECK_STATUS(status, NT_STATUS_OK);
212         CHECK_VALUE(wr.writex.out.nwritten, 1);
213
214         torture_comment(tctx, "logoff the new vuid\n");
215         status = smb_raw_ulogoff(session);
216         CHECK_STATUS(status, NT_STATUS_OK);
217
218         torture_comment(tctx, "the new vuid should not now be accessible\n");
219         status = smb_raw_write(tree, &wr);
220         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
221
222         torture_comment(tctx, "second logoff for the new vuid should fail\n");
223         status = smb_raw_ulogoff(session);
224         CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV, ERRbaduid));
225         talloc_free(tree);
226         talloc_free(session);
227
228         torture_comment(tctx, "the fnum should have been auto-closed\n");
229         cl.close.level = RAW_CLOSE_CLOSE;
230         cl.close.in.file.fnum = fnum;
231         cl.close.in.write_time = 0;
232         status = smb_raw_close(cli->tree, &cl);
233         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
234
235         torture_comment(tctx, "create %d secondary security contexts on the same transport\n",
236                (int)ARRAY_SIZE(sessions));
237         for (i=0; i <ARRAY_SIZE(sessions); i++) {
238                 setups[i].in.sesskey = cli->transport->negotiate.sesskey;
239                 setups[i].in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
240                 setups[i].in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
241                 
242                 setups[i].in.credentials = samba_cmdline_get_creds();
243                 setups[i].in.gensec_settings = gensec_settings;
244
245                 sessions[i] = smbcli_session_init(cli->transport, tctx, false, options);
246                 composite_contexts[i] = smb_composite_sesssetup_send(sessions[i], &setups[i]);
247
248         }
249
250
251         torture_comment(tctx, "finishing %d secondary security contexts on the same transport\n",
252                (int)ARRAY_SIZE(sessions));
253         for (i=0; i< ARRAY_SIZE(sessions); i++) {
254                 status = smb_composite_sesssetup_recv(composite_contexts[i]);
255                 CHECK_STATUS(status, NT_STATUS_OK);
256                 sessions[i]->vuid = setups[i].out.vuid;
257                 torture_comment(tctx, "VUID: %d\n", sessions[i]->vuid);
258                 status = smb_raw_ulogoff(sessions[i]);
259                 CHECK_STATUS(status, NT_STATUS_OK);
260         }
261
262 done:
263         return ret;
264 }
265
266
267 /*
268   test tree ops
269 */
270 static bool test_tree(struct torture_context *tctx, struct smbcli_state *cli)
271 {
272         NTSTATUS status;
273         bool ret = true;
274         const char *share, *host;
275         struct smbcli_tree *tree;
276         union smb_tcon tcon;
277         union smb_open io;
278         union smb_write wr;
279         union smb_close cl;
280         int fnum;
281         const char *fname = BASEDIR "\\test.txt";
282         uint8_t c = 1;
283
284         torture_comment(tctx, "TESTING TREE HANDLING\n");
285
286         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
287
288         share = torture_setting_string(tctx, "share", NULL);
289         host  = torture_setting_string(tctx, "host", NULL);
290         
291         torture_comment(tctx, "create a second tree context on the same session\n");
292         tree = smbcli_tree_init(cli->session, tctx, false);
293
294         tcon.generic.level = RAW_TCON_TCONX;
295         tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
296         tcon.tconx.in.password = data_blob(NULL, 0);
297         tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
298         tcon.tconx.in.device = "A:";    
299         status = smb_raw_tcon(tree, tctx, &tcon);
300         CHECK_STATUS(status, NT_STATUS_OK);
301         
302
303         tree->tid = tcon.tconx.out.tid;
304         torture_comment(tctx, "tid1=%d tid2=%d\n", cli->tree->tid, tree->tid);
305
306         torture_comment(tctx, "try a tconx with a bad device type\n");
307         tcon.tconx.in.device = "FOO";   
308         status = smb_raw_tcon(tree, tctx, &tcon);
309         CHECK_STATUS(status, NT_STATUS_BAD_DEVICE_TYPE);
310
311
312         torture_comment(tctx, "create a file using the new tid\n");
313         io.generic.level = RAW_OPEN_NTCREATEX;
314         io.ntcreatex.in.root_fid.fnum = 0;
315         io.ntcreatex.in.flags = 0;
316         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
317         io.ntcreatex.in.create_options = 0;
318         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
319         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
320         io.ntcreatex.in.alloc_size = 0;
321         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
322         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
323         io.ntcreatex.in.security_flags = 0;
324         io.ntcreatex.in.fname = fname;
325         status = smb_raw_open(tree, tctx, &io);
326         CHECK_STATUS(status, NT_STATUS_OK);
327         fnum = io.ntcreatex.out.file.fnum;
328
329         torture_comment(tctx, "write using the old tid\n");
330         wr.generic.level = RAW_WRITE_WRITEX;
331         wr.writex.in.file.fnum = fnum;
332         wr.writex.in.offset = 0;
333         wr.writex.in.wmode = 0;
334         wr.writex.in.remaining = 0;
335         wr.writex.in.count = 1;
336         wr.writex.in.data = &c;
337
338         status = smb_raw_write(cli->tree, &wr);
339         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
340
341         torture_comment(tctx, "write with the new tid\n");
342         status = smb_raw_write(tree, &wr);
343         CHECK_STATUS(status, NT_STATUS_OK);
344         CHECK_VALUE(wr.writex.out.nwritten, 1);
345
346         torture_comment(tctx, "disconnect the new tid\n");
347         status = smb_tree_disconnect(tree);
348         CHECK_STATUS(status, NT_STATUS_OK);
349
350         torture_comment(tctx, "the new tid should not now be accessible\n");
351         status = smb_raw_write(tree, &wr);
352         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
353
354         torture_comment(tctx, "the fnum should have been auto-closed\n");
355         cl.close.level = RAW_CLOSE_CLOSE;
356         cl.close.in.file.fnum = fnum;
357         cl.close.in.write_time = 0;
358         status = smb_raw_close(cli->tree, &cl);
359         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
360
361         /* close down the new tree */
362         talloc_free(tree);
363         
364 done:
365         return ret;
366 }
367
368 /*
369   test tree with ulogoff
370   this demonstrates that a tcon isn't autoclosed by a ulogoff
371   the tcon can be reused using any other valid session later
372 */
373 static bool test_tree_ulogoff(struct torture_context *tctx, struct smbcli_state *cli)
374 {
375         NTSTATUS status;
376         bool ret = true;
377         const char *share, *host;
378         struct smbcli_session *session1;
379         struct smbcli_session *session2;
380         struct smb_composite_sesssetup setup;
381         struct smbcli_tree *tree;
382         union smb_tcon tcon;
383         union smb_open io;
384         union smb_write wr;
385         int fnum1, fnum2;
386         const char *fname1 = BASEDIR "\\test1.txt";
387         const char *fname2 = BASEDIR "\\test2.txt";
388         uint8_t c = 1;
389         struct smbcli_session_options options;
390
391         torture_comment(tctx, "TESTING TREE with ulogoff\n");
392
393         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
394
395         share = torture_setting_string(tctx, "share", NULL);
396         host  = torture_setting_string(tctx, "host", NULL);
397
398         lpcfg_smbcli_session_options(tctx->lp_ctx, &options);
399
400         torture_comment(tctx, "create the first new sessions\n");
401         session1 = smbcli_session_init(cli->transport, tctx, false, options);
402         setup.in.sesskey = cli->transport->negotiate.sesskey;
403         setup.in.capabilities = cli->transport->negotiate.capabilities;
404         setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
405         setup.in.credentials = samba_cmdline_get_creds();
406         setup.in.gensec_settings = lpcfg_gensec_settings(tctx, tctx->lp_ctx);
407         status = smb_composite_sesssetup(session1, &setup);
408         CHECK_STATUS(status, NT_STATUS_OK);
409         session1->vuid = setup.out.vuid;
410         torture_comment(tctx, "vuid1=%d\n", session1->vuid);
411
412         torture_comment(tctx, "create a tree context on the with vuid1\n");
413         tree = smbcli_tree_init(session1, tctx, false);
414         tcon.generic.level = RAW_TCON_TCONX;
415         tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
416         tcon.tconx.in.password = data_blob(NULL, 0);
417         tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
418         tcon.tconx.in.device = "A:";
419         status = smb_raw_tcon(tree, tctx, &tcon);
420         CHECK_STATUS(status, NT_STATUS_OK);
421         tree->tid = tcon.tconx.out.tid;
422         torture_comment(tctx, "tid=%d\n", tree->tid);
423
424         torture_comment(tctx, "create a file using vuid1\n");
425         io.generic.level = RAW_OPEN_NTCREATEX;
426         io.ntcreatex.in.root_fid.fnum = 0;
427         io.ntcreatex.in.flags = 0;
428         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
429         io.ntcreatex.in.create_options = 0;
430         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
431         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
432         io.ntcreatex.in.alloc_size = 0;
433         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
434         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
435         io.ntcreatex.in.security_flags = 0;
436         io.ntcreatex.in.fname = fname1;
437         status = smb_raw_open(tree, tctx, &io);
438         CHECK_STATUS(status, NT_STATUS_OK);
439         fnum1 = io.ntcreatex.out.file.fnum;
440
441         torture_comment(tctx, "write using vuid1\n");
442         wr.generic.level = RAW_WRITE_WRITEX;
443         wr.writex.in.file.fnum = fnum1;
444         wr.writex.in.offset = 0;
445         wr.writex.in.wmode = 0;
446         wr.writex.in.remaining = 0;
447         wr.writex.in.count = 1;
448         wr.writex.in.data = &c;
449         status = smb_raw_write(tree, &wr);
450         CHECK_STATUS(status, NT_STATUS_OK);
451         CHECK_VALUE(wr.writex.out.nwritten, 1);
452
453         torture_comment(tctx, "ulogoff the vuid1\n");
454         status = smb_raw_ulogoff(session1);
455         CHECK_STATUS(status, NT_STATUS_OK);
456
457         torture_comment(tctx, "create the second new sessions\n");
458         session2 = smbcli_session_init(cli->transport, tctx, false, options);
459         setup.in.sesskey = cli->transport->negotiate.sesskey;
460         setup.in.capabilities = cli->transport->negotiate.capabilities;
461         setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
462         setup.in.credentials = samba_cmdline_get_creds();
463         setup.in.gensec_settings = lpcfg_gensec_settings(tctx, tctx->lp_ctx);
464         status = smb_composite_sesssetup(session2, &setup);
465         CHECK_STATUS(status, NT_STATUS_OK);
466         session2->vuid = setup.out.vuid;
467         torture_comment(tctx, "vuid2=%d\n", session2->vuid);
468
469         torture_comment(tctx, "use the existing tree with vuid2\n");
470         tree->session = session2;
471
472         torture_comment(tctx, "create a file using vuid2\n");
473         io.generic.level = RAW_OPEN_NTCREATEX;
474         io.ntcreatex.in.root_fid.fnum = 0;
475         io.ntcreatex.in.flags = 0;
476         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
477         io.ntcreatex.in.create_options = 0;
478         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
479         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
480         io.ntcreatex.in.alloc_size = 0;
481         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
482         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
483         io.ntcreatex.in.security_flags = 0;
484         io.ntcreatex.in.fname = fname2;
485         status = smb_raw_open(tree, tctx, &io);
486         CHECK_STATUS(status, NT_STATUS_OK);
487         fnum2 = io.ntcreatex.out.file.fnum;
488
489         torture_comment(tctx, "write using vuid2\n");
490         wr.generic.level = RAW_WRITE_WRITEX;
491         wr.writex.in.file.fnum = fnum2;
492         wr.writex.in.offset = 0;
493         wr.writex.in.wmode = 0;
494         wr.writex.in.remaining = 0;
495         wr.writex.in.count = 1;
496         wr.writex.in.data = &c;
497         status = smb_raw_write(tree, &wr);
498         CHECK_STATUS(status, NT_STATUS_OK);
499         CHECK_VALUE(wr.writex.out.nwritten, 1);
500
501         torture_comment(tctx, "ulogoff the vuid2\n");
502         status = smb_raw_ulogoff(session2);
503         CHECK_STATUS(status, NT_STATUS_OK);
504
505         /* this also demonstrates that SMBtdis doesn't need a valid vuid */
506         torture_comment(tctx, "disconnect the existing tree connection\n");
507         status = smb_tree_disconnect(tree);
508         CHECK_STATUS(status, NT_STATUS_OK);
509
510         torture_comment(tctx, "disconnect the existing tree connection\n");
511         status = smb_tree_disconnect(tree);
512         CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV,ERRinvnid));
513
514         /* close down the new tree */
515         talloc_free(tree);
516         
517 done:
518         return ret;
519 }
520
521 /*
522   test pid ops
523   this test demonstrates that exit() only sees the PID
524   used for the open() calls
525 */
526 static bool test_pid_exit_only_sees_open(struct torture_context *tctx,
527                                          struct smbcli_state *cli)
528 {
529         NTSTATUS status;
530         TALLOC_CTX *mem_ctx = tctx;
531         bool ret = true;
532         union smb_open io;
533         union smb_write wr;
534         union smb_close cl;
535         int fnum;
536         const char *fname = BASEDIR "\\test.txt";
537         uint8_t c = 1;
538         uint16_t pid1, pid2;
539
540         torture_comment(tctx, "TESTING PID HANDLING exit() only cares about open() PID\n");
541
542         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
543
544         pid1 = cli->session->pid;
545         pid2 = pid1 + 1;
546
547         torture_comment(tctx, "pid1=%d pid2=%d\n", pid1, pid2);
548
549         torture_comment(tctx, "create a file using pid1\n");
550         cli->session->pid = pid1;
551         io.generic.level = RAW_OPEN_NTCREATEX;
552         io.ntcreatex.in.root_fid.fnum = 0;
553         io.ntcreatex.in.flags = 0;
554         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
555         io.ntcreatex.in.create_options = 0;
556         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
557         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
558         io.ntcreatex.in.alloc_size = 0;
559         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
560         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
561         io.ntcreatex.in.security_flags = 0;
562         io.ntcreatex.in.fname = fname;
563         status = smb_raw_open(cli->tree, mem_ctx, &io);
564         CHECK_STATUS(status, NT_STATUS_OK);
565         fnum = io.ntcreatex.out.file.fnum;
566
567         torture_comment(tctx, "write using pid2\n");
568         cli->session->pid = pid2;
569         wr.generic.level = RAW_WRITE_WRITEX;
570         wr.writex.in.file.fnum = fnum;
571         wr.writex.in.offset = 0;
572         wr.writex.in.wmode = 0;
573         wr.writex.in.remaining = 0;
574         wr.writex.in.count = 1;
575         wr.writex.in.data = &c;
576         status = smb_raw_write(cli->tree, &wr);
577         CHECK_STATUS(status, NT_STATUS_OK);
578         CHECK_VALUE(wr.writex.out.nwritten, 1);
579
580         torture_comment(tctx, "exit pid2\n");
581         cli->session->pid = pid2;
582         status = smb_raw_exit(cli->session);
583         CHECK_STATUS(status, NT_STATUS_OK);
584
585         torture_comment(tctx, "the fnum should still be accessible via pid2\n");
586         cli->session->pid = pid2;
587         status = smb_raw_write(cli->tree, &wr);
588         CHECK_STATUS(status, NT_STATUS_OK);
589         CHECK_VALUE(wr.writex.out.nwritten, 1);
590
591         torture_comment(tctx, "exit pid2\n");
592         cli->session->pid = pid2;
593         status = smb_raw_exit(cli->session);
594         CHECK_STATUS(status, NT_STATUS_OK);
595
596         torture_comment(tctx, "the fnum should still be accessible via pid1 and pid2\n");
597         cli->session->pid = pid1;
598         status = smb_raw_write(cli->tree, &wr);
599         CHECK_STATUS(status, NT_STATUS_OK);
600         CHECK_VALUE(wr.writex.out.nwritten, 1);
601         cli->session->pid = pid2;
602         status = smb_raw_write(cli->tree, &wr);
603         CHECK_STATUS(status, NT_STATUS_OK);
604         CHECK_VALUE(wr.writex.out.nwritten, 1);
605
606         torture_comment(tctx, "exit pid1\n");
607         cli->session->pid = pid1;
608         status = smb_raw_exit(cli->session);
609         CHECK_STATUS(status, NT_STATUS_OK);
610
611         torture_comment(tctx, "the fnum should not now be accessible via pid1 or pid2\n");
612         cli->session->pid = pid1;
613         status = smb_raw_write(cli->tree, &wr);
614         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
615         cli->session->pid = pid2;
616         status = smb_raw_write(cli->tree, &wr);
617         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
618
619         torture_comment(tctx, "the fnum should have been auto-closed\n");
620         cli->session->pid = pid1;
621         cl.close.level = RAW_CLOSE_CLOSE;
622         cl.close.in.file.fnum = fnum;
623         cl.close.in.write_time = 0;
624         status = smb_raw_close(cli->tree, &cl);
625         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
626
627 done:
628         return ret;
629 }
630
631 /*
632   test pid ops with 2 sessions
633 */
634 static bool test_pid_2sess(struct torture_context *tctx,
635                            struct smbcli_state *cli)
636 {
637         NTSTATUS status;
638         bool ret = true;
639         struct smbcli_session *session;
640         struct smb_composite_sesssetup setup;
641         union smb_open io;
642         union smb_write wr;
643         union smb_close cl;
644         int fnum;
645         const char *fname = BASEDIR "\\test.txt";
646         uint8_t c = 1;
647         uint16_t vuid1, vuid2;
648         struct smbcli_session_options options;
649
650         torture_comment(tctx, "TESTING PID HANDLING WITH 2 SESSIONS\n");
651
652         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
653
654         lpcfg_smbcli_session_options(tctx->lp_ctx, &options);
655
656         torture_comment(tctx, "create a second security context on the same transport\n");
657         session = smbcli_session_init(cli->transport, tctx, false, options);
658
659         setup.in.sesskey = cli->transport->negotiate.sesskey;
660         setup.in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
661         setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
662         setup.in.credentials = samba_cmdline_get_creds();
663         setup.in.gensec_settings = lpcfg_gensec_settings(tctx, tctx->lp_ctx);
664
665         status = smb_composite_sesssetup(session, &setup);
666         CHECK_STATUS(status, NT_STATUS_OK);     
667         session->vuid = setup.out.vuid;
668
669         vuid1 = cli->session->vuid;
670         vuid2 = session->vuid;
671
672         torture_comment(tctx, "vuid1=%d vuid2=%d\n", vuid1, vuid2);
673
674         torture_comment(tctx, "create a file using the vuid1\n");
675         cli->session->vuid = vuid1;
676         io.generic.level = RAW_OPEN_NTCREATEX;
677         io.ntcreatex.in.root_fid.fnum = 0;
678         io.ntcreatex.in.flags = 0;
679         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
680         io.ntcreatex.in.create_options = 0;
681         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
682         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
683         io.ntcreatex.in.alloc_size = 0;
684         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
685         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
686         io.ntcreatex.in.security_flags = 0;
687         io.ntcreatex.in.fname = fname;
688         status = smb_raw_open(cli->tree, tctx, &io);
689         CHECK_STATUS(status, NT_STATUS_OK);
690         fnum = io.ntcreatex.out.file.fnum;
691
692         torture_comment(tctx, "write using the vuid1 (fnum=%d)\n", fnum);
693         cli->session->vuid = vuid1;
694         wr.generic.level = RAW_WRITE_WRITEX;
695         wr.writex.in.file.fnum = fnum;
696         wr.writex.in.offset = 0;
697         wr.writex.in.wmode = 0;
698         wr.writex.in.remaining = 0;
699         wr.writex.in.count = 1;
700         wr.writex.in.data = &c;
701
702         status = smb_raw_write(cli->tree, &wr);
703         CHECK_STATUS(status, NT_STATUS_OK);
704         CHECK_VALUE(wr.writex.out.nwritten, 1);
705
706         torture_comment(tctx, "exit the pid with vuid2\n");
707         cli->session->vuid = vuid2;
708         status = smb_raw_exit(cli->session);
709         CHECK_STATUS(status, NT_STATUS_OK);
710
711         torture_comment(tctx, "the fnum should still be accessible\n");
712         cli->session->vuid = vuid1;
713         status = smb_raw_write(cli->tree, &wr);
714         CHECK_STATUS(status, NT_STATUS_OK);
715         CHECK_VALUE(wr.writex.out.nwritten, 1);
716
717         torture_comment(tctx, "exit the pid with vuid1\n");
718         cli->session->vuid = vuid1;
719         status = smb_raw_exit(cli->session);
720         CHECK_STATUS(status, NT_STATUS_OK);
721
722         torture_comment(tctx, "the fnum should not now be accessible\n");
723         status = smb_raw_write(cli->tree, &wr);
724         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
725
726         torture_comment(tctx, "the fnum should have been auto-closed\n");
727         cl.close.level = RAW_CLOSE_CLOSE;
728         cl.close.in.file.fnum = fnum;
729         cl.close.in.write_time = 0;
730         status = smb_raw_close(cli->tree, &cl);
731         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
732
733 done:
734         return ret;
735 }
736
737 /*
738   test pid ops with 2 tcons
739 */
740 static bool test_pid_2tcon(struct torture_context *tctx,
741                            struct smbcli_state *cli)
742 {
743         NTSTATUS status;
744         bool ret = true;
745         const char *share, *host;
746         struct smbcli_tree *tree;
747         union smb_tcon tcon;
748         union smb_open io;
749         union smb_write wr;
750         union smb_close cl;
751         int fnum1, fnum2;
752         const char *fname1 = BASEDIR "\\test1.txt";
753         const char *fname2 = BASEDIR "\\test2.txt";
754         uint8_t c = 1;
755         uint16_t tid1, tid2;
756
757         torture_comment(tctx, "TESTING PID HANDLING WITH 2 TCONS\n");
758
759         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
760
761         share = torture_setting_string(tctx, "share", NULL);
762         host  = torture_setting_string(tctx, "host", NULL);
763         
764         torture_comment(tctx, "create a second tree context on the same session\n");
765         tree = smbcli_tree_init(cli->session, tctx, false);
766
767         tcon.generic.level = RAW_TCON_TCONX;
768         tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
769         tcon.tconx.in.password = data_blob(NULL, 0);
770         tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
771         tcon.tconx.in.device = "A:";    
772         status = smb_raw_tcon(tree, tctx, &tcon);
773         CHECK_STATUS(status, NT_STATUS_OK);     
774
775         tree->tid = tcon.tconx.out.tid;
776
777         tid1 = cli->tree->tid;
778         tid2 = tree->tid;
779         torture_comment(tctx, "tid1=%d tid2=%d\n", tid1, tid2);
780
781         torture_comment(tctx, "create a file using the tid1\n");
782         cli->tree->tid = tid1;
783         io.generic.level = RAW_OPEN_NTCREATEX;
784         io.ntcreatex.in.root_fid.fnum = 0;
785         io.ntcreatex.in.flags = 0;
786         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
787         io.ntcreatex.in.create_options = 0;
788         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
789         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
790         io.ntcreatex.in.alloc_size = 0;
791         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
792         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
793         io.ntcreatex.in.security_flags = 0;
794         io.ntcreatex.in.fname = fname1;
795         status = smb_raw_open(cli->tree, tctx, &io);
796         CHECK_STATUS(status, NT_STATUS_OK);
797         fnum1 = io.ntcreatex.out.file.fnum;
798
799         torture_comment(tctx, "write using the tid1\n");
800         wr.generic.level = RAW_WRITE_WRITEX;
801         wr.writex.in.file.fnum = fnum1;
802         wr.writex.in.offset = 0;
803         wr.writex.in.wmode = 0;
804         wr.writex.in.remaining = 0;
805         wr.writex.in.count = 1;
806         wr.writex.in.data = &c;
807
808         status = smb_raw_write(cli->tree, &wr);
809         CHECK_STATUS(status, NT_STATUS_OK);
810         CHECK_VALUE(wr.writex.out.nwritten, 1);
811
812         torture_comment(tctx, "create a file using the tid2\n");
813         cli->tree->tid = tid2;
814         io.generic.level = RAW_OPEN_NTCREATEX;
815         io.ntcreatex.in.root_fid.fnum = 0;
816         io.ntcreatex.in.flags = 0;
817         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
818         io.ntcreatex.in.create_options = 0;
819         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
820         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
821         io.ntcreatex.in.alloc_size = 0;
822         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
823         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
824         io.ntcreatex.in.security_flags = 0;
825         io.ntcreatex.in.fname = fname2;
826         status = smb_raw_open(cli->tree, tctx, &io);
827         CHECK_STATUS(status, NT_STATUS_OK);
828         fnum2 = io.ntcreatex.out.file.fnum;
829
830         torture_comment(tctx, "write using the tid2\n");
831         wr.generic.level = RAW_WRITE_WRITEX;
832         wr.writex.in.file.fnum = fnum2;
833         wr.writex.in.offset = 0;
834         wr.writex.in.wmode = 0;
835         wr.writex.in.remaining = 0;
836         wr.writex.in.count = 1;
837         wr.writex.in.data = &c;
838
839         status = smb_raw_write(cli->tree, &wr);
840         CHECK_STATUS(status, NT_STATUS_OK);
841         CHECK_VALUE(wr.writex.out.nwritten, 1);
842
843         torture_comment(tctx, "exit the pid\n");
844         status = smb_raw_exit(cli->session);
845         CHECK_STATUS(status, NT_STATUS_OK);
846
847         torture_comment(tctx, "the fnum1 on tid1 should not be accessible\n");
848         cli->tree->tid = tid1;
849         wr.writex.in.file.fnum = fnum1;
850         status = smb_raw_write(cli->tree, &wr);
851         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
852
853         torture_comment(tctx, "the fnum1 on tid1 should have been auto-closed\n");
854         cl.close.level = RAW_CLOSE_CLOSE;
855         cl.close.in.file.fnum = fnum1;
856         cl.close.in.write_time = 0;
857         status = smb_raw_close(cli->tree, &cl);
858         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
859
860         torture_comment(tctx, "the fnum2 on tid2 should not be accessible\n");
861         cli->tree->tid = tid2;
862         wr.writex.in.file.fnum = fnum2;
863         status = smb_raw_write(cli->tree, &wr);
864         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
865
866         torture_comment(tctx, "the fnum2 on tid2 should have been auto-closed\n");
867         cl.close.level = RAW_CLOSE_CLOSE;
868         cl.close.in.file.fnum = fnum2;
869         cl.close.in.write_time = 0;
870         status = smb_raw_close(cli->tree, &cl);
871         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
872
873 done:
874         return ret;
875 }
876
877 struct torture_suite *torture_raw_context(TALLOC_CTX *mem_ctx)
878 {
879         struct torture_suite *suite = torture_suite_create(mem_ctx, "context");
880
881         torture_suite_add_1smb_test(suite, "session1", test_session);
882         /*
883          * TODO: add test_session with 'use spnego = false'
884          * torture_suite_add_1smb_test(suite, "session1", test_session);
885          */
886         torture_suite_add_1smb_test(suite, "tree", test_tree);
887         torture_suite_add_1smb_test(suite, "tree_ulogoff", test_tree_ulogoff);
888         torture_suite_add_1smb_test(suite, "pid_only_sess", test_pid_exit_only_sees_open);
889         torture_suite_add_1smb_test(suite, "pid_2sess", test_pid_2sess);
890         torture_suite_add_1smb_test(suite, "pid_2tcon", test_pid_2tcon);
891
892         return suite;
893 }