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