lib/util: Build iov_buf library only when building samba
[Samba.git] / source4 / torture / smb2 / util.c
blob814e398dd085cc87a8317480b1caf0e5369ce7cc
1 /*
2 Unix SMB/CIFS implementation.
4 helper functions for SMB2 test suite
6 Copyright (C) Andrew Tridgell 2005
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.
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.
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/>.
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/popt_common.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"
34 #include "torture/torture.h"
35 #include "torture/smb2/proto.h"
39 write to a file on SMB2
41 NTSTATUS smb2_util_write(struct smb2_tree *tree,
42 struct smb2_handle handle,
43 const void *buf, off_t offset, size_t size)
45 struct smb2_write w;
47 ZERO_STRUCT(w);
48 w.in.file.handle = handle;
49 w.in.offset = offset;
50 w.in.data = data_blob_const(buf, size);
52 return smb2_write(tree, &w);
56 create a complex file/dir using the SMB2 protocol
58 static NTSTATUS smb2_create_complex(struct smb2_tree *tree, const char *fname,
59 struct smb2_handle *handle, bool dir)
61 TALLOC_CTX *tmp_ctx = talloc_new(tree);
62 char buf[7] = "abc";
63 struct smb2_create io;
64 union smb_setfileinfo setfile;
65 union smb_fileinfo fileinfo;
66 time_t t = (time(NULL) & ~1);
67 NTSTATUS status;
69 smb2_util_unlink(tree, fname);
70 ZERO_STRUCT(io);
71 io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
72 io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
73 io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
74 io.in.share_access =
75 NTCREATEX_SHARE_ACCESS_DELETE|
76 NTCREATEX_SHARE_ACCESS_READ|
77 NTCREATEX_SHARE_ACCESS_WRITE;
78 io.in.create_options = 0;
79 io.in.fname = fname;
80 if (dir) {
81 io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
82 io.in.share_access &= ~NTCREATEX_SHARE_ACCESS_DELETE;
83 io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
84 io.in.create_disposition = NTCREATEX_DISP_CREATE;
87 /* it seems vista is now fussier about alignment? */
88 if (strchr(fname, ':') == NULL) {
89 /* setup some EAs */
90 io.in.eas.num_eas = 2;
91 io.in.eas.eas = talloc_array(tmp_ctx, struct ea_struct, 2);
92 io.in.eas.eas[0].flags = 0;
93 io.in.eas.eas[0].name.s = "EAONE";
94 io.in.eas.eas[0].value = data_blob_talloc(tmp_ctx, "VALUE1", 6);
95 io.in.eas.eas[1].flags = 0;
96 io.in.eas.eas[1].name.s = "SECONDEA";
97 io.in.eas.eas[1].value = data_blob_talloc(tmp_ctx, "ValueTwo", 8);
100 status = smb2_create(tree, tmp_ctx, &io);
101 talloc_free(tmp_ctx);
102 NT_STATUS_NOT_OK_RETURN(status);
104 *handle = io.out.file.handle;
106 if (!dir) {
107 status = smb2_util_write(tree, *handle, buf, 0, sizeof(buf));
108 NT_STATUS_NOT_OK_RETURN(status);
111 /* make sure all the timestamps aren't the same, and are also
112 in different DST zones*/
113 setfile.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
114 setfile.generic.in.file.handle = *handle;
116 unix_to_nt_time(&setfile.basic_info.in.create_time, t + 9*30*24*60*60);
117 unix_to_nt_time(&setfile.basic_info.in.access_time, t + 6*30*24*60*60);
118 unix_to_nt_time(&setfile.basic_info.in.write_time, t + 3*30*24*60*60);
119 unix_to_nt_time(&setfile.basic_info.in.change_time, t + 1*30*24*60*60);
120 setfile.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL;
122 status = smb2_setinfo_file(tree, &setfile);
123 if (!NT_STATUS_IS_OK(status)) {
124 printf("Failed to setup file times - %s\n", nt_errstr(status));
125 return status;
128 /* make sure all the timestamps aren't the same */
129 fileinfo.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
130 fileinfo.generic.in.file.handle = *handle;
132 status = smb2_getinfo_file(tree, tree, &fileinfo);
133 if (!NT_STATUS_IS_OK(status)) {
134 printf("Failed to query file times - %s\n", nt_errstr(status));
135 return status;
139 #define CHECK_TIME(field) do {\
140 if (setfile.basic_info.in.field != fileinfo.all_info2.out.field) { \
141 printf("(%s) " #field " not setup correctly: %s(%llu) => %s(%llu)\n", \
142 __location__, \
143 nt_time_string(tree, setfile.basic_info.in.field), \
144 (unsigned long long)setfile.basic_info.in.field, \
145 nt_time_string(tree, fileinfo.basic_info.out.field), \
146 (unsigned long long)fileinfo.basic_info.out.field); \
147 status = NT_STATUS_INVALID_PARAMETER; \
149 } while (0)
151 CHECK_TIME(create_time);
152 CHECK_TIME(access_time);
153 CHECK_TIME(write_time);
154 CHECK_TIME(change_time);
156 return status;
160 create a complex file using the SMB2 protocol
162 NTSTATUS smb2_create_complex_file(struct smb2_tree *tree, const char *fname,
163 struct smb2_handle *handle)
165 return smb2_create_complex(tree, fname, handle, false);
169 create a complex dir using the SMB2 protocol
171 NTSTATUS smb2_create_complex_dir(struct smb2_tree *tree, const char *fname,
172 struct smb2_handle *handle)
174 return smb2_create_complex(tree, fname, handle, true);
178 show lots of information about a file
180 void torture_smb2_all_info(struct smb2_tree *tree, struct smb2_handle handle)
182 NTSTATUS status;
183 TALLOC_CTX *tmp_ctx = talloc_new(tree);
184 union smb_fileinfo io;
186 io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
187 io.generic.in.file.handle = handle;
189 status = smb2_getinfo_file(tree, tmp_ctx, &io);
190 if (!NT_STATUS_IS_OK(status)) {
191 DEBUG(0,("getinfo failed - %s\n", nt_errstr(status)));
192 talloc_free(tmp_ctx);
193 return;
196 d_printf("all_info for '%s'\n", io.all_info2.out.fname.s);
197 d_printf("\tcreate_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.create_time));
198 d_printf("\taccess_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.access_time));
199 d_printf("\twrite_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.write_time));
200 d_printf("\tchange_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.change_time));
201 d_printf("\tattrib: 0x%x\n", io.all_info2.out.attrib);
202 d_printf("\tunknown1: 0x%x\n", io.all_info2.out.unknown1);
203 d_printf("\talloc_size: %llu\n", (long long)io.all_info2.out.alloc_size);
204 d_printf("\tsize: %llu\n", (long long)io.all_info2.out.size);
205 d_printf("\tnlink: %u\n", io.all_info2.out.nlink);
206 d_printf("\tdelete_pending: %u\n", io.all_info2.out.delete_pending);
207 d_printf("\tdirectory: %u\n", io.all_info2.out.directory);
208 d_printf("\tfile_id: %llu\n", (long long)io.all_info2.out.file_id);
209 d_printf("\tea_size: %u\n", io.all_info2.out.ea_size);
210 d_printf("\taccess_mask: 0x%08x\n", io.all_info2.out.access_mask);
211 d_printf("\tposition: 0x%llx\n", (long long)io.all_info2.out.position);
212 d_printf("\tmode: 0x%llx\n", (long long)io.all_info2.out.mode);
214 /* short name, if any */
215 io.generic.level = RAW_FILEINFO_ALT_NAME_INFORMATION;
216 status = smb2_getinfo_file(tree, tmp_ctx, &io);
217 if (NT_STATUS_IS_OK(status)) {
218 d_printf("\tshort name: '%s'\n", io.alt_name_info.out.fname.s);
221 /* the EAs, if any */
222 io.generic.level = RAW_FILEINFO_SMB2_ALL_EAS;
223 status = smb2_getinfo_file(tree, tmp_ctx, &io);
224 if (NT_STATUS_IS_OK(status)) {
225 int i;
226 for (i=0;i<io.all_eas.out.num_eas;i++) {
227 d_printf("\tEA[%d] flags=%d len=%d '%s'\n", i,
228 io.all_eas.out.eas[i].flags,
229 (int)io.all_eas.out.eas[i].value.length,
230 io.all_eas.out.eas[i].name.s);
234 /* streams, if available */
235 io.generic.level = RAW_FILEINFO_STREAM_INFORMATION;
236 status = smb2_getinfo_file(tree, tmp_ctx, &io);
237 if (NT_STATUS_IS_OK(status)) {
238 int i;
239 for (i=0;i<io.stream_info.out.num_streams;i++) {
240 d_printf("\tstream %d:\n", i);
241 d_printf("\t\tsize %ld\n",
242 (long)io.stream_info.out.streams[i].size);
243 d_printf("\t\talloc size %ld\n",
244 (long)io.stream_info.out.streams[i].alloc_size);
245 d_printf("\t\tname %s\n", io.stream_info.out.streams[i].stream_name.s);
249 if (DEBUGLVL(1)) {
250 /* the security descriptor */
251 io.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
252 io.query_secdesc.in.secinfo_flags =
253 SECINFO_OWNER|SECINFO_GROUP|
254 SECINFO_DACL;
255 status = smb2_getinfo_file(tree, tmp_ctx, &io);
256 if (NT_STATUS_IS_OK(status)) {
257 NDR_PRINT_DEBUG(security_descriptor, io.query_secdesc.out.sd);
261 talloc_free(tmp_ctx);
265 * open a smb2 tree connect
267 bool torture_smb2_tree_connect(struct torture_context *tctx,
268 struct smb2_session *session,
269 TALLOC_CTX *mem_ctx,
270 struct smb2_tree **_tree)
272 NTSTATUS status;
273 const char *host = torture_setting_string(tctx, "host", NULL);
274 const char *share = torture_setting_string(tctx, "share", NULL);
275 const char *unc;
276 struct smb2_tree *tree;
277 struct tevent_req *subreq;
278 uint32_t timeout_msec;
280 unc = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
281 torture_assert(tctx, unc != NULL, "talloc_asprintf");
283 tree = smb2_tree_init(session, mem_ctx, false);
284 torture_assert(tctx, tree != NULL, "smb2_tree_init");
286 timeout_msec = session->transport->options.request_timeout * 1000;
288 subreq = smb2cli_tcon_send(tree, tctx->ev,
289 session->transport->conn,
290 timeout_msec,
291 session->smbXcli,
292 tree->smbXcli,
293 0, /* flags */
294 unc);
295 torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send");
297 torture_assert(tctx,
298 tevent_req_poll_ntstatus(subreq, tctx->ev, &status),
299 "tevent_req_poll_ntstatus");
301 status = smb2cli_tcon_recv(subreq);
302 TALLOC_FREE(subreq);
303 torture_assert_ntstatus_ok(tctx, status, "smb2cli_tcon_recv");
305 *_tree = tree;
307 return true;
311 * do a smb2 session setup (without a tree connect)
313 bool torture_smb2_session_setup(struct torture_context *tctx,
314 struct smb2_transport *transport,
315 uint64_t previous_session_id,
316 TALLOC_CTX *mem_ctx,
317 struct smb2_session **_session)
319 NTSTATUS status;
320 struct smb2_session *session;
321 struct cli_credentials *credentials = cmdline_credentials;
323 session = smb2_session_init(transport,
324 lpcfg_gensec_settings(tctx, tctx->lp_ctx),
325 mem_ctx);
327 if (session == NULL) {
328 return false;
331 status = smb2_session_setup_spnego(session, credentials,
332 previous_session_id);
333 if (!NT_STATUS_IS_OK(status)) {
334 printf("session setup failed: %s\n", nt_errstr(status));
335 talloc_free(session);
336 return false;
339 *_session = session;
341 return true;
345 open a smb2 connection
347 bool torture_smb2_connection_ext(struct torture_context *tctx,
348 uint64_t previous_session_id,
349 const struct smbcli_options *options,
350 struct smb2_tree **tree)
352 NTSTATUS status;
353 const char *host = torture_setting_string(tctx, "host", NULL);
354 const char *share = torture_setting_string(tctx, "share", NULL);
355 struct cli_credentials *credentials = cmdline_credentials;
357 status = smb2_connect_ext(tctx,
358 host,
359 lpcfg_smb_ports(tctx->lp_ctx),
360 share,
361 lpcfg_resolve_context(tctx->lp_ctx),
362 credentials,
363 previous_session_id,
364 tree,
365 tctx->ev,
366 options,
367 lpcfg_socket_options(tctx->lp_ctx),
368 lpcfg_gensec_settings(tctx, tctx->lp_ctx)
370 if (!NT_STATUS_IS_OK(status)) {
371 printf("Failed to connect to SMB2 share \\\\%s\\%s - %s\n",
372 host, share, nt_errstr(status));
373 return false;
375 return true;
378 bool torture_smb2_connection(struct torture_context *tctx, struct smb2_tree **tree)
380 bool ret;
381 struct smbcli_options options;
383 lpcfg_smbcli_options(tctx->lp_ctx, &options);
385 ret = torture_smb2_connection_ext(tctx, 0, &options, tree);
387 return ret;
391 * SMB2 connect with share from soption
393 bool torture_smb2_con_sopt(struct torture_context *tctx,
394 const char *soption,
395 struct smb2_tree **tree)
397 struct smbcli_options options;
398 NTSTATUS status;
399 const char *host = torture_setting_string(tctx, "host", NULL);
400 const char *share = torture_setting_string(tctx, soption, NULL);
401 struct cli_credentials *credentials = cmdline_credentials;
403 lpcfg_smbcli_options(tctx->lp_ctx, &options);
405 if (share == NULL) {
406 printf("No share for option %s\n", soption);
407 return false;
410 status = smb2_connect_ext(tctx,
411 host,
412 lpcfg_smb_ports(tctx->lp_ctx),
413 share,
414 lpcfg_resolve_context(tctx->lp_ctx),
415 credentials,
417 tree,
418 tctx->ev,
419 &options,
420 lpcfg_socket_options(tctx->lp_ctx),
421 lpcfg_gensec_settings(tctx, tctx->lp_ctx)
423 if (!NT_STATUS_IS_OK(status)) {
424 printf("Failed to connect to SMB2 share \\\\%s\\%s - %s\n",
425 host, share, nt_errstr(status));
426 return false;
428 return true;
433 create and return a handle to a test file
435 NTSTATUS torture_smb2_testfile(struct smb2_tree *tree, const char *fname,
436 struct smb2_handle *handle)
438 struct smb2_create io;
439 NTSTATUS status;
441 ZERO_STRUCT(io);
442 io.in.oplock_level = 0;
443 io.in.desired_access = SEC_RIGHTS_FILE_ALL;
444 io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
445 io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
446 io.in.share_access =
447 NTCREATEX_SHARE_ACCESS_DELETE|
448 NTCREATEX_SHARE_ACCESS_READ|
449 NTCREATEX_SHARE_ACCESS_WRITE;
450 io.in.create_options = 0;
451 io.in.fname = fname;
453 status = smb2_create(tree, tree, &io);
454 NT_STATUS_NOT_OK_RETURN(status);
456 *handle = io.out.file.handle;
458 return NT_STATUS_OK;
462 create and return a handle to a test directory
464 NTSTATUS torture_smb2_testdir(struct smb2_tree *tree, const char *fname,
465 struct smb2_handle *handle)
467 struct smb2_create io;
468 NTSTATUS status;
470 ZERO_STRUCT(io);
471 io.in.oplock_level = 0;
472 io.in.desired_access = SEC_RIGHTS_DIR_ALL;
473 io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
474 io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
475 io.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE;
476 io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
477 io.in.fname = fname;
479 status = smb2_create(tree, tree, &io);
480 NT_STATUS_NOT_OK_RETURN(status);
482 *handle = io.out.file.handle;
484 return NT_STATUS_OK;
489 create a complex file using SMB2, to make it easier to
490 find fields in SMB2 getinfo levels
492 NTSTATUS torture_setup_complex_file(struct smb2_tree *tree, const char *fname)
494 struct smb2_handle handle;
495 NTSTATUS status = smb2_create_complex_file(tree, fname, &handle);
496 NT_STATUS_NOT_OK_RETURN(status);
497 return smb2_util_close(tree, handle);
502 create a complex dir using SMB2, to make it easier to
503 find fields in SMB2 getinfo levels
505 NTSTATUS torture_setup_complex_dir(struct smb2_tree *tree, const char *fname)
507 struct smb2_handle handle;
508 NTSTATUS status = smb2_create_complex_dir(tree, fname, &handle);
509 NT_STATUS_NOT_OK_RETURN(status);
510 return smb2_util_close(tree, handle);
515 return a handle to the root of the share
517 NTSTATUS smb2_util_roothandle(struct smb2_tree *tree, struct smb2_handle *handle)
519 struct smb2_create io;
520 NTSTATUS status;
522 ZERO_STRUCT(io);
523 io.in.oplock_level = 0;
524 io.in.desired_access = SEC_STD_SYNCHRONIZE | SEC_DIR_READ_ATTRIBUTE | SEC_DIR_LIST;
525 io.in.file_attributes = 0;
526 io.in.create_disposition = NTCREATEX_DISP_OPEN;
527 io.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE;
528 io.in.create_options = NTCREATEX_OPTIONS_ASYNC_ALERT;
529 io.in.fname = "";
531 status = smb2_create(tree, tree, &io);
532 NT_STATUS_NOT_OK_RETURN(status);
534 *handle = io.out.file.handle;
536 return NT_STATUS_OK;
539 /* Comparable to torture_setup_dir, but for SMB2. */
540 bool smb2_util_setup_dir(struct torture_context *tctx, struct smb2_tree *tree,
541 const char *dname)
543 NTSTATUS status;
545 /* XXX: smb_raw_exit equivalent?
546 smb_raw_exit(cli->session); */
547 if (smb2_deltree(tree, dname) == -1) {
548 torture_result(tctx, TORTURE_ERROR, "Unable to deltree when setting up %s.\n", dname);
549 return false;
552 status = smb2_util_mkdir(tree, dname);
553 if (NT_STATUS_IS_ERR(status)) {
554 torture_result(tctx, TORTURE_ERROR, "Unable to mkdir when setting up %s - %s\n", dname,
555 nt_errstr(status));
556 return false;
559 return true;
562 #define CHECK_STATUS(status, correct) do { \
563 if (!NT_STATUS_EQUAL(status, correct)) { \
564 torture_result(tctx, TORTURE_FAIL, "(%s) Incorrect status %s - should be %s\n", \
565 __location__, nt_errstr(status), nt_errstr(correct)); \
566 ret = false; \
567 goto done; \
568 }} while (0)
571 * Helper function to verify a security descriptor, by querying
572 * and comparing against the passed in sd.
574 bool smb2_util_verify_sd(TALLOC_CTX *tctx, struct smb2_tree *tree,
575 struct smb2_handle handle, struct security_descriptor *sd)
577 NTSTATUS status;
578 bool ret = true;
579 union smb_fileinfo q = {};
581 q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
582 q.query_secdesc.in.file.handle = handle;
583 q.query_secdesc.in.secinfo_flags =
584 SECINFO_OWNER |
585 SECINFO_GROUP |
586 SECINFO_DACL;
587 status = smb2_getinfo_file(tree, tctx, &q);
588 CHECK_STATUS(status, NT_STATUS_OK);
590 if (!security_acl_equal(
591 q.query_secdesc.out.sd->dacl, sd->dacl)) {
592 torture_warning(tctx, "%s: security descriptors don't match!\n",
593 __location__);
594 torture_warning(tctx, "got:\n");
595 NDR_PRINT_DEBUG(security_descriptor,
596 q.query_secdesc.out.sd);
597 torture_warning(tctx, "expected:\n");
598 NDR_PRINT_DEBUG(security_descriptor, sd);
599 ret = false;
602 done:
603 return ret;
607 * Helper function to verify attributes, by querying
608 * and comparing against the passed in attrib.
610 bool smb2_util_verify_attrib(TALLOC_CTX *tctx, struct smb2_tree *tree,
611 struct smb2_handle handle, uint32_t attrib)
613 NTSTATUS status;
614 bool ret = true;
615 union smb_fileinfo q = {};
617 q.standard.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
618 q.standard.in.file.handle = handle;
619 status = smb2_getinfo_file(tree, tctx, &q);
620 CHECK_STATUS(status, NT_STATUS_OK);
622 q.all_info2.out.attrib &= ~(FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_NONINDEXED);
624 if (q.all_info2.out.attrib != attrib) {
625 torture_warning(tctx, "%s: attributes don't match! "
626 "got %x, expected %x\n", __location__,
627 (uint32_t)q.standard.out.attrib,
628 (uint32_t)attrib);
629 ret = false;
632 done:
633 return ret;
637 uint32_t smb2_util_lease_state(const char *ls)
639 uint32_t val = 0;
640 int i;
642 for (i = 0; i < strlen(ls); i++) {
643 switch (ls[i]) {
644 case 'R':
645 val |= SMB2_LEASE_READ;
646 break;
647 case 'H':
648 val |= SMB2_LEASE_HANDLE;
649 break;
650 case 'W':
651 val |= SMB2_LEASE_WRITE;
652 break;
656 return val;
660 uint32_t smb2_util_share_access(const char *sharemode)
662 uint32_t val = NTCREATEX_SHARE_ACCESS_NONE; /* 0 */
663 int i;
665 for (i = 0; i < strlen(sharemode); i++) {
666 switch(sharemode[i]) {
667 case 'R':
668 val |= NTCREATEX_SHARE_ACCESS_READ;
669 break;
670 case 'W':
671 val |= NTCREATEX_SHARE_ACCESS_WRITE;
672 break;
673 case 'D':
674 val |= NTCREATEX_SHARE_ACCESS_DELETE;
675 break;
679 return val;
682 uint8_t smb2_util_oplock_level(const char *op)
684 uint8_t val = SMB2_OPLOCK_LEVEL_NONE;
685 int i;
687 for (i = 0; i < strlen(op); i++) {
688 switch (op[i]) {
689 case 's':
690 return SMB2_OPLOCK_LEVEL_II;
691 case 'x':
692 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
693 case 'b':
694 return SMB2_OPLOCK_LEVEL_BATCH;
695 default:
696 continue;
700 return val;
704 * Helper functions to fill a smb2_create struct for several
705 * open scenarios.
707 void smb2_generic_create_share(struct smb2_create *io, struct smb2_lease *ls,
708 bool dir, const char *name, uint32_t disposition,
709 uint32_t share_access,
710 uint8_t oplock, uint64_t leasekey,
711 uint32_t leasestate)
713 ZERO_STRUCT(*io);
714 io->in.security_flags = 0x00;
715 io->in.oplock_level = oplock;
716 io->in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
717 io->in.create_flags = 0x00000000;
718 io->in.reserved = 0x00000000;
719 io->in.desired_access = SEC_RIGHTS_FILE_ALL;
720 io->in.file_attributes = FILE_ATTRIBUTE_NORMAL;
721 io->in.share_access = share_access;
722 io->in.create_disposition = disposition;
723 io->in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
724 NTCREATEX_OPTIONS_ASYNC_ALERT |
725 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
726 0x00200000;
727 io->in.fname = name;
729 if (dir) {
730 io->in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
731 io->in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
732 io->in.create_disposition = NTCREATEX_DISP_CREATE;
735 if (ls) {
736 ZERO_STRUCTPN(ls);
737 ls->lease_key.data[0] = leasekey;
738 ls->lease_key.data[1] = ~leasekey;
739 ls->lease_state = leasestate;
740 io->in.lease_request = ls;
744 void smb2_generic_create(struct smb2_create *io, struct smb2_lease *ls,
745 bool dir, const char *name, uint32_t disposition,
746 uint8_t oplock, uint64_t leasekey,
747 uint32_t leasestate)
749 smb2_generic_create_share(io, ls, dir, name, disposition,
750 smb2_util_share_access("RWD"),
751 oplock,
752 leasekey, leasestate);
755 void smb2_lease_create_share(struct smb2_create *io, struct smb2_lease *ls,
756 bool dir, const char *name, uint32_t share_access,
757 uint64_t leasekey, uint32_t leasestate)
759 smb2_generic_create_share(io, ls, dir, name, NTCREATEX_DISP_OPEN_IF,
760 share_access, SMB2_OPLOCK_LEVEL_LEASE,
761 leasekey, leasestate);
764 void smb2_lease_create(struct smb2_create *io, struct smb2_lease *ls,
765 bool dir, const char *name, uint64_t leasekey,
766 uint32_t leasestate)
768 smb2_lease_create_share(io, ls, dir, name,
769 smb2_util_share_access("RWD"),
770 leasekey, leasestate);
773 void smb2_lease_v2_create_share(struct smb2_create *io,
774 struct smb2_lease *ls,
775 bool dir,
776 const char *name,
777 uint32_t share_access,
778 uint64_t leasekey,
779 const uint64_t *parentleasekey,
780 uint32_t leasestate,
781 uint16_t lease_epoch)
783 smb2_generic_create_share(io, NULL, dir, name, NTCREATEX_DISP_OPEN_IF,
784 share_access, SMB2_OPLOCK_LEVEL_LEASE, 0, 0);
786 if (ls) {
787 ZERO_STRUCT(*ls);
788 ls->lease_key.data[0] = leasekey;
789 ls->lease_key.data[1] = ~leasekey;
790 ls->lease_state = leasestate;
791 if (parentleasekey != NULL) {
792 ls->lease_flags |= SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET;
793 ls->parent_lease_key.data[0] = *parentleasekey;
794 ls->parent_lease_key.data[1] = ~(*parentleasekey);
796 ls->lease_epoch = lease_epoch;
797 io->in.lease_request_v2 = ls;
801 void smb2_lease_v2_create(struct smb2_create *io,
802 struct smb2_lease *ls,
803 bool dir,
804 const char *name,
805 uint64_t leasekey,
806 const uint64_t *parentleasekey,
807 uint32_t leasestate,
808 uint16_t lease_epoch)
810 smb2_lease_v2_create_share(io, ls, dir, name,
811 smb2_util_share_access("RWD"),
812 leasekey, parentleasekey,
813 leasestate, lease_epoch);
817 void smb2_oplock_create_share(struct smb2_create *io, const char *name,
818 uint32_t share_access, uint8_t oplock)
820 smb2_generic_create_share(io, NULL, false, name, NTCREATEX_DISP_OPEN_IF,
821 share_access, oplock, 0, 0);
823 void smb2_oplock_create(struct smb2_create *io, const char *name, uint8_t oplock)
825 smb2_oplock_create_share(io, name, smb2_util_share_access("RWD"),
826 oplock);