43e059e23d7541f16d8f9df1ba2a787ef20fcd70
[jelmer/samba4-debian.git] / source / 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 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 "torture/torture.h"
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/composite/composite.h"
25 #include "libcli/smb_composite/smb_composite.h"
26 #include "lib/cmdline/popt_common.h"
27 #include "lib/events/events.h"
28 #include "libcli/libcli.h"
29
30 #define BASEDIR "\\rawcontext"
31
32 #define CHECK_STATUS(status, correct) do { \
33         if (!NT_STATUS_EQUAL(status, correct)) { \
34                 printf("(%s) Incorrect status %s - should be %s\n", \
35                        __location__, nt_errstr(status), nt_errstr(correct)); \
36                 ret = False; \
37                 goto done; \
38         }} while (0)
39
40 #define CHECK_VALUE(v, correct) do { \
41         if ((v) != (correct)) { \
42                 printf("(%s) Incorrect value %s=%d - should be %d\n", \
43                        __location__, #v, v, correct); \
44                 ret = False; \
45                 goto done; \
46         }} while (0)
47
48 #define CHECK_NOT_VALUE(v, correct) do { \
49         if ((v) == (correct)) { \
50                 printf("(%s) Incorrect value %s=%d - should not be %d\n", \
51                        __location__, #v, v, correct); \
52                 ret = False; \
53                 goto done; \
54         }} while (0)
55
56
57 /*
58   test session ops
59 */
60 static BOOL test_session(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
61 {
62         NTSTATUS status;
63         BOOL ret = True;
64         struct smbcli_session *session;
65         struct smbcli_session *session2;
66         struct smbcli_session *session3;
67         struct smbcli_session *session4;
68         struct cli_credentials *anon_creds;
69         struct smbcli_session *sessions[15];
70         struct composite_context *composite_contexts[15];
71         struct smbcli_tree *tree;
72         struct smb_composite_sesssetup setup;
73         struct smb_composite_sesssetup setups[15];
74         union smb_open io;
75         union smb_write wr;
76         union smb_close cl;
77         int fnum;
78         const char *fname = BASEDIR "\\test.txt";
79         uint8_t c = 1;
80         int i;
81
82         printf("TESTING SESSION HANDLING\n");
83
84         if (!torture_setup_dir(cli, BASEDIR)) {
85                 return False;
86         }
87
88         printf("create a second security context on the same transport\n");
89         session = smbcli_session_init(cli->transport, mem_ctx, False);
90
91         setup.in.sesskey = cli->transport->negotiate.sesskey;
92         setup.in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
93         setup.in.workgroup = lp_workgroup();
94
95         setup.in.credentials = cmdline_credentials;
96
97         status = smb_composite_sesssetup(session, &setup);
98         CHECK_STATUS(status, NT_STATUS_OK);
99         
100         session->vuid = setup.out.vuid;
101
102         printf("create a third security context on the same transport, with vuid set\n");
103         session2 = smbcli_session_init(cli->transport, mem_ctx, False);
104
105         session2->vuid = session->vuid;
106         setup.in.sesskey = cli->transport->negotiate.sesskey;
107         setup.in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
108         setup.in.workgroup = lp_workgroup();
109
110         setup.in.credentials = cmdline_credentials;
111
112         status = smb_composite_sesssetup(session2, &setup);
113         CHECK_STATUS(status, NT_STATUS_OK);
114
115         session2->vuid = setup.out.vuid;
116         printf("vuid1=%d vuid2=%d vuid3=%d\n", cli->session->vuid, session->vuid, session2->vuid);
117         
118         if (cli->transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) {
119                 /* Samba4 currently fails this - we need to determine if this insane behaviour is important */
120                 if (session2->vuid == session->vuid) {
121                         printf("server allows the user to re-use an existing vuid in session setup \n");
122                 }
123         } else {
124                 CHECK_NOT_VALUE(session2->vuid, session->vuid);
125         }
126         talloc_free(session2);
127
128         if (cli->transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) {
129                 printf("create a fourth security context on the same transport, without extended security\n");
130                 session3 = smbcli_session_init(cli->transport, mem_ctx, False);
131
132                 session3->vuid = session->vuid;
133                 setup.in.sesskey = cli->transport->negotiate.sesskey;
134                 setup.in.capabilities &= ~CAP_EXTENDED_SECURITY; /* force a non extended security login (should fail) */
135                 setup.in.workgroup = lp_workgroup();
136         
137                 setup.in.credentials = cmdline_credentials;
138         
139
140                 status = smb_composite_sesssetup(session3, &setup);
141                 CHECK_STATUS(status, NT_STATUS_LOGON_FAILURE);
142
143                 printf("create a fouth anonymous security context on the same transport, without extended security\n");
144                 session4 = smbcli_session_init(cli->transport, mem_ctx, False);
145
146                 session4->vuid = session->vuid;
147                 setup.in.sesskey = cli->transport->negotiate.sesskey;
148                 setup.in.capabilities &= ~CAP_EXTENDED_SECURITY; /* force a non extended security login (should fail) */
149                 setup.in.workgroup = lp_workgroup();
150                 
151                 anon_creds = cli_credentials_init(mem_ctx);
152                 cli_credentials_set_conf(anon_creds);
153                 cli_credentials_set_anonymous(anon_creds);
154
155                 setup.in.credentials = anon_creds;
156         
157                 status = smb_composite_sesssetup(session3, &setup);
158                 CHECK_STATUS(status, NT_STATUS_OK);
159
160                 talloc_free(session4);
161         }
162                 
163         printf("use the same tree as the existing connection\n");
164         tree = smbcli_tree_init(session, mem_ctx, False);
165         tree->tid = cli->tree->tid;
166
167         printf("create a file using the new vuid\n");
168         io.generic.level = RAW_OPEN_NTCREATEX;
169         io.ntcreatex.in.root_fid = 0;
170         io.ntcreatex.in.flags = 0;
171         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
172         io.ntcreatex.in.create_options = 0;
173         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
174         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
175         io.ntcreatex.in.alloc_size = 0;
176         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
177         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
178         io.ntcreatex.in.security_flags = 0;
179         io.ntcreatex.in.fname = fname;
180         status = smb_raw_open(tree, mem_ctx, &io);
181         CHECK_STATUS(status, NT_STATUS_OK);
182         fnum = io.ntcreatex.out.fnum;
183
184         printf("write using the old vuid\n");
185         wr.generic.level = RAW_WRITE_WRITEX;
186         wr.writex.in.fnum = fnum;
187         wr.writex.in.offset = 0;
188         wr.writex.in.wmode = 0;
189         wr.writex.in.remaining = 0;
190         wr.writex.in.count = 1;
191         wr.writex.in.data = &c;
192
193         status = smb_raw_write(cli->tree, &wr);
194         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
195
196         printf("write with the new vuid\n");
197         status = smb_raw_write(tree, &wr);
198         CHECK_STATUS(status, NT_STATUS_OK);
199         CHECK_VALUE(wr.writex.out.nwritten, 1);
200
201         printf("logoff the new vuid\n");
202         status = smb_raw_ulogoff(session);
203         CHECK_STATUS(status, NT_STATUS_OK);
204
205         printf("the new vuid should not now be accessible\n");
206         status = smb_raw_write(tree, &wr);
207         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
208
209         printf("second logoff for the new vuid should fail\n");
210         status = smb_raw_ulogoff(session);
211         CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV, ERRbaduid));
212         talloc_free(session);
213
214         printf("the fnum should have been auto-closed\n");
215         cl.close.level = RAW_CLOSE_CLOSE;
216         cl.close.in.fnum = fnum;
217         cl.close.in.write_time = 0;
218         status = smb_raw_close(cli->tree, &cl);
219         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
220
221         printf("create %d secondary security contexts on the same transport\n", 
222                (int)ARRAY_SIZE(sessions));
223         for (i=0; i <ARRAY_SIZE(sessions); i++) {
224                 setups[i].in.sesskey = cli->transport->negotiate.sesskey;
225                 setups[i].in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
226                 setups[i].in.workgroup = lp_workgroup();
227                 
228                 setups[i].in.credentials = cmdline_credentials;
229
230                 sessions[i] = smbcli_session_init(cli->transport, mem_ctx, False);
231                 composite_contexts[i] = smb_composite_sesssetup_send(sessions[i], &setups[i]);
232
233         }
234
235
236         /* flush the queue */
237         for (i=0; i < ARRAY_SIZE(sessions); i++) {
238                 event_loop_once(composite_contexts[0]->event_ctx);
239         }
240
241         printf("finishing %d secondary security contexts on the same transport\n", 
242                (int)ARRAY_SIZE(sessions));
243         for (i=0; i< ARRAY_SIZE(sessions); i++) {
244                 status = smb_composite_sesssetup_recv(composite_contexts[i]);
245                 CHECK_STATUS(status, NT_STATUS_OK);
246                 sessions[i]->vuid = setups[i].out.vuid;
247                 printf("VUID: %d\n", sessions[i]->vuid);
248                 status = smb_raw_ulogoff(sessions[i]);
249                 CHECK_STATUS(status, NT_STATUS_OK);
250         }
251
252
253         talloc_free(tree);
254         
255 done:
256         return ret;
257 }
258
259
260 /*
261   test tree ops
262 */
263 static BOOL test_tree(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
264 {
265         NTSTATUS status;
266         BOOL ret = True;
267         const char *share, *host;
268         struct smbcli_tree *tree;
269         union smb_tcon tcon;
270         union smb_open io;
271         union smb_write wr;
272         union smb_close cl;
273         int fnum;
274         const char *fname = BASEDIR "\\test.txt";
275         uint8_t c = 1;
276
277         printf("TESTING TREE HANDLING\n");
278
279         if (!torture_setup_dir(cli, BASEDIR)) {
280                 return False;
281         }
282
283         share = lp_parm_string(-1, "torture", "share");
284         host  = lp_parm_string(-1, "torture", "host");
285         
286         printf("create a second tree context on the same session\n");
287         tree = smbcli_tree_init(cli->session, mem_ctx, False);
288
289         tcon.generic.level = RAW_TCON_TCONX;
290         tcon.tconx.in.flags = 0;
291         tcon.tconx.in.password = data_blob(NULL, 0);
292         tcon.tconx.in.path = talloc_asprintf(mem_ctx, "\\\\%s\\%s", host, share);
293         tcon.tconx.in.device = "A:";    
294         status = smb_raw_tcon(tree, mem_ctx, &tcon);
295         CHECK_STATUS(status, NT_STATUS_OK);
296         
297
298         tree->tid = tcon.tconx.out.tid;
299         printf("tid1=%d tid2=%d\n", cli->tree->tid, tree->tid);
300
301         printf("try a tconx with a bad device type\n");
302         tcon.tconx.in.device = "FOO";   
303         status = smb_raw_tcon(tree, mem_ctx, &tcon);
304         CHECK_STATUS(status, NT_STATUS_BAD_DEVICE_TYPE);
305
306
307         printf("create a file using the new tid\n");
308         io.generic.level = RAW_OPEN_NTCREATEX;
309         io.ntcreatex.in.root_fid = 0;
310         io.ntcreatex.in.flags = 0;
311         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
312         io.ntcreatex.in.create_options = 0;
313         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
314         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
315         io.ntcreatex.in.alloc_size = 0;
316         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
317         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
318         io.ntcreatex.in.security_flags = 0;
319         io.ntcreatex.in.fname = fname;
320         status = smb_raw_open(tree, mem_ctx, &io);
321         CHECK_STATUS(status, NT_STATUS_OK);
322         fnum = io.ntcreatex.out.fnum;
323
324         printf("write using the old tid\n");
325         wr.generic.level = RAW_WRITE_WRITEX;
326         wr.writex.in.fnum = fnum;
327         wr.writex.in.offset = 0;
328         wr.writex.in.wmode = 0;
329         wr.writex.in.remaining = 0;
330         wr.writex.in.count = 1;
331         wr.writex.in.data = &c;
332
333         status = smb_raw_write(cli->tree, &wr);
334         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
335
336         printf("write with the new tid\n");
337         status = smb_raw_write(tree, &wr);
338         CHECK_STATUS(status, NT_STATUS_OK);
339         CHECK_VALUE(wr.writex.out.nwritten, 1);
340
341         printf("disconnect the new tid\n");
342         status = smb_tree_disconnect(tree);
343         CHECK_STATUS(status, NT_STATUS_OK);
344
345         printf("the new tid should not now be accessible\n");
346         status = smb_raw_write(tree, &wr);
347         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
348
349         printf("the fnum should have been auto-closed\n");
350         cl.close.level = RAW_CLOSE_CLOSE;
351         cl.close.in.fnum = fnum;
352         cl.close.in.write_time = 0;
353         status = smb_raw_close(cli->tree, &cl);
354         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
355
356         /* close down the new tree */
357         talloc_free(tree);
358         
359 done:
360         return ret;
361 }
362
363
364 /*
365   test pid ops
366 */
367 static BOOL test_pid(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
368 {
369         NTSTATUS status;
370         BOOL ret = True;
371         union smb_open io;
372         union smb_write wr;
373         union smb_close cl;
374         int fnum;
375         const char *fname = BASEDIR "\\test.txt";
376         uint8_t c = 1;
377         uint16_t pid1, pid2;
378
379         printf("TESTING PID HANDLING\n");
380
381         if (!torture_setup_dir(cli, BASEDIR)) {
382                 return False;
383         }
384
385         printf("create a second pid\n");
386         pid1 = cli->session->pid;
387         pid2 = pid1+1;
388
389         printf("pid1=%d pid2=%d\n", pid1, pid2);
390
391         printf("create a file using the new pid\n");
392         cli->session->pid = pid2;
393         io.generic.level = RAW_OPEN_NTCREATEX;
394         io.ntcreatex.in.root_fid = 0;
395         io.ntcreatex.in.flags = 0;
396         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
397         io.ntcreatex.in.create_options = 0;
398         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
399         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
400         io.ntcreatex.in.alloc_size = 0;
401         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
402         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
403         io.ntcreatex.in.security_flags = 0;
404         io.ntcreatex.in.fname = fname;
405         status = smb_raw_open(cli->tree, mem_ctx, &io);
406         CHECK_STATUS(status, NT_STATUS_OK);
407         fnum = io.ntcreatex.out.fnum;
408
409         printf("write using the old pid\n");
410         cli->session->pid = pid1;
411         wr.generic.level = RAW_WRITE_WRITEX;
412         wr.writex.in.fnum = fnum;
413         wr.writex.in.offset = 0;
414         wr.writex.in.wmode = 0;
415         wr.writex.in.remaining = 0;
416         wr.writex.in.count = 1;
417         wr.writex.in.data = &c;
418
419         status = smb_raw_write(cli->tree, &wr);
420         CHECK_STATUS(status, NT_STATUS_OK);
421         CHECK_VALUE(wr.writex.out.nwritten, 1);
422
423         printf("write with the new pid\n");
424         cli->session->pid = pid2;
425         status = smb_raw_write(cli->tree, &wr);
426         CHECK_STATUS(status, NT_STATUS_OK);
427         CHECK_VALUE(wr.writex.out.nwritten, 1);
428
429         printf("exit the old pid\n");
430         cli->session->pid = pid1;
431         status = smb_raw_exit(cli->session);
432         CHECK_STATUS(status, NT_STATUS_OK);
433
434         printf("the fnum should still be accessible\n");
435         cli->session->pid = pid1;
436         status = smb_raw_write(cli->tree, &wr);
437         CHECK_STATUS(status, NT_STATUS_OK);
438         CHECK_VALUE(wr.writex.out.nwritten, 1);
439
440         printf("exit the new pid\n");
441         cli->session->pid = pid2;
442         status = smb_raw_exit(cli->session);
443         CHECK_STATUS(status, NT_STATUS_OK);
444
445         printf("the fnum should not now be accessible\n");
446         cli->session->pid = pid1;
447         status = smb_raw_write(cli->tree, &wr);
448         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
449
450         printf("the fnum should have been auto-closed\n");
451         cl.close.level = RAW_CLOSE_CLOSE;
452         cl.close.in.fnum = fnum;
453         cl.close.in.write_time = 0;
454         status = smb_raw_close(cli->tree, &cl);
455         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
456
457 done:
458         return ret;
459 }
460
461
462 /* 
463    basic testing of session/tree context calls
464 */
465 static BOOL torture_raw_context_int(void)
466 {
467         struct smbcli_state *cli;
468         BOOL ret = True;
469         TALLOC_CTX *mem_ctx;
470
471         if (!torture_open_connection(&cli)) {
472                 return False;
473         }
474
475         mem_ctx = talloc_init("torture_raw_context");
476
477         if (!test_session(cli, mem_ctx)) {
478                 ret = False;
479         }
480
481         if (!test_tree(cli, mem_ctx)) {
482                 ret = False;
483         }
484
485         if (!test_pid(cli, mem_ctx)) {
486                 ret = False;
487         }
488
489         smb_raw_exit(cli->session);
490         smbcli_deltree(cli->tree, BASEDIR);
491
492         torture_close_connection(cli);
493         talloc_free(mem_ctx);
494
495         return ret;
496 }
497 /* 
498    basic testing of session/tree context calls
499 */
500 BOOL torture_raw_context(void)
501 {
502         BOOL ret = True;
503         if (lp_use_spnego()) {
504                 ret &= torture_raw_context_int();
505                 lp_set_cmdline("use spnego", "False");
506         }
507
508         ret &= torture_raw_context_int();
509
510         return ret;
511 }