s4:torture/smb2: make it possible to pass existing_conn to smb2_connect_ext()
[gd/samba-autobuild/.git] / source4 / torture / smb2 / util.c
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 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         ZERO_STRUCT(w);
52         w.in.file.handle = handle;
53         w.in.offset      = offset;
54         w.in.data        = data_blob_const(buf, size);
55
56         return smb2_write(tree, &w);
57 }
58
59 /*
60   create a complex file/dir using the SMB2 protocol
61 */
62 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         TALLOC_CTX *tmp_ctx = talloc_new(tree);
69         char buf[7] = "abc";
70         struct smb2_create io;
71         union smb_setfileinfo setfile;
72         union smb_fileinfo fileinfo;
73         time_t t = (time(NULL) & ~1);
74         NTSTATUS status;
75
76         smb2_util_unlink(tree, fname);
77         ZERO_STRUCT(io);
78         io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
79         io.in.file_attributes   = FILE_ATTRIBUTE_NORMAL;
80         io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
81         io.in.share_access = 
82                 NTCREATEX_SHARE_ACCESS_DELETE|
83                 NTCREATEX_SHARE_ACCESS_READ|
84                 NTCREATEX_SHARE_ACCESS_WRITE;
85         io.in.create_options = 0;
86         io.in.fname = fname;
87         if (dir) {
88                 io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
89                 io.in.share_access &= ~NTCREATEX_SHARE_ACCESS_DELETE;
90                 io.in.file_attributes   = FILE_ATTRIBUTE_DIRECTORY;
91                 io.in.create_disposition = NTCREATEX_DISP_CREATE;
92         }
93
94         /* it seems vista is now fussier about alignment? */
95         if (strchr(fname, ':') == NULL) {
96                 /* setup some EAs */
97                 io.in.eas.num_eas = 2;
98                 io.in.eas.eas = talloc_array(tmp_ctx, struct ea_struct, 2);
99                 io.in.eas.eas[0].flags = 0;
100                 io.in.eas.eas[0].name.s = "EAONE";
101                 io.in.eas.eas[0].value = data_blob_talloc(tmp_ctx, "VALUE1", 6);
102                 io.in.eas.eas[1].flags = 0;
103                 io.in.eas.eas[1].name.s = "SECONDEA";
104                 io.in.eas.eas[1].value = data_blob_talloc(tmp_ctx, "ValueTwo", 8);
105         }
106
107         status = smb2_create(tree, tmp_ctx, &io);
108         if (NT_STATUS_EQUAL(status, NT_STATUS_EAS_NOT_SUPPORTED)) {
109                 torture_comment(
110                         tctx, "EAs not supported, creating: %s\n", fname);
111                 io.in.eas.num_eas = 0;
112                 status = smb2_create(tree, tmp_ctx, &io);
113         }
114
115         talloc_free(tmp_ctx);
116         NT_STATUS_NOT_OK_RETURN(status);
117
118         *handle = io.out.file.handle;
119
120         if (!dir) {
121                 status = smb2_util_write(tree, *handle, buf, 0, sizeof(buf));
122                 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         setfile.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
128         setfile.generic.in.file.handle = *handle;
129
130         unix_to_nt_time(&setfile.basic_info.in.create_time, t + 9*30*24*60*60);
131         unix_to_nt_time(&setfile.basic_info.in.access_time, t + 6*30*24*60*60);
132         unix_to_nt_time(&setfile.basic_info.in.write_time,  t + 3*30*24*60*60);
133         unix_to_nt_time(&setfile.basic_info.in.change_time, t + 1*30*24*60*60);
134         setfile.basic_info.in.attrib      = FILE_ATTRIBUTE_NORMAL;
135
136         status = smb2_setinfo_file(tree, &setfile);
137         if (!NT_STATUS_IS_OK(status)) {
138                 torture_comment(tctx, "Failed to setup file times - %s\n", nt_errstr(status));
139                 return status;
140         }
141
142         /* make sure all the timestamps aren't the same */
143         fileinfo.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
144         fileinfo.generic.in.file.handle = *handle;
145
146         status = smb2_getinfo_file(tree, tree, &fileinfo);
147         if (!NT_STATUS_IS_OK(status)) {
148                 torture_comment(tctx, "Failed to query file times - %s\n", nt_errstr(status));
149                 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         CHECK_TIME(create_time);
166         CHECK_TIME(access_time);
167         CHECK_TIME(write_time);
168         CHECK_TIME(change_time);
169
170         return status;
171 }
172
173 /*
174   create a complex file using the SMB2 protocol
175 */
176 NTSTATUS smb2_create_complex_file(struct torture_context *tctx,
177                                   struct smb2_tree *tree, const char *fname,
178                                   struct smb2_handle *handle)
179 {
180         return smb2_create_complex(tctx, tree, fname, handle, false);
181 }
182
183 /*
184   create a complex dir using the SMB2 protocol
185 */
186 NTSTATUS smb2_create_complex_dir(struct torture_context *tctx,
187                                  struct smb2_tree *tree, const char *fname,
188                                  struct smb2_handle *handle)
189 {
190         return smb2_create_complex(tctx, tree, fname, handle, true);
191 }
192
193 /*
194   show lots of information about a file
195 */
196 void torture_smb2_all_info(struct torture_context *tctx,
197                            struct smb2_tree *tree, struct smb2_handle handle)
198 {
199         NTSTATUS status;
200         TALLOC_CTX *tmp_ctx = talloc_new(tree);
201         union smb_fileinfo io;
202
203         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
204         io.generic.in.file.handle = handle;
205
206         status = smb2_getinfo_file(tree, tmp_ctx, &io);
207         if (!NT_STATUS_IS_OK(status)) {
208                 DEBUG(0,("getinfo failed - %s\n", nt_errstr(status)));
209                 talloc_free(tmp_ctx);
210                 return;
211         }
212
213         torture_comment(tctx, "all_info for '%s'\n", io.all_info2.out.fname.s);
214         torture_comment(tctx, "\tcreate_time:    %s\n", nt_time_string(tmp_ctx, io.all_info2.out.create_time));
215         torture_comment(tctx, "\taccess_time:    %s\n", nt_time_string(tmp_ctx, io.all_info2.out.access_time));
216         torture_comment(tctx, "\twrite_time:     %s\n", nt_time_string(tmp_ctx, io.all_info2.out.write_time));
217         torture_comment(tctx, "\tchange_time:    %s\n", nt_time_string(tmp_ctx, io.all_info2.out.change_time));
218         torture_comment(tctx, "\tattrib:         0x%x\n", io.all_info2.out.attrib);
219         torture_comment(tctx, "\tunknown1:       0x%x\n", io.all_info2.out.unknown1);
220         torture_comment(tctx, "\talloc_size:     %llu\n", (long long)io.all_info2.out.alloc_size);
221         torture_comment(tctx, "\tsize:           %llu\n", (long long)io.all_info2.out.size);
222         torture_comment(tctx, "\tnlink:          %u\n", io.all_info2.out.nlink);
223         torture_comment(tctx, "\tdelete_pending: %u\n", io.all_info2.out.delete_pending);
224         torture_comment(tctx, "\tdirectory:      %u\n", io.all_info2.out.directory);
225         torture_comment(tctx, "\tfile_id:        %llu\n", (long long)io.all_info2.out.file_id);
226         torture_comment(tctx, "\tea_size:        %u\n", io.all_info2.out.ea_size);
227         torture_comment(tctx, "\taccess_mask:    0x%08x\n", io.all_info2.out.access_mask);
228         torture_comment(tctx, "\tposition:       0x%llx\n", (long long)io.all_info2.out.position);
229         torture_comment(tctx, "\tmode:           0x%llx\n", (long long)io.all_info2.out.mode);
230
231         /* short name, if any */
232         io.generic.level = RAW_FILEINFO_ALT_NAME_INFORMATION;
233         status = smb2_getinfo_file(tree, tmp_ctx, &io);
234         if (NT_STATUS_IS_OK(status)) {
235                 torture_comment(tctx, "\tshort name:     '%s'\n", io.alt_name_info.out.fname.s);
236         }
237
238         /* the EAs, if any */
239         io.generic.level = RAW_FILEINFO_SMB2_ALL_EAS;
240         status = smb2_getinfo_file(tree, tmp_ctx, &io);
241         if (NT_STATUS_IS_OK(status)) {
242                 int i;
243                 for (i=0;i<io.all_eas.out.num_eas;i++) {
244                         torture_comment(tctx, "\tEA[%d] flags=%d len=%d '%s'\n", i,
245                                  io.all_eas.out.eas[i].flags,
246                                  (int)io.all_eas.out.eas[i].value.length,
247                                  io.all_eas.out.eas[i].name.s);
248                 }
249         }
250
251         /* streams, if available */
252         io.generic.level = RAW_FILEINFO_STREAM_INFORMATION;
253         status = smb2_getinfo_file(tree, tmp_ctx, &io);
254         if (NT_STATUS_IS_OK(status)) {
255                 int i;
256                 for (i=0;i<io.stream_info.out.num_streams;i++) {
257                         torture_comment(tctx, "\tstream %d:\n", i);
258                         torture_comment(tctx, "\t\tsize       %ld\n",
259                                  (long)io.stream_info.out.streams[i].size);
260                         torture_comment(tctx, "\t\talloc size %ld\n",
261                                  (long)io.stream_info.out.streams[i].alloc_size);
262                         torture_comment(tctx, "\t\tname       %s\n", io.stream_info.out.streams[i].stream_name.s);
263                 }
264         }       
265
266         if (DEBUGLVL(1)) {
267                 /* the security descriptor */
268                 io.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
269                 io.query_secdesc.in.secinfo_flags = 
270                         SECINFO_OWNER|SECINFO_GROUP|
271                         SECINFO_DACL;
272                 status = smb2_getinfo_file(tree, tmp_ctx, &io);
273                 if (NT_STATUS_IS_OK(status)) {
274                         NDR_PRINT_DEBUG(security_descriptor, io.query_secdesc.out.sd);
275                 }
276         }
277
278         talloc_free(tmp_ctx);   
279 }
280
281 /*
282   get granted access of a file handle
283 */
284 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         TALLOC_CTX *tmp_ctx = talloc_new(tree);
290         union smb_fileinfo io;
291
292         io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
293         io.generic.in.file.handle = handle;
294
295         status = smb2_getinfo_file(tree, tmp_ctx, &io);
296         if (!NT_STATUS_IS_OK(status)) {
297                 DEBUG(0, ("getinfo failed - %s\n", nt_errstr(status)));
298                 goto out;
299         }
300
301         *granted_access = io.all_info2.out.access_mask;
302
303 out:
304         talloc_free(tmp_ctx);
305         return status;
306 }
307
308 /**
309  * open a smb2 tree connect
310  */
311 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         const char *host = torture_setting_string(tctx, "host", NULL);
318         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         unc = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
325         torture_assert(tctx, unc != NULL, "talloc_asprintf");
326
327         tree = smb2_tree_init(session, mem_ctx, false);
328         torture_assert(tctx, tree != NULL, "smb2_tree_init");
329
330         timeout_msec = session->transport->options.request_timeout * 1000;
331
332         subreq = smb2cli_tcon_send(tree, tctx->ev,
333                                    session->transport->conn,
334                                    timeout_msec,
335                                    session->smbXcli,
336                                    tree->smbXcli,
337                                    0, /* flags */
338                                    unc);
339         torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send");
340
341         torture_assert(tctx,
342                        tevent_req_poll_ntstatus(subreq, tctx->ev, &status),
343                        "tevent_req_poll_ntstatus");
344
345         status = smb2cli_tcon_recv(subreq);
346         TALLOC_FREE(subreq);
347         torture_assert_ntstatus_ok(tctx, status, "smb2cli_tcon_recv");
348
349         *_tree = tree;
350
351         return true;
352 }
353
354 /**
355  * do a smb2 session setup (without a tree connect)
356  */
357 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         session = smb2_session_init(transport,
367                                     lpcfg_gensec_settings(tctx, tctx->lp_ctx),
368                                     mem_ctx);
369
370         if (session == NULL) {
371                 return false;
372         }
373
374         status = smb2_session_setup_spnego(session,
375                                            samba_cmdline_get_creds(),
376                                            previous_session_id);
377         if (!NT_STATUS_IS_OK(status)) {
378                 torture_comment(tctx, "session setup failed: %s\n", nt_errstr(status));
379                 talloc_free(session);
380                 return false;
381         }
382
383         *_session = session;
384
385         return true;
386 }
387
388 /*
389   open a smb2 connection
390 */
391 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         const char *host = torture_setting_string(tctx, "host", NULL);
398         const char *share = torture_setting_string(tctx, "share", NULL);
399         const char *p = torture_setting_string(tctx, "unclist", NULL);
400         TALLOC_CTX *mem_ctx = NULL;
401         bool ok;
402
403         if (p != NULL) {
404                 char *host2 = NULL;
405                 char *share2 = NULL;
406
407                 mem_ctx = talloc_new(tctx);
408                 if (mem_ctx == NULL) {
409                         return false;
410                 }
411
412                 ok = torture_get_conn_index(tctx->conn_index++, mem_ctx, tctx,
413                                             &host2, &share2);
414                 if (!ok) {
415                         TALLOC_FREE(mem_ctx);
416                         return false;
417                 }
418
419                 host = host2;
420                 share = share2;
421         }
422
423         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         if (!NT_STATUS_IS_OK(status)) {
438                 torture_comment(tctx, "Failed to connect to SMB2 share \\\\%s\\%s - %s\n",
439                        host, share, nt_errstr(status));
440                 TALLOC_FREE(mem_ctx);
441                 return false;
442         }
443
444         TALLOC_FREE(mem_ctx);
445         return true;
446 }
447
448 bool torture_smb2_connection(struct torture_context *tctx, struct smb2_tree **tree)
449 {
450         bool ret;
451         struct smbcli_options options;
452
453         lpcfg_smbcli_options(tctx->lp_ctx, &options);
454
455         ret = torture_smb2_connection_ext(tctx, 0, &options, tree);
456
457         return ret;
458 }
459
460 /**
461  * SMB2 connect with share from soption
462  **/
463 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         const char *host = torture_setting_string(tctx, "host", NULL);
470
471         lpcfg_smbcli_options(tctx->lp_ctx, &options);
472
473         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         if (!NT_STATUS_IS_OK(status)) {
486                 torture_comment(tctx, "Failed to connect to SMB2 share \\\\%s\\%s - %s\n",
487                        host, share, nt_errstr(status));
488                 return false;
489         }
490         return true;
491 }
492
493 /**
494  * SMB2 connect with share from soption
495  **/
496 bool torture_smb2_con_sopt(struct torture_context *tctx,
497                            const char *soption,
498                            struct smb2_tree **tree)
499 {
500         const char *share = torture_setting_string(tctx, soption, NULL);
501
502         if (share == NULL) {
503                 torture_comment(tctx, "No share for option %s\n", soption);
504                 return false;
505         }
506
507         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 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         ZERO_STRUCT(io);
522         io.in.oplock_level = 0;
523         io.in.desired_access = desired_access;
524         io.in.file_attributes   = FILE_ATTRIBUTE_NORMAL;
525         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
526         io.in.share_access = 
527                 NTCREATEX_SHARE_ACCESS_DELETE|
528                 NTCREATEX_SHARE_ACCESS_READ|
529                 NTCREATEX_SHARE_ACCESS_WRITE;
530         io.in.create_options = 0;
531         io.in.fname = fname;
532
533         status = smb2_create(tree, tree, &io);
534         NT_STATUS_NOT_OK_RETURN(status);
535
536         *handle = io.out.file.handle;
537
538         return NT_STATUS_OK;
539 }
540
541 /*
542   create and return a handle to a test file
543 */
544 NTSTATUS torture_smb2_testfile(struct smb2_tree *tree, const char *fname,
545                                struct smb2_handle *handle)
546 {
547         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 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         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         status = smb2_create(tree, tree, &io);
572         if (!NT_STATUS_IS_OK(status)) {
573                 return status;
574         }
575
576         *handle = io.out.file.handle;
577
578         return NT_STATUS_OK;
579 }
580
581 /*
582   create and return a handle to a test directory
583   with specific desired access
584 */
585 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         ZERO_STRUCT(io);
593         io.in.oplock_level = 0;
594         io.in.desired_access = desired_access;
595         io.in.file_attributes   = FILE_ATTRIBUTE_DIRECTORY;
596         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
597         io.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE;
598         io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
599         io.in.fname = fname;
600
601         status = smb2_create(tree, tree, &io);
602         NT_STATUS_NOT_OK_RETURN(status);
603
604         *handle = io.out.file.handle;
605
606         return NT_STATUS_OK;
607 }
608
609 /*
610   create and return a handle to a test directory
611 */
612 NTSTATUS torture_smb2_testdir(struct smb2_tree *tree, const char *fname,
613                               struct smb2_handle *handle)
614 {
615         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 NTSTATUS smb2_create_simple_file(struct torture_context *tctx,
623                                  struct smb2_tree *tree, const char *fname,
624                                  struct smb2_handle *handle)
625 {
626         char buf[7] = "abc";
627         NTSTATUS status;
628
629         smb2_util_unlink(tree, fname);
630         status = torture_smb2_testfile_access(tree,
631                                               fname, handle,
632                                               SEC_FLAG_MAXIMUM_ALLOWED);
633         NT_STATUS_NOT_OK_RETURN(status);
634
635         status = smb2_util_write(tree, *handle, buf, 0, sizeof(buf));
636         NT_STATUS_NOT_OK_RETURN(status);
637
638         return NT_STATUS_OK;
639 }
640
641 /*
642   create a simple file using SMB2.
643 */
644 NTSTATUS torture_setup_simple_file(struct torture_context *tctx,
645                                    struct smb2_tree *tree, const char *fname)
646 {
647         struct smb2_handle handle;
648         NTSTATUS status = smb2_create_simple_file(tctx, tree, fname, &handle);
649         NT_STATUS_NOT_OK_RETURN(status);
650         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 NTSTATUS torture_setup_complex_file(struct torture_context *tctx,
658                                     struct smb2_tree *tree, const char *fname)
659 {
660         struct smb2_handle handle;
661         NTSTATUS status = smb2_create_complex_file(tctx, tree, fname, &handle);
662         NT_STATUS_NOT_OK_RETURN(status);
663         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 NTSTATUS torture_setup_complex_dir(struct torture_context *tctx,
672                                    struct smb2_tree *tree, const char *fname)
673 {
674         struct smb2_handle handle;
675         NTSTATUS status = smb2_create_complex_dir(tctx, tree, fname, &handle);
676         NT_STATUS_NOT_OK_RETURN(status);
677         return smb2_util_close(tree, handle);
678 }
679
680
681 /*
682   return a handle to the root of the share
683 */
684 NTSTATUS smb2_util_roothandle(struct smb2_tree *tree, struct smb2_handle *handle)
685 {
686         struct smb2_create io;
687         NTSTATUS status;
688
689         ZERO_STRUCT(io);
690         io.in.oplock_level = 0;
691         io.in.desired_access = SEC_STD_SYNCHRONIZE | SEC_DIR_READ_ATTRIBUTE | SEC_DIR_LIST;
692         io.in.file_attributes   = 0;
693         io.in.create_disposition = NTCREATEX_DISP_OPEN;
694         io.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE;
695         io.in.create_options = NTCREATEX_OPTIONS_ASYNC_ALERT;
696         io.in.fname = "";
697
698         status = smb2_create(tree, tree, &io);
699         NT_STATUS_NOT_OK_RETURN(status);
700
701         *handle = io.out.file.handle;
702
703         return NT_STATUS_OK;
704 }
705
706 /* Comparable to torture_setup_dir, but for SMB2. */
707 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         if (smb2_deltree(tree, dname) == -1) {
715                 torture_result(tctx, TORTURE_ERROR, "Unable to deltree when setting up %s.\n", dname);
716                 return false;
717         }
718
719         status = smb2_util_mkdir(tree, dname);
720         if (NT_STATUS_IS_ERR(status)) {
721                 torture_result(tctx, TORTURE_ERROR, "Unable to mkdir when setting up %s - %s\n", dname,
722                     nt_errstr(status));
723                 return false;
724         }
725
726         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 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         bool ret = true;
746         union smb_fileinfo q = {};
747
748         q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
749         q.query_secdesc.in.file.handle = handle;
750         q.query_secdesc.in.secinfo_flags =
751             SECINFO_OWNER |
752             SECINFO_GROUP |
753             SECINFO_DACL;
754         status = smb2_getinfo_file(tree, tctx, &q);
755         CHECK_STATUS(status, NT_STATUS_OK);
756
757         if (!security_acl_equal(
758             q.query_secdesc.out.sd->dacl, sd->dacl)) {
759                 torture_warning(tctx, "%s: security descriptors don't match!\n",
760                     __location__);
761                 torture_warning(tctx, "got:\n");
762                 NDR_PRINT_DEBUG(security_descriptor,
763                     q.query_secdesc.out.sd);
764                 torture_warning(tctx, "expected:\n");
765                 NDR_PRINT_DEBUG(security_descriptor, sd);
766                 ret = false;
767         }
768
769  done:
770         return ret;
771 }
772
773 /*
774  * Helper function to verify attributes, by querying
775  * and comparing against the passed in attrib.
776  */
777 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         bool ret = true;
782         union smb_fileinfo q = {};
783
784         q.standard.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
785         q.standard.in.file.handle = handle;
786         status = smb2_getinfo_file(tree, tctx, &q);
787         CHECK_STATUS(status, NT_STATUS_OK);
788
789         q.all_info2.out.attrib &= ~(FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_NONINDEXED);
790
791         if (q.all_info2.out.attrib != attrib) {
792                 torture_warning(tctx, "%s: attributes don't match! "
793                     "got %x, expected %x\n", __location__,
794                     (uint32_t)q.standard.out.attrib,
795                     (uint32_t)attrib);
796                 ret = false;
797         }
798
799  done:
800         return ret;
801 }
802
803
804 uint32_t smb2_util_lease_state(const char *ls)
805 {
806         uint32_t val = 0;
807         int i;
808
809         for (i = 0; i < strlen(ls); i++) {
810                 switch (ls[i]) {
811                 case 'R':
812                         val |= SMB2_LEASE_READ;
813                         break;
814                 case 'H':
815                         val |= SMB2_LEASE_HANDLE;
816                         break;
817                 case 'W':
818                         val |= SMB2_LEASE_WRITE;
819                         break;
820                 }
821         }
822
823         return val;
824 }
825
826 char *smb2_util_lease_state_string(TALLOC_CTX *mem_ctx, uint32_t ls)
827 {
828         return talloc_asprintf(mem_ctx, "0x%0x (%s%s%s)",
829                                (unsigned)ls,
830                                ls & SMB2_LEASE_READ ? "R": "",
831                                ls & SMB2_LEASE_HANDLE ? "H": "",
832                                ls & SMB2_LEASE_WRITE ? "W": "");
833 }
834
835 uint32_t smb2_util_share_access(const char *sharemode)
836 {
837         uint32_t val = NTCREATEX_SHARE_ACCESS_NONE; /* 0 */
838         int i;
839
840         for (i = 0; i < strlen(sharemode); i++) {
841                 switch(sharemode[i]) {
842                 case 'R':
843                         val |= NTCREATEX_SHARE_ACCESS_READ;
844                         break;
845                 case 'W':
846                         val |= NTCREATEX_SHARE_ACCESS_WRITE;
847                         break;
848                 case 'D':
849                         val |= NTCREATEX_SHARE_ACCESS_DELETE;
850                         break;
851                 }
852         }
853
854         return val;
855 }
856
857 uint8_t smb2_util_oplock_level(const char *op)
858 {
859         uint8_t val = SMB2_OPLOCK_LEVEL_NONE;
860         int i;
861
862         for (i = 0; i < strlen(op); i++) {
863                 switch (op[i]) {
864                 case 's':
865                         return SMB2_OPLOCK_LEVEL_II;
866                 case 'x':
867                         return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
868                 case 'b':
869                         return SMB2_OPLOCK_LEVEL_BATCH;
870                 default:
871                         continue;
872                 }
873         }
874
875         return val;
876 }
877
878 /**
879  * Helper functions to fill a smb2_create struct for several
880  * open scenarios.
881  */
882 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         ZERO_STRUCT(*io);
889         io->in.security_flags           = 0x00;
890         io->in.oplock_level             = oplock;
891         io->in.impersonation_level      = NTCREATEX_IMPERSONATION_IMPERSONATION;
892         io->in.create_flags             = 0x00000000;
893         io->in.reserved                 = 0x00000000;
894         io->in.desired_access           = SEC_RIGHTS_FILE_ALL;
895         io->in.file_attributes          = FILE_ATTRIBUTE_NORMAL;
896         io->in.share_access             = share_access;
897         io->in.create_disposition       = disposition;
898         io->in.create_options           = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
899                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
900                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
901                                           0x00200000;
902         io->in.fname                    = name;
903
904         if (dir) {
905                 io->in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
906                 io->in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
907                 io->in.create_disposition = NTCREATEX_DISP_CREATE;
908         }
909
910         if (ls) {
911                 ZERO_STRUCTPN(ls);
912                 ls->lease_key.data[0] = leasekey;
913                 ls->lease_key.data[1] = ~leasekey;
914                 ls->lease_state = leasestate;
915                 io->in.lease_request = ls;
916         }
917 }
918
919 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         smb2_generic_create_share(io, ls, dir, name, disposition,
925                                   smb2_util_share_access("RWD"),
926                                   oplock,
927                                   leasekey, leasestate);
928 }
929
930 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         smb2_generic_create_share(io, ls, dir, name, NTCREATEX_DISP_OPEN_IF,
935                                   share_access, SMB2_OPLOCK_LEVEL_LEASE,
936                                   leasekey, leasestate);
937 }
938
939 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         smb2_lease_create_share(io, ls, dir, name,
944                                 smb2_util_share_access("RWD"),
945                                 leasekey, leasestate);
946 }
947
948 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         smb2_generic_create_share(io, NULL, dir, name, NTCREATEX_DISP_OPEN_IF,
959                                   share_access, SMB2_OPLOCK_LEVEL_LEASE, 0, 0);
960
961         if (ls) {
962                 ZERO_STRUCT(*ls);
963                 ls->lease_key.data[0] = leasekey;
964                 ls->lease_key.data[1] = ~leasekey;
965                 ls->lease_state = leasestate;
966                 if (parentleasekey != NULL) {
967                         ls->lease_flags |= SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET;
968                         ls->parent_lease_key.data[0] = *parentleasekey;
969                         ls->parent_lease_key.data[1] = ~(*parentleasekey);
970                 }
971                 ls->lease_epoch = lease_epoch;
972                 io->in.lease_request_v2 = ls;
973         }
974 }
975
976 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         smb2_lease_v2_create_share(io, ls, dir, name,
986                                    smb2_util_share_access("RWD"),
987                                    leasekey, parentleasekey,
988                                    leasestate, lease_epoch);
989 }
990
991
992 void smb2_oplock_create_share(struct smb2_create *io, const char *name,
993                               uint32_t share_access, uint8_t oplock)
994 {
995         smb2_generic_create_share(io, NULL, false, name, NTCREATEX_DISP_OPEN_IF,
996                                   share_access, oplock, 0, 0);
997 }
998 void smb2_oplock_create(struct smb2_create *io, const char *name, uint8_t oplock)
999 {
1000         smb2_oplock_create_share(io, name, smb2_util_share_access("RWD"),
1001                                  oplock);
1002 }
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 NTSTATUS torture_smb2_check_privilege(struct smb2_tree *tree,
1011                                      const char *sid_str,
1012                                      const char *privilege)
1013 {
1014         struct dom_sid *sid = NULL;
1015         TALLOC_CTX *tmp_ctx = NULL;
1016         uint32_t rid;
1017         NTSTATUS status;
1018
1019         tmp_ctx = talloc_new(tree);
1020         if (tmp_ctx == NULL) {
1021                 return NT_STATUS_NO_MEMORY;
1022         }
1023
1024         sid = dom_sid_parse_talloc(tmp_ctx, sid_str);
1025         if (sid == NULL) {
1026                 talloc_free(tmp_ctx);
1027                 return NT_STATUS_INVALID_SID;
1028         }
1029
1030         status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
1031         if (!NT_STATUS_IS_OK(status)) {
1032                 TALLOC_FREE(tmp_ctx);
1033                 return status;
1034         }
1035
1036         if (rid == DOMAIN_RID_ADMINISTRATOR) {
1037                 /* assume the administrator has them all */
1038                 TALLOC_FREE(tmp_ctx);
1039                 return NT_STATUS_OK;
1040         }
1041
1042         talloc_free(tmp_ctx);
1043
1044         return smb2lsa_sid_check_privilege(tree, sid_str, privilege);
1045 }