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 53932 : 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 2 : struct smb2_write w;
50 :
51 53932 : ZERO_STRUCT(w);
52 53932 : w.in.file.handle = handle;
53 53932 : w.in.offset = offset;
54 53932 : w.in.data = data_blob_const(buf, size);
55 :
56 53932 : return smb2_write(tree, &w);
57 : }
58 :
59 : /*
60 : create a complex file/dir using the SMB2 protocol
61 : */
62 228 : 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 228 : TALLOC_CTX *tmp_ctx = talloc_new(tree);
69 228 : char buf[7] = "abc";
70 0 : struct smb2_create io;
71 0 : union smb_setfileinfo setfile;
72 0 : union smb_fileinfo fileinfo;
73 228 : time_t t = (time(NULL) & ~1);
74 0 : NTSTATUS status;
75 :
76 228 : smb2_util_unlink(tree, fname);
77 228 : ZERO_STRUCT(io);
78 228 : io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
79 228 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
80 228 : io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
81 228 : io.in.share_access =
82 : NTCREATEX_SHARE_ACCESS_DELETE|
83 : NTCREATEX_SHARE_ACCESS_READ|
84 : NTCREATEX_SHARE_ACCESS_WRITE;
85 228 : io.in.create_options = 0;
86 228 : io.in.fname = fname;
87 228 : 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 228 : if (strchr(fname, ':') == NULL) {
96 : /* setup some EAs */
97 226 : io.in.eas.num_eas = 2;
98 226 : io.in.eas.eas = talloc_array(tmp_ctx, struct ea_struct, 2);
99 226 : io.in.eas.eas[0].flags = 0;
100 226 : io.in.eas.eas[0].name.s = "EAONE";
101 226 : io.in.eas.eas[0].value = data_blob_talloc(tmp_ctx, "VALUE1", 6);
102 226 : io.in.eas.eas[1].flags = 0;
103 226 : io.in.eas.eas[1].name.s = "SECONDEA";
104 226 : io.in.eas.eas[1].value = data_blob_talloc(tmp_ctx, "ValueTwo", 8);
105 : }
106 :
107 228 : status = smb2_create(tree, tmp_ctx, &io);
108 228 : 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 228 : talloc_free(tmp_ctx);
116 228 : NT_STATUS_NOT_OK_RETURN(status);
117 :
118 227 : *handle = io.out.file.handle;
119 :
120 227 : if (!dir) {
121 226 : status = smb2_util_write(tree, *handle, buf, 0, sizeof(buf));
122 226 : 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 227 : setfile.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
128 227 : setfile.generic.in.file.handle = *handle;
129 :
130 227 : unix_to_nt_time(&setfile.basic_info.in.create_time, t + 9*30*24*60*60);
131 227 : unix_to_nt_time(&setfile.basic_info.in.access_time, t + 6*30*24*60*60);
132 227 : unix_to_nt_time(&setfile.basic_info.in.write_time, t + 3*30*24*60*60);
133 227 : unix_to_nt_time(&setfile.basic_info.in.change_time, t + 1*30*24*60*60);
134 227 : setfile.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL;
135 :
136 227 : status = smb2_setinfo_file(tree, &setfile);
137 227 : 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 227 : fileinfo.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
144 227 : fileinfo.generic.in.file.handle = *handle;
145 :
146 227 : status = smb2_getinfo_file(tree, tree, &fileinfo);
147 227 : 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 227 : CHECK_TIME(create_time);
166 227 : CHECK_TIME(access_time);
167 227 : CHECK_TIME(write_time);
168 227 : CHECK_TIME(change_time);
169 :
170 227 : return status;
171 : }
172 :
173 : /*
174 : create a complex file using the SMB2 protocol
175 : */
176 227 : NTSTATUS smb2_create_complex_file(struct torture_context *tctx,
177 : struct smb2_tree *tree, const char *fname,
178 : struct smb2_handle *handle)
179 : {
180 227 : 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 15 : void torture_smb2_all_info(struct torture_context *tctx,
197 : struct smb2_tree *tree, struct smb2_handle handle)
198 : {
199 0 : NTSTATUS status;
200 15 : TALLOC_CTX *tmp_ctx = talloc_new(tree);
201 0 : union smb_fileinfo io;
202 :
203 15 : io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
204 15 : io.generic.in.file.handle = handle;
205 :
206 15 : status = smb2_getinfo_file(tree, tmp_ctx, &io);
207 15 : 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 15 : torture_comment(tctx, "all_info for '%s'\n", io.all_info2.out.fname.s);
214 15 : torture_comment(tctx, "\tcreate_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.create_time));
215 15 : torture_comment(tctx, "\taccess_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.access_time));
216 15 : torture_comment(tctx, "\twrite_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.write_time));
217 15 : torture_comment(tctx, "\tchange_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.change_time));
218 15 : torture_comment(tctx, "\tattrib: 0x%x\n", io.all_info2.out.attrib);
219 15 : torture_comment(tctx, "\tunknown1: 0x%x\n", io.all_info2.out.unknown1);
220 15 : torture_comment(tctx, "\talloc_size: %llu\n", (long long)io.all_info2.out.alloc_size);
221 15 : torture_comment(tctx, "\tsize: %llu\n", (long long)io.all_info2.out.size);
222 15 : torture_comment(tctx, "\tnlink: %u\n", io.all_info2.out.nlink);
223 15 : torture_comment(tctx, "\tdelete_pending: %u\n", io.all_info2.out.delete_pending);
224 15 : torture_comment(tctx, "\tdirectory: %u\n", io.all_info2.out.directory);
225 15 : torture_comment(tctx, "\tfile_id: %llu\n", (long long)io.all_info2.out.file_id);
226 15 : torture_comment(tctx, "\tea_size: %u\n", io.all_info2.out.ea_size);
227 15 : torture_comment(tctx, "\taccess_mask: 0x%08x\n", io.all_info2.out.access_mask);
228 15 : torture_comment(tctx, "\tposition: 0x%llx\n", (long long)io.all_info2.out.position);
229 15 : torture_comment(tctx, "\tmode: 0x%llx\n", (long long)io.all_info2.out.mode);
230 :
231 : /* short name, if any */
232 15 : io.generic.level = RAW_FILEINFO_ALT_NAME_INFORMATION;
233 15 : status = smb2_getinfo_file(tree, tmp_ctx, &io);
234 15 : if (NT_STATUS_IS_OK(status)) {
235 15 : torture_comment(tctx, "\tshort name: '%s'\n", io.alt_name_info.out.fname.s);
236 : }
237 :
238 : /* the EAs, if any */
239 15 : io.generic.level = RAW_FILEINFO_SMB2_ALL_EAS;
240 15 : status = smb2_getinfo_file(tree, tmp_ctx, &io);
241 15 : if (NT_STATUS_IS_OK(status)) {
242 : int i;
243 3 : for (i=0;i<io.all_eas.out.num_eas;i++) {
244 2 : 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 15 : io.generic.level = RAW_FILEINFO_STREAM_INFORMATION;
253 15 : status = smb2_getinfo_file(tree, tmp_ctx, &io);
254 15 : if (NT_STATUS_IS_OK(status)) {
255 : int i;
256 30 : for (i=0;i<io.stream_info.out.num_streams;i++) {
257 15 : torture_comment(tctx, "\tstream %d:\n", i);
258 15 : torture_comment(tctx, "\t\tsize %ld\n",
259 15 : (long)io.stream_info.out.streams[i].size);
260 15 : torture_comment(tctx, "\t\talloc size %ld\n",
261 15 : (long)io.stream_info.out.streams[i].alloc_size);
262 15 : torture_comment(tctx, "\t\tname %s\n", io.stream_info.out.streams[i].stream_name.s);
263 : }
264 : }
265 :
266 15 : if (DEBUGLVL(1)) {
267 : /* the security descriptor */
268 15 : io.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
269 15 : io.query_secdesc.in.secinfo_flags =
270 : SECINFO_OWNER|SECINFO_GROUP|
271 : SECINFO_DACL;
272 15 : status = smb2_getinfo_file(tree, tmp_ctx, &io);
273 15 : if (NT_STATUS_IS_OK(status)) {
274 15 : NDR_PRINT_DEBUG(security_descriptor, io.query_secdesc.out.sd);
275 : }
276 : }
277 :
278 15 : talloc_free(tmp_ctx);
279 : }
280 :
281 : /*
282 : get granted access of a file handle
283 : */
284 10 : NTSTATUS torture_smb2_get_allinfo_access(struct smb2_tree *tree,
285 : struct smb2_handle handle,
286 : uint32_t *granted_access)
287 : {
288 0 : NTSTATUS status;
289 10 : TALLOC_CTX *tmp_ctx = talloc_new(tree);
290 0 : union smb_fileinfo io;
291 :
292 10 : io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
293 10 : io.generic.in.file.handle = handle;
294 :
295 10 : status = smb2_getinfo_file(tree, tmp_ctx, &io);
296 10 : if (!NT_STATUS_IS_OK(status)) {
297 0 : DEBUG(0, ("getinfo failed - %s\n", nt_errstr(status)));
298 0 : goto out;
299 : }
300 :
301 10 : *granted_access = io.all_info2.out.access_mask;
302 :
303 10 : out:
304 10 : talloc_free(tmp_ctx);
305 10 : return status;
306 : }
307 :
308 : /**
309 : * open a smb2 tree connect
310 : */
311 48 : 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 0 : NTSTATUS status;
317 48 : const char *host = torture_setting_string(tctx, "host", NULL);
318 48 : const char *share = torture_setting_string(tctx, "share", NULL);
319 0 : const char *unc;
320 0 : struct smb2_tree *tree;
321 0 : struct tevent_req *subreq;
322 0 : uint32_t timeout_msec;
323 :
324 48 : unc = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
325 48 : torture_assert(tctx, unc != NULL, "talloc_asprintf");
326 :
327 48 : tree = smb2_tree_init(session, mem_ctx, false);
328 48 : torture_assert(tctx, tree != NULL, "smb2_tree_init");
329 :
330 48 : timeout_msec = session->transport->options.request_timeout * 1000;
331 :
332 48 : subreq = smb2cli_tcon_send(tree, tctx->ev,
333 48 : session->transport->conn,
334 : timeout_msec,
335 : session->smbXcli,
336 : tree->smbXcli,
337 : 0, /* flags */
338 : unc);
339 48 : torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send");
340 :
341 48 : torture_assert(tctx,
342 : tevent_req_poll_ntstatus(subreq, tctx->ev, &status),
343 : "tevent_req_poll_ntstatus");
344 :
345 48 : status = smb2cli_tcon_recv(subreq);
346 48 : TALLOC_FREE(subreq);
347 48 : torture_assert_ntstatus_ok(tctx, status, "smb2cli_tcon_recv");
348 :
349 48 : *_tree = tree;
350 :
351 48 : return true;
352 : }
353 :
354 : /**
355 : * do a smb2 session setup (without a tree connect)
356 : */
357 18 : 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 2 : NTSTATUS status;
364 2 : struct smb2_session *session;
365 :
366 18 : session = smb2_session_init(transport,
367 : lpcfg_gensec_settings(tctx, tctx->lp_ctx),
368 : mem_ctx);
369 :
370 18 : if (session == NULL) {
371 0 : return false;
372 : }
373 :
374 18 : status = smb2_session_setup_spnego(session,
375 : samba_cmdline_get_creds(),
376 : previous_session_id);
377 18 : 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 18 : *_session = session;
384 :
385 18 : return true;
386 : }
387 :
388 : /*
389 : open a smb2 connection
390 : */
391 4169 : 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 125 : NTSTATUS status;
397 4169 : const char *host = torture_setting_string(tctx, "host", NULL);
398 4169 : const char *share = torture_setting_string(tctx, "share", NULL);
399 4169 : const char *p = torture_setting_string(tctx, "unclist", NULL);
400 4169 : TALLOC_CTX *mem_ctx = NULL;
401 125 : bool ok;
402 :
403 4169 : 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 4169 : 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 4169 : 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 4169 : TALLOC_FREE(mem_ctx);
445 4044 : return true;
446 : }
447 :
448 3999 : bool torture_smb2_connection(struct torture_context *tctx, struct smb2_tree **tree)
449 : {
450 121 : bool ret;
451 121 : struct smbcli_options options;
452 :
453 3999 : lpcfg_smbcli_options(tctx->lp_ctx, &options);
454 :
455 3999 : ret = torture_smb2_connection_ext(tctx, 0, &options, tree);
456 :
457 3999 : return ret;
458 : }
459 :
460 : /**
461 : * SMB2 connect with share from soption
462 : **/
463 26 : bool torture_smb2_con_share(struct torture_context *tctx,
464 : const char *share,
465 : struct smb2_tree **tree)
466 : {
467 0 : struct smbcli_options options;
468 0 : NTSTATUS status;
469 26 : const char *host = torture_setting_string(tctx, "host", NULL);
470 :
471 26 : lpcfg_smbcli_options(tctx->lp_ctx, &options);
472 :
473 26 : 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 26 : 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 26 : return true;
491 : }
492 :
493 : /**
494 : * SMB2 connect with share from soption
495 : **/
496 18 : bool torture_smb2_con_sopt(struct torture_context *tctx,
497 : const char *soption,
498 : struct smb2_tree **tree)
499 : {
500 18 : const char *share = torture_setting_string(tctx, soption, NULL);
501 :
502 18 : if (share == NULL) {
503 0 : torture_comment(tctx, "No share for option %s\n", soption);
504 0 : return false;
505 : }
506 :
507 18 : 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 959 : NTSTATUS torture_smb2_testfile_access(struct smb2_tree *tree, const char *fname,
515 : struct smb2_handle *handle,
516 : uint32_t desired_access)
517 : {
518 0 : struct smb2_create io;
519 0 : NTSTATUS status;
520 :
521 959 : ZERO_STRUCT(io);
522 959 : io.in.oplock_level = 0;
523 959 : io.in.desired_access = desired_access;
524 959 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
525 959 : io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
526 959 : io.in.share_access =
527 : NTCREATEX_SHARE_ACCESS_DELETE|
528 : NTCREATEX_SHARE_ACCESS_READ|
529 : NTCREATEX_SHARE_ACCESS_WRITE;
530 959 : io.in.create_options = 0;
531 959 : io.in.fname = fname;
532 :
533 959 : status = smb2_create(tree, tree, &io);
534 959 : NT_STATUS_NOT_OK_RETURN(status);
535 :
536 958 : *handle = io.out.file.handle;
537 :
538 958 : return NT_STATUS_OK;
539 : }
540 :
541 : /*
542 : create and return a handle to a test file
543 : */
544 392 : NTSTATUS torture_smb2_testfile(struct smb2_tree *tree, const char *fname,
545 : struct smb2_handle *handle)
546 : {
547 392 : 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 690 : NTSTATUS torture_smb2_open(struct smb2_tree *tree,
556 : const char *fname,
557 : uint32_t desired_access,
558 : struct smb2_handle *handle)
559 : {
560 0 : struct smb2_create io;
561 0 : NTSTATUS status;
562 :
563 690 : 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 690 : status = smb2_create(tree, tree, &io);
572 690 : if (!NT_STATUS_IS_OK(status)) {
573 432 : return status;
574 : }
575 :
576 258 : *handle = io.out.file.handle;
577 :
578 258 : return NT_STATUS_OK;
579 : }
580 :
581 : /*
582 : create and return a handle to a test directory
583 : with specific desired access
584 : */
585 954 : NTSTATUS torture_smb2_testdir_access(struct smb2_tree *tree, const char *fname,
586 : struct smb2_handle *handle,
587 : uint32_t desired_access)
588 : {
589 2 : struct smb2_create io;
590 2 : NTSTATUS status;
591 :
592 954 : ZERO_STRUCT(io);
593 954 : io.in.oplock_level = 0;
594 954 : io.in.desired_access = desired_access;
595 954 : io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
596 954 : io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
597 954 : io.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE;
598 954 : io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
599 954 : io.in.fname = fname;
600 :
601 954 : status = smb2_create(tree, tree, &io);
602 954 : NT_STATUS_NOT_OK_RETURN(status);
603 :
604 954 : *handle = io.out.file.handle;
605 :
606 954 : return NT_STATUS_OK;
607 : }
608 :
609 : /*
610 : create and return a handle to a test directory
611 : */
612 949 : NTSTATUS torture_smb2_testdir(struct smb2_tree *tree, const char *fname,
613 : struct smb2_handle *handle)
614 : {
615 949 : 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 13 : NTSTATUS smb2_create_simple_file(struct torture_context *tctx,
623 : struct smb2_tree *tree, const char *fname,
624 : struct smb2_handle *handle)
625 : {
626 13 : char buf[7] = "abc";
627 0 : NTSTATUS status;
628 :
629 13 : smb2_util_unlink(tree, fname);
630 13 : status = torture_smb2_testfile_access(tree,
631 : fname, handle,
632 : SEC_FLAG_MAXIMUM_ALLOWED);
633 13 : NT_STATUS_NOT_OK_RETURN(status);
634 :
635 13 : status = smb2_util_write(tree, *handle, buf, 0, sizeof(buf));
636 13 : NT_STATUS_NOT_OK_RETURN(status);
637 :
638 13 : return NT_STATUS_OK;
639 : }
640 :
641 : /*
642 : create a simple file using SMB2.
643 : */
644 13 : NTSTATUS torture_setup_simple_file(struct torture_context *tctx,
645 : struct smb2_tree *tree, const char *fname)
646 : {
647 0 : struct smb2_handle handle;
648 13 : NTSTATUS status = smb2_create_simple_file(tctx, tree, fname, &handle);
649 13 : NT_STATUS_NOT_OK_RETURN(status);
650 13 : 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 12 : NTSTATUS torture_setup_complex_file(struct torture_context *tctx,
658 : struct smb2_tree *tree, const char *fname)
659 : {
660 0 : struct smb2_handle handle;
661 12 : NTSTATUS status = smb2_create_complex_file(tctx, tree, fname, &handle);
662 12 : 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 0 : 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 125 : NTSTATUS smb2_util_roothandle(struct smb2_tree *tree, struct smb2_handle *handle)
685 : {
686 18 : struct smb2_create io;
687 18 : NTSTATUS status;
688 :
689 125 : ZERO_STRUCT(io);
690 125 : io.in.oplock_level = 0;
691 125 : io.in.desired_access = SEC_STD_SYNCHRONIZE | SEC_DIR_READ_ATTRIBUTE | SEC_DIR_LIST;
692 125 : io.in.file_attributes = 0;
693 125 : io.in.create_disposition = NTCREATEX_DISP_OPEN;
694 125 : io.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE;
695 125 : io.in.create_options = NTCREATEX_OPTIONS_ASYNC_ALERT;
696 125 : io.in.fname = "";
697 :
698 125 : status = smb2_create(tree, tree, &io);
699 125 : NT_STATUS_NOT_OK_RETURN(status);
700 :
701 115 : *handle = io.out.file.handle;
702 :
703 115 : return NT_STATUS_OK;
704 : }
705 :
706 : /* Comparable to torture_setup_dir, but for SMB2. */
707 101 : bool smb2_util_setup_dir(struct torture_context *tctx, struct smb2_tree *tree,
708 : const char *dname)
709 : {
710 2 : NTSTATUS status;
711 :
712 : /* XXX: smb_raw_exit equivalent?
713 : smb_raw_exit(cli->session); */
714 101 : 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 101 : status = smb2_util_mkdir(tree, dname);
720 101 : 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 99 : 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 36 : bool smb2_util_verify_sd(TALLOC_CTX *tctx, struct smb2_tree *tree,
742 : struct smb2_handle handle, struct security_descriptor *sd)
743 : {
744 0 : NTSTATUS status;
745 36 : bool ret = true;
746 36 : union smb_fileinfo q = {};
747 :
748 36 : q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
749 36 : q.query_secdesc.in.file.handle = handle;
750 36 : q.query_secdesc.in.secinfo_flags =
751 : SECINFO_OWNER |
752 : SECINFO_GROUP |
753 : SECINFO_DACL;
754 36 : status = smb2_getinfo_file(tree, tctx, &q);
755 36 : CHECK_STATUS(status, NT_STATUS_OK);
756 :
757 36 : if (!security_acl_equal(
758 36 : 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 36 : done:
770 36 : return ret;
771 : }
772 :
773 : /*
774 : * Helper function to verify attributes, by querying
775 : * and comparing against the passed in attrib.
776 : */
777 34 : bool smb2_util_verify_attrib(TALLOC_CTX *tctx, struct smb2_tree *tree,
778 : struct smb2_handle handle, uint32_t attrib)
779 : {
780 0 : NTSTATUS status;
781 34 : bool ret = true;
782 34 : union smb_fileinfo q = {};
783 :
784 34 : q.standard.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
785 34 : q.standard.in.file.handle = handle;
786 34 : status = smb2_getinfo_file(tree, tctx, &q);
787 34 : CHECK_STATUS(status, NT_STATUS_OK);
788 :
789 34 : q.all_info2.out.attrib &= ~(FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_NONINDEXED);
790 :
791 34 : 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 33 : done:
800 34 : return ret;
801 : }
802 :
803 :
804 2918 : uint32_t smb2_util_lease_state(const char *ls)
805 : {
806 2918 : uint32_t val = 0;
807 0 : int i;
808 :
809 8550 : for (i = 0; i < strlen(ls); i++) {
810 5632 : switch (ls[i]) {
811 2640 : case 'R':
812 2640 : val |= SMB2_LEASE_READ;
813 2640 : break;
814 1756 : case 'H':
815 1756 : val |= SMB2_LEASE_HANDLE;
816 1756 : break;
817 1236 : case 'W':
818 1236 : val |= SMB2_LEASE_WRITE;
819 1236 : break;
820 : }
821 : }
822 :
823 2918 : return val;
824 : }
825 :
826 258 : char *smb2_util_lease_state_string(TALLOC_CTX *mem_ctx, uint32_t ls)
827 : {
828 774 : return talloc_asprintf(mem_ctx, "0x%0x (%s%s%s)",
829 : (unsigned)ls,
830 258 : ls & SMB2_LEASE_READ ? "R": "",
831 258 : ls & SMB2_LEASE_HANDLE ? "H": "",
832 258 : ls & SMB2_LEASE_WRITE ? "W": "");
833 : }
834 :
835 4023 : uint32_t smb2_util_share_access(const char *sharemode)
836 : {
837 4023 : uint32_t val = NTCREATEX_SHARE_ACCESS_NONE; /* 0 */
838 130 : int i;
839 :
840 10816 : for (i = 0; i < strlen(sharemode); i++) {
841 6793 : switch(sharemode[i]) {
842 2317 : case 'R':
843 2317 : val |= NTCREATEX_SHARE_ACCESS_READ;
844 2317 : break;
845 2290 : case 'W':
846 2290 : val |= NTCREATEX_SHARE_ACCESS_WRITE;
847 2290 : break;
848 2186 : case 'D':
849 2186 : val |= NTCREATEX_SHARE_ACCESS_DELETE;
850 2186 : break;
851 : }
852 : }
853 :
854 4023 : return val;
855 : }
856 :
857 3056 : uint8_t smb2_util_oplock_level(const char *op)
858 : {
859 3056 : uint8_t val = SMB2_OPLOCK_LEVEL_NONE;
860 257 : int i;
861 :
862 3056 : for (i = 0; i < strlen(op); i++) {
863 2742 : switch (op[i]) {
864 436 : case 's':
865 436 : return SMB2_OPLOCK_LEVEL_II;
866 240 : case 'x':
867 240 : return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
868 2066 : case 'b':
869 2066 : return SMB2_OPLOCK_LEVEL_BATCH;
870 0 : default:
871 0 : continue;
872 : }
873 : }
874 :
875 300 : return val;
876 : }
877 :
878 : /**
879 : * Helper functions to fill a smb2_create struct for several
880 : * open scenarios.
881 : */
882 2580 : 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 2580 : ZERO_STRUCT(*io);
889 2580 : io->in.security_flags = 0x00;
890 2580 : io->in.oplock_level = oplock;
891 2580 : io->in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
892 2580 : io->in.create_flags = 0x00000000;
893 2580 : io->in.reserved = 0x00000000;
894 2580 : io->in.desired_access = SEC_RIGHTS_FILE_ALL;
895 2580 : io->in.file_attributes = FILE_ATTRIBUTE_NORMAL;
896 2580 : io->in.share_access = share_access;
897 2580 : io->in.create_disposition = disposition;
898 2580 : io->in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
899 : NTCREATEX_OPTIONS_ASYNC_ALERT |
900 : NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
901 : 0x00200000;
902 2580 : io->in.fname = name;
903 :
904 2580 : if (dir) {
905 4 : io->in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
906 4 : io->in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
907 4 : io->in.create_disposition = NTCREATEX_DISP_CREATE;
908 : }
909 :
910 2580 : if (ls) {
911 892 : ZERO_STRUCTPN(ls);
912 892 : ls->lease_key.data[0] = leasekey;
913 892 : ls->lease_key.data[1] = ~leasekey;
914 892 : ls->lease_state = leasestate;
915 892 : io->in.lease_request = ls;
916 : }
917 2580 : }
918 :
919 4 : 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 4 : smb2_generic_create_share(io, ls, dir, name, disposition,
925 : smb2_util_share_access("RWD"),
926 : oplock,
927 : leasekey, leasestate);
928 4 : }
929 :
930 894 : 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 894 : smb2_generic_create_share(io, ls, dir, name, NTCREATEX_DISP_OPEN_IF,
935 : share_access, SMB2_OPLOCK_LEVEL_LEASE,
936 : leasekey, leasestate);
937 894 : }
938 :
939 580 : 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 580 : smb2_lease_create_share(io, ls, dir, name,
944 : smb2_util_share_access("RWD"),
945 : leasekey, leasestate);
946 580 : }
947 :
948 120 : 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 120 : smb2_generic_create_share(io, NULL, dir, name, NTCREATEX_DISP_OPEN_IF,
959 : share_access, SMB2_OPLOCK_LEVEL_LEASE, 0, 0);
960 :
961 120 : if (ls) {
962 120 : ZERO_STRUCT(*ls);
963 120 : ls->lease_key.data[0] = leasekey;
964 120 : ls->lease_key.data[1] = ~leasekey;
965 120 : ls->lease_state = leasestate;
966 120 : 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 120 : ls->lease_epoch = lease_epoch;
972 120 : io->in.lease_request_v2 = ls;
973 : }
974 120 : }
975 :
976 92 : 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 92 : smb2_lease_v2_create_share(io, ls, dir, name,
986 : smb2_util_share_access("RWD"),
987 : leasekey, parentleasekey,
988 : leasestate, lease_epoch);
989 92 : }
990 :
991 :
992 1562 : void smb2_oplock_create_share(struct smb2_create *io, const char *name,
993 : uint32_t share_access, uint8_t oplock)
994 : {
995 1562 : smb2_generic_create_share(io, NULL, false, name, NTCREATEX_DISP_OPEN_IF,
996 : share_access, oplock, 0, 0);
997 1562 : }
998 236 : void smb2_oplock_create(struct smb2_create *io, const char *name, uint8_t oplock)
999 : {
1000 236 : smb2_oplock_create_share(io, name, smb2_util_share_access("RWD"),
1001 : oplock);
1002 236 : }
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 15 : NTSTATUS torture_smb2_check_privilege(struct smb2_tree *tree,
1011 : const char *sid_str,
1012 : const char *privilege)
1013 : {
1014 15 : struct dom_sid *sid = NULL;
1015 15 : TALLOC_CTX *tmp_ctx = NULL;
1016 0 : uint32_t rid;
1017 0 : NTSTATUS status;
1018 :
1019 15 : tmp_ctx = talloc_new(tree);
1020 15 : if (tmp_ctx == NULL) {
1021 0 : return NT_STATUS_NO_MEMORY;
1022 : }
1023 :
1024 15 : sid = dom_sid_parse_talloc(tmp_ctx, sid_str);
1025 15 : if (sid == NULL) {
1026 0 : talloc_free(tmp_ctx);
1027 0 : return NT_STATUS_INVALID_SID;
1028 : }
1029 :
1030 15 : status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
1031 15 : if (!NT_STATUS_IS_OK(status)) {
1032 0 : TALLOC_FREE(tmp_ctx);
1033 0 : return status;
1034 : }
1035 :
1036 15 : if (rid == DOMAIN_RID_ADMINISTRATOR) {
1037 : /* assume the administrator has them all */
1038 9 : TALLOC_FREE(tmp_ctx);
1039 9 : return NT_STATUS_OK;
1040 : }
1041 :
1042 6 : talloc_free(tmp_ctx);
1043 :
1044 6 : return smb2lsa_sid_check_privilege(tree, sid_str, privilege);
1045 : }
|