Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : helper functions for SMB2 test suite
5 :
6 : Copyright (C) Andrew Tridgell 2005
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "includes.h"
23 : #include "libcli/security/security_descriptor.h"
24 : #include "libcli/smb2/smb2.h"
25 : #include "libcli/smb2/smb2_calls.h"
26 : #include "../libcli/smb/smbXcli_base.h"
27 : #include "lib/cmdline/cmdline.h"
28 : #include "system/time.h"
29 : #include "librpc/gen_ndr/ndr_security.h"
30 : #include "param/param.h"
31 : #include "libcli/resolve/resolve.h"
32 : #include "lib/util/tevent_ntstatus.h"
33 :
34 : #include "torture/torture.h"
35 : #include "torture/smb2/proto.h"
36 : #include "source4/torture/util.h"
37 : #include "libcli/security/dom_sid.h"
38 : #include "librpc/gen_ndr/lsa.h"
39 : #include "libcli/util/clilsa.h"
40 :
41 :
42 : /*
43 : write to a file on SMB2
44 : */
45 107 : NTSTATUS smb2_util_write(struct smb2_tree *tree,
46 : struct smb2_handle handle,
47 : const void *buf, off_t offset, size_t size)
48 : {
49 : struct smb2_write w;
50 :
51 107 : ZERO_STRUCT(w);
52 107 : w.in.file.handle = handle;
53 107 : w.in.offset = offset;
54 107 : w.in.data = data_blob_const(buf, size);
55 :
56 107 : return smb2_write(tree, &w);
57 : }
58 :
59 : /*
60 : create a complex file/dir using the SMB2 protocol
61 : */
62 8 : static NTSTATUS smb2_create_complex(struct torture_context *tctx,
63 : struct smb2_tree *tree,
64 : const char *fname,
65 : struct smb2_handle *handle,
66 : bool dir)
67 : {
68 8 : TALLOC_CTX *tmp_ctx = talloc_new(tree);
69 8 : char buf[7] = "abc";
70 : struct smb2_create io;
71 : union smb_setfileinfo setfile;
72 : union smb_fileinfo fileinfo;
73 8 : time_t t = (time(NULL) & ~1);
74 : NTSTATUS status;
75 :
76 8 : smb2_util_unlink(tree, fname);
77 8 : ZERO_STRUCT(io);
78 8 : io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
79 8 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
80 8 : io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
81 8 : io.in.share_access =
82 : NTCREATEX_SHARE_ACCESS_DELETE|
83 : NTCREATEX_SHARE_ACCESS_READ|
84 : NTCREATEX_SHARE_ACCESS_WRITE;
85 8 : io.in.create_options = 0;
86 8 : io.in.fname = fname;
87 8 : if (dir) {
88 1 : io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
89 1 : io.in.share_access &= ~NTCREATEX_SHARE_ACCESS_DELETE;
90 1 : io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
91 1 : io.in.create_disposition = NTCREATEX_DISP_CREATE;
92 : }
93 :
94 : /* it seems vista is now fussier about alignment? */
95 8 : if (strchr(fname, ':') == NULL) {
96 : /* setup some EAs */
97 6 : io.in.eas.num_eas = 2;
98 6 : io.in.eas.eas = talloc_array(tmp_ctx, struct ea_struct, 2);
99 6 : io.in.eas.eas[0].flags = 0;
100 6 : io.in.eas.eas[0].name.s = "EAONE";
101 6 : io.in.eas.eas[0].value = data_blob_talloc(tmp_ctx, "VALUE1", 6);
102 6 : io.in.eas.eas[1].flags = 0;
103 6 : io.in.eas.eas[1].name.s = "SECONDEA";
104 6 : io.in.eas.eas[1].value = data_blob_talloc(tmp_ctx, "ValueTwo", 8);
105 : }
106 :
107 8 : status = smb2_create(tree, tmp_ctx, &io);
108 8 : if (NT_STATUS_EQUAL(status, NT_STATUS_EAS_NOT_SUPPORTED)) {
109 0 : torture_comment(
110 : tctx, "EAs not supported, creating: %s\n", fname);
111 0 : io.in.eas.num_eas = 0;
112 0 : status = smb2_create(tree, tmp_ctx, &io);
113 : }
114 :
115 8 : talloc_free(tmp_ctx);
116 8 : NT_STATUS_NOT_OK_RETURN(status);
117 :
118 7 : *handle = io.out.file.handle;
119 :
120 7 : if (!dir) {
121 6 : status = smb2_util_write(tree, *handle, buf, 0, sizeof(buf));
122 6 : NT_STATUS_NOT_OK_RETURN(status);
123 : }
124 :
125 : /* make sure all the timestamps aren't the same, and are also
126 : in different DST zones*/
127 7 : setfile.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
128 7 : setfile.generic.in.file.handle = *handle;
129 :
130 7 : unix_to_nt_time(&setfile.basic_info.in.create_time, t + 9*30*24*60*60);
131 7 : unix_to_nt_time(&setfile.basic_info.in.access_time, t + 6*30*24*60*60);
132 7 : unix_to_nt_time(&setfile.basic_info.in.write_time, t + 3*30*24*60*60);
133 7 : unix_to_nt_time(&setfile.basic_info.in.change_time, t + 1*30*24*60*60);
134 7 : setfile.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL;
135 :
136 7 : status = smb2_setinfo_file(tree, &setfile);
137 7 : if (!NT_STATUS_IS_OK(status)) {
138 0 : torture_comment(tctx, "Failed to setup file times - %s\n", nt_errstr(status));
139 0 : return status;
140 : }
141 :
142 : /* make sure all the timestamps aren't the same */
143 7 : fileinfo.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
144 7 : fileinfo.generic.in.file.handle = *handle;
145 :
146 7 : status = smb2_getinfo_file(tree, tree, &fileinfo);
147 7 : if (!NT_STATUS_IS_OK(status)) {
148 0 : torture_comment(tctx, "Failed to query file times - %s\n", nt_errstr(status));
149 0 : return status;
150 :
151 : }
152 :
153 : #define CHECK_TIME(field) do {\
154 : if (setfile.basic_info.in.field != fileinfo.all_info2.out.field) { \
155 : torture_comment(tctx, "(%s) " #field " not setup correctly: %s(%llu) => %s(%llu)\n", \
156 : __location__, \
157 : nt_time_string(tree, setfile.basic_info.in.field), \
158 : (unsigned long long)setfile.basic_info.in.field, \
159 : nt_time_string(tree, fileinfo.basic_info.out.field), \
160 : (unsigned long long)fileinfo.basic_info.out.field); \
161 : status = NT_STATUS_INVALID_PARAMETER; \
162 : } \
163 : } while (0)
164 :
165 7 : CHECK_TIME(create_time);
166 7 : CHECK_TIME(access_time);
167 7 : CHECK_TIME(write_time);
168 7 : CHECK_TIME(change_time);
169 :
170 7 : return status;
171 : }
172 :
173 : /*
174 : create a complex file using the SMB2 protocol
175 : */
176 7 : NTSTATUS smb2_create_complex_file(struct torture_context *tctx,
177 : struct smb2_tree *tree, const char *fname,
178 : struct smb2_handle *handle)
179 : {
180 7 : return smb2_create_complex(tctx, tree, fname, handle, false);
181 : }
182 :
183 : /*
184 : create a complex dir using the SMB2 protocol
185 : */
186 1 : NTSTATUS smb2_create_complex_dir(struct torture_context *tctx,
187 : struct smb2_tree *tree, const char *fname,
188 : struct smb2_handle *handle)
189 : {
190 1 : return smb2_create_complex(tctx, tree, fname, handle, true);
191 : }
192 :
193 : /*
194 : show lots of information about a file
195 : */
196 3 : void torture_smb2_all_info(struct torture_context *tctx,
197 : struct smb2_tree *tree, struct smb2_handle handle)
198 : {
199 : NTSTATUS status;
200 3 : TALLOC_CTX *tmp_ctx = talloc_new(tree);
201 : union smb_fileinfo io;
202 :
203 3 : io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
204 3 : io.generic.in.file.handle = handle;
205 :
206 3 : status = smb2_getinfo_file(tree, tmp_ctx, &io);
207 3 : if (!NT_STATUS_IS_OK(status)) {
208 0 : DEBUG(0,("getinfo failed - %s\n", nt_errstr(status)));
209 0 : talloc_free(tmp_ctx);
210 0 : return;
211 : }
212 :
213 3 : torture_comment(tctx, "all_info for '%s'\n", io.all_info2.out.fname.s);
214 3 : torture_comment(tctx, "\tcreate_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.create_time));
215 3 : torture_comment(tctx, "\taccess_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.access_time));
216 3 : torture_comment(tctx, "\twrite_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.write_time));
217 3 : torture_comment(tctx, "\tchange_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.change_time));
218 3 : torture_comment(tctx, "\tattrib: 0x%x\n", io.all_info2.out.attrib);
219 3 : torture_comment(tctx, "\tunknown1: 0x%x\n", io.all_info2.out.unknown1);
220 3 : torture_comment(tctx, "\talloc_size: %llu\n", (long long)io.all_info2.out.alloc_size);
221 3 : torture_comment(tctx, "\tsize: %llu\n", (long long)io.all_info2.out.size);
222 3 : torture_comment(tctx, "\tnlink: %u\n", io.all_info2.out.nlink);
223 3 : torture_comment(tctx, "\tdelete_pending: %u\n", io.all_info2.out.delete_pending);
224 3 : torture_comment(tctx, "\tdirectory: %u\n", io.all_info2.out.directory);
225 3 : torture_comment(tctx, "\tfile_id: %llu\n", (long long)io.all_info2.out.file_id);
226 3 : torture_comment(tctx, "\tea_size: %u\n", io.all_info2.out.ea_size);
227 3 : torture_comment(tctx, "\taccess_mask: 0x%08x\n", io.all_info2.out.access_mask);
228 3 : torture_comment(tctx, "\tposition: 0x%llx\n", (long long)io.all_info2.out.position);
229 3 : torture_comment(tctx, "\tmode: 0x%llx\n", (long long)io.all_info2.out.mode);
230 :
231 : /* short name, if any */
232 3 : io.generic.level = RAW_FILEINFO_ALT_NAME_INFORMATION;
233 3 : status = smb2_getinfo_file(tree, tmp_ctx, &io);
234 3 : if (NT_STATUS_IS_OK(status)) {
235 3 : torture_comment(tctx, "\tshort name: '%s'\n", io.alt_name_info.out.fname.s);
236 : }
237 :
238 : /* the EAs, if any */
239 3 : io.generic.level = RAW_FILEINFO_SMB2_ALL_EAS;
240 3 : status = smb2_getinfo_file(tree, tmp_ctx, &io);
241 3 : if (NT_STATUS_IS_OK(status)) {
242 : int i;
243 3 : for (i=0;i<io.all_eas.out.num_eas;i++) {
244 6 : torture_comment(tctx, "\tEA[%d] flags=%d len=%d '%s'\n", i,
245 2 : io.all_eas.out.eas[i].flags,
246 2 : (int)io.all_eas.out.eas[i].value.length,
247 2 : io.all_eas.out.eas[i].name.s);
248 : }
249 : }
250 :
251 : /* streams, if available */
252 3 : io.generic.level = RAW_FILEINFO_STREAM_INFORMATION;
253 3 : status = smb2_getinfo_file(tree, tmp_ctx, &io);
254 3 : if (NT_STATUS_IS_OK(status)) {
255 : int i;
256 6 : for (i=0;i<io.stream_info.out.num_streams;i++) {
257 3 : torture_comment(tctx, "\tstream %d:\n", i);
258 3 : torture_comment(tctx, "\t\tsize %ld\n",
259 3 : (long)io.stream_info.out.streams[i].size);
260 3 : torture_comment(tctx, "\t\talloc size %ld\n",
261 3 : (long)io.stream_info.out.streams[i].alloc_size);
262 3 : torture_comment(tctx, "\t\tname %s\n", io.stream_info.out.streams[i].stream_name.s);
263 : }
264 : }
265 :
266 3 : if (DEBUGLVL(1)) {
267 : /* the security descriptor */
268 3 : io.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
269 3 : io.query_secdesc.in.secinfo_flags =
270 : SECINFO_OWNER|SECINFO_GROUP|
271 : SECINFO_DACL;
272 3 : status = smb2_getinfo_file(tree, tmp_ctx, &io);
273 3 : if (NT_STATUS_IS_OK(status)) {
274 3 : NDR_PRINT_DEBUG(security_descriptor, io.query_secdesc.out.sd);
275 : }
276 : }
277 :
278 3 : talloc_free(tmp_ctx);
279 : }
280 :
281 : /*
282 : get granted access of a file handle
283 : */
284 2 : NTSTATUS torture_smb2_get_allinfo_access(struct smb2_tree *tree,
285 : struct smb2_handle handle,
286 : uint32_t *granted_access)
287 : {
288 : NTSTATUS status;
289 2 : TALLOC_CTX *tmp_ctx = talloc_new(tree);
290 : union smb_fileinfo io;
291 :
292 2 : io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
293 2 : io.generic.in.file.handle = handle;
294 :
295 2 : status = smb2_getinfo_file(tree, tmp_ctx, &io);
296 2 : if (!NT_STATUS_IS_OK(status)) {
297 0 : DEBUG(0, ("getinfo failed - %s\n", nt_errstr(status)));
298 0 : goto out;
299 : }
300 :
301 2 : *granted_access = io.all_info2.out.access_mask;
302 :
303 2 : out:
304 2 : talloc_free(tmp_ctx);
305 2 : return status;
306 : }
307 :
308 : /**
309 : * open a smb2 tree connect
310 : */
311 4 : bool torture_smb2_tree_connect(struct torture_context *tctx,
312 : struct smb2_session *session,
313 : TALLOC_CTX *mem_ctx,
314 : struct smb2_tree **_tree)
315 : {
316 : NTSTATUS status;
317 4 : const char *host = torture_setting_string(tctx, "host", NULL);
318 4 : const char *share = torture_setting_string(tctx, "share", NULL);
319 : const char *unc;
320 : struct smb2_tree *tree;
321 : struct tevent_req *subreq;
322 : uint32_t timeout_msec;
323 :
324 4 : unc = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
325 4 : torture_assert(tctx, unc != NULL, "talloc_asprintf");
326 :
327 4 : tree = smb2_tree_init(session, mem_ctx, false);
328 4 : torture_assert(tctx, tree != NULL, "smb2_tree_init");
329 :
330 4 : timeout_msec = session->transport->options.request_timeout * 1000;
331 :
332 8 : subreq = smb2cli_tcon_send(tree, tctx->ev,
333 4 : session->transport->conn,
334 : timeout_msec,
335 : session->smbXcli,
336 : tree->smbXcli,
337 : 0, /* flags */
338 : unc);
339 4 : torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send");
340 :
341 4 : torture_assert(tctx,
342 : tevent_req_poll_ntstatus(subreq, tctx->ev, &status),
343 : "tevent_req_poll_ntstatus");
344 :
345 4 : status = smb2cli_tcon_recv(subreq);
346 4 : TALLOC_FREE(subreq);
347 4 : torture_assert_ntstatus_ok(tctx, status, "smb2cli_tcon_recv");
348 :
349 4 : *_tree = tree;
350 :
351 4 : return true;
352 : }
353 :
354 : /**
355 : * do a smb2 session setup (without a tree connect)
356 : */
357 2 : bool torture_smb2_session_setup(struct torture_context *tctx,
358 : struct smb2_transport *transport,
359 : uint64_t previous_session_id,
360 : TALLOC_CTX *mem_ctx,
361 : struct smb2_session **_session)
362 : {
363 : NTSTATUS status;
364 : struct smb2_session *session;
365 :
366 2 : session = smb2_session_init(transport,
367 : lpcfg_gensec_settings(tctx, tctx->lp_ctx),
368 : mem_ctx);
369 :
370 2 : if (session == NULL) {
371 0 : return false;
372 : }
373 :
374 2 : status = smb2_session_setup_spnego(session,
375 : samba_cmdline_get_creds(),
376 : previous_session_id);
377 2 : if (!NT_STATUS_IS_OK(status)) {
378 0 : torture_comment(tctx, "session setup failed: %s\n", nt_errstr(status));
379 0 : talloc_free(session);
380 0 : return false;
381 : }
382 :
383 2 : *_session = session;
384 :
385 2 : return true;
386 : }
387 :
388 : /*
389 : open a smb2 connection
390 : */
391 509 : bool torture_smb2_connection_ext(struct torture_context *tctx,
392 : uint64_t previous_session_id,
393 : const struct smbcli_options *options,
394 : struct smb2_tree **tree)
395 : {
396 : NTSTATUS status;
397 509 : const char *host = torture_setting_string(tctx, "host", NULL);
398 509 : const char *share = torture_setting_string(tctx, "share", NULL);
399 509 : const char *p = torture_setting_string(tctx, "unclist", NULL);
400 509 : TALLOC_CTX *mem_ctx = NULL;
401 : bool ok;
402 :
403 509 : if (p != NULL) {
404 0 : char *host2 = NULL;
405 0 : char *share2 = NULL;
406 :
407 0 : mem_ctx = talloc_new(tctx);
408 0 : if (mem_ctx == NULL) {
409 0 : return false;
410 : }
411 :
412 0 : ok = torture_get_conn_index(tctx->conn_index++, mem_ctx, tctx,
413 : &host2, &share2);
414 0 : if (!ok) {
415 0 : TALLOC_FREE(mem_ctx);
416 0 : return false;
417 : }
418 :
419 0 : host = host2;
420 0 : share = share2;
421 : }
422 :
423 509 : status = smb2_connect_ext(tctx,
424 : host,
425 : lpcfg_smb_ports(tctx->lp_ctx),
426 : share,
427 : lpcfg_resolve_context(tctx->lp_ctx),
428 : samba_cmdline_get_creds(),
429 : NULL, /* existing_conn */
430 : previous_session_id,
431 : tree,
432 : tctx->ev,
433 : options,
434 : lpcfg_socket_options(tctx->lp_ctx),
435 : lpcfg_gensec_settings(tctx, tctx->lp_ctx)
436 : );
437 509 : if (!NT_STATUS_IS_OK(status)) {
438 0 : torture_comment(tctx, "Failed to connect to SMB2 share \\\\%s\\%s - %s\n",
439 : host, share, nt_errstr(status));
440 0 : TALLOC_FREE(mem_ctx);
441 0 : return false;
442 : }
443 :
444 509 : TALLOC_FREE(mem_ctx);
445 509 : return true;
446 : }
447 :
448 505 : bool torture_smb2_connection(struct torture_context *tctx, struct smb2_tree **tree)
449 : {
450 : bool ret;
451 : struct smbcli_options options;
452 :
453 505 : lpcfg_smbcli_options(tctx->lp_ctx, &options);
454 :
455 505 : ret = torture_smb2_connection_ext(tctx, 0, &options, tree);
456 :
457 505 : return ret;
458 : }
459 :
460 : /**
461 : * SMB2 connect with share from soption
462 : **/
463 0 : bool torture_smb2_con_share(struct torture_context *tctx,
464 : const char *share,
465 : struct smb2_tree **tree)
466 : {
467 : struct smbcli_options options;
468 : NTSTATUS status;
469 0 : const char *host = torture_setting_string(tctx, "host", NULL);
470 :
471 0 : lpcfg_smbcli_options(tctx->lp_ctx, &options);
472 :
473 0 : status = smb2_connect(tctx,
474 : host,
475 : lpcfg_smb_ports(tctx->lp_ctx),
476 : share,
477 : lpcfg_resolve_context(tctx->lp_ctx),
478 : samba_cmdline_get_creds(),
479 : tree,
480 : tctx->ev,
481 : &options,
482 : lpcfg_socket_options(tctx->lp_ctx),
483 : lpcfg_gensec_settings(tctx, tctx->lp_ctx)
484 : );
485 0 : if (!NT_STATUS_IS_OK(status)) {
486 0 : torture_comment(tctx, "Failed to connect to SMB2 share \\\\%s\\%s - %s\n",
487 : host, share, nt_errstr(status));
488 0 : return false;
489 : }
490 0 : return true;
491 : }
492 :
493 : /**
494 : * SMB2 connect with share from soption
495 : **/
496 0 : bool torture_smb2_con_sopt(struct torture_context *tctx,
497 : const char *soption,
498 : struct smb2_tree **tree)
499 : {
500 0 : const char *share = torture_setting_string(tctx, soption, NULL);
501 :
502 0 : if (share == NULL) {
503 0 : torture_comment(tctx, "No share for option %s\n", soption);
504 0 : return false;
505 : }
506 :
507 0 : return torture_smb2_con_share(tctx, share, tree);
508 : }
509 :
510 : /*
511 : create and return a handle to a test file
512 : with a specific access mask
513 : */
514 56 : NTSTATUS torture_smb2_testfile_access(struct smb2_tree *tree, const char *fname,
515 : struct smb2_handle *handle,
516 : uint32_t desired_access)
517 : {
518 : struct smb2_create io;
519 : NTSTATUS status;
520 :
521 56 : ZERO_STRUCT(io);
522 56 : io.in.oplock_level = 0;
523 56 : io.in.desired_access = desired_access;
524 56 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
525 56 : io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
526 56 : io.in.share_access =
527 : NTCREATEX_SHARE_ACCESS_DELETE|
528 : NTCREATEX_SHARE_ACCESS_READ|
529 : NTCREATEX_SHARE_ACCESS_WRITE;
530 56 : io.in.create_options = 0;
531 56 : io.in.fname = fname;
532 :
533 56 : status = smb2_create(tree, tree, &io);
534 56 : NT_STATUS_NOT_OK_RETURN(status);
535 :
536 55 : *handle = io.out.file.handle;
537 :
538 55 : return NT_STATUS_OK;
539 : }
540 :
541 : /*
542 : create and return a handle to a test file
543 : */
544 51 : NTSTATUS torture_smb2_testfile(struct smb2_tree *tree, const char *fname,
545 : struct smb2_handle *handle)
546 : {
547 51 : return torture_smb2_testfile_access(tree, fname, handle,
548 : SEC_RIGHTS_FILE_ALL);
549 : }
550 :
551 : /*
552 : create and return a handle to a test file
553 : with a specific access mask
554 : */
555 6 : NTSTATUS torture_smb2_open(struct smb2_tree *tree,
556 : const char *fname,
557 : uint32_t desired_access,
558 : struct smb2_handle *handle)
559 : {
560 : struct smb2_create io;
561 : NTSTATUS status;
562 :
563 6 : io = (struct smb2_create) {
564 : .in.fname = fname,
565 : .in.desired_access = desired_access,
566 : .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
567 : .in.create_disposition = NTCREATEX_DISP_OPEN,
568 : .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
569 : };
570 :
571 6 : status = smb2_create(tree, tree, &io);
572 6 : if (!NT_STATUS_IS_OK(status)) {
573 0 : return status;
574 : }
575 :
576 6 : *handle = io.out.file.handle;
577 :
578 6 : return NT_STATUS_OK;
579 : }
580 :
581 : /*
582 : create and return a handle to a test directory
583 : with specific desired access
584 : */
585 86 : NTSTATUS torture_smb2_testdir_access(struct smb2_tree *tree, const char *fname,
586 : struct smb2_handle *handle,
587 : uint32_t desired_access)
588 : {
589 : struct smb2_create io;
590 : NTSTATUS status;
591 :
592 86 : ZERO_STRUCT(io);
593 86 : io.in.oplock_level = 0;
594 86 : io.in.desired_access = desired_access;
595 86 : io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
596 86 : io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
597 86 : io.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE;
598 86 : io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
599 86 : io.in.fname = fname;
600 :
601 86 : status = smb2_create(tree, tree, &io);
602 86 : NT_STATUS_NOT_OK_RETURN(status);
603 :
604 86 : *handle = io.out.file.handle;
605 :
606 86 : return NT_STATUS_OK;
607 : }
608 :
609 : /*
610 : create and return a handle to a test directory
611 : */
612 85 : NTSTATUS torture_smb2_testdir(struct smb2_tree *tree, const char *fname,
613 : struct smb2_handle *handle)
614 : {
615 85 : return torture_smb2_testdir_access(tree, fname, handle,
616 : SEC_RIGHTS_DIR_ALL);
617 : }
618 :
619 : /*
620 : create a simple file using the SMB2 protocol
621 : */
622 1 : NTSTATUS smb2_create_simple_file(struct torture_context *tctx,
623 : struct smb2_tree *tree, const char *fname,
624 : struct smb2_handle *handle)
625 : {
626 1 : char buf[7] = "abc";
627 : NTSTATUS status;
628 :
629 1 : smb2_util_unlink(tree, fname);
630 1 : status = torture_smb2_testfile_access(tree,
631 : fname, handle,
632 : SEC_FLAG_MAXIMUM_ALLOWED);
633 1 : NT_STATUS_NOT_OK_RETURN(status);
634 :
635 1 : status = smb2_util_write(tree, *handle, buf, 0, sizeof(buf));
636 1 : NT_STATUS_NOT_OK_RETURN(status);
637 :
638 1 : return NT_STATUS_OK;
639 : }
640 :
641 : /*
642 : create a simple file using SMB2.
643 : */
644 1 : NTSTATUS torture_setup_simple_file(struct torture_context *tctx,
645 : struct smb2_tree *tree, const char *fname)
646 : {
647 : struct smb2_handle handle;
648 1 : NTSTATUS status = smb2_create_simple_file(tctx, tree, fname, &handle);
649 1 : NT_STATUS_NOT_OK_RETURN(status);
650 1 : return smb2_util_close(tree, handle);
651 : }
652 :
653 : /*
654 : create a complex file using SMB2, to make it easier to
655 : find fields in SMB2 getinfo levels
656 : */
657 4 : NTSTATUS torture_setup_complex_file(struct torture_context *tctx,
658 : struct smb2_tree *tree, const char *fname)
659 : {
660 : struct smb2_handle handle;
661 4 : NTSTATUS status = smb2_create_complex_file(tctx, tree, fname, &handle);
662 4 : NT_STATUS_NOT_OK_RETURN(status);
663 3 : return smb2_util_close(tree, handle);
664 : }
665 :
666 :
667 : /*
668 : create a complex dir using SMB2, to make it easier to
669 : find fields in SMB2 getinfo levels
670 : */
671 1 : NTSTATUS torture_setup_complex_dir(struct torture_context *tctx,
672 : struct smb2_tree *tree, const char *fname)
673 : {
674 : struct smb2_handle handle;
675 1 : NTSTATUS status = smb2_create_complex_dir(tctx, tree, fname, &handle);
676 1 : NT_STATUS_NOT_OK_RETURN(status);
677 1 : return smb2_util_close(tree, handle);
678 : }
679 :
680 :
681 : /*
682 : return a handle to the root of the share
683 : */
684 25 : NTSTATUS smb2_util_roothandle(struct smb2_tree *tree, struct smb2_handle *handle)
685 : {
686 : struct smb2_create io;
687 : NTSTATUS status;
688 :
689 25 : ZERO_STRUCT(io);
690 25 : io.in.oplock_level = 0;
691 25 : io.in.desired_access = SEC_STD_SYNCHRONIZE | SEC_DIR_READ_ATTRIBUTE | SEC_DIR_LIST;
692 25 : io.in.file_attributes = 0;
693 25 : io.in.create_disposition = NTCREATEX_DISP_OPEN;
694 25 : io.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE;
695 25 : io.in.create_options = NTCREATEX_OPTIONS_ASYNC_ALERT;
696 25 : io.in.fname = "";
697 :
698 25 : status = smb2_create(tree, tree, &io);
699 25 : NT_STATUS_NOT_OK_RETURN(status);
700 :
701 21 : *handle = io.out.file.handle;
702 :
703 21 : return NT_STATUS_OK;
704 : }
705 :
706 : /* Comparable to torture_setup_dir, but for SMB2. */
707 6 : bool smb2_util_setup_dir(struct torture_context *tctx, struct smb2_tree *tree,
708 : const char *dname)
709 : {
710 : NTSTATUS status;
711 :
712 : /* XXX: smb_raw_exit equivalent?
713 : smb_raw_exit(cli->session); */
714 6 : if (smb2_deltree(tree, dname) == -1) {
715 0 : torture_result(tctx, TORTURE_ERROR, "Unable to deltree when setting up %s.\n", dname);
716 0 : return false;
717 : }
718 :
719 6 : status = smb2_util_mkdir(tree, dname);
720 6 : if (NT_STATUS_IS_ERR(status)) {
721 0 : torture_result(tctx, TORTURE_ERROR, "Unable to mkdir when setting up %s - %s\n", dname,
722 : nt_errstr(status));
723 0 : return false;
724 : }
725 :
726 6 : return true;
727 : }
728 :
729 : #define CHECK_STATUS(status, correct) do { \
730 : if (!NT_STATUS_EQUAL(status, correct)) { \
731 : torture_result(tctx, TORTURE_FAIL, "(%s) Incorrect status %s - should be %s\n", \
732 : __location__, nt_errstr(status), nt_errstr(correct)); \
733 : ret = false; \
734 : goto done; \
735 : }} while (0)
736 :
737 : /*
738 : * Helper function to verify a security descriptor, by querying
739 : * and comparing against the passed in sd.
740 : */
741 12 : bool smb2_util_verify_sd(TALLOC_CTX *tctx, struct smb2_tree *tree,
742 : struct smb2_handle handle, struct security_descriptor *sd)
743 : {
744 : NTSTATUS status;
745 12 : bool ret = true;
746 12 : union smb_fileinfo q = {};
747 :
748 12 : q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
749 12 : q.query_secdesc.in.file.handle = handle;
750 12 : q.query_secdesc.in.secinfo_flags =
751 : SECINFO_OWNER |
752 : SECINFO_GROUP |
753 : SECINFO_DACL;
754 12 : status = smb2_getinfo_file(tree, tctx, &q);
755 12 : CHECK_STATUS(status, NT_STATUS_OK);
756 :
757 12 : if (!security_acl_equal(
758 12 : q.query_secdesc.out.sd->dacl, sd->dacl)) {
759 0 : torture_warning(tctx, "%s: security descriptors don't match!\n",
760 : __location__);
761 0 : torture_warning(tctx, "got:\n");
762 0 : NDR_PRINT_DEBUG(security_descriptor,
763 : q.query_secdesc.out.sd);
764 0 : torture_warning(tctx, "expected:\n");
765 0 : NDR_PRINT_DEBUG(security_descriptor, sd);
766 0 : ret = false;
767 : }
768 :
769 24 : done:
770 12 : return ret;
771 : }
772 :
773 : /*
774 : * Helper function to verify attributes, by querying
775 : * and comparing against the passed in attrib.
776 : */
777 10 : bool smb2_util_verify_attrib(TALLOC_CTX *tctx, struct smb2_tree *tree,
778 : struct smb2_handle handle, uint32_t attrib)
779 : {
780 : NTSTATUS status;
781 10 : bool ret = true;
782 10 : union smb_fileinfo q = {};
783 :
784 10 : q.standard.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
785 10 : q.standard.in.file.handle = handle;
786 10 : status = smb2_getinfo_file(tree, tctx, &q);
787 10 : CHECK_STATUS(status, NT_STATUS_OK);
788 :
789 10 : q.all_info2.out.attrib &= ~(FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_NONINDEXED);
790 :
791 10 : if (q.all_info2.out.attrib != attrib) {
792 1 : torture_warning(tctx, "%s: attributes don't match! "
793 : "got %x, expected %x\n", __location__,
794 1 : (uint32_t)q.standard.out.attrib,
795 : (uint32_t)attrib);
796 1 : ret = false;
797 : }
798 :
799 19 : done:
800 10 : return ret;
801 : }
802 :
803 :
804 0 : uint32_t smb2_util_lease_state(const char *ls)
805 : {
806 0 : uint32_t val = 0;
807 : int i;
808 :
809 0 : for (i = 0; i < strlen(ls); i++) {
810 0 : switch (ls[i]) {
811 0 : case 'R':
812 0 : val |= SMB2_LEASE_READ;
813 0 : break;
814 0 : case 'H':
815 0 : val |= SMB2_LEASE_HANDLE;
816 0 : break;
817 0 : case 'W':
818 0 : val |= SMB2_LEASE_WRITE;
819 0 : break;
820 : }
821 : }
822 :
823 0 : return val;
824 : }
825 :
826 0 : char *smb2_util_lease_state_string(TALLOC_CTX *mem_ctx, uint32_t ls)
827 : {
828 0 : return talloc_asprintf(mem_ctx, "0x%0x (%s%s%s)",
829 : (unsigned)ls,
830 0 : ls & SMB2_LEASE_READ ? "R": "",
831 0 : ls & SMB2_LEASE_HANDLE ? "H": "",
832 0 : ls & SMB2_LEASE_WRITE ? "W": "");
833 : }
834 :
835 157 : uint32_t smb2_util_share_access(const char *sharemode)
836 : {
837 157 : uint32_t val = NTCREATEX_SHARE_ACCESS_NONE; /* 0 */
838 : int i;
839 :
840 182 : for (i = 0; i < strlen(sharemode); i++) {
841 25 : switch(sharemode[i]) {
842 25 : case 'R':
843 25 : val |= NTCREATEX_SHARE_ACCESS_READ;
844 25 : break;
845 0 : case 'W':
846 0 : val |= NTCREATEX_SHARE_ACCESS_WRITE;
847 0 : break;
848 0 : case 'D':
849 0 : val |= NTCREATEX_SHARE_ACCESS_DELETE;
850 0 : break;
851 : }
852 : }
853 :
854 157 : return val;
855 : }
856 :
857 263 : uint8_t smb2_util_oplock_level(const char *op)
858 : {
859 263 : uint8_t val = SMB2_OPLOCK_LEVEL_NONE;
860 : int i;
861 :
862 263 : for (i = 0; i < strlen(op); i++) {
863 249 : switch (op[i]) {
864 0 : case 's':
865 0 : return SMB2_OPLOCK_LEVEL_II;
866 0 : case 'x':
867 0 : return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
868 249 : case 'b':
869 249 : return SMB2_OPLOCK_LEVEL_BATCH;
870 0 : default:
871 0 : continue;
872 : }
873 : }
874 :
875 14 : return val;
876 : }
877 :
878 : /**
879 : * Helper functions to fill a smb2_create struct for several
880 : * open scenarios.
881 : */
882 132 : void smb2_generic_create_share(struct smb2_create *io, struct smb2_lease *ls,
883 : bool dir, const char *name, uint32_t disposition,
884 : uint32_t share_access,
885 : uint8_t oplock, uint64_t leasekey,
886 : uint32_t leasestate)
887 : {
888 132 : ZERO_STRUCT(*io);
889 132 : io->in.security_flags = 0x00;
890 132 : io->in.oplock_level = oplock;
891 132 : io->in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
892 132 : io->in.create_flags = 0x00000000;
893 132 : io->in.reserved = 0x00000000;
894 132 : io->in.desired_access = SEC_RIGHTS_FILE_ALL;
895 132 : io->in.file_attributes = FILE_ATTRIBUTE_NORMAL;
896 132 : io->in.share_access = share_access;
897 132 : io->in.create_disposition = disposition;
898 132 : io->in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
899 : NTCREATEX_OPTIONS_ASYNC_ALERT |
900 : NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
901 : 0x00200000;
902 132 : io->in.fname = name;
903 :
904 132 : if (dir) {
905 0 : io->in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
906 0 : io->in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
907 0 : io->in.create_disposition = NTCREATEX_DISP_CREATE;
908 : }
909 :
910 132 : if (ls) {
911 0 : ZERO_STRUCTPN(ls);
912 0 : ls->lease_key.data[0] = leasekey;
913 0 : ls->lease_key.data[1] = ~leasekey;
914 0 : ls->lease_state = leasestate;
915 0 : io->in.lease_request = ls;
916 : }
917 132 : }
918 :
919 0 : void smb2_generic_create(struct smb2_create *io, struct smb2_lease *ls,
920 : bool dir, const char *name, uint32_t disposition,
921 : uint8_t oplock, uint64_t leasekey,
922 : uint32_t leasestate)
923 : {
924 0 : smb2_generic_create_share(io, ls, dir, name, disposition,
925 : smb2_util_share_access("RWD"),
926 : oplock,
927 : leasekey, leasestate);
928 0 : }
929 :
930 0 : void smb2_lease_create_share(struct smb2_create *io, struct smb2_lease *ls,
931 : bool dir, const char *name, uint32_t share_access,
932 : uint64_t leasekey, uint32_t leasestate)
933 : {
934 0 : smb2_generic_create_share(io, ls, dir, name, NTCREATEX_DISP_OPEN_IF,
935 : share_access, SMB2_OPLOCK_LEVEL_LEASE,
936 : leasekey, leasestate);
937 0 : }
938 :
939 0 : void smb2_lease_create(struct smb2_create *io, struct smb2_lease *ls,
940 : bool dir, const char *name, uint64_t leasekey,
941 : uint32_t leasestate)
942 : {
943 0 : smb2_lease_create_share(io, ls, dir, name,
944 : smb2_util_share_access("RWD"),
945 : leasekey, leasestate);
946 0 : }
947 :
948 0 : void smb2_lease_v2_create_share(struct smb2_create *io,
949 : struct smb2_lease *ls,
950 : bool dir,
951 : const char *name,
952 : uint32_t share_access,
953 : uint64_t leasekey,
954 : const uint64_t *parentleasekey,
955 : uint32_t leasestate,
956 : uint16_t lease_epoch)
957 : {
958 0 : smb2_generic_create_share(io, NULL, dir, name, NTCREATEX_DISP_OPEN_IF,
959 : share_access, SMB2_OPLOCK_LEVEL_LEASE, 0, 0);
960 :
961 0 : if (ls) {
962 0 : ZERO_STRUCT(*ls);
963 0 : ls->lease_key.data[0] = leasekey;
964 0 : ls->lease_key.data[1] = ~leasekey;
965 0 : ls->lease_state = leasestate;
966 0 : if (parentleasekey != NULL) {
967 0 : ls->lease_flags |= SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET;
968 0 : ls->parent_lease_key.data[0] = *parentleasekey;
969 0 : ls->parent_lease_key.data[1] = ~(*parentleasekey);
970 : }
971 0 : ls->lease_epoch = lease_epoch;
972 0 : io->in.lease_request_v2 = ls;
973 : }
974 0 : }
975 :
976 0 : void smb2_lease_v2_create(struct smb2_create *io,
977 : struct smb2_lease *ls,
978 : bool dir,
979 : const char *name,
980 : uint64_t leasekey,
981 : const uint64_t *parentleasekey,
982 : uint32_t leasestate,
983 : uint16_t lease_epoch)
984 : {
985 0 : smb2_lease_v2_create_share(io, ls, dir, name,
986 : smb2_util_share_access("RWD"),
987 : leasekey, parentleasekey,
988 : leasestate, lease_epoch);
989 0 : }
990 :
991 :
992 132 : void smb2_oplock_create_share(struct smb2_create *io, const char *name,
993 : uint32_t share_access, uint8_t oplock)
994 : {
995 132 : smb2_generic_create_share(io, NULL, false, name, NTCREATEX_DISP_OPEN_IF,
996 : share_access, oplock, 0, 0);
997 132 : }
998 0 : void smb2_oplock_create(struct smb2_create *io, const char *name, uint8_t oplock)
999 : {
1000 0 : smb2_oplock_create_share(io, name, smb2_util_share_access("RWD"),
1001 : oplock);
1002 0 : }
1003 :
1004 : /*
1005 : a wrapper around smblsa_sid_check_privilege, that tries to take
1006 : account of the fact that the lsa privileges calls don't expand
1007 : group memberships, using an explicit check for administrator. There
1008 : must be a better way ...
1009 : */
1010 3 : NTSTATUS torture_smb2_check_privilege(struct smb2_tree *tree,
1011 : const char *sid_str,
1012 : const char *privilege)
1013 : {
1014 3 : struct dom_sid *sid = NULL;
1015 3 : TALLOC_CTX *tmp_ctx = NULL;
1016 : uint32_t rid;
1017 : NTSTATUS status;
1018 :
1019 3 : tmp_ctx = talloc_new(tree);
1020 3 : if (tmp_ctx == NULL) {
1021 0 : return NT_STATUS_NO_MEMORY;
1022 : }
1023 :
1024 3 : sid = dom_sid_parse_talloc(tmp_ctx, sid_str);
1025 3 : if (sid == NULL) {
1026 0 : talloc_free(tmp_ctx);
1027 0 : return NT_STATUS_INVALID_SID;
1028 : }
1029 :
1030 3 : status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
1031 3 : if (!NT_STATUS_IS_OK(status)) {
1032 0 : TALLOC_FREE(tmp_ctx);
1033 0 : return status;
1034 : }
1035 :
1036 3 : if (rid == DOMAIN_RID_ADMINISTRATOR) {
1037 : /* assume the administrator has them all */
1038 3 : TALLOC_FREE(tmp_ctx);
1039 3 : return NT_STATUS_OK;
1040 : }
1041 :
1042 0 : talloc_free(tmp_ctx);
1043 :
1044 0 : return smb2lsa_sid_check_privilege(tree, sid_str, privilege);
1045 : }
|