s4:torture/raw/context: add subtests as torture testcases
[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/popt_common.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         struct smbcli_session *session3;
56         struct smbcli_session *session4;
57         struct cli_credentials *anon_creds;
58         struct smbcli_session *sessions[15];
59         struct composite_context *composite_contexts[15];
60         struct smbcli_tree *tree;
61         struct smb_composite_sesssetup setup;
62         struct smb_composite_sesssetup setups[15];
63         struct gensec_settings *gensec_settings;
64         union smb_open io;
65         union smb_write wr;
66         union smb_close cl;
67         int fnum;
68         const char *fname = BASEDIR "\\test.txt";
69         uint8_t c = 1;
70         int i;
71         struct smbcli_session_options options;
72
73         torture_comment(tctx, "TESTING SESSION HANDLING\n");
74
75         if (!torture_setup_dir(cli, BASEDIR)) {
76                 return false;
77         }
78
79         torture_comment(tctx, "create a second security context on the same transport\n");
80
81         lpcfg_smbcli_session_options(tctx->lp_ctx, &options);
82         gensec_settings = lpcfg_gensec_settings(tctx, tctx->lp_ctx);
83
84         session = smbcli_session_init(cli->transport, tctx, false, options);
85
86         setup.in.sesskey = cli->transport->negotiate.sesskey;
87         setup.in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
88         setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
89
90         setup.in.credentials = cmdline_credentials;
91         setup.in.gensec_settings = gensec_settings;
92
93         status = smb_composite_sesssetup(session, &setup);
94         CHECK_STATUS(status, NT_STATUS_OK);
95         
96         session->vuid = setup.out.vuid;
97
98         torture_comment(tctx, "create a third security context on the same transport, with vuid set\n");
99         session2 = smbcli_session_init(cli->transport, tctx, false, options);
100
101         session2->vuid = session->vuid;
102         setup.in.sesskey = cli->transport->negotiate.sesskey;
103         setup.in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
104         setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
105
106         setup.in.credentials = cmdline_credentials;
107
108         status = smb_composite_sesssetup(session2, &setup);
109         CHECK_STATUS(status, NT_STATUS_OK);
110
111         session2->vuid = setup.out.vuid;
112         torture_comment(tctx, "vuid1=%d vuid2=%d vuid3=%d\n", cli->session->vuid, session->vuid, session2->vuid);
113         
114         if (cli->transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) {
115                 /* Samba4 currently fails this - we need to determine if this insane behaviour is important */
116                 if (session2->vuid == session->vuid) {
117                         torture_comment(tctx, "server allows the user to re-use an existing vuid in session setup \n");
118                 }
119         } else {
120                 CHECK_NOT_VALUE(session2->vuid, session->vuid);
121         }
122         talloc_free(session2);
123
124         if (cli->transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) {
125                 torture_comment(tctx, "create a fourth security context on the same transport, without extended security\n");
126                 session3 = smbcli_session_init(cli->transport, tctx, false, options);
127
128                 session3->vuid = session->vuid;
129                 setup.in.sesskey = cli->transport->negotiate.sesskey;
130                 setup.in.capabilities &= ~CAP_EXTENDED_SECURITY; /* force a non extended security login (should fail) */
131                 setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
132         
133                 setup.in.credentials = cmdline_credentials;
134
135                 status = smb_composite_sesssetup(session3, &setup);
136                 if (!NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)) {
137                         /*
138                          * Windows 2008 R2 returns INVALID_PARAMETER
139                          * while Windows 2000 sp4 returns LOGON_FAILURE...
140                          */
141                         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
142                 }
143
144                 torture_comment(tctx, "create a fouth anonymous security context on the same transport, without extended security\n");
145                 session4 = smbcli_session_init(cli->transport, tctx, false, options);
146
147                 session4->vuid = session->vuid;
148                 setup.in.sesskey = cli->transport->negotiate.sesskey;
149                 setup.in.capabilities &= ~CAP_EXTENDED_SECURITY; /* force a non extended security login (should fail) */
150                 setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
151                 
152                 anon_creds = cli_credentials_init(tctx);
153                 cli_credentials_set_conf(anon_creds, tctx->lp_ctx);
154                 cli_credentials_set_anonymous(anon_creds);
155
156                 setup.in.credentials = anon_creds;
157         
158                 status = smb_composite_sesssetup(session3, &setup);
159                 CHECK_STATUS(status, NT_STATUS_OK);
160
161                 talloc_free(session4);
162         }
163                 
164         torture_comment(tctx, "use the same tree as the existing connection\n");
165         tree = smbcli_tree_init(session, tctx, false);
166         tree->tid = cli->tree->tid;
167
168         torture_comment(tctx, "create a file using the new vuid\n");
169         io.generic.level = RAW_OPEN_NTCREATEX;
170         io.ntcreatex.in.root_fid.fnum = 0;
171         io.ntcreatex.in.flags = 0;
172         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
173         io.ntcreatex.in.create_options = 0;
174         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
175         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
176         io.ntcreatex.in.alloc_size = 0;
177         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
178         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
179         io.ntcreatex.in.security_flags = 0;
180         io.ntcreatex.in.fname = fname;
181         status = smb_raw_open(tree, tctx, &io);
182         CHECK_STATUS(status, NT_STATUS_OK);
183         fnum = io.ntcreatex.out.file.fnum;
184
185         torture_comment(tctx, "write using the old vuid\n");
186         wr.generic.level = RAW_WRITE_WRITEX;
187         wr.writex.in.file.fnum = fnum;
188         wr.writex.in.offset = 0;
189         wr.writex.in.wmode = 0;
190         wr.writex.in.remaining = 0;
191         wr.writex.in.count = 1;
192         wr.writex.in.data = &c;
193
194         status = smb_raw_write(cli->tree, &wr);
195         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
196
197         torture_comment(tctx, "write with the new vuid\n");
198         status = smb_raw_write(tree, &wr);
199         CHECK_STATUS(status, NT_STATUS_OK);
200         CHECK_VALUE(wr.writex.out.nwritten, 1);
201
202         torture_comment(tctx, "logoff the new vuid\n");
203         status = smb_raw_ulogoff(session);
204         CHECK_STATUS(status, NT_STATUS_OK);
205
206         torture_comment(tctx, "the new vuid should not now be accessible\n");
207         status = smb_raw_write(tree, &wr);
208         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
209
210         torture_comment(tctx, "second logoff for the new vuid should fail\n");
211         status = smb_raw_ulogoff(session);
212         CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV, ERRbaduid));
213         talloc_free(session);
214
215         torture_comment(tctx, "the fnum should have been auto-closed\n");
216         cl.close.level = RAW_CLOSE_CLOSE;
217         cl.close.in.file.fnum = fnum;
218         cl.close.in.write_time = 0;
219         status = smb_raw_close(cli->tree, &cl);
220         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
221
222         torture_comment(tctx, "create %d secondary security contexts on the same transport\n",
223                (int)ARRAY_SIZE(sessions));
224         for (i=0; i <ARRAY_SIZE(sessions); i++) {
225                 setups[i].in.sesskey = cli->transport->negotiate.sesskey;
226                 setups[i].in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
227                 setups[i].in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
228                 
229                 setups[i].in.credentials = cmdline_credentials;
230                 setups[i].in.gensec_settings = gensec_settings;
231
232                 sessions[i] = smbcli_session_init(cli->transport, tctx, false, options);
233                 composite_contexts[i] = smb_composite_sesssetup_send(sessions[i], &setups[i]);
234
235         }
236
237
238         torture_comment(tctx, "finishing %d secondary security contexts on the same transport\n",
239                (int)ARRAY_SIZE(sessions));
240         for (i=0; i< ARRAY_SIZE(sessions); i++) {
241                 status = smb_composite_sesssetup_recv(composite_contexts[i]);
242                 CHECK_STATUS(status, NT_STATUS_OK);
243                 sessions[i]->vuid = setups[i].out.vuid;
244                 torture_comment(tctx, "VUID: %d\n", sessions[i]->vuid);
245                 status = smb_raw_ulogoff(sessions[i]);
246                 CHECK_STATUS(status, NT_STATUS_OK);
247         }
248
249
250         talloc_free(tree);
251         
252 done:
253         return ret;
254 }
255
256
257 /*
258   test tree ops
259 */
260 static bool test_tree(struct torture_context *tctx, struct smbcli_state *cli)
261 {
262         NTSTATUS status;
263         bool ret = true;
264         const char *share, *host;
265         struct smbcli_tree *tree;
266         union smb_tcon tcon;
267         union smb_open io;
268         union smb_write wr;
269         union smb_close cl;
270         int fnum;
271         const char *fname = BASEDIR "\\test.txt";
272         uint8_t c = 1;
273
274         torture_comment(tctx, "TESTING TREE HANDLING\n");
275
276         if (!torture_setup_dir(cli, BASEDIR)) {
277                 return false;
278         }
279
280         share = torture_setting_string(tctx, "share", NULL);
281         host  = torture_setting_string(tctx, "host", NULL);
282         
283         torture_comment(tctx, "create a second tree context on the same session\n");
284         tree = smbcli_tree_init(cli->session, tctx, false);
285
286         tcon.generic.level = RAW_TCON_TCONX;
287         tcon.tconx.in.flags = 0;
288         tcon.tconx.in.password = data_blob(NULL, 0);
289         tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
290         tcon.tconx.in.device = "A:";    
291         status = smb_raw_tcon(tree, tctx, &tcon);
292         CHECK_STATUS(status, NT_STATUS_OK);
293         
294
295         tree->tid = tcon.tconx.out.tid;
296         torture_comment(tctx, "tid1=%d tid2=%d\n", cli->tree->tid, tree->tid);
297
298         torture_comment(tctx, "try a tconx with a bad device type\n");
299         tcon.tconx.in.device = "FOO";   
300         status = smb_raw_tcon(tree, tctx, &tcon);
301         CHECK_STATUS(status, NT_STATUS_BAD_DEVICE_TYPE);
302
303
304         torture_comment(tctx, "create a file using the new tid\n");
305         io.generic.level = RAW_OPEN_NTCREATEX;
306         io.ntcreatex.in.root_fid.fnum = 0;
307         io.ntcreatex.in.flags = 0;
308         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
309         io.ntcreatex.in.create_options = 0;
310         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
311         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
312         io.ntcreatex.in.alloc_size = 0;
313         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
314         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
315         io.ntcreatex.in.security_flags = 0;
316         io.ntcreatex.in.fname = fname;
317         status = smb_raw_open(tree, tctx, &io);
318         CHECK_STATUS(status, NT_STATUS_OK);
319         fnum = io.ntcreatex.out.file.fnum;
320
321         torture_comment(tctx, "write using the old tid\n");
322         wr.generic.level = RAW_WRITE_WRITEX;
323         wr.writex.in.file.fnum = fnum;
324         wr.writex.in.offset = 0;
325         wr.writex.in.wmode = 0;
326         wr.writex.in.remaining = 0;
327         wr.writex.in.count = 1;
328         wr.writex.in.data = &c;
329
330         status = smb_raw_write(cli->tree, &wr);
331         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
332
333         torture_comment(tctx, "write with the new tid\n");
334         status = smb_raw_write(tree, &wr);
335         CHECK_STATUS(status, NT_STATUS_OK);
336         CHECK_VALUE(wr.writex.out.nwritten, 1);
337
338         torture_comment(tctx, "disconnect the new tid\n");
339         status = smb_tree_disconnect(tree);
340         CHECK_STATUS(status, NT_STATUS_OK);
341
342         torture_comment(tctx, "the new tid should not now be accessible\n");
343         status = smb_raw_write(tree, &wr);
344         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
345
346         torture_comment(tctx, "the fnum should have been auto-closed\n");
347         cl.close.level = RAW_CLOSE_CLOSE;
348         cl.close.in.file.fnum = fnum;
349         cl.close.in.write_time = 0;
350         status = smb_raw_close(cli->tree, &cl);
351         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
352
353         /* close down the new tree */
354         talloc_free(tree);
355         
356 done:
357         return ret;
358 }
359
360 /*
361   test tree with ulogoff
362   this demonstrates that a tcon isn't autoclosed by a ulogoff
363   the tcon can be reused using any other valid session later
364 */
365 static bool test_tree_ulogoff(struct torture_context *tctx, struct smbcli_state *cli)
366 {
367         NTSTATUS status;
368         bool ret = true;
369         const char *share, *host;
370         struct smbcli_session *session1;
371         struct smbcli_session *session2;
372         struct smb_composite_sesssetup setup;
373         struct smbcli_tree *tree;
374         union smb_tcon tcon;
375         union smb_open io;
376         union smb_write wr;
377         int fnum1, fnum2;
378         const char *fname1 = BASEDIR "\\test1.txt";
379         const char *fname2 = BASEDIR "\\test2.txt";
380         uint8_t c = 1;
381         struct smbcli_session_options options;
382
383         torture_comment(tctx, "TESTING TREE with ulogoff\n");
384
385         if (!torture_setup_dir(cli, BASEDIR)) {
386                 return false;
387         }
388
389         share = torture_setting_string(tctx, "share", NULL);
390         host  = torture_setting_string(tctx, "host", NULL);
391
392         lpcfg_smbcli_session_options(tctx->lp_ctx, &options);
393
394         torture_comment(tctx, "create the first new sessions\n");
395         session1 = smbcli_session_init(cli->transport, tctx, false, options);
396         setup.in.sesskey = cli->transport->negotiate.sesskey;
397         setup.in.capabilities = cli->transport->negotiate.capabilities;
398         setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
399         setup.in.credentials = cmdline_credentials;
400         setup.in.gensec_settings = lpcfg_gensec_settings(tctx, tctx->lp_ctx);
401         status = smb_composite_sesssetup(session1, &setup);
402         CHECK_STATUS(status, NT_STATUS_OK);
403         session1->vuid = setup.out.vuid;
404         torture_comment(tctx, "vuid1=%d\n", session1->vuid);
405
406         torture_comment(tctx, "create a tree context on the with vuid1\n");
407         tree = smbcli_tree_init(session1, tctx, false);
408         tcon.generic.level = RAW_TCON_TCONX;
409         tcon.tconx.in.flags = 0;
410         tcon.tconx.in.password = data_blob(NULL, 0);
411         tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
412         tcon.tconx.in.device = "A:";
413         status = smb_raw_tcon(tree, tctx, &tcon);
414         CHECK_STATUS(status, NT_STATUS_OK);
415         tree->tid = tcon.tconx.out.tid;
416         torture_comment(tctx, "tid=%d\n", tree->tid);
417
418         torture_comment(tctx, "create a file using vuid1\n");
419         io.generic.level = RAW_OPEN_NTCREATEX;
420         io.ntcreatex.in.root_fid.fnum = 0;
421         io.ntcreatex.in.flags = 0;
422         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
423         io.ntcreatex.in.create_options = 0;
424         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
425         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
426         io.ntcreatex.in.alloc_size = 0;
427         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
428         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
429         io.ntcreatex.in.security_flags = 0;
430         io.ntcreatex.in.fname = fname1;
431         status = smb_raw_open(tree, tctx, &io);
432         CHECK_STATUS(status, NT_STATUS_OK);
433         fnum1 = io.ntcreatex.out.file.fnum;
434
435         torture_comment(tctx, "write using vuid1\n");
436         wr.generic.level = RAW_WRITE_WRITEX;
437         wr.writex.in.file.fnum = fnum1;
438         wr.writex.in.offset = 0;
439         wr.writex.in.wmode = 0;
440         wr.writex.in.remaining = 0;
441         wr.writex.in.count = 1;
442         wr.writex.in.data = &c;
443         status = smb_raw_write(tree, &wr);
444         CHECK_STATUS(status, NT_STATUS_OK);
445         CHECK_VALUE(wr.writex.out.nwritten, 1);
446
447         torture_comment(tctx, "ulogoff the vuid1\n");
448         status = smb_raw_ulogoff(session1);
449         CHECK_STATUS(status, NT_STATUS_OK);
450
451         torture_comment(tctx, "create the second new sessions\n");
452         session2 = smbcli_session_init(cli->transport, tctx, false, options);
453         setup.in.sesskey = cli->transport->negotiate.sesskey;
454         setup.in.capabilities = cli->transport->negotiate.capabilities;
455         setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
456         setup.in.credentials = cmdline_credentials;
457         setup.in.gensec_settings = lpcfg_gensec_settings(tctx, tctx->lp_ctx);
458         status = smb_composite_sesssetup(session2, &setup);
459         CHECK_STATUS(status, NT_STATUS_OK);
460         session2->vuid = setup.out.vuid;
461         torture_comment(tctx, "vuid2=%d\n", session2->vuid);
462
463         torture_comment(tctx, "use the existing tree with vuid2\n");
464         tree->session = session2;
465
466         torture_comment(tctx, "create a file using vuid2\n");
467         io.generic.level = RAW_OPEN_NTCREATEX;
468         io.ntcreatex.in.root_fid.fnum = 0;
469         io.ntcreatex.in.flags = 0;
470         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
471         io.ntcreatex.in.create_options = 0;
472         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
473         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
474         io.ntcreatex.in.alloc_size = 0;
475         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
476         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
477         io.ntcreatex.in.security_flags = 0;
478         io.ntcreatex.in.fname = fname2;
479         status = smb_raw_open(tree, tctx, &io);
480         CHECK_STATUS(status, NT_STATUS_OK);
481         fnum2 = io.ntcreatex.out.file.fnum;
482
483         torture_comment(tctx, "write using vuid2\n");
484         wr.generic.level = RAW_WRITE_WRITEX;
485         wr.writex.in.file.fnum = fnum2;
486         wr.writex.in.offset = 0;
487         wr.writex.in.wmode = 0;
488         wr.writex.in.remaining = 0;
489         wr.writex.in.count = 1;
490         wr.writex.in.data = &c;
491         status = smb_raw_write(tree, &wr);
492         CHECK_STATUS(status, NT_STATUS_OK);
493         CHECK_VALUE(wr.writex.out.nwritten, 1);
494
495         torture_comment(tctx, "ulogoff the vuid2\n");
496         status = smb_raw_ulogoff(session2);
497         CHECK_STATUS(status, NT_STATUS_OK);
498
499         /* this also demonstrates that SMBtdis doesn't need a valid vuid */
500         torture_comment(tctx, "disconnect the existing tree connection\n");
501         status = smb_tree_disconnect(tree);
502         CHECK_STATUS(status, NT_STATUS_OK);
503
504         torture_comment(tctx, "disconnect the existing tree connection\n");
505         status = smb_tree_disconnect(tree);
506         CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV,ERRinvnid));
507
508         /* close down the new tree */
509         talloc_free(tree);
510         
511 done:
512         return ret;
513 }
514
515 /*
516   test pid ops
517   this test demonstrates that exit() only sees the PID
518   used for the open() calls
519 */
520 static bool test_pid_exit_only_sees_open(struct torture_context *tctx,
521                                          struct smbcli_state *cli)
522 {
523         NTSTATUS status;
524         TALLOC_CTX *mem_ctx = tctx;
525         bool ret = true;
526         union smb_open io;
527         union smb_write wr;
528         union smb_close cl;
529         int fnum;
530         const char *fname = BASEDIR "\\test.txt";
531         uint8_t c = 1;
532         uint16_t pid1, pid2;
533
534         torture_comment(tctx, "TESTING PID HANDLING exit() only cares about open() PID\n");
535
536         if (!torture_setup_dir(cli, BASEDIR)) {
537                 return false;
538         }
539
540         pid1 = cli->session->pid;
541         pid2 = pid1 + 1;
542
543         torture_comment(tctx, "pid1=%d pid2=%d\n", pid1, pid2);
544
545         torture_comment(tctx, "create a file using pid1\n");
546         cli->session->pid = pid1;
547         io.generic.level = RAW_OPEN_NTCREATEX;
548         io.ntcreatex.in.root_fid.fnum = 0;
549         io.ntcreatex.in.flags = 0;
550         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
551         io.ntcreatex.in.create_options = 0;
552         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
553         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
554         io.ntcreatex.in.alloc_size = 0;
555         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
556         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
557         io.ntcreatex.in.security_flags = 0;
558         io.ntcreatex.in.fname = fname;
559         status = smb_raw_open(cli->tree, mem_ctx, &io);
560         CHECK_STATUS(status, NT_STATUS_OK);
561         fnum = io.ntcreatex.out.file.fnum;
562
563         torture_comment(tctx, "write using pid2\n");
564         cli->session->pid = pid2;
565         wr.generic.level = RAW_WRITE_WRITEX;
566         wr.writex.in.file.fnum = fnum;
567         wr.writex.in.offset = 0;
568         wr.writex.in.wmode = 0;
569         wr.writex.in.remaining = 0;
570         wr.writex.in.count = 1;
571         wr.writex.in.data = &c;
572         status = smb_raw_write(cli->tree, &wr);
573         CHECK_STATUS(status, NT_STATUS_OK);
574         CHECK_VALUE(wr.writex.out.nwritten, 1);
575
576         torture_comment(tctx, "exit pid2\n");
577         cli->session->pid = pid2;
578         status = smb_raw_exit(cli->session);
579         CHECK_STATUS(status, NT_STATUS_OK);
580
581         torture_comment(tctx, "the fnum should still be accessible via pid2\n");
582         cli->session->pid = pid2;
583         status = smb_raw_write(cli->tree, &wr);
584         CHECK_STATUS(status, NT_STATUS_OK);
585         CHECK_VALUE(wr.writex.out.nwritten, 1);
586
587         torture_comment(tctx, "exit pid2\n");
588         cli->session->pid = pid2;
589         status = smb_raw_exit(cli->session);
590         CHECK_STATUS(status, NT_STATUS_OK);
591
592         torture_comment(tctx, "the fnum should still be accessible via pid1 and pid2\n");
593         cli->session->pid = pid1;
594         status = smb_raw_write(cli->tree, &wr);
595         CHECK_STATUS(status, NT_STATUS_OK);
596         CHECK_VALUE(wr.writex.out.nwritten, 1);
597         cli->session->pid = pid2;
598         status = smb_raw_write(cli->tree, &wr);
599         CHECK_STATUS(status, NT_STATUS_OK);
600         CHECK_VALUE(wr.writex.out.nwritten, 1);
601
602         torture_comment(tctx, "exit pid1\n");
603         cli->session->pid = pid1;
604         status = smb_raw_exit(cli->session);
605         CHECK_STATUS(status, NT_STATUS_OK);
606
607         torture_comment(tctx, "the fnum should not now be accessible via pid1 or pid2\n");
608         cli->session->pid = pid1;
609         status = smb_raw_write(cli->tree, &wr);
610         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
611         cli->session->pid = pid2;
612         status = smb_raw_write(cli->tree, &wr);
613         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
614
615         torture_comment(tctx, "the fnum should have been auto-closed\n");
616         cli->session->pid = pid1;
617         cl.close.level = RAW_CLOSE_CLOSE;
618         cl.close.in.file.fnum = fnum;
619         cl.close.in.write_time = 0;
620         status = smb_raw_close(cli->tree, &cl);
621         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
622
623 done:
624         return ret;
625 }
626
627 /*
628   test pid ops with 2 sessions
629 */
630 static bool test_pid_2sess(struct torture_context *tctx,
631                            struct smbcli_state *cli)
632 {
633         NTSTATUS status;
634         bool ret = true;
635         struct smbcli_session *session;
636         struct smb_composite_sesssetup setup;
637         union smb_open io;
638         union smb_write wr;
639         union smb_close cl;
640         int fnum;
641         const char *fname = BASEDIR "\\test.txt";
642         uint8_t c = 1;
643         uint16_t vuid1, vuid2;
644         struct smbcli_session_options options;
645
646         torture_comment(tctx, "TESTING PID HANDLING WITH 2 SESSIONS\n");
647
648         if (!torture_setup_dir(cli, BASEDIR)) {
649                 return false;
650         }
651
652         lpcfg_smbcli_session_options(tctx->lp_ctx, &options);
653
654         torture_comment(tctx, "create a second security context on the same transport\n");
655         session = smbcli_session_init(cli->transport, tctx, false, options);
656
657         setup.in.sesskey = cli->transport->negotiate.sesskey;
658         setup.in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
659         setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
660         setup.in.credentials = cmdline_credentials;
661         setup.in.gensec_settings = lpcfg_gensec_settings(tctx, tctx->lp_ctx);
662
663         status = smb_composite_sesssetup(session, &setup);
664         CHECK_STATUS(status, NT_STATUS_OK);     
665         session->vuid = setup.out.vuid;
666
667         vuid1 = cli->session->vuid;
668         vuid2 = session->vuid;
669
670         torture_comment(tctx, "vuid1=%d vuid2=%d\n", vuid1, vuid2);
671
672         torture_comment(tctx, "create a file using the vuid1\n");
673         cli->session->vuid = vuid1;
674         io.generic.level = RAW_OPEN_NTCREATEX;
675         io.ntcreatex.in.root_fid.fnum = 0;
676         io.ntcreatex.in.flags = 0;
677         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
678         io.ntcreatex.in.create_options = 0;
679         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
680         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
681         io.ntcreatex.in.alloc_size = 0;
682         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
683         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
684         io.ntcreatex.in.security_flags = 0;
685         io.ntcreatex.in.fname = fname;
686         status = smb_raw_open(cli->tree, tctx, &io);
687         CHECK_STATUS(status, NT_STATUS_OK);
688         fnum = io.ntcreatex.out.file.fnum;
689
690         torture_comment(tctx, "write using the vuid1 (fnum=%d)\n", fnum);
691         cli->session->vuid = vuid1;
692         wr.generic.level = RAW_WRITE_WRITEX;
693         wr.writex.in.file.fnum = fnum;
694         wr.writex.in.offset = 0;
695         wr.writex.in.wmode = 0;
696         wr.writex.in.remaining = 0;
697         wr.writex.in.count = 1;
698         wr.writex.in.data = &c;
699
700         status = smb_raw_write(cli->tree, &wr);
701         CHECK_STATUS(status, NT_STATUS_OK);
702         CHECK_VALUE(wr.writex.out.nwritten, 1);
703
704         torture_comment(tctx, "exit the pid with vuid2\n");
705         cli->session->vuid = vuid2;
706         status = smb_raw_exit(cli->session);
707         CHECK_STATUS(status, NT_STATUS_OK);
708
709         torture_comment(tctx, "the fnum should still be accessible\n");
710         cli->session->vuid = vuid1;
711         status = smb_raw_write(cli->tree, &wr);
712         CHECK_STATUS(status, NT_STATUS_OK);
713         CHECK_VALUE(wr.writex.out.nwritten, 1);
714
715         torture_comment(tctx, "exit the pid with vuid1\n");
716         cli->session->vuid = vuid1;
717         status = smb_raw_exit(cli->session);
718         CHECK_STATUS(status, NT_STATUS_OK);
719
720         torture_comment(tctx, "the fnum should not now be accessible\n");
721         status = smb_raw_write(cli->tree, &wr);
722         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
723
724         torture_comment(tctx, "the fnum should have been auto-closed\n");
725         cl.close.level = RAW_CLOSE_CLOSE;
726         cl.close.in.file.fnum = fnum;
727         cl.close.in.write_time = 0;
728         status = smb_raw_close(cli->tree, &cl);
729         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
730
731 done:
732         return ret;
733 }
734
735 /*
736   test pid ops with 2 tcons
737 */
738 static bool test_pid_2tcon(struct torture_context *tctx,
739                            struct smbcli_state *cli)
740 {
741         NTSTATUS status;
742         bool ret = true;
743         const char *share, *host;
744         struct smbcli_tree *tree;
745         union smb_tcon tcon;
746         union smb_open io;
747         union smb_write wr;
748         union smb_close cl;
749         int fnum1, fnum2;
750         const char *fname1 = BASEDIR "\\test1.txt";
751         const char *fname2 = BASEDIR "\\test2.txt";
752         uint8_t c = 1;
753         uint16_t tid1, tid2;
754
755         torture_comment(tctx, "TESTING PID HANDLING WITH 2 TCONS\n");
756
757         if (!torture_setup_dir(cli, BASEDIR)) {
758                 return false;
759         }
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 = 0;
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 }