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