LCOV - code coverage report
Current view: top level - source4/torture/smb2 - compound.c (source / functions) Hit Total Coverage
Test: coverage report for vadcx-master-patch-75612 fe003de8 Lines: 1318 1489 88.5 %
Date: 2024-02-29 22:57:05 Functions: 31 31 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    test suite for SMB2 compounded requests
       5             : 
       6             :    Copyright (C) Stefan Metzmacher 2009
       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 "tevent.h"
      24             : #include "libcli/smb2/smb2.h"
      25             : #include "libcli/smb2/smb2_calls.h"
      26             : #include "torture/torture.h"
      27             : #include "torture/smb2/proto.h"
      28             : #include "libcli/security/security.h"
      29             : #include "librpc/gen_ndr/ndr_security.h"
      30             : #include "../libcli/smb/smbXcli_base.h"
      31             : 
      32             : #define CHECK_STATUS(status, correct) do { \
      33             :         if (!NT_STATUS_EQUAL(status, correct)) { \
      34             :                 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
      35             :                        nt_errstr(status), nt_errstr(correct)); \
      36             :                 ret = false; \
      37             :                 goto done; \
      38             :         }} while (0)
      39             : 
      40             : #define CHECK_VALUE(v, correct) do { \
      41             :         if ((v) != (correct)) { \
      42             :                 torture_result(tctx, TORTURE_FAIL, \
      43             :                     "(%s) Incorrect value %s=%d - should be %d\n", \
      44             :                     __location__, #v, (int)v, (int)correct); \
      45             :                 ret = false; \
      46             :         }} while (0)
      47             : 
      48             : #define WAIT_FOR_ASYNC_RESPONSE(req) \
      49             :         while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) { \
      50             :                 if (tevent_loop_once(tctx->ev) != 0) { \
      51             :                         break; \
      52             :                 } \
      53             :         }
      54             : 
      55             : static struct {
      56             :         struct smb2_handle handle;
      57             :         uint8_t level;
      58             :         struct smb2_break br;
      59             :         int count;
      60             :         int failures;
      61             :         NTSTATUS failure_status;
      62             : } break_info;
      63             : 
      64           6 : static void torture_oplock_break_callback(struct smb2_request *req)
      65             : {
      66           0 :         NTSTATUS status;
      67           0 :         struct smb2_break br;
      68             : 
      69           6 :         ZERO_STRUCT(br);
      70           6 :         status = smb2_break_recv(req, &break_info.br);
      71           6 :         if (!NT_STATUS_IS_OK(status)) {
      72           0 :                 break_info.failures++;
      73           0 :                 break_info.failure_status = status;
      74             :         }
      75             : 
      76           6 :         return;
      77             : }
      78             : 
      79             : /* A general oplock break notification handler.  This should be used when a
      80             :  * test expects to break from batch or exclusive to a lower level. */
      81           6 : static bool torture_oplock_handler(struct smb2_transport *transport,
      82             :                                    const struct smb2_handle *handle,
      83             :                                    uint8_t level,
      84             :                                    void *private_data)
      85             : {
      86           6 :         struct smb2_tree *tree = private_data;
      87           0 :         const char *name;
      88           0 :         struct smb2_request *req;
      89           6 :         ZERO_STRUCT(break_info.br);
      90             : 
      91           6 :         break_info.handle       = *handle;
      92           6 :         break_info.level        = level;
      93           6 :         break_info.count++;
      94             : 
      95           6 :         switch (level) {
      96           6 :         case SMB2_OPLOCK_LEVEL_II:
      97           6 :                 name = "level II";
      98           6 :                 break;
      99           0 :         case SMB2_OPLOCK_LEVEL_NONE:
     100           0 :                 name = "none";
     101           0 :                 break;
     102           0 :         default:
     103           0 :                 name = "unknown";
     104           0 :                 break_info.failures++;
     105             :         }
     106           6 :         printf("Acking to %s [0x%02X] in oplock handler\n", name, level);
     107             : 
     108           6 :         break_info.br.in.file.handle    = *handle;
     109           6 :         break_info.br.in.oplock_level   = level;
     110           6 :         break_info.br.in.reserved       = 0;
     111           6 :         break_info.br.in.reserved2      = 0;
     112             : 
     113           6 :         req = smb2_break_send(tree, &break_info.br);
     114           6 :         req->async.fn = torture_oplock_break_callback;
     115           6 :         req->async.private_data = NULL;
     116           6 :         return true;
     117             : }
     118             : 
     119           6 : static bool test_compound_break(struct torture_context *tctx,
     120             :                                  struct smb2_tree *tree)
     121             : {
     122           6 :         const char *fname1 = "some-file.pptx";
     123           0 :         NTSTATUS status;
     124           6 :         bool ret = true;
     125           0 :         union smb_open io1;
     126           0 :         struct smb2_create io2;
     127           0 :         struct smb2_getinfo gf;
     128           0 :         struct smb2_request *req[2];
     129           0 :         struct smb2_handle h1;
     130           0 :         struct smb2_handle h;
     131             : 
     132           6 :         tree->session->transport->oplock.handler = torture_oplock_handler;
     133           6 :         tree->session->transport->oplock.private_data = tree;
     134             : 
     135           6 :         ZERO_STRUCT(break_info);
     136             : 
     137             :         /*
     138             :           base ntcreatex parms
     139             :         */
     140           6 :         ZERO_STRUCT(io1.smb2);
     141           6 :         io1.generic.level = RAW_OPEN_SMB2;
     142           6 :         io1.smb2.in.desired_access = (SEC_STD_SYNCHRONIZE|
     143             :                                         SEC_STD_READ_CONTROL|
     144             :                                         SEC_FILE_READ_ATTRIBUTE|
     145             :                                         SEC_FILE_READ_EA|
     146             :                                         SEC_FILE_READ_DATA);
     147           6 :         io1.smb2.in.alloc_size = 0;
     148           6 :         io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
     149           6 :         io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
     150             :                         NTCREATEX_SHARE_ACCESS_WRITE|
     151             :                         NTCREATEX_SHARE_ACCESS_DELETE;
     152           6 :         io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
     153           6 :         io1.smb2.in.create_options = 0;
     154           6 :         io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
     155           6 :         io1.smb2.in.security_flags = 0;
     156           6 :         io1.smb2.in.fname = fname1;
     157             : 
     158           6 :         torture_comment(tctx, "TEST2: open a file with an batch "
     159             :                         "oplock (share mode: all)\n");
     160           6 :         io1.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
     161             : 
     162           6 :         status = smb2_create(tree, tctx, &(io1.smb2));
     163           6 :         torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
     164             : 
     165           6 :         h1 = io1.smb2.out.file.handle;
     166             : 
     167           6 :         torture_comment(tctx, "TEST2: Opening second time with compound\n");
     168             : 
     169           6 :         ZERO_STRUCT(io2);
     170             : 
     171           6 :         io2.in.desired_access = (SEC_STD_SYNCHRONIZE|
     172             :                                 SEC_FILE_READ_ATTRIBUTE|
     173             :                                 SEC_FILE_READ_EA);
     174           6 :         io2.in.alloc_size = 0;
     175           6 :         io2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
     176           6 :         io2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
     177             :                         NTCREATEX_SHARE_ACCESS_WRITE|
     178             :                         NTCREATEX_SHARE_ACCESS_DELETE;
     179           6 :         io2.in.create_disposition = NTCREATEX_DISP_OPEN;
     180           6 :         io2.in.create_options = 0;
     181           6 :         io2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
     182           6 :         io2.in.security_flags = 0;
     183           6 :         io2.in.fname = fname1;
     184           6 :         io2.in.oplock_level = 0;
     185             : 
     186           6 :         smb2_transport_compound_start(tree->session->transport, 2);
     187             : 
     188           6 :         req[0] = smb2_create_send(tree, &io2);
     189             : 
     190           6 :         smb2_transport_compound_set_related(tree->session->transport, true);
     191             : 
     192           6 :         h.data[0] = UINT64_MAX;
     193           6 :         h.data[1] = UINT64_MAX;
     194             : 
     195           6 :         ZERO_STRUCT(gf);
     196           6 :         gf.in.file.handle = h;
     197           6 :         gf.in.info_type = SMB2_0_INFO_FILE;
     198           6 :         gf.in.info_class = 0x16;
     199           6 :         gf.in.output_buffer_length = 0x1000;
     200           6 :         gf.in.input_buffer = data_blob_null;
     201             : 
     202           6 :         req[1] = smb2_getinfo_send(tree, &gf);
     203             : 
     204           6 :         status = smb2_create_recv(req[0], tree, &io2);
     205           6 :         CHECK_STATUS(status, NT_STATUS_OK);
     206             : 
     207           6 :         status = smb2_getinfo_recv(req[1], tree, &gf);
     208           6 :         CHECK_STATUS(status, NT_STATUS_OK);
     209             : 
     210           6 : done:
     211             : 
     212           6 :         smb2_util_close(tree, h1);
     213           6 :         smb2_util_unlink(tree, fname1);
     214           6 :         return ret;
     215             : }
     216             : 
     217           6 : static bool test_compound_related1(struct torture_context *tctx,
     218             :                                    struct smb2_tree *tree)
     219             : {
     220           0 :         struct smb2_handle hd;
     221           0 :         struct smb2_create cr;
     222           0 :         NTSTATUS status;
     223           6 :         const char *fname = "compound_related1.dat";
     224           0 :         struct smb2_close cl;
     225           6 :         bool ret = true;
     226           0 :         struct smb2_request *req[2];
     227           6 :         struct smbXcli_tcon *saved_tcon = tree->smbXcli;
     228           6 :         struct smbXcli_session *saved_session = tree->session->smbXcli;
     229             : 
     230           6 :         smb2_transport_credits_ask_num(tree->session->transport, 2);
     231             : 
     232           6 :         smb2_util_unlink(tree, fname);
     233             : 
     234           6 :         smb2_transport_credits_ask_num(tree->session->transport, 1);
     235             : 
     236           6 :         ZERO_STRUCT(cr);
     237           6 :         cr.in.security_flags            = 0x00;
     238           6 :         cr.in.oplock_level              = 0;
     239           6 :         cr.in.impersonation_level       = NTCREATEX_IMPERSONATION_IMPERSONATION;
     240           6 :         cr.in.create_flags              = 0x00000000;
     241           6 :         cr.in.reserved                  = 0x00000000;
     242           6 :         cr.in.desired_access            = SEC_RIGHTS_FILE_ALL;
     243           6 :         cr.in.file_attributes           = FILE_ATTRIBUTE_NORMAL;
     244           6 :         cr.in.share_access              = NTCREATEX_SHARE_ACCESS_READ |
     245             :                                           NTCREATEX_SHARE_ACCESS_WRITE |
     246             :                                           NTCREATEX_SHARE_ACCESS_DELETE;
     247           6 :         cr.in.create_disposition        = NTCREATEX_DISP_OPEN_IF;
     248           6 :         cr.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
     249             :                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
     250             :                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
     251             :                                           0x00200000;
     252           6 :         cr.in.fname                     = fname;
     253             : 
     254           6 :         smb2_transport_compound_start(tree->session->transport, 2);
     255             : 
     256           6 :         req[0] = smb2_create_send(tree, &cr);
     257             : 
     258           6 :         smb2_transport_compound_set_related(tree->session->transport, true);
     259             : 
     260           6 :         hd.data[0] = UINT64_MAX;
     261           6 :         hd.data[1] = UINT64_MAX;
     262             : 
     263           6 :         ZERO_STRUCT(cl);
     264           6 :         cl.in.file.handle = hd;
     265             : 
     266           6 :         tree->smbXcli = smbXcli_tcon_create(tree);
     267           6 :         smb2cli_tcon_set_values(tree->smbXcli,
     268             :                                 NULL, /* session */
     269             :                                 0xFFFFFFFF, /* tcon_id */
     270             :                                 0, /* type */
     271             :                                 0, /* flags */
     272             :                                 0, /* capabilities */
     273             :                                 0 /* maximal_access */);
     274             : 
     275          12 :         tree->session->smbXcli = smbXcli_session_shallow_copy(tree->session,
     276           6 :                                                         tree->session->smbXcli);
     277           6 :         smb2cli_session_set_id_and_flags(tree->session->smbXcli, UINT64_MAX, 0);
     278             : 
     279           6 :         req[1] = smb2_close_send(tree, &cl);
     280             : 
     281           6 :         status = smb2_create_recv(req[0], tree, &cr);
     282           6 :         CHECK_STATUS(status, NT_STATUS_OK);
     283           6 :         status = smb2_close_recv(req[1], &cl);
     284           6 :         CHECK_STATUS(status, NT_STATUS_OK);
     285             : 
     286           6 :         TALLOC_FREE(tree->smbXcli);
     287           6 :         tree->smbXcli = saved_tcon;
     288           6 :         TALLOC_FREE(tree->session->smbXcli);
     289           6 :         tree->session->smbXcli = saved_session;
     290             : 
     291           6 :         smb2_util_unlink(tree, fname);
     292           6 : done:
     293           6 :         return ret;
     294             : }
     295             : 
     296           6 : static bool test_compound_related2(struct torture_context *tctx,
     297             :                                    struct smb2_tree *tree)
     298             : {
     299           0 :         struct smb2_handle hd;
     300           0 :         struct smb2_create cr;
     301           0 :         NTSTATUS status;
     302           6 :         const char *fname = "compound_related2.dat";
     303           0 :         struct smb2_close cl;
     304           6 :         bool ret = true;
     305           0 :         struct smb2_request *req[5];
     306           6 :         struct smbXcli_tcon *saved_tcon = tree->smbXcli;
     307           6 :         struct smbXcli_session *saved_session = tree->session->smbXcli;
     308             : 
     309           6 :         smb2_transport_credits_ask_num(tree->session->transport, 5);
     310             : 
     311           6 :         smb2_util_unlink(tree, fname);
     312             : 
     313           6 :         smb2_transport_credits_ask_num(tree->session->transport, 1);
     314             : 
     315           6 :         ZERO_STRUCT(cr);
     316           6 :         cr.in.security_flags            = 0x00;
     317           6 :         cr.in.oplock_level              = 0;
     318           6 :         cr.in.impersonation_level       = NTCREATEX_IMPERSONATION_IMPERSONATION;
     319           6 :         cr.in.create_flags              = 0x00000000;
     320           6 :         cr.in.reserved                  = 0x00000000;
     321           6 :         cr.in.desired_access            = SEC_RIGHTS_FILE_ALL;
     322           6 :         cr.in.file_attributes           = FILE_ATTRIBUTE_NORMAL;
     323           6 :         cr.in.share_access              = NTCREATEX_SHARE_ACCESS_READ |
     324             :                                           NTCREATEX_SHARE_ACCESS_WRITE |
     325             :                                           NTCREATEX_SHARE_ACCESS_DELETE;
     326           6 :         cr.in.create_disposition        = NTCREATEX_DISP_OPEN_IF;
     327           6 :         cr.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
     328             :                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
     329             :                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
     330             :                                           0x00200000;
     331           6 :         cr.in.fname                     = fname;
     332             : 
     333           6 :         smb2_transport_compound_start(tree->session->transport, 5);
     334             : 
     335           6 :         req[0] = smb2_create_send(tree, &cr);
     336             : 
     337           6 :         hd.data[0] = UINT64_MAX;
     338           6 :         hd.data[1] = UINT64_MAX;
     339             : 
     340           6 :         smb2_transport_compound_set_related(tree->session->transport, true);
     341             : 
     342           6 :         ZERO_STRUCT(cl);
     343           6 :         cl.in.file.handle = hd;
     344             : 
     345           6 :         tree->smbXcli = smbXcli_tcon_create(tree);
     346           6 :         smb2cli_tcon_set_values(tree->smbXcli,
     347             :                                 NULL, /* session */
     348             :                                 0xFFFFFFFF, /* tcon_id */
     349             :                                 0, /* type */
     350             :                                 0, /* flags */
     351             :                                 0, /* capabilities */
     352             :                                 0 /* maximal_access */);
     353             : 
     354          12 :         tree->session->smbXcli = smbXcli_session_shallow_copy(tree->session,
     355           6 :                                                         tree->session->smbXcli);
     356           6 :         smb2cli_session_set_id_and_flags(tree->session->smbXcli, UINT64_MAX, 0);
     357             : 
     358           6 :         req[1] = smb2_close_send(tree, &cl);
     359           6 :         req[2] = smb2_close_send(tree, &cl);
     360           6 :         req[3] = smb2_close_send(tree, &cl);
     361           6 :         req[4] = smb2_close_send(tree, &cl);
     362             : 
     363           6 :         status = smb2_create_recv(req[0], tree, &cr);
     364           6 :         CHECK_STATUS(status, NT_STATUS_OK);
     365           6 :         status = smb2_close_recv(req[1], &cl);
     366           6 :         CHECK_STATUS(status, NT_STATUS_OK);
     367           6 :         status = smb2_close_recv(req[2], &cl);
     368           6 :         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
     369           6 :         status = smb2_close_recv(req[3], &cl);
     370           6 :         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
     371           6 :         status = smb2_close_recv(req[4], &cl);
     372           6 :         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
     373             : 
     374           6 :         TALLOC_FREE(tree->smbXcli);
     375           6 :         tree->smbXcli = saved_tcon;
     376           6 :         TALLOC_FREE(tree->session->smbXcli);
     377           6 :         tree->session->smbXcli = saved_session;
     378             : 
     379           6 :         smb2_util_unlink(tree, fname);
     380           6 : done:
     381           6 :         return ret;
     382             : }
     383             : 
     384           6 : static bool test_compound_related3(struct torture_context *tctx,
     385             :                                    struct smb2_tree *tree)
     386             : {
     387           0 :         struct smb2_handle hd;
     388           0 :         struct smb2_ioctl io;
     389           0 :         struct smb2_create cr;
     390           0 :         struct smb2_close cl;
     391           6 :         const char *fname = "compound_related3.dat";
     392           0 :         struct smb2_request *req[3];
     393           0 :         NTSTATUS status;
     394           6 :         bool ret = false;
     395             : 
     396           6 :         smb2_util_unlink(tree, fname);
     397             : 
     398           6 :         ZERO_STRUCT(cr);
     399           6 :         cr.in.security_flags    = 0x00;
     400           6 :         cr.in.oplock_level      = 0;
     401           6 :         cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
     402           6 :         cr.in.create_flags      = 0x00000000;
     403           6 :         cr.in.reserved          = 0x00000000;
     404           6 :         cr.in.desired_access    = SEC_RIGHTS_FILE_ALL;
     405           6 :         cr.in.file_attributes   = FILE_ATTRIBUTE_NORMAL;
     406           6 :         cr.in.share_access      = NTCREATEX_SHARE_ACCESS_READ |
     407             :                                   NTCREATEX_SHARE_ACCESS_WRITE |
     408             :                                   NTCREATEX_SHARE_ACCESS_DELETE;
     409           6 :         cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
     410           6 :         cr.in.create_options    = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
     411             :                                   NTCREATEX_OPTIONS_ASYNC_ALERT |
     412             :                                   NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
     413             :                                   0x00200000;
     414           6 :         cr.in.fname             = fname;
     415             : 
     416           6 :         smb2_transport_compound_start(tree->session->transport, 3);
     417             : 
     418           6 :         req[0] = smb2_create_send(tree, &cr);
     419             : 
     420           6 :         hd.data[0] = UINT64_MAX;
     421           6 :         hd.data[1] = UINT64_MAX;
     422             : 
     423           6 :         smb2_transport_compound_set_related(tree->session->transport, true);
     424             : 
     425           6 :         ZERO_STRUCT(io);
     426           6 :         io.in.function = FSCTL_CREATE_OR_GET_OBJECT_ID;
     427           6 :         io.in.file.handle = hd;
     428           6 :         io.in.reserved2 = 0;
     429           6 :         io.in.max_output_response = 64;
     430           6 :         io.in.flags = 1;
     431             : 
     432           6 :         req[1] = smb2_ioctl_send(tree, &io);
     433             : 
     434           6 :         ZERO_STRUCT(cl);
     435           6 :         cl.in.file.handle = hd;
     436             : 
     437           6 :         req[2] = smb2_close_send(tree, &cl);
     438             : 
     439           6 :         status = smb2_create_recv(req[0], tree, &cr);
     440           6 :         CHECK_STATUS(status, NT_STATUS_OK);
     441           6 :         status = smb2_ioctl_recv(req[1], tree, &io);
     442           6 :         CHECK_STATUS(status, NT_STATUS_OK);
     443           6 :         status = smb2_close_recv(req[2], &cl);
     444           6 :         CHECK_STATUS(status, NT_STATUS_OK);
     445             : 
     446           6 :         status = smb2_util_unlink(tree, fname);
     447           6 :         CHECK_STATUS(status, NT_STATUS_OK);
     448             : 
     449           6 :         ret = true;
     450           6 : done:
     451           6 :         return ret;
     452             : }
     453             : 
     454           6 : static bool test_compound_related4(struct torture_context *tctx,
     455             :                         struct smb2_tree *tree)
     456             : {
     457           6 :         const char *fname = "compound_related4.dat";
     458           6 :         struct security_descriptor *sd = NULL;
     459           0 :         struct smb2_handle hd;
     460           0 :         struct smb2_create cr;
     461           0 :         union smb_setfileinfo set;
     462           0 :         struct smb2_ioctl io;
     463           0 :         struct smb2_close cl;
     464           0 :         struct smb2_request *req[4];
     465           0 :         NTSTATUS status;
     466           6 :         bool ret = true;
     467             : 
     468           6 :         smb2_util_unlink(tree, fname);
     469             : 
     470           6 :         ZERO_STRUCT(cr);
     471           6 :         cr.level = RAW_OPEN_SMB2;
     472           6 :         cr.in.create_flags = 0;
     473           6 :         cr.in.desired_access = SEC_STD_READ_CONTROL |
     474             :                                 SEC_STD_WRITE_DAC |
     475             :                                 SEC_STD_WRITE_OWNER;
     476           6 :         cr.in.create_options = 0;
     477           6 :         cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
     478           6 :         cr.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
     479             :                                 NTCREATEX_SHARE_ACCESS_READ |
     480             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
     481           6 :         cr.in.alloc_size = 0;
     482           6 :         cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
     483           6 :         cr.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
     484           6 :         cr.in.security_flags = 0;
     485           6 :         cr.in.fname = fname;
     486             : 
     487           6 :         status = smb2_create(tree, tctx, &cr);
     488           6 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed\n");
     489             : 
     490           6 :         hd = cr.out.file.handle;
     491           6 :         torture_comment(tctx, "set a sec desc allowing no write by CREATOR_OWNER\n");
     492             : 
     493           6 :         sd = security_descriptor_dacl_create(tctx,
     494             :                         0, NULL, NULL,
     495             :                         SID_CREATOR_OWNER,
     496             :                         SEC_ACE_TYPE_ACCESS_ALLOWED,
     497             :                         SEC_RIGHTS_FILE_READ | SEC_STD_ALL,
     498             :                         0,
     499             :                         NULL);
     500           6 :         torture_assert_not_null_goto(tctx, sd, ret, done,
     501             :                                      "security_descriptor_dacl_create failed\n");
     502             : 
     503           6 :         set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
     504           6 :         set.set_secdesc.in.file.handle = hd;
     505           6 :         set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
     506           6 :         set.set_secdesc.in.sd = sd;
     507             : 
     508           6 :         status = smb2_setinfo_file(tree, &set);
     509           6 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     510             :                                         "smb2_setinfo_file failed\n");
     511             : 
     512           6 :         torture_comment(tctx, "try open for write\n");
     513           6 :         cr.in.desired_access = SEC_FILE_WRITE_DATA;
     514           6 :         smb2_transport_compound_start(tree->session->transport, 4);
     515             : 
     516           6 :         req[0] = smb2_create_send(tree, &cr);
     517           6 :         torture_assert_not_null_goto(tctx, req[0], ret, done,
     518             :                                      "smb2_create_send failed\n");
     519             : 
     520           6 :         hd.data[0] = UINT64_MAX;
     521           6 :         hd.data[1] = UINT64_MAX;
     522             : 
     523           6 :         smb2_transport_compound_set_related(tree->session->transport, true);
     524           6 :         ZERO_STRUCT(io);
     525           6 :         io.in.function = FSCTL_CREATE_OR_GET_OBJECT_ID;
     526           6 :         io.in.file.handle = hd;
     527           6 :         io.in.flags = 1;
     528             : 
     529           6 :         req[1] = smb2_ioctl_send(tree, &io);
     530           6 :         torture_assert_not_null_goto(tctx, req[1], ret, done,
     531             :                                      "smb2_ioctl_send failed\n");
     532             : 
     533           6 :         ZERO_STRUCT(cl);
     534           6 :         cl.in.file.handle = hd;
     535             : 
     536           6 :         req[2] = smb2_close_send(tree, &cl);
     537           6 :         torture_assert_not_null_goto(tctx, req[2], ret, done,
     538             :                                      "smb2_create_send failed\n");
     539             : 
     540           6 :         set.set_secdesc.in.file.handle = hd;
     541             : 
     542           6 :         req[3] = smb2_setinfo_file_send(tree, &set);
     543           6 :         torture_assert_not_null_goto(tctx, req[3], ret, done,
     544             :                                      "smb2_create_send failed\n");
     545             : 
     546           6 :         status = smb2_create_recv(req[0], tree, &cr);
     547           6 :         torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
     548             :                                            ret, done,
     549             :                                            "smb2_create_recv failed\n");
     550             : 
     551           6 :         status = smb2_ioctl_recv(req[1], tree, &io);
     552           6 :         torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
     553             :                                            ret, done,
     554             :                                            "smb2_ioctl_recv failed\n");
     555             : 
     556           6 :         status = smb2_close_recv(req[2], &cl);
     557           6 :         torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
     558             :                                            ret, done,
     559             :                                            "smb2_close_recv failed\n");
     560             : 
     561           6 :         status = smb2_setinfo_recv(req[3]);
     562           6 :         torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
     563             :                                            ret, done,
     564             :                                            "smb2_setinfo_recv failed\n");
     565             : 
     566           6 : done:
     567           6 :         smb2_util_unlink(tree, fname);
     568           6 :         smb2_tdis(tree);
     569           6 :         smb2_logoff(tree->session);
     570           6 :         return ret;
     571             : }
     572             : 
     573           6 : static bool test_compound_related5(struct torture_context *tctx,
     574             :                                    struct smb2_tree *tree)
     575             : {
     576           0 :         struct smb2_handle hd;
     577           0 :         struct smb2_ioctl io;
     578           0 :         struct smb2_close cl;
     579           0 :         struct smb2_request *req[2];
     580           0 :         NTSTATUS status;
     581           6 :         bool ret = false;
     582             : 
     583           6 :         smb2_transport_compound_start(tree->session->transport, 2);
     584             : 
     585           6 :         hd.data[0] = UINT64_MAX;
     586           6 :         hd.data[1] = UINT64_MAX;
     587             : 
     588           6 :         ZERO_STRUCT(io);
     589           6 :         io.in.function = FSCTL_CREATE_OR_GET_OBJECT_ID;
     590           6 :         io.in.file.handle = hd;
     591           6 :         io.in.flags = 1;
     592             : 
     593           6 :         req[0] = smb2_ioctl_send(tree, &io);
     594           6 :         torture_assert_not_null_goto(tctx, req[0], ret, done,
     595             :                                      "smb2_ioctl_send failed\n");
     596             : 
     597           6 :         smb2_transport_compound_set_related(tree->session->transport, true);
     598             : 
     599           6 :         ZERO_STRUCT(cl);
     600           6 :         cl.in.file.handle = hd;
     601             : 
     602           6 :         req[1] = smb2_close_send(tree, &cl);
     603           6 :         torture_assert_not_null_goto(tctx, req[1], ret, done,
     604             :                                      "smb2_create_send failed\n");
     605             : 
     606           6 :         status = smb2_ioctl_recv(req[0], tree, &io);
     607           6 :         torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_FILE_CLOSED,
     608             :                                            ret, done,
     609             :                                            "smb2_ioctl_recv failed\n");
     610             : 
     611           6 :         status = smb2_close_recv(req[1], &cl);
     612           6 :         torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_FILE_CLOSED,
     613             :                                            ret, done,
     614             :                                            "smb2_close_recv failed\n");
     615             : 
     616           6 :         ret = true;
     617             : 
     618           6 : done:
     619           6 :         smb2_tdis(tree);
     620           6 :         smb2_logoff(tree->session);
     621           6 :         return ret;
     622             : }
     623             : 
     624           6 : static bool test_compound_related6(struct torture_context *tctx,
     625             :                                 struct smb2_tree *tree)
     626             : {
     627           0 :         struct smb2_handle hd;
     628           0 :         struct smb2_create cr;
     629           0 :         struct smb2_read rd;
     630           0 :         struct smb2_write wr;
     631           0 :         struct smb2_close cl;
     632           0 :         NTSTATUS status;
     633           6 :         const char *fname = "compound_related6.dat";
     634           0 :         struct smb2_request *req[5];
     635           0 :         uint8_t buf[64];
     636           6 :         bool ret = true;
     637             : 
     638           6 :         smb2_util_unlink(tree, fname);
     639             : 
     640           6 :         ZERO_STRUCT(cr);
     641           6 :         cr.level = RAW_OPEN_SMB2;
     642           6 :         cr.in.create_flags = 0;
     643           6 :         cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
     644           6 :         cr.in.create_options = 0;
     645           6 :         cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
     646           6 :         cr.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
     647             :                                 NTCREATEX_SHARE_ACCESS_READ |
     648             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
     649           6 :         cr.in.alloc_size = 0;
     650           6 :         cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
     651           6 :         cr.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
     652           6 :         cr.in.security_flags = 0;
     653           6 :         cr.in.fname = fname;
     654             : 
     655           6 :         status = smb2_create(tree, tctx, &cr);
     656           6 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     657             :                                         "smb2_create failed\n");
     658             : 
     659           6 :         hd = cr.out.file.handle;
     660             : 
     661           6 :         ZERO_STRUCT(buf);
     662           6 :         status = smb2_util_write(tree, hd, buf, 0, ARRAY_SIZE(buf));
     663           6 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     664             :                                         "smb2_util_write failed\n");
     665             : 
     666           6 :         torture_comment(tctx, "try open for read\n");
     667           6 :         cr.in.desired_access = SEC_FILE_READ_DATA;
     668           6 :         smb2_transport_compound_start(tree->session->transport, 5);
     669             : 
     670           6 :         req[0] = smb2_create_send(tree, &cr);
     671           6 :         torture_assert_not_null_goto(tctx, req[0], ret, done,
     672             :                                      "smb2_create_send failed\n");
     673             : 
     674           6 :         hd.data[0] = UINT64_MAX;
     675           6 :         hd.data[1] = UINT64_MAX;
     676             : 
     677           6 :         smb2_transport_compound_set_related(tree->session->transport, true);
     678             : 
     679           6 :         ZERO_STRUCT(rd);
     680           6 :         rd.in.file.handle = hd;
     681           6 :         rd.in.length      = 1;
     682           6 :         rd.in.offset      = 0;
     683             : 
     684           6 :         req[1] = smb2_read_send(tree, &rd);
     685           6 :         torture_assert_not_null_goto(tctx, req[1], ret, done,
     686             :                                      "smb2_read_send failed\n");
     687             : 
     688           6 :         ZERO_STRUCT(wr);
     689           6 :         wr.in.file.handle = hd;
     690           6 :         wr.in.offset = 0;
     691           6 :         wr.in.data = data_blob_talloc(tctx, NULL, 64);
     692             : 
     693           6 :         req[2] = smb2_write_send(tree, &wr);
     694           6 :         torture_assert_not_null_goto(tctx, req[2], ret, done,
     695             :                                      "smb2_write_send failed\n");
     696             : 
     697           6 :         ZERO_STRUCT(rd);
     698           6 :         rd.in.file.handle = hd;
     699           6 :         rd.in.length      = 1;
     700           6 :         rd.in.offset      = 0;
     701             : 
     702           6 :         req[3] = smb2_read_send(tree, &rd);
     703           6 :         torture_assert_not_null_goto(tctx, req[3], ret, done,
     704             :                                      "smb2_read_send failed\n");
     705             : 
     706           6 :         ZERO_STRUCT(cl);
     707           6 :         cl.in.file.handle = hd;
     708             : 
     709           6 :         req[4] = smb2_close_send(tree, &cl);
     710           6 :         torture_assert_not_null_goto(tctx, req[4], ret, done,
     711             :                                      "smb2_close_send failed\n");
     712             : 
     713           6 :         status = smb2_create_recv(req[0], tree, &cr);
     714           6 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     715             :                                         "smb2_create_recv failed\n");
     716             : 
     717           6 :         status = smb2_read_recv(req[1], tree, &rd);
     718           6 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     719             :                                         "smb2_read_recv failed\n");
     720             : 
     721           6 :         status = smb2_write_recv(req[2], &wr);
     722           6 :         torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
     723             :                                            ret, done,
     724             :                                            "smb2_write_recv failed\n");
     725             : 
     726           6 :         status = smb2_read_recv(req[3], tree, &rd);
     727           6 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     728             :                                         "smb2_read_recv failed\n");
     729             : 
     730           6 :         status = smb2_close_recv(req[4], &cl);
     731           6 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     732             :                                         "smb2_close_recv failed\n");
     733             : 
     734           6 :   done:
     735           6 :         smb2_util_unlink(tree, fname);
     736           6 :         smb2_tdis(tree);
     737           6 :         smb2_logoff(tree->session);
     738           6 :         return ret;
     739             : }
     740             : 
     741           6 : static bool test_compound_related7(struct torture_context *tctx,
     742             :                         struct smb2_tree *tree)
     743             : {
     744           6 :         const char *fname = "compound_related4.dat";
     745           6 :         struct security_descriptor *sd = NULL;
     746           0 :         struct smb2_handle hd;
     747           0 :         struct smb2_create cr;
     748           0 :         union smb_setfileinfo set;
     749           0 :         struct smb2_notify nt;
     750           0 :         struct smb2_close cl;
     751           0 :         NTSTATUS status;
     752           0 :         struct smb2_request *req[4];
     753           6 :         bool ret = true;
     754             : 
     755           6 :         smb2_util_unlink(tree, fname);
     756             : 
     757           6 :         ZERO_STRUCT(cr);
     758           6 :         cr.level = RAW_OPEN_SMB2;
     759           6 :         cr.in.create_flags = 0;
     760           6 :         cr.in.desired_access = SEC_STD_READ_CONTROL |
     761             :                                 SEC_STD_WRITE_DAC |
     762             :                                 SEC_STD_WRITE_OWNER;
     763           6 :         cr.in.create_options = 0;
     764           6 :         cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
     765           6 :         cr.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
     766             :                                 NTCREATEX_SHARE_ACCESS_READ |
     767             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
     768           6 :         cr.in.alloc_size = 0;
     769           6 :         cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
     770           6 :         cr.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
     771           6 :         cr.in.security_flags = 0;
     772           6 :         cr.in.fname = fname;
     773             : 
     774           6 :         status = smb2_create(tree, tctx, &cr);
     775           6 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     776             :                                         "smb2_create failed\n");
     777             : 
     778           6 :         hd = cr.out.file.handle;
     779           6 :         torture_comment(tctx, "set a sec desc allowing no write by CREATOR_OWNER\n");
     780           6 :         sd = security_descriptor_dacl_create(tctx,
     781             :                         0, NULL, NULL,
     782             :                         SID_CREATOR_OWNER,
     783             :                         SEC_ACE_TYPE_ACCESS_ALLOWED,
     784             :                         SEC_RIGHTS_FILE_READ | SEC_STD_ALL,
     785             :                         0,
     786             :                         NULL);
     787           6 :         torture_assert_not_null_goto(tctx, sd, ret, done,
     788             :                                      "security_descriptor_dacl_create failed\n");
     789             : 
     790           6 :         set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
     791           6 :         set.set_secdesc.in.file.handle = hd;
     792           6 :         set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
     793           6 :         set.set_secdesc.in.sd = sd;
     794             : 
     795           6 :         status = smb2_setinfo_file(tree, &set);
     796           6 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     797             :                                         "smb2_setinfo_file failed\n");
     798             : 
     799           6 :         torture_comment(tctx, "try open for write\n");
     800           6 :         cr.in.desired_access = SEC_FILE_WRITE_DATA;
     801           6 :         smb2_transport_compound_start(tree->session->transport, 4);
     802             : 
     803           6 :         req[0] = smb2_create_send(tree, &cr);
     804           6 :         torture_assert_not_null_goto(tctx, req[0], ret, done,
     805             :                                      "smb2_create_send failed\n");
     806             : 
     807           6 :         hd.data[0] = UINT64_MAX;
     808           6 :         hd.data[1] = UINT64_MAX;
     809             : 
     810           6 :         smb2_transport_compound_set_related(tree->session->transport, true);
     811             : 
     812           6 :         ZERO_STRUCT(nt);
     813           6 :         nt.in.recursive          = true;
     814           6 :         nt.in.buffer_size        = 0x1000;
     815           6 :         nt.in.file.handle        = hd;
     816           6 :         nt.in.completion_filter  = FILE_NOTIFY_CHANGE_NAME;
     817           6 :         nt.in.unknown            = 0x00000000;
     818             : 
     819           6 :         req[1] = smb2_notify_send(tree, &nt);
     820           6 :         torture_assert_not_null_goto(tctx, req[1], ret, done,
     821             :                                      "smb2_notify_send failed\n");
     822             : 
     823           6 :         ZERO_STRUCT(cl);
     824           6 :         cl.in.file.handle = hd;
     825             : 
     826           6 :         req[2] = smb2_close_send(tree, &cl);
     827           6 :         torture_assert_not_null_goto(tctx, req[2], ret, done,
     828             :                                      "smb2_close_send failed\n");
     829             : 
     830           6 :         set.set_secdesc.in.file.handle = hd;
     831             : 
     832           6 :         req[3] = smb2_setinfo_file_send(tree, &set);
     833           6 :         torture_assert_not_null_goto(tctx, req[3], ret, done,
     834             :                                      "smb2_setinfo_file_send failed\n");
     835             : 
     836           6 :         status = smb2_create_recv(req[0], tree, &cr);
     837           6 :         torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
     838             :                                            ret, done,
     839             :                                            "smb2_create_recv failed\n");
     840             : 
     841           6 :         status = smb2_notify_recv(req[1], tree, &nt);
     842           6 :         torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
     843             :                                            ret, done,
     844             :                                            "smb2_notify_recv failed\n");
     845             : 
     846           6 :         status = smb2_close_recv(req[2], &cl);
     847           6 :         torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
     848             :                                            ret, done,
     849             :                                            "smb2_close_recv failed\n");
     850             : 
     851           6 :         status = smb2_setinfo_recv(req[3]);
     852           6 :         torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
     853             :                                            ret, done,
     854             :                                            "smb2_setinfo_recv failed\n");
     855             : 
     856           6 : done:
     857           6 :         smb2_util_unlink(tree, fname);
     858           6 :         smb2_tdis(tree);
     859           6 :         smb2_logoff(tree->session);
     860           6 :         return ret;
     861             : }
     862             : 
     863           6 : static bool test_compound_related8(struct torture_context *tctx,
     864             :                                    struct smb2_tree *tree)
     865             : {
     866           6 :         const char *fname = "compound_related8.dat";
     867           6 :         const char *fname_nonexisting = "compound_related8.dat.void";
     868           6 :         struct security_descriptor *sd = NULL;
     869           0 :         struct smb2_handle hd;
     870           0 :         struct smb2_create cr;
     871           0 :         union smb_setfileinfo set;
     872           0 :         struct smb2_notify nt;
     873           0 :         struct smb2_close cl;
     874           0 :         NTSTATUS status;
     875           0 :         struct smb2_request *req[4];
     876           6 :         bool ret = true;
     877             : 
     878           6 :         smb2_util_unlink(tree, fname);
     879             : 
     880           6 :         ZERO_STRUCT(cr);
     881           6 :         cr.level = RAW_OPEN_SMB2;
     882           6 :         cr.in.create_flags = 0;
     883           6 :         cr.in.desired_access = SEC_STD_READ_CONTROL |
     884             :                                 SEC_STD_WRITE_DAC |
     885             :                                 SEC_STD_WRITE_OWNER;
     886           6 :         cr.in.create_options = 0;
     887           6 :         cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
     888           6 :         cr.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
     889             :                                 NTCREATEX_SHARE_ACCESS_READ |
     890             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
     891           6 :         cr.in.alloc_size = 0;
     892           6 :         cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
     893           6 :         cr.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
     894           6 :         cr.in.security_flags = 0;
     895           6 :         cr.in.fname = fname;
     896             : 
     897           6 :         status = smb2_create(tree, tctx, &cr);
     898           6 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     899             :                                         "smb2_create failed\n");
     900             : 
     901           6 :         hd = cr.out.file.handle;
     902             : 
     903           6 :         smb2_transport_compound_start(tree->session->transport, 4);
     904             : 
     905           6 :         torture_comment(tctx, "try open for write\n");
     906           6 :         cr.in.fname = fname_nonexisting;
     907           6 :         cr.in.create_disposition = NTCREATEX_DISP_OPEN;
     908             : 
     909           6 :         req[0] = smb2_create_send(tree, &cr);
     910           6 :         torture_assert_not_null_goto(tctx, req[0], ret, done,
     911             :                                      "smb2_create_send failed\n");
     912             : 
     913           6 :         hd.data[0] = UINT64_MAX;
     914           6 :         hd.data[1] = UINT64_MAX;
     915             : 
     916           6 :         smb2_transport_compound_set_related(tree->session->transport, true);
     917             : 
     918           6 :         ZERO_STRUCT(nt);
     919           6 :         nt.in.recursive          = true;
     920           6 :         nt.in.buffer_size        = 0x1000;
     921           6 :         nt.in.file.handle        = hd;
     922           6 :         nt.in.completion_filter  = FILE_NOTIFY_CHANGE_NAME;
     923           6 :         nt.in.unknown            = 0x00000000;
     924             : 
     925           6 :         req[1] = smb2_notify_send(tree, &nt);
     926           6 :         torture_assert_not_null_goto(tctx, req[1], ret, done,
     927             :                                      "smb2_notify_send failed\n");
     928             : 
     929           6 :         ZERO_STRUCT(cl);
     930           6 :         cl.in.file.handle = hd;
     931             : 
     932           6 :         req[2] = smb2_close_send(tree, &cl);
     933           6 :         torture_assert_not_null_goto(tctx, req[2], ret, done,
     934             :                                      "smb2_close_send failed\n");
     935             : 
     936           6 :         sd = security_descriptor_dacl_create(tctx,
     937             :                         0, NULL, NULL,
     938             :                         SID_CREATOR_OWNER,
     939             :                         SEC_ACE_TYPE_ACCESS_ALLOWED,
     940             :                         SEC_RIGHTS_FILE_READ | SEC_STD_ALL,
     941             :                         0,
     942             :                         NULL);
     943           6 :         torture_assert_not_null_goto(tctx, sd, ret, done,
     944             :                                      "security_descriptor_dacl_create failed\n");
     945             : 
     946           6 :         set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
     947           6 :         set.set_secdesc.in.file.handle = hd;
     948           6 :         set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
     949           6 :         set.set_secdesc.in.sd = sd;
     950             : 
     951           6 :         req[3] = smb2_setinfo_file_send(tree, &set);
     952           6 :         torture_assert_not_null_goto(tctx, req[3], ret, done,
     953             :                                      "smb2_setinfo_file_send failed\n");
     954             : 
     955           6 :         status = smb2_create_recv(req[0], tree, &cr);
     956           6 :         torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
     957             :                                            ret, done,
     958             :                                            "smb2_create_recv failed\n");
     959             : 
     960           6 :         status = smb2_notify_recv(req[1], tree, &nt);
     961           6 :         torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
     962             :                                            ret, done,
     963             :                                            "smb2_notify_recv failed\n");
     964             : 
     965           6 :         status = smb2_close_recv(req[2], &cl);
     966           6 :         torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
     967             :                                            ret, done,
     968             :                                            "smb2_close_recv failed\n");
     969             : 
     970           6 :         status = smb2_setinfo_recv(req[3]);
     971           6 :         torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
     972             :                                            ret, done,
     973             :                                            "smb2_setinfo_recv failed\n");
     974             : 
     975           6 : done:
     976           6 :         smb2_util_unlink(tree, fname);
     977           6 :         smb2_tdis(tree);
     978           6 :         smb2_logoff(tree->session);
     979           6 :         return ret;
     980             : }
     981             : 
     982           6 : static bool test_compound_related9(struct torture_context *tctx,
     983             :                                    struct smb2_tree *tree)
     984             : {
     985           6 :         const char *fname = "compound_related9.dat";
     986           6 :         struct security_descriptor *sd = NULL;
     987           0 :         struct smb2_handle hd;
     988           0 :         struct smb2_create cr;
     989           0 :         union smb_setfileinfo set;
     990           0 :         struct smb2_notify nt;
     991           0 :         struct smb2_close cl;
     992           0 :         NTSTATUS status;
     993           0 :         struct smb2_request *req[3];
     994           6 :         bool ret = true;
     995             : 
     996           6 :         smb2_util_unlink(tree, fname);
     997             : 
     998           6 :         ZERO_STRUCT(cr);
     999           6 :         cr.level = RAW_OPEN_SMB2;
    1000           6 :         cr.in.create_flags = 0;
    1001           6 :         cr.in.desired_access = SEC_STD_READ_CONTROL |
    1002             :                                 SEC_STD_WRITE_DAC |
    1003             :                                 SEC_STD_WRITE_OWNER;
    1004           6 :         cr.in.create_options = 0;
    1005           6 :         cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1006           6 :         cr.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
    1007             :                                 NTCREATEX_SHARE_ACCESS_READ |
    1008             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    1009           6 :         cr.in.alloc_size = 0;
    1010           6 :         cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
    1011           6 :         cr.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
    1012           6 :         cr.in.security_flags = 0;
    1013           6 :         cr.in.fname = fname;
    1014             : 
    1015           6 :         status = smb2_create(tree, tctx, &cr);
    1016           6 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1017             :                                         "smb2_create failed\n");
    1018             : 
    1019           6 :         hd = cr.out.file.handle;
    1020             : 
    1021           6 :         smb2_transport_compound_start(tree->session->transport, 3);
    1022           6 :         smb2_transport_compound_set_related(tree->session->transport, true);
    1023             : 
    1024           6 :         ZERO_STRUCT(nt);
    1025           6 :         nt.in.recursive          = true;
    1026           6 :         nt.in.buffer_size        = 0x1000;
    1027           6 :         nt.in.completion_filter  = FILE_NOTIFY_CHANGE_NAME;
    1028             : 
    1029           6 :         req[0] = smb2_notify_send(tree, &nt);
    1030           6 :         torture_assert_not_null_goto(tctx, req[0], ret, done,
    1031             :                                      "smb2_notify_send failed\n");
    1032             : 
    1033           6 :         ZERO_STRUCT(cl);
    1034           6 :         cl.in.file.handle = hd;
    1035             : 
    1036           6 :         req[1] = smb2_close_send(tree, &cl);
    1037           6 :         torture_assert_not_null_goto(tctx, req[1], ret, done,
    1038             :                                      "smb2_close_send failed\n");
    1039             : 
    1040           6 :         sd = security_descriptor_dacl_create(tctx,
    1041             :                         0, NULL, NULL,
    1042             :                         SID_CREATOR_OWNER,
    1043             :                         SEC_ACE_TYPE_ACCESS_ALLOWED,
    1044             :                         SEC_RIGHTS_FILE_READ | SEC_STD_ALL,
    1045             :                         0,
    1046             :                         NULL);
    1047           6 :         torture_assert_not_null_goto(tctx, sd, ret, done,
    1048             :                                      "security_descriptor_dacl_create failed\n");
    1049             : 
    1050           6 :         set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
    1051           6 :         set.set_secdesc.in.file.handle = hd;
    1052           6 :         set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
    1053           6 :         set.set_secdesc.in.sd = sd;
    1054             : 
    1055           6 :         req[2] = smb2_setinfo_file_send(tree, &set);
    1056           6 :         torture_assert_not_null_goto(tctx, req[2], ret, done,
    1057             :                                      "smb2_setinfo_file_send failed\n");
    1058             : 
    1059           6 :         status = smb2_notify_recv(req[0], tree, &nt);
    1060           6 :         torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_INVALID_PARAMETER,
    1061             :                                            ret, done,
    1062             :                                            "smb2_notify_recv failed\n");
    1063             : 
    1064           6 :         status = smb2_close_recv(req[1], &cl);
    1065           6 :         torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_INVALID_PARAMETER,
    1066             :                                            ret, done,
    1067             :                                            "smb2_close_recv failed\n");
    1068             : 
    1069           6 :         status = smb2_setinfo_recv(req[2]);
    1070           6 :         torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_INVALID_PARAMETER,
    1071             :                                            ret, done,
    1072             :                                            "smb2_setinfo_recv failed\n");
    1073             : 
    1074           6 : done:
    1075           6 :         smb2_util_unlink(tree, fname);
    1076           6 :         smb2_tdis(tree);
    1077           6 :         smb2_logoff(tree->session);
    1078           6 :         return ret;
    1079             : }
    1080             : 
    1081           6 : static bool test_compound_padding(struct torture_context *tctx,
    1082             :                                   struct smb2_tree *tree)
    1083             : {
    1084           0 :         struct smb2_handle h;
    1085           0 :         struct smb2_create cr;
    1086           0 :         struct smb2_read r;
    1087           0 :         struct smb2_read r2;
    1088           6 :         const char *fname = "compound_read.dat";
    1089           6 :         const char *sname = "compound_read.dat:foo";
    1090           0 :         struct smb2_request *req[3];
    1091           0 :         NTSTATUS status;
    1092           6 :         bool ret = false;
    1093             : 
    1094           6 :         smb2_util_unlink(tree, fname);
    1095             : 
    1096             :         /* Write file */
    1097           6 :         ZERO_STRUCT(cr);
    1098           6 :         cr.in.desired_access = SEC_FILE_WRITE_DATA;
    1099           6 :         cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1100           6 :         cr.in.create_disposition = NTCREATEX_DISP_CREATE;
    1101           6 :         cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1102           6 :         cr.in.fname = fname;
    1103           6 :         cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
    1104             :                 NTCREATEX_SHARE_ACCESS_WRITE|
    1105             :                 NTCREATEX_SHARE_ACCESS_DELETE;
    1106           6 :         status = smb2_create(tree, tctx, &cr);
    1107           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    1108           6 :         h = cr.out.file.handle;
    1109             : 
    1110           6 :         status = smb2_util_write(tree, h, "123", 0, 3);
    1111           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    1112             : 
    1113           6 :         smb2_util_close(tree, h);
    1114             : 
    1115             :         /* Write stream */
    1116           6 :         ZERO_STRUCT(cr);
    1117           6 :         cr.in.desired_access = SEC_FILE_WRITE_DATA;
    1118           6 :         cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1119           6 :         cr.in.create_disposition = NTCREATEX_DISP_CREATE;
    1120           6 :         cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1121           6 :         cr.in.fname = sname;
    1122           6 :         cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
    1123             :                 NTCREATEX_SHARE_ACCESS_WRITE|
    1124             :                 NTCREATEX_SHARE_ACCESS_DELETE;
    1125           6 :         status = smb2_create(tree, tctx, &cr);
    1126           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    1127           6 :         h = cr.out.file.handle;
    1128             : 
    1129           6 :         status = smb2_util_write(tree, h, "456", 0, 3);
    1130           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    1131             : 
    1132           6 :         smb2_util_close(tree, h);
    1133             : 
    1134             :         /* Check compound read from basefile */
    1135           6 :         smb2_transport_compound_start(tree->session->transport, 3);
    1136             : 
    1137           6 :         ZERO_STRUCT(cr);
    1138           6 :         cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1139           6 :         cr.in.desired_access    = SEC_FILE_READ_DATA;
    1140           6 :         cr.in.file_attributes   = FILE_ATTRIBUTE_NORMAL;
    1141           6 :         cr.in.create_disposition = NTCREATEX_DISP_OPEN;
    1142           6 :         cr.in.fname             = fname;
    1143           6 :         cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
    1144             :                 NTCREATEX_SHARE_ACCESS_WRITE|
    1145             :                 NTCREATEX_SHARE_ACCESS_DELETE;
    1146           6 :         req[0] = smb2_create_send(tree, &cr);
    1147             : 
    1148           6 :         smb2_transport_compound_set_related(tree->session->transport, true);
    1149             : 
    1150             :         /*
    1151             :          * We send 2 reads in the compound here as the protocol
    1152             :          * allows the last read to be split off and possibly
    1153             :          * go async. Check the padding on the first read returned,
    1154             :          * not the second as the second may not be part of the
    1155             :          * returned compound.
    1156             :         */
    1157             : 
    1158           6 :         ZERO_STRUCT(r);
    1159           6 :         h.data[0] = UINT64_MAX;
    1160           6 :         h.data[1] = UINT64_MAX;
    1161           6 :         r.in.file.handle = h;
    1162           6 :         r.in.length      = 3;
    1163           6 :         r.in.offset      = 0;
    1164           6 :         r.in.min_count      = 1;
    1165           6 :         req[1] = smb2_read_send(tree, &r);
    1166             : 
    1167           6 :         ZERO_STRUCT(r2);
    1168           6 :         h.data[0] = UINT64_MAX;
    1169           6 :         h.data[1] = UINT64_MAX;
    1170           6 :         r2.in.file.handle = h;
    1171           6 :         r2.in.length      = 3;
    1172           6 :         r2.in.offset      = 0;
    1173           6 :         r2.in.min_count      = 1;
    1174           6 :         req[2] = smb2_read_send(tree, &r2);
    1175             : 
    1176           6 :         status = smb2_create_recv(req[0], tree, &cr);
    1177           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    1178             : 
    1179             :         /*
    1180             :          * We must do a manual smb2_request_receive() in order to be
    1181             :          * able to check the transport layer info, as smb2_read_recv()
    1182             :          * will destroy the req. smb2_read_recv() will call
    1183             :          * smb2_request_receive() again, but that's ok.
    1184             :          */
    1185           6 :         if (!smb2_request_receive(req[1]) ||
    1186           6 :             !smb2_request_is_ok(req[1])) {
    1187           0 :                 torture_fail(tctx, "failed to receive read request");
    1188             :         }
    1189             : 
    1190             :         /*
    1191             :          * size must be 24: 16 byte read response header plus 3
    1192             :          * requested bytes padded to an 8 byte boundary.
    1193             :          */
    1194           6 :         CHECK_VALUE(req[1]->in.body_size, 24);
    1195             : 
    1196           6 :         status = smb2_read_recv(req[1], tree, &r);
    1197           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    1198             : 
    1199             :         /* Pick up the second, possibly async, read. */
    1200           6 :         status = smb2_read_recv(req[2], tree, &r2);
    1201           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    1202             : 
    1203           6 :         smb2_util_close(tree, cr.out.file.handle);
    1204             : 
    1205             :         /* Check compound read from stream */
    1206           6 :         smb2_transport_compound_start(tree->session->transport, 3);
    1207             : 
    1208           6 :         ZERO_STRUCT(cr);
    1209           6 :         cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1210           6 :         cr.in.desired_access    = SEC_FILE_READ_DATA;
    1211           6 :         cr.in.file_attributes   = FILE_ATTRIBUTE_NORMAL;
    1212           6 :         cr.in.create_disposition = NTCREATEX_DISP_OPEN;
    1213           6 :         cr.in.fname             = sname;
    1214           6 :         cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
    1215             :                 NTCREATEX_SHARE_ACCESS_WRITE|
    1216             :                 NTCREATEX_SHARE_ACCESS_DELETE;
    1217           6 :         req[0] = smb2_create_send(tree, &cr);
    1218             : 
    1219           6 :         smb2_transport_compound_set_related(tree->session->transport, true);
    1220             : 
    1221             :         /*
    1222             :          * We send 2 reads in the compound here as the protocol
    1223             :          * allows the last read to be split off and possibly
    1224             :          * go async. Check the padding on the first read returned,
    1225             :          * not the second as the second may not be part of the
    1226             :          * returned compound.
    1227             :          */
    1228             : 
    1229           6 :         ZERO_STRUCT(r);
    1230           6 :         h.data[0] = UINT64_MAX;
    1231           6 :         h.data[1] = UINT64_MAX;
    1232           6 :         r.in.file.handle = h;
    1233           6 :         r.in.length      = 3;
    1234           6 :         r.in.offset      = 0;
    1235           6 :         r.in.min_count   = 1;
    1236           6 :         req[1] = smb2_read_send(tree, &r);
    1237             : 
    1238           6 :         ZERO_STRUCT(r2);
    1239           6 :         h.data[0] = UINT64_MAX;
    1240           6 :         h.data[1] = UINT64_MAX;
    1241           6 :         r2.in.file.handle = h;
    1242           6 :         r2.in.length      = 3;
    1243           6 :         r2.in.offset      = 0;
    1244           6 :         r2.in.min_count   = 1;
    1245           6 :         req[2] = smb2_read_send(tree, &r2);
    1246             : 
    1247           6 :         status = smb2_create_recv(req[0], tree, &cr);
    1248           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    1249             : 
    1250             :         /*
    1251             :          * We must do a manual smb2_request_receive() in order to be
    1252             :          * able to check the transport layer info, as smb2_read_recv()
    1253             :          * will destroy the req. smb2_read_recv() will call
    1254             :          * smb2_request_receive() again, but that's ok.
    1255             :          */
    1256           6 :         if (!smb2_request_receive(req[1]) ||
    1257           6 :             !smb2_request_is_ok(req[1])) {
    1258           0 :                 torture_fail(tctx, "failed to receive read request");
    1259             :         }
    1260             : 
    1261             :         /*
    1262             :          * size must be 24: 16 byte read response header plus 3
    1263             :          * requested bytes padded to an 8 byte boundary.
    1264             :          */
    1265           6 :         CHECK_VALUE(req[1]->in.body_size, 24);
    1266             : 
    1267           6 :         status = smb2_read_recv(req[1], tree, &r);
    1268           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    1269             : 
    1270             :         /* Pick up the second, possibly async, read. */
    1271           6 :         status = smb2_read_recv(req[2], tree, &r2);
    1272           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    1273             : 
    1274           6 :         h = cr.out.file.handle;
    1275             : 
    1276             :         /* Check 2 compound (unrelateated) reads from existing stream handle */
    1277           6 :         smb2_transport_compound_start(tree->session->transport, 2);
    1278             : 
    1279           6 :         ZERO_STRUCT(r);
    1280           6 :         r.in.file.handle = h;
    1281           6 :         r.in.length      = 3;
    1282           6 :         r.in.offset      = 0;
    1283           6 :         r.in.min_count   = 1;
    1284           6 :         req[0] = smb2_read_send(tree, &r);
    1285           6 :         req[1] = smb2_read_send(tree, &r);
    1286             : 
    1287             :         /*
    1288             :          * We must do a manual smb2_request_receive() in order to be
    1289             :          * able to check the transport layer info, as smb2_read_recv()
    1290             :          * will destroy the req. smb2_read_recv() will call
    1291             :          * smb2_request_receive() again, but that's ok.
    1292             :          */
    1293           6 :         if (!smb2_request_receive(req[0]) ||
    1294           6 :             !smb2_request_is_ok(req[0])) {
    1295           0 :                 torture_fail(tctx, "failed to receive read request");
    1296             :         }
    1297           6 :         if (!smb2_request_receive(req[1]) ||
    1298           6 :             !smb2_request_is_ok(req[1])) {
    1299           0 :                 torture_fail(tctx, "failed to receive read request");
    1300             :         }
    1301             : 
    1302             :         /*
    1303             :          * size must be 24: 16 byte read response header plus 3
    1304             :          * requested bytes padded to an 8 byte boundary.
    1305             :          */
    1306           6 :         CHECK_VALUE(req[0]->in.body_size, 24);
    1307           6 :         CHECK_VALUE(req[1]->in.body_size, 24);
    1308             : 
    1309           6 :         status = smb2_read_recv(req[0], tree, &r);
    1310           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    1311           6 :         status = smb2_read_recv(req[1], tree, &r);
    1312           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    1313             : 
    1314             :         /*
    1315             :          * now try a single read from the stream and verify there's no padding
    1316             :          */
    1317           6 :         ZERO_STRUCT(r);
    1318           6 :         r.in.file.handle = h;
    1319           6 :         r.in.length      = 3;
    1320           6 :         r.in.offset      = 0;
    1321           6 :         r.in.min_count   = 1;
    1322           6 :         req[0] = smb2_read_send(tree, &r);
    1323             : 
    1324             :         /*
    1325             :          * We must do a manual smb2_request_receive() in order to be
    1326             :          * able to check the transport layer info, as smb2_read_recv()
    1327             :          * will destroy the req. smb2_read_recv() will call
    1328             :          * smb2_request_receive() again, but that's ok.
    1329             :          */
    1330           6 :         if (!smb2_request_receive(req[0]) ||
    1331           6 :             !smb2_request_is_ok(req[0])) {
    1332           0 :                 torture_fail(tctx, "failed to receive read request");
    1333             :         }
    1334             : 
    1335             :         /*
    1336             :          * size must be 19: 16 byte read response header plus 3
    1337             :          * requested bytes without padding.
    1338             :          */
    1339           6 :         CHECK_VALUE(req[0]->in.body_size, 19);
    1340             : 
    1341           6 :         status = smb2_read_recv(req[0], tree, &r);
    1342           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    1343             : 
    1344           6 :         smb2_util_close(tree, h);
    1345             : 
    1346           6 :         status = smb2_util_unlink(tree, fname);
    1347           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    1348             : 
    1349           6 :         ret = true;
    1350           6 : done:
    1351           6 :         return ret;
    1352             : }
    1353             : 
    1354           6 : static bool test_compound_create_write_close(struct torture_context *tctx,
    1355             :                                              struct smb2_tree *tree)
    1356             : {
    1357           6 :         struct smb2_handle handle = { .data = { UINT64_MAX, UINT64_MAX } };
    1358           0 :         struct smb2_create create;
    1359           0 :         struct smb2_write write;
    1360           0 :         struct smb2_close close;
    1361           6 :         const char *fname = "compound_create_write_close.dat";
    1362           0 :         struct smb2_request *req[3];
    1363           0 :         NTSTATUS status;
    1364           6 :         bool ret = false;
    1365             : 
    1366           6 :         smb2_util_unlink(tree, fname);
    1367             : 
    1368           6 :         ZERO_STRUCT(create);
    1369           6 :         create.in.security_flags = 0x00;
    1370           6 :         create.in.oplock_level = 0;
    1371           6 :         create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
    1372           6 :         create.in.create_flags = 0x00000000;
    1373           6 :         create.in.reserved = 0x00000000;
    1374           6 :         create.in.desired_access = SEC_RIGHTS_FILE_ALL;
    1375           6 :         create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1376           6 :         create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1377             :                 NTCREATEX_SHARE_ACCESS_WRITE |
    1378             :                 NTCREATEX_SHARE_ACCESS_DELETE;
    1379           6 :         create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
    1380           6 :         create.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
    1381             :                 NTCREATEX_OPTIONS_ASYNC_ALERT |
    1382             :                 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
    1383             :                 0x00200000;
    1384           6 :         create.in.fname = fname;
    1385             : 
    1386           6 :         smb2_transport_compound_start(tree->session->transport, 3);
    1387             : 
    1388           6 :         req[0] = smb2_create_send(tree, &create);
    1389             : 
    1390           6 :         smb2_transport_compound_set_related(tree->session->transport, true);
    1391             : 
    1392           6 :         ZERO_STRUCT(write);
    1393           6 :         write.in.file.handle = handle;
    1394           6 :         write.in.offset = 0;
    1395           6 :         write.in.data = data_blob_talloc(tctx, NULL, 1024);
    1396             : 
    1397           6 :         req[1] = smb2_write_send(tree, &write);
    1398             : 
    1399           6 :         ZERO_STRUCT(close);
    1400           6 :         close.in.file.handle = handle;
    1401             : 
    1402           6 :         req[2] = smb2_close_send(tree, &close);
    1403             : 
    1404           6 :         status = smb2_create_recv(req[0], tree, &create);
    1405           6 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1406             :                                         "CREATE failed.");
    1407             : 
    1408           6 :         status = smb2_write_recv(req[1], &write);
    1409           6 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1410             :                                         "WRITE failed.");
    1411             : 
    1412           6 :         status = smb2_close_recv(req[2], &close);
    1413           6 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1414             :                                         "CLOSE failed.");
    1415             : 
    1416           6 :         status = smb2_util_unlink(tree, fname);
    1417           6 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1418             :                                         "File deletion failed.");
    1419             : 
    1420           6 :         ret = true;
    1421           6 : done:
    1422           6 :         return ret;
    1423             : }
    1424             : 
    1425           6 : static bool test_compound_unrelated1(struct torture_context *tctx,
    1426             :                                      struct smb2_tree *tree)
    1427             : {
    1428           0 :         struct smb2_handle hd;
    1429           0 :         struct smb2_create cr;
    1430           0 :         NTSTATUS status;
    1431           6 :         const char *fname = "compound_unrelated1.dat";
    1432           0 :         struct smb2_close cl;
    1433           6 :         bool ret = true;
    1434           0 :         struct smb2_request *req[5];
    1435             : 
    1436           6 :         smb2_transport_credits_ask_num(tree->session->transport, 5);
    1437             : 
    1438           6 :         smb2_util_unlink(tree, fname);
    1439             : 
    1440           6 :         smb2_transport_credits_ask_num(tree->session->transport, 1);
    1441             : 
    1442           6 :         ZERO_STRUCT(cr);
    1443           6 :         cr.in.security_flags            = 0x00;
    1444           6 :         cr.in.oplock_level              = 0;
    1445           6 :         cr.in.impersonation_level       = NTCREATEX_IMPERSONATION_IMPERSONATION;
    1446           6 :         cr.in.create_flags              = 0x00000000;
    1447           6 :         cr.in.reserved                  = 0x00000000;
    1448           6 :         cr.in.desired_access            = SEC_RIGHTS_FILE_ALL;
    1449           6 :         cr.in.file_attributes           = FILE_ATTRIBUTE_NORMAL;
    1450           6 :         cr.in.share_access              = NTCREATEX_SHARE_ACCESS_READ |
    1451             :                                           NTCREATEX_SHARE_ACCESS_WRITE |
    1452             :                                           NTCREATEX_SHARE_ACCESS_DELETE;
    1453           6 :         cr.in.create_disposition        = NTCREATEX_DISP_OPEN_IF;
    1454           6 :         cr.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
    1455             :                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
    1456             :                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
    1457             :                                           0x00200000;
    1458           6 :         cr.in.fname                     = fname;
    1459             : 
    1460           6 :         smb2_transport_compound_start(tree->session->transport, 5);
    1461             : 
    1462           6 :         req[0] = smb2_create_send(tree, &cr);
    1463             : 
    1464           6 :         hd.data[0] = UINT64_MAX;
    1465           6 :         hd.data[1] = UINT64_MAX;
    1466             : 
    1467           6 :         ZERO_STRUCT(cl);
    1468           6 :         cl.in.file.handle = hd;
    1469           6 :         req[1] = smb2_close_send(tree, &cl);
    1470           6 :         req[2] = smb2_close_send(tree, &cl);
    1471           6 :         req[3] = smb2_close_send(tree, &cl);
    1472           6 :         req[4] = smb2_close_send(tree, &cl);
    1473             : 
    1474           6 :         status = smb2_create_recv(req[0], tree, &cr);
    1475           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    1476           6 :         status = smb2_close_recv(req[1], &cl);
    1477           6 :         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
    1478           6 :         status = smb2_close_recv(req[2], &cl);
    1479           6 :         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
    1480           6 :         status = smb2_close_recv(req[3], &cl);
    1481           6 :         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
    1482           6 :         status = smb2_close_recv(req[4], &cl);
    1483           6 :         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
    1484             : 
    1485           6 :         smb2_util_unlink(tree, fname);
    1486           6 : done:
    1487           6 :         return ret;
    1488             : }
    1489             : 
    1490           6 : static bool test_compound_invalid1(struct torture_context *tctx,
    1491             :                                    struct smb2_tree *tree)
    1492             : {
    1493           0 :         struct smb2_handle hd;
    1494           0 :         struct smb2_create cr;
    1495           0 :         NTSTATUS status;
    1496           6 :         const char *fname = "compound_invalid1.dat";
    1497           0 :         struct smb2_close cl;
    1498           6 :         bool ret = true;
    1499           0 :         struct smb2_request *req[3];
    1500             : 
    1501           6 :         smb2_transport_credits_ask_num(tree->session->transport, 3);
    1502             : 
    1503           6 :         smb2_util_unlink(tree, fname);
    1504             : 
    1505           6 :         smb2_transport_credits_ask_num(tree->session->transport, 1);
    1506             : 
    1507           6 :         ZERO_STRUCT(cr);
    1508           6 :         cr.in.security_flags            = 0x00;
    1509           6 :         cr.in.oplock_level              = 0;
    1510           6 :         cr.in.impersonation_level       = NTCREATEX_IMPERSONATION_IMPERSONATION;
    1511           6 :         cr.in.create_flags              = 0x00000000;
    1512           6 :         cr.in.reserved                  = 0x00000000;
    1513           6 :         cr.in.desired_access            = SEC_RIGHTS_FILE_ALL;
    1514           6 :         cr.in.file_attributes           = FILE_ATTRIBUTE_NORMAL;
    1515           6 :         cr.in.share_access              = NTCREATEX_SHARE_ACCESS_READ |
    1516             :                                           NTCREATEX_SHARE_ACCESS_WRITE |
    1517             :                                           NTCREATEX_SHARE_ACCESS_DELETE;
    1518           6 :         cr.in.create_disposition        = NTCREATEX_DISP_OPEN_IF;
    1519           6 :         cr.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
    1520             :                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
    1521             :                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
    1522             :                                           0x00200000;
    1523           6 :         cr.in.fname                     = fname;
    1524             : 
    1525           6 :         smb2_transport_compound_start(tree->session->transport, 3);
    1526             : 
    1527             :         /* passing the first request with the related flag is invalid */
    1528           6 :         smb2_transport_compound_set_related(tree->session->transport, true);
    1529             : 
    1530           6 :         req[0] = smb2_create_send(tree, &cr);
    1531             : 
    1532           6 :         hd.data[0] = UINT64_MAX;
    1533           6 :         hd.data[1] = UINT64_MAX;
    1534             : 
    1535           6 :         ZERO_STRUCT(cl);
    1536           6 :         cl.in.file.handle = hd;
    1537           6 :         req[1] = smb2_close_send(tree, &cl);
    1538             : 
    1539           6 :         smb2_transport_compound_set_related(tree->session->transport, false);
    1540           6 :         req[2] = smb2_close_send(tree, &cl);
    1541             : 
    1542           6 :         status = smb2_create_recv(req[0], tree, &cr);
    1543             :         /* TODO: check why this fails with --signing=required */
    1544           6 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
    1545           6 :         status = smb2_close_recv(req[1], &cl);
    1546           6 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
    1547           6 :         status = smb2_close_recv(req[2], &cl);
    1548           6 :         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
    1549             : 
    1550           6 :         smb2_util_unlink(tree, fname);
    1551           6 : done:
    1552           6 :         return ret;
    1553             : }
    1554             : 
    1555           6 : static bool test_compound_invalid2(struct torture_context *tctx,
    1556             :                                    struct smb2_tree *tree)
    1557             : {
    1558           0 :         struct smb2_handle hd;
    1559           0 :         struct smb2_create cr;
    1560           0 :         NTSTATUS status;
    1561           6 :         const char *fname = "compound_invalid2.dat";
    1562           0 :         struct smb2_close cl;
    1563           6 :         bool ret = true;
    1564           0 :         struct smb2_request *req[5];
    1565           6 :         struct smbXcli_tcon *saved_tcon = tree->smbXcli;
    1566           6 :         struct smbXcli_session *saved_session = tree->session->smbXcli;
    1567             : 
    1568           6 :         smb2_transport_credits_ask_num(tree->session->transport, 5);
    1569             : 
    1570           6 :         smb2_util_unlink(tree, fname);
    1571             : 
    1572           6 :         smb2_transport_credits_ask_num(tree->session->transport, 1);
    1573             : 
    1574           6 :         ZERO_STRUCT(cr);
    1575           6 :         cr.in.security_flags            = 0x00;
    1576           6 :         cr.in.oplock_level              = 0;
    1577           6 :         cr.in.impersonation_level       = NTCREATEX_IMPERSONATION_IMPERSONATION;
    1578           6 :         cr.in.create_flags              = 0x00000000;
    1579           6 :         cr.in.reserved                  = 0x00000000;
    1580           6 :         cr.in.desired_access            = SEC_RIGHTS_FILE_ALL;
    1581           6 :         cr.in.file_attributes           = FILE_ATTRIBUTE_NORMAL;
    1582           6 :         cr.in.share_access              = NTCREATEX_SHARE_ACCESS_READ |
    1583             :                                           NTCREATEX_SHARE_ACCESS_WRITE |
    1584             :                                           NTCREATEX_SHARE_ACCESS_DELETE;
    1585           6 :         cr.in.create_disposition        = NTCREATEX_DISP_OPEN_IF;
    1586           6 :         cr.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
    1587             :                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
    1588             :                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
    1589             :                                           0x00200000;
    1590           6 :         cr.in.fname                     = fname;
    1591             : 
    1592           6 :         smb2_transport_compound_start(tree->session->transport, 5);
    1593             : 
    1594           6 :         req[0] = smb2_create_send(tree, &cr);
    1595             : 
    1596           6 :         hd.data[0] = UINT64_MAX;
    1597           6 :         hd.data[1] = UINT64_MAX;
    1598             : 
    1599           6 :         smb2_transport_compound_set_related(tree->session->transport, true);
    1600             : 
    1601           6 :         ZERO_STRUCT(cl);
    1602           6 :         cl.in.file.handle = hd;
    1603             : 
    1604           6 :         tree->smbXcli = smbXcli_tcon_create(tree);
    1605           6 :         smb2cli_tcon_set_values(tree->smbXcli,
    1606             :                                 NULL, /* session */
    1607             :                                 0xFFFFFFFF, /* tcon_id */
    1608             :                                 0, /* type */
    1609             :                                 0, /* flags */
    1610             :                                 0, /* capabilities */
    1611             :                                 0 /* maximal_access */);
    1612             : 
    1613          12 :         tree->session->smbXcli = smbXcli_session_shallow_copy(tree->session,
    1614           6 :                                                         tree->session->smbXcli);
    1615           6 :         smb2cli_session_set_id_and_flags(tree->session->smbXcli, UINT64_MAX, 0);
    1616             : 
    1617           6 :         req[1] = smb2_close_send(tree, &cl);
    1618             :         /* strange that this is not generating invalid parameter */
    1619           6 :         smb2_transport_compound_set_related(tree->session->transport, false);
    1620           6 :         req[2] = smb2_close_send(tree, &cl);
    1621           6 :         req[3] = smb2_close_send(tree, &cl);
    1622           6 :         smb2_transport_compound_set_related(tree->session->transport, true);
    1623           6 :         req[4] = smb2_close_send(tree, &cl);
    1624             : 
    1625           6 :         status = smb2_create_recv(req[0], tree, &cr);
    1626           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    1627           6 :         status = smb2_close_recv(req[1], &cl);
    1628           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    1629           6 :         status = smb2_close_recv(req[2], &cl);
    1630           6 :         CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
    1631           6 :         status = smb2_close_recv(req[3], &cl);
    1632           6 :         CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
    1633           6 :         status = smb2_close_recv(req[4], &cl);
    1634           6 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
    1635             : 
    1636           6 :         TALLOC_FREE(tree->smbXcli);
    1637           6 :         tree->smbXcli = saved_tcon;
    1638           6 :         TALLOC_FREE(tree->session->smbXcli);
    1639           6 :         tree->session->smbXcli = saved_session;
    1640             : 
    1641           6 :         smb2_util_unlink(tree, fname);
    1642           6 : done:
    1643           6 :         return ret;
    1644             : }
    1645             : 
    1646           6 : static bool test_compound_invalid3(struct torture_context *tctx,
    1647             :                                    struct smb2_tree *tree)
    1648             : {
    1649           0 :         struct smb2_handle hd;
    1650           0 :         struct smb2_create cr;
    1651           0 :         NTSTATUS status;
    1652           6 :         const char *fname = "compound_invalid3.dat";
    1653           0 :         struct smb2_close cl;
    1654           6 :         bool ret = true;
    1655           0 :         struct smb2_request *req[5];
    1656             : 
    1657           6 :         smb2_transport_credits_ask_num(tree->session->transport, 5);
    1658             : 
    1659           6 :         smb2_util_unlink(tree, fname);
    1660             : 
    1661           6 :         smb2_transport_credits_ask_num(tree->session->transport, 1);
    1662             : 
    1663           6 :         ZERO_STRUCT(cr);
    1664           6 :         cr.in.security_flags            = 0x00;
    1665           6 :         cr.in.oplock_level              = 0;
    1666           6 :         cr.in.impersonation_level       = NTCREATEX_IMPERSONATION_IMPERSONATION;
    1667           6 :         cr.in.create_flags              = 0x00000000;
    1668           6 :         cr.in.reserved                  = 0x00000000;
    1669           6 :         cr.in.desired_access            = SEC_RIGHTS_FILE_ALL;
    1670           6 :         cr.in.file_attributes           = FILE_ATTRIBUTE_NORMAL;
    1671           6 :         cr.in.share_access              = NTCREATEX_SHARE_ACCESS_READ |
    1672             :                                           NTCREATEX_SHARE_ACCESS_WRITE |
    1673             :                                           NTCREATEX_SHARE_ACCESS_DELETE;
    1674           6 :         cr.in.create_disposition        = NTCREATEX_DISP_OPEN_IF;
    1675           6 :         cr.in.create_options            = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
    1676             :                                           NTCREATEX_OPTIONS_ASYNC_ALERT |
    1677             :                                           NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
    1678             :                                           0x00200000;
    1679           6 :         cr.in.fname                     = fname;
    1680             : 
    1681           6 :         smb2_transport_compound_start(tree->session->transport, 5);
    1682             : 
    1683           6 :         req[0] = smb2_create_send(tree, &cr);
    1684             : 
    1685           6 :         hd.data[0] = UINT64_MAX;
    1686           6 :         hd.data[1] = UINT64_MAX;
    1687             : 
    1688           6 :         ZERO_STRUCT(cl);
    1689           6 :         cl.in.file.handle = hd;
    1690           6 :         req[1] = smb2_close_send(tree, &cl);
    1691           6 :         req[2] = smb2_close_send(tree, &cl);
    1692             :         /* flipping the related flag is invalid */
    1693           6 :         smb2_transport_compound_set_related(tree->session->transport, true);
    1694           6 :         req[3] = smb2_close_send(tree, &cl);
    1695           6 :         req[4] = smb2_close_send(tree, &cl);
    1696             : 
    1697           6 :         status = smb2_create_recv(req[0], tree, &cr);
    1698           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    1699           6 :         status = smb2_close_recv(req[1], &cl);
    1700           6 :         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
    1701           6 :         status = smb2_close_recv(req[2], &cl);
    1702           6 :         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
    1703           6 :         status = smb2_close_recv(req[3], &cl);
    1704           6 :         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
    1705           6 :         status = smb2_close_recv(req[4], &cl);
    1706           6 :         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
    1707             : 
    1708           6 :         smb2_util_unlink(tree, fname);
    1709           6 : done:
    1710           6 :         return ret;
    1711             : }
    1712             : 
    1713           6 : static bool test_compound_invalid4(struct torture_context *tctx,
    1714             :                                    struct smb2_tree *tree)
    1715             : {
    1716           0 :         struct smb2_create cr;
    1717           0 :         struct smb2_read rd;
    1718           0 :         NTSTATUS status;
    1719           6 :         const char *fname = "compound_invalid4.dat";
    1720           0 :         struct smb2_close cl;
    1721           6 :         bool ret = true;
    1722           0 :         bool ok;
    1723           0 :         struct smb2_request *req[2];
    1724             : 
    1725           6 :         smb2_transport_credits_ask_num(tree->session->transport, 2);
    1726             : 
    1727           6 :         smb2_util_unlink(tree, fname);
    1728             : 
    1729           6 :         ZERO_STRUCT(cr);
    1730           6 :         cr.in.security_flags      = 0x00;
    1731           6 :         cr.in.oplock_level        = 0;
    1732           6 :         cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
    1733           6 :         cr.in.create_flags        = 0x00000000;
    1734           6 :         cr.in.reserved            = 0x00000000;
    1735           6 :         cr.in.desired_access      = SEC_RIGHTS_FILE_ALL;
    1736           6 :         cr.in.file_attributes     = FILE_ATTRIBUTE_NORMAL;
    1737           6 :         cr.in.share_access        = NTCREATEX_SHARE_ACCESS_READ |
    1738             :                                     NTCREATEX_SHARE_ACCESS_WRITE |
    1739             :                                     NTCREATEX_SHARE_ACCESS_DELETE;
    1740           6 :         cr.in.create_disposition  = NTCREATEX_DISP_OPEN_IF;
    1741           6 :         cr.in.create_options      = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
    1742             :                                     NTCREATEX_OPTIONS_ASYNC_ALERT       |
    1743             :                                     NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
    1744             :                                     0x00200000;
    1745           6 :         cr.in.fname               = fname;
    1746             : 
    1747           6 :         status = smb2_create(tree, tctx, &cr);
    1748           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    1749             : 
    1750           6 :         smb2_transport_compound_start(tree->session->transport, 2);
    1751             : 
    1752           6 :         ZERO_STRUCT(rd);
    1753           6 :         rd.in.file.handle = cr.out.file.handle;
    1754           6 :         rd.in.length      = 1;
    1755           6 :         rd.in.offset      = 0;
    1756           6 :         req[0] = smb2_read_send(tree, &rd);
    1757             : 
    1758           6 :         smb2_transport_compound_set_related(tree->session->transport, true);
    1759             : 
    1760             :         /*
    1761             :          * Send a completely bogus request as second compound
    1762             :          * element. This triggers smbd_smb2_request_error() in in
    1763             :          * smbd_smb2_request_dispatch() before calling
    1764             :          * smbd_smb2_request_dispatch_update_counts().
    1765             :          */
    1766             : 
    1767           6 :         req[1] = smb2_request_init_tree(tree, 0xff, 0x04, false, 0);
    1768           6 :         smb2_transport_send(req[1]);
    1769             : 
    1770           6 :         status = smb2_read_recv(req[0], tctx, &rd);
    1771           6 :         CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
    1772             : 
    1773           6 :         ok = smb2_request_receive(req[1]);
    1774           6 :         torture_assert(tctx, ok, "Invalid request failed\n");
    1775           6 :         CHECK_STATUS(req[1]->status, NT_STATUS_INVALID_PARAMETER);
    1776             : 
    1777           6 :         ZERO_STRUCT(cl);
    1778           6 :         cl.in.file.handle = cr.out.file.handle;
    1779             : 
    1780           6 :         status = smb2_close(tree, &cl);
    1781           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    1782             : 
    1783           6 :         smb2_util_unlink(tree, fname);
    1784           6 : done:
    1785           6 :         return ret;
    1786             : }
    1787             : 
    1788             : /* Send a compound request where we expect the last request (Create, Notify)
    1789             :  * to go asynchronous. This works against a Win7 server and the reply is
    1790             :  * sent in two different packets. */
    1791           6 : static bool test_compound_interim1(struct torture_context *tctx,
    1792             :                                    struct smb2_tree *tree)
    1793             : {
    1794           0 :     struct smb2_handle hd;
    1795           0 :     struct smb2_create cr;
    1796           6 :     NTSTATUS status = NT_STATUS_OK;
    1797           6 :     const char *dname = "compound_interim_dir";
    1798           0 :     struct smb2_notify nt;
    1799           6 :     bool ret = true;
    1800           0 :     struct smb2_request *req[2];
    1801             : 
    1802             :     /* Win7 compound request implementation deviates substantially from the
    1803             :      * SMB2 spec as noted in MS-SMB2 <159>, <162>.  This, test currently
    1804             :      * verifies the Windows behavior, not the general spec behavior. */
    1805             : 
    1806           6 :     smb2_transport_credits_ask_num(tree->session->transport, 5);
    1807             : 
    1808           6 :     smb2_deltree(tree, dname);
    1809             : 
    1810           6 :     smb2_transport_credits_ask_num(tree->session->transport, 1);
    1811             : 
    1812           6 :     ZERO_STRUCT(cr);
    1813           6 :     cr.in.desired_access        = SEC_RIGHTS_FILE_ALL;
    1814           6 :     cr.in.create_options        = NTCREATEX_OPTIONS_DIRECTORY;
    1815           6 :     cr.in.file_attributes       = FILE_ATTRIBUTE_DIRECTORY;
    1816           6 :     cr.in.share_access          = NTCREATEX_SHARE_ACCESS_READ |
    1817             :                                   NTCREATEX_SHARE_ACCESS_WRITE |
    1818             :                                   NTCREATEX_SHARE_ACCESS_DELETE;
    1819           6 :     cr.in.create_disposition    = NTCREATEX_DISP_CREATE;
    1820           6 :     cr.in.fname                 = dname;
    1821             : 
    1822           6 :     smb2_transport_compound_start(tree->session->transport, 2);
    1823             : 
    1824           6 :     req[0] = smb2_create_send(tree, &cr);
    1825             : 
    1826           6 :     smb2_transport_compound_set_related(tree->session->transport, true);
    1827             : 
    1828           6 :     hd.data[0] = UINT64_MAX;
    1829           6 :     hd.data[1] = UINT64_MAX;
    1830             : 
    1831           6 :     ZERO_STRUCT(nt);
    1832           6 :     nt.in.recursive          = true;
    1833           6 :     nt.in.buffer_size        = 0x1000;
    1834           6 :     nt.in.file.handle        = hd;
    1835           6 :     nt.in.completion_filter  = FILE_NOTIFY_CHANGE_NAME;
    1836           6 :     nt.in.unknown            = 0x00000000;
    1837             : 
    1838           6 :     req[1] = smb2_notify_send(tree, &nt);
    1839             : 
    1840           6 :     status = smb2_create_recv(req[0], tree, &cr);
    1841           6 :     CHECK_STATUS(status, NT_STATUS_OK);
    1842             : 
    1843           6 :     smb2_cancel(req[1]);
    1844           6 :     status = smb2_notify_recv(req[1], tree, &nt);
    1845           6 :     CHECK_STATUS(status, NT_STATUS_CANCELLED);
    1846             : 
    1847           6 :     smb2_util_close(tree, cr.out.file.handle);
    1848             : 
    1849           6 :     smb2_deltree(tree, dname);
    1850           6 : done:
    1851           6 :     return ret;
    1852             : }
    1853             : 
    1854             : /* Send a compound request where we expect the middle request (Create, Notify,
    1855             :  * GetInfo) to go asynchronous. Against Win7 the sync request succeed while
    1856             :  * the async fails. All are returned in the same compound response. */
    1857           6 : static bool test_compound_interim2(struct torture_context *tctx,
    1858             :                                    struct smb2_tree *tree)
    1859             : {
    1860           0 :     struct smb2_handle hd;
    1861           0 :     struct smb2_create cr;
    1862           6 :     NTSTATUS status = NT_STATUS_OK;
    1863           6 :     const char *dname = "compound_interim_dir";
    1864           0 :     struct smb2_getinfo gf;
    1865           0 :     struct smb2_notify  nt;
    1866           6 :     bool ret = true;
    1867           0 :     struct smb2_request *req[3];
    1868             : 
    1869             :     /* Win7 compound request implementation deviates substantially from the
    1870             :      * SMB2 spec as noted in MS-SMB2 <159>, <162>.  This, test currently
    1871             :      * verifies the Windows behavior, not the general spec behavior. */
    1872             : 
    1873           6 :     smb2_transport_credits_ask_num(tree->session->transport, 5);
    1874             : 
    1875           6 :     smb2_deltree(tree, dname);
    1876             : 
    1877           6 :     smb2_transport_credits_ask_num(tree->session->transport, 1);
    1878             : 
    1879           6 :     ZERO_STRUCT(cr);
    1880           6 :     cr.in.desired_access        = SEC_RIGHTS_FILE_ALL;
    1881           6 :     cr.in.create_options        = NTCREATEX_OPTIONS_DIRECTORY;
    1882           6 :     cr.in.file_attributes       = FILE_ATTRIBUTE_DIRECTORY;
    1883           6 :     cr.in.share_access      = NTCREATEX_SHARE_ACCESS_READ |
    1884             :                       NTCREATEX_SHARE_ACCESS_WRITE |
    1885             :                       NTCREATEX_SHARE_ACCESS_DELETE;
    1886           6 :     cr.in.create_disposition    = NTCREATEX_DISP_CREATE;
    1887           6 :     cr.in.fname         = dname;
    1888             : 
    1889           6 :     smb2_transport_compound_start(tree->session->transport, 3);
    1890             : 
    1891           6 :     req[0] = smb2_create_send(tree, &cr);
    1892             : 
    1893           6 :     smb2_transport_compound_set_related(tree->session->transport, true);
    1894             : 
    1895           6 :     hd.data[0] = UINT64_MAX;
    1896           6 :     hd.data[1] = UINT64_MAX;
    1897             : 
    1898           6 :     ZERO_STRUCT(nt);
    1899           6 :     nt.in.recursive          = true;
    1900           6 :     nt.in.buffer_size        = 0x1000;
    1901           6 :     nt.in.file.handle        = hd;
    1902           6 :     nt.in.completion_filter  = FILE_NOTIFY_CHANGE_NAME;
    1903           6 :     nt.in.unknown            = 0x00000000;
    1904             : 
    1905           6 :     req[1] = smb2_notify_send(tree, &nt);
    1906             : 
    1907           6 :     ZERO_STRUCT(gf);
    1908           6 :     gf.in.file.handle = hd;
    1909           6 :     gf.in.info_type   = SMB2_0_INFO_FILE;
    1910           6 :     gf.in.info_class  = 0x04; /* FILE_BASIC_INFORMATION */
    1911           6 :     gf.in.output_buffer_length = 0x1000;
    1912           6 :     gf.in.input_buffer = data_blob_null;
    1913             : 
    1914           6 :     req[2] = smb2_getinfo_send(tree, &gf);
    1915             : 
    1916           6 :     status = smb2_create_recv(req[0], tree, &cr);
    1917           6 :     CHECK_STATUS(status, NT_STATUS_OK);
    1918             : 
    1919           6 :     status = smb2_notify_recv(req[1], tree, &nt);
    1920           6 :     CHECK_STATUS(status, NT_STATUS_INTERNAL_ERROR);
    1921             : 
    1922           0 :     status = smb2_getinfo_recv(req[2], tree, &gf);
    1923           0 :     CHECK_STATUS(status, NT_STATUS_OK);
    1924             : 
    1925           0 :     smb2_util_close(tree, cr.out.file.handle);
    1926             : 
    1927           0 :     smb2_deltree(tree, dname);
    1928           6 : done:
    1929           6 :     return ret;
    1930             : }
    1931             : 
    1932             : /* Test compound related finds */
    1933           8 : static bool test_compound_find_related(struct torture_context *tctx,
    1934             :                                        struct smb2_tree *tree)
    1935             : {
    1936           8 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1937           8 :         const char *dname = "compound_find_dir";
    1938           0 :         struct smb2_create create;
    1939           0 :         struct smb2_find f;
    1940           0 :         struct smb2_handle h;
    1941           0 :         struct smb2_request *req[2];
    1942           0 :         NTSTATUS status;
    1943           8 :         bool ret = true;
    1944             : 
    1945           8 :         smb2_deltree(tree, dname);
    1946             : 
    1947           8 :         ZERO_STRUCT(create);
    1948           8 :         create.in.desired_access = SEC_RIGHTS_DIR_ALL;
    1949           8 :         create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1950           8 :         create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
    1951           8 :         create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1952             :                                  NTCREATEX_SHARE_ACCESS_WRITE |
    1953             :                                  NTCREATEX_SHARE_ACCESS_DELETE;
    1954           8 :         create.in.create_disposition = NTCREATEX_DISP_CREATE;
    1955           8 :         create.in.fname = dname;
    1956             : 
    1957           8 :         status = smb2_create(tree, mem_ctx, &create);
    1958           8 :         h = create.out.file.handle;
    1959             : 
    1960           8 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed\n");
    1961             : 
    1962           8 :         smb2_transport_compound_start(tree->session->transport, 2);
    1963             : 
    1964           8 :         ZERO_STRUCT(f);
    1965           8 :         f.in.file.handle        = h;
    1966           8 :         f.in.pattern            = "*";
    1967           8 :         f.in.max_response_size  = 0x100;
    1968           8 :         f.in.level              = SMB2_FIND_BOTH_DIRECTORY_INFO;
    1969             : 
    1970           8 :         req[0] = smb2_find_send(tree, &f);
    1971             : 
    1972           8 :         smb2_transport_compound_set_related(tree->session->transport, true);
    1973             : 
    1974           8 :         req[1] = smb2_find_send(tree, &f);
    1975             : 
    1976           8 :         status = smb2_find_recv(req[0], mem_ctx, &f);
    1977           8 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_find_recv failed\n");
    1978             : 
    1979           8 :         status = smb2_find_recv(req[1], mem_ctx, &f);
    1980           8 :         torture_assert_ntstatus_equal_goto(tctx, status, STATUS_NO_MORE_FILES, ret, done, "smb2_find_recv failed\n");
    1981             : 
    1982           8 : done:
    1983           8 :         smb2_util_close(tree, h);
    1984           8 :         smb2_deltree(tree, dname);
    1985           8 :         TALLOC_FREE(mem_ctx);
    1986           8 :         return ret;
    1987             : }
    1988             : 
    1989             : /* Test compound related finds */
    1990           8 : static bool test_compound_find_close(struct torture_context *tctx,
    1991             :                                      struct smb2_tree *tree)
    1992             : {
    1993           8 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1994           8 :         const char *dname = "compound_find_dir";
    1995           0 :         struct smb2_create create;
    1996           0 :         struct smb2_find f;
    1997           0 :         struct smb2_handle h;
    1998           8 :         struct smb2_request *req = NULL;
    1999           8 :         const int num_files = 5000;
    2000           0 :         int i;
    2001           0 :         NTSTATUS status;
    2002           8 :         bool ret = true;
    2003             : 
    2004           8 :         smb2_deltree(tree, dname);
    2005             : 
    2006           8 :         ZERO_STRUCT(create);
    2007           8 :         create.in.desired_access = SEC_RIGHTS_DIR_ALL;
    2008           8 :         create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    2009           8 :         create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
    2010           8 :         create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    2011             :                                  NTCREATEX_SHARE_ACCESS_WRITE |
    2012             :                                  NTCREATEX_SHARE_ACCESS_DELETE;
    2013           8 :         create.in.create_disposition = NTCREATEX_DISP_CREATE;
    2014           8 :         create.in.fname = dname;
    2015             : 
    2016           8 :         smb2cli_conn_set_max_credits(tree->session->transport->conn, 256);
    2017             : 
    2018           8 :         status = smb2_create(tree, mem_ctx, &create);
    2019           8 :         h = create.out.file.handle;
    2020             : 
    2021           8 :         ZERO_STRUCT(create);
    2022           8 :         create.in.desired_access = SEC_RIGHTS_FILE_ALL;
    2023           8 :         create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    2024           8 :         create.in.create_disposition = NTCREATEX_DISP_CREATE;
    2025             : 
    2026       40008 :         for (i = 0; i < num_files; i++) {
    2027       40000 :                 create.in.fname = talloc_asprintf(mem_ctx, "%s\\file%d",
    2028             :                                                   dname, i);
    2029       40000 :                 status = smb2_create(tree, mem_ctx, &create);
    2030       40000 :                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
    2031       40000 :                 smb2_util_close(tree, create.out.file.handle);
    2032             :         }
    2033             : 
    2034           8 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed\n");
    2035             : 
    2036           8 :         ZERO_STRUCT(f);
    2037           8 :         f.in.file.handle        = h;
    2038           8 :         f.in.pattern            = "*";
    2039           8 :         f.in.max_response_size  = 8*1024*1024;
    2040           8 :         f.in.level              = SMB2_FIND_BOTH_DIRECTORY_INFO;
    2041             : 
    2042           8 :         req = smb2_find_send(tree, &f);
    2043             : 
    2044           8 :         status = smb2_util_close(tree, h);
    2045           8 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_close failed\n");
    2046             : 
    2047           8 :         status = smb2_find_recv(req, mem_ctx, &f);
    2048           8 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_find_recv failed\n");
    2049             : 
    2050           8 : done:
    2051           8 :         smb2_util_close(tree, h);
    2052           8 :         smb2_deltree(tree, dname);
    2053           8 :         TALLOC_FREE(mem_ctx);
    2054           8 :         return ret;
    2055             : }
    2056             : 
    2057             : /* Test compound unrelated finds */
    2058           8 : static bool test_compound_find_unrelated(struct torture_context *tctx,
    2059             :                                          struct smb2_tree *tree)
    2060             : {
    2061           8 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2062           8 :         const char *dname = "compound_find_dir";
    2063           0 :         struct smb2_create create;
    2064           0 :         struct smb2_find f;
    2065           0 :         struct smb2_handle h;
    2066           0 :         struct smb2_request *req[2];
    2067           0 :         NTSTATUS status;
    2068           8 :         bool ret = true;
    2069             : 
    2070           8 :         smb2_deltree(tree, dname);
    2071             : 
    2072           8 :         ZERO_STRUCT(create);
    2073           8 :         create.in.desired_access = SEC_RIGHTS_DIR_ALL;
    2074           8 :         create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    2075           8 :         create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
    2076           8 :         create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    2077             :                                  NTCREATEX_SHARE_ACCESS_WRITE |
    2078             :                                  NTCREATEX_SHARE_ACCESS_DELETE;
    2079           8 :         create.in.create_disposition = NTCREATEX_DISP_CREATE;
    2080           8 :         create.in.fname = dname;
    2081             : 
    2082           8 :         status = smb2_create(tree, mem_ctx, &create);
    2083           8 :         h = create.out.file.handle;
    2084             : 
    2085           8 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed\n");
    2086             : 
    2087           8 :         smb2_transport_compound_start(tree->session->transport, 2);
    2088             : 
    2089           8 :         ZERO_STRUCT(f);
    2090           8 :         f.in.file.handle        = h;
    2091           8 :         f.in.pattern            = "*";
    2092           8 :         f.in.max_response_size  = 0x100;
    2093           8 :         f.in.level              = SMB2_FIND_BOTH_DIRECTORY_INFO;
    2094             : 
    2095           8 :         req[0] = smb2_find_send(tree, &f);
    2096           8 :         req[1] = smb2_find_send(tree, &f);
    2097             : 
    2098           8 :         status = smb2_find_recv(req[0], mem_ctx, &f);
    2099           8 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_find_recv failed\n");
    2100             : 
    2101           8 :         status = smb2_find_recv(req[1], mem_ctx, &f);
    2102           8 :         torture_assert_ntstatus_equal_goto(tctx, status, STATUS_NO_MORE_FILES, ret, done, "smb2_find_recv failed\n");
    2103             : 
    2104           8 : done:
    2105           8 :         smb2_util_close(tree, h);
    2106           8 :         smb2_deltree(tree, dname);
    2107           8 :         TALLOC_FREE(mem_ctx);
    2108           8 :         return ret;
    2109             : }
    2110             : 
    2111           2 : static bool test_compound_async_flush_close(struct torture_context *tctx,
    2112             :                                             struct smb2_tree *tree)
    2113             : {
    2114           2 :         struct smb2_handle fhandle = { .data = { 0, 0 } };
    2115           2 :         struct smb2_handle relhandle = { .data = { UINT64_MAX, UINT64_MAX } };
    2116           0 :         struct smb2_close cl;
    2117           0 :         struct smb2_flush fl;
    2118           2 :         const char *fname = "compound_async_flush_close";
    2119           0 :         struct smb2_request *req[2];
    2120           0 :         NTSTATUS status;
    2121           2 :         bool ret = false;
    2122             : 
    2123             :         /* Start clean. */
    2124           2 :         smb2_util_unlink(tree, fname);
    2125             : 
    2126             :         /* Create a file. */
    2127           2 :         status = torture_smb2_testfile_access(tree,
    2128             :                                               fname,
    2129             :                                               &fhandle,
    2130             :                                               SEC_RIGHTS_FILE_ALL);
    2131           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2132             : 
    2133             :         /* Now do a compound flush + close handle. */
    2134           2 :         smb2_transport_compound_start(tree->session->transport, 2);
    2135             : 
    2136           2 :         ZERO_STRUCT(fl);
    2137           2 :         fl.in.file.handle = fhandle;
    2138             : 
    2139           2 :         req[0] = smb2_flush_send(tree, &fl);
    2140           2 :         torture_assert_not_null_goto(tctx, req[0], ret, done,
    2141             :                 "smb2_flush_send failed\n");
    2142             : 
    2143           2 :         smb2_transport_compound_set_related(tree->session->transport, true);
    2144             : 
    2145           2 :         ZERO_STRUCT(cl);
    2146           2 :         cl.in.file.handle = relhandle;
    2147           2 :         req[1] = smb2_close_send(tree, &cl);
    2148           2 :         torture_assert_not_null_goto(tctx, req[1], ret, done,
    2149             :                 "smb2_close_send failed\n");
    2150             : 
    2151           2 :         status = smb2_flush_recv(req[0], &fl);
    2152             :         /*
    2153             :          * On Windows, this flush will usually
    2154             :          * succeed as we have nothing to flush,
    2155             :          * so allow NT_STATUS_OK. Once bug #15172
    2156             :          * is fixed Samba will do the flush synchronously
    2157             :          * so allow NT_STATUS_OK.
    2158             :          */
    2159           2 :         if (!NT_STATUS_IS_OK(status)) {
    2160             :                 /*
    2161             :                  * If we didn't get NT_STATUS_OK, we *must*
    2162             :                  * get NT_STATUS_INTERNAL_ERROR if the flush
    2163             :                  * goes async.
    2164             :                  *
    2165             :                  * For pre-bugfix #15172 Samba, the flush goes async and
    2166             :                  * we should get NT_STATUS_INTERNAL_ERROR.
    2167             :                  */
    2168           0 :                 torture_assert_ntstatus_equal_goto(tctx,
    2169             :                         status,
    2170             :                         NT_STATUS_INTERNAL_ERROR,
    2171             :                         ret,
    2172             :                         done,
    2173             :                         "smb2_flush_recv didn't return "
    2174             :                         "NT_STATUS_INTERNAL_ERROR.\n");
    2175             :         }
    2176           2 :         status = smb2_close_recv(req[1], &cl);
    2177           2 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2178             :                         "smb2_close_recv failed.");
    2179             : 
    2180           2 :         ZERO_STRUCT(fhandle);
    2181             : 
    2182             :         /*
    2183             :          * Do several more operations on the tree, spaced
    2184             :          * out by 1 sec sleeps to make sure the server didn't
    2185             :          * crash on the close. The sleeps are required to
    2186             :          * make test test for a crash reliable, as we ensure
    2187             :          * the pthread fsync internally finishes and accesses
    2188             :          * freed memory. Without them the test occasionally
    2189             :          * passes as we disconnect before the pthread fsync
    2190             :          * finishes.
    2191             :          */
    2192           2 :         status = smb2_util_unlink(tree, fname);
    2193           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2194             : 
    2195           2 :         sleep(1);
    2196           2 :         status = smb2_util_unlink(tree, fname);
    2197           2 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    2198             : 
    2199           2 :         sleep(1);
    2200           2 :         status = smb2_util_unlink(tree, fname);
    2201           2 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    2202             : 
    2203           2 :         ret = true;
    2204             : 
    2205           2 :   done:
    2206             : 
    2207           2 :         if (fhandle.data[0] != 0) {
    2208           0 :                 smb2_util_close(tree, fhandle);
    2209             :         }
    2210             : 
    2211           2 :         smb2_util_unlink(tree, fname);
    2212           2 :         return ret;
    2213             : }
    2214             : 
    2215           2 : static bool test_compound_async_flush_flush(struct torture_context *tctx,
    2216             :                                             struct smb2_tree *tree)
    2217             : {
    2218           2 :         struct smb2_handle fhandle = { .data = { 0, 0 } };
    2219           2 :         struct smb2_handle relhandle = { .data = { UINT64_MAX, UINT64_MAX } };
    2220           0 :         struct smb2_flush fl1;
    2221           0 :         struct smb2_flush fl2;
    2222           2 :         const char *fname = "compound_async_flush_flush";
    2223           0 :         struct smb2_request *req[2];
    2224           0 :         NTSTATUS status;
    2225           2 :         bool ret = false;
    2226             : 
    2227             :         /* Start clean. */
    2228           2 :         smb2_util_unlink(tree, fname);
    2229             : 
    2230             :         /* Create a file. */
    2231           2 :         status = torture_smb2_testfile_access(tree,
    2232             :                                               fname,
    2233             :                                               &fhandle,
    2234             :                                               SEC_RIGHTS_FILE_ALL);
    2235           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2236             : 
    2237             :         /* Now do a compound flush + flush handle. */
    2238           2 :         smb2_transport_compound_start(tree->session->transport, 2);
    2239             : 
    2240           2 :         ZERO_STRUCT(fl1);
    2241           2 :         fl1.in.file.handle = fhandle;
    2242             : 
    2243           2 :         req[0] = smb2_flush_send(tree, &fl1);
    2244           2 :         torture_assert_not_null_goto(tctx, req[0], ret, done,
    2245             :                 "smb2_flush_send (1) failed\n");
    2246             : 
    2247           2 :         smb2_transport_compound_set_related(tree->session->transport, true);
    2248             : 
    2249           2 :         ZERO_STRUCT(fl2);
    2250           2 :         fl2.in.file.handle = relhandle;
    2251             : 
    2252           2 :         req[1] = smb2_flush_send(tree, &fl2);
    2253           2 :         torture_assert_not_null_goto(tctx, req[1], ret, done,
    2254             :                 "smb2_flush_send (2) failed\n");
    2255             : 
    2256           2 :         status = smb2_flush_recv(req[0], &fl1);
    2257             :         /*
    2258             :          * On Windows, this flush will usually
    2259             :          * succeed as we have nothing to flush,
    2260             :          * so allow NT_STATUS_OK. Once bug #15172
    2261             :          * is fixed Samba will do the flush synchronously
    2262             :          * so allow NT_STATUS_OK.
    2263             :          */
    2264           2 :         if (!NT_STATUS_IS_OK(status)) {
    2265             :                 /*
    2266             :                  * If we didn't get NT_STATUS_OK, we *must*
    2267             :                  * get NT_STATUS_INTERNAL_ERROR if the flush
    2268             :                  * goes async.
    2269             :                  *
    2270             :                  * For pre-bugfix #15172 Samba, the flush goes async and
    2271             :                  * we should get NT_STATUS_INTERNAL_ERROR.
    2272             :                  */
    2273           0 :                 torture_assert_ntstatus_equal_goto(tctx,
    2274             :                         status,
    2275             :                         NT_STATUS_INTERNAL_ERROR,
    2276             :                         ret,
    2277             :                         done,
    2278             :                         "smb2_flush_recv (1) didn't return "
    2279             :                         "NT_STATUS_INTERNAL_ERROR.\n");
    2280             :         }
    2281             : 
    2282             :         /*
    2283             :          * If the flush is the last entry in a compound,
    2284             :          * it should always succeed even if it goes async.
    2285             :          */
    2286           2 :         status = smb2_flush_recv(req[1], &fl2);
    2287           2 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2288             :                 "smb2_flush_recv (2) failed.");
    2289             : 
    2290           2 :         status = smb2_util_close(tree, fhandle);
    2291           2 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2292             :                 "smb2_util_close failed.");
    2293           2 :         ZERO_STRUCT(fhandle);
    2294             : 
    2295             :         /*
    2296             :          * Do several more operations on the tree, spaced
    2297             :          * out by 1 sec sleeps to make sure the server didn't
    2298             :          * crash on the close. The sleeps are required to
    2299             :          * make test test for a crash reliable, as we ensure
    2300             :          * the pthread fsync internally finishes and accesses
    2301             :          * freed memory. Without them the test occasionally
    2302             :          * passes as we disconnect before the pthread fsync
    2303             :          * finishes.
    2304             :          */
    2305           2 :         status = smb2_util_unlink(tree, fname);
    2306           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2307             : 
    2308           2 :         sleep(1);
    2309           2 :         status = smb2_util_unlink(tree, fname);
    2310           2 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    2311             : 
    2312           2 :         sleep(1);
    2313           2 :         status = smb2_util_unlink(tree, fname);
    2314           2 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    2315             : 
    2316           2 :         ret = true;
    2317             : 
    2318           2 :   done:
    2319             : 
    2320           2 :         if (fhandle.data[0] != 0) {
    2321           0 :                 smb2_util_close(tree, fhandle);
    2322             :         }
    2323             : 
    2324           2 :         smb2_util_unlink(tree, fname);
    2325           2 :         return ret;
    2326             : }
    2327             : 
    2328             : /*
    2329             :  * For Samba/smbd this test must be run against the aio_delay_inject share
    2330             :  * as we need to ensure the last write in the compound takes longer than
    2331             :  * 500 us, which is the threshold for going async in smbd SMB2 writes.
    2332             :  */
    2333             : 
    2334           2 : static bool test_compound_async_write_write(struct torture_context *tctx,
    2335             :                                             struct smb2_tree *tree)
    2336             : {
    2337           2 :         struct smb2_handle fhandle = { .data = { 0, 0 } };
    2338           2 :         struct smb2_handle relhandle = { .data = { UINT64_MAX, UINT64_MAX } };
    2339           0 :         struct smb2_write w1;
    2340           0 :         struct smb2_write w2;
    2341           2 :         const char *fname = "compound_async_write_write";
    2342           0 :         struct smb2_request *req[2];
    2343           0 :         NTSTATUS status;
    2344           2 :         bool is_smbd = torture_setting_bool(tctx, "smbd", true);
    2345           2 :         bool ret = false;
    2346             : 
    2347             :         /* Start clean. */
    2348           2 :         smb2_util_unlink(tree, fname);
    2349             : 
    2350             :         /* Create a file. */
    2351           2 :         status = torture_smb2_testfile_access(tree,
    2352             :                                               fname,
    2353             :                                               &fhandle,
    2354             :                                               SEC_RIGHTS_FILE_ALL);
    2355           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2356             : 
    2357             :         /* Now do a compound write + write handle. */
    2358           2 :         smb2_transport_compound_start(tree->session->transport, 2);
    2359             : 
    2360           2 :         ZERO_STRUCT(w1);
    2361           2 :         w1.in.file.handle = fhandle;
    2362           2 :         w1.in.offset = 0;
    2363           2 :         w1.in.data = data_blob_talloc_zero(tctx, 64);
    2364           2 :         req[0] = smb2_write_send(tree, &w1);
    2365             : 
    2366           2 :         torture_assert_not_null_goto(tctx, req[0], ret, done,
    2367             :                 "smb2_write_send (1) failed\n");
    2368             : 
    2369           2 :         smb2_transport_compound_set_related(tree->session->transport, true);
    2370             : 
    2371           2 :         ZERO_STRUCT(w2);
    2372           2 :         w2.in.file.handle = relhandle;
    2373           2 :         w2.in.offset = 64;
    2374           2 :         w2.in.data = data_blob_talloc_zero(tctx, 64);
    2375           2 :         req[1] = smb2_write_send(tree, &w2);
    2376             : 
    2377           2 :         torture_assert_not_null_goto(tctx, req[0], ret, done,
    2378             :                 "smb2_write_send (2) failed\n");
    2379             : 
    2380           2 :         status = smb2_write_recv(req[0], &w1);
    2381           2 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2382             :                 "smb2_write_recv (1) failed.");
    2383             : 
    2384           2 :         if (!is_smbd) {
    2385             :                 /*
    2386             :                  * Windows and other servers don't go async.
    2387             :                  */
    2388           0 :                 status = smb2_write_recv(req[1], &w2);
    2389             :         } else {
    2390             :                 /*
    2391             :                  * For smbd, the second write should go async
    2392             :                  * as it's the last element of a compound.
    2393             :                  */
    2394           8 :                 WAIT_FOR_ASYNC_RESPONSE(req[1]);
    2395           2 :                 CHECK_VALUE(req[1]->cancel.can_cancel, true);
    2396             :                 /*
    2397             :                  * Now pick up the real return.
    2398             :                  */
    2399           2 :                 status = smb2_write_recv(req[1], &w2);
    2400             :         }
    2401             : 
    2402           2 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2403             :                 "smb2_write_recv (2) failed.");
    2404             : 
    2405           2 :         status = smb2_util_close(tree, fhandle);
    2406           2 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2407             :                 "smb2_util_close failed.");
    2408           2 :         ZERO_STRUCT(fhandle);
    2409             : 
    2410           2 :         ret = true;
    2411             : 
    2412           2 :   done:
    2413             : 
    2414           2 :         if (fhandle.data[0] != 0) {
    2415           0 :                 smb2_util_close(tree, fhandle);
    2416             :         }
    2417             : 
    2418           2 :         smb2_util_unlink(tree, fname);
    2419           2 :         return ret;
    2420             : }
    2421             : 
    2422             : /*
    2423             :  * For Samba/smbd this test must be run against the aio_delay_inject share
    2424             :  * as we need to ensure the last read in the compound takes longer than
    2425             :  * 500 us, which is the threshold for going async in smbd SMB2 reads.
    2426             :  */
    2427             : 
    2428           2 : static bool test_compound_async_read_read(struct torture_context *tctx,
    2429             :                                             struct smb2_tree *tree)
    2430             : {
    2431           2 :         struct smb2_handle fhandle = { .data = { 0, 0 } };
    2432           2 :         struct smb2_handle relhandle = { .data = { UINT64_MAX, UINT64_MAX } };
    2433           0 :         struct smb2_write w;
    2434           0 :         struct smb2_read r1;
    2435           0 :         struct smb2_read r2;
    2436           2 :         const char *fname = "compound_async_read_read";
    2437           0 :         struct smb2_request *req[2];
    2438           0 :         NTSTATUS status;
    2439           2 :         bool is_smbd = torture_setting_bool(tctx, "smbd", true);
    2440           2 :         bool ret = false;
    2441             : 
    2442             :         /* Start clean. */
    2443           2 :         smb2_util_unlink(tree, fname);
    2444             : 
    2445             :         /* Create a file. */
    2446           2 :         status = torture_smb2_testfile_access(tree,
    2447             :                                               fname,
    2448             :                                               &fhandle,
    2449             :                                               SEC_RIGHTS_FILE_ALL);
    2450           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2451             : 
    2452             :         /* Write 128 bytes. */
    2453           2 :         ZERO_STRUCT(w);
    2454           2 :         w.in.file.handle = fhandle;
    2455           2 :         w.in.offset = 0;
    2456           2 :         w.in.data = data_blob_talloc_zero(tctx, 128);
    2457           2 :         status = smb2_write(tree, &w);
    2458           2 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2459             :                 "smb2_write_recv (1) failed.");
    2460             : 
    2461             :         /* Now do a compound read + read handle. */
    2462           2 :         smb2_transport_compound_start(tree->session->transport, 2);
    2463             : 
    2464           2 :         ZERO_STRUCT(r1);
    2465           2 :         r1.in.file.handle = fhandle;
    2466           2 :         r1.in.length      = 64;
    2467           2 :         r1.in.offset      = 0;
    2468           2 :         req[0] = smb2_read_send(tree, &r1);
    2469             : 
    2470           2 :         torture_assert_not_null_goto(tctx, req[0], ret, done,
    2471             :                 "smb2_read_send (1) failed\n");
    2472             : 
    2473           2 :         smb2_transport_compound_set_related(tree->session->transport, true);
    2474             : 
    2475           2 :         ZERO_STRUCT(r2);
    2476           2 :         r2.in.file.handle = relhandle;
    2477           2 :         r2.in.length      = 64;
    2478           2 :         r2.in.offset      = 64;
    2479           2 :         req[1] = smb2_read_send(tree, &r2);
    2480             : 
    2481           2 :         torture_assert_not_null_goto(tctx, req[0], ret, done,
    2482             :                 "smb2_read_send (2) failed\n");
    2483             : 
    2484           2 :         status = smb2_read_recv(req[0], tree, &r1);
    2485           2 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2486             :                 "smb2_read_recv (1) failed.");
    2487             : 
    2488           2 :         if (!is_smbd) {
    2489             :                 /*
    2490             :                  * Windows and other servers don't go async.
    2491             :                  */
    2492           0 :                 status = smb2_read_recv(req[1], tree, &r2);
    2493             :         } else {
    2494             :                 /*
    2495             :                  * For smbd, the second write should go async
    2496             :                  * as it's the last element of a compound.
    2497             :                  */
    2498           8 :                 WAIT_FOR_ASYNC_RESPONSE(req[1]);
    2499           2 :                 CHECK_VALUE(req[1]->cancel.can_cancel, true);
    2500             :                 /*
    2501             :                  * Now pick up the real return.
    2502             :                  */
    2503           2 :                 status = smb2_read_recv(req[1], tree, &r2);
    2504             :         }
    2505             : 
    2506           2 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2507             :                 "smb2_read_recv (2) failed.");
    2508             : 
    2509           2 :         status = smb2_util_close(tree, fhandle);
    2510           2 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2511             :                 "smb2_util_close failed.");
    2512           2 :         ZERO_STRUCT(fhandle);
    2513             : 
    2514           2 :         ret = true;
    2515             : 
    2516           2 :   done:
    2517             : 
    2518           2 :         if (fhandle.data[0] != 0) {
    2519           0 :                 smb2_util_close(tree, fhandle);
    2520             :         }
    2521             : 
    2522           2 :         smb2_util_unlink(tree, fname);
    2523           2 :         return ret;
    2524             : }
    2525             : 
    2526             : 
    2527        2354 : struct torture_suite *torture_smb2_compound_init(TALLOC_CTX *ctx)
    2528             : {
    2529        2354 :         struct torture_suite *suite = torture_suite_create(ctx, "compound");
    2530             : 
    2531        2354 :         torture_suite_add_1smb2_test(suite, "related1", test_compound_related1);
    2532        2354 :         torture_suite_add_1smb2_test(suite, "related2", test_compound_related2);
    2533        2354 :         torture_suite_add_1smb2_test(suite, "related3",
    2534             :                                      test_compound_related3);
    2535        2354 :         torture_suite_add_1smb2_test(suite, "related4",
    2536             :                                      test_compound_related4);
    2537        2354 :         torture_suite_add_1smb2_test(suite, "related5",
    2538             :                                      test_compound_related5);
    2539        2354 :         torture_suite_add_1smb2_test(suite, "related6",
    2540             :                                      test_compound_related6);
    2541        2354 :         torture_suite_add_1smb2_test(suite, "related7",
    2542             :                                      test_compound_related7);
    2543        2354 :         torture_suite_add_1smb2_test(suite, "related8",
    2544             :                                      test_compound_related8);
    2545        2354 :         torture_suite_add_1smb2_test(suite, "related9",
    2546             :                                      test_compound_related9);
    2547        2354 :         torture_suite_add_1smb2_test(suite, "unrelated1", test_compound_unrelated1);
    2548        2354 :         torture_suite_add_1smb2_test(suite, "invalid1", test_compound_invalid1);
    2549        2354 :         torture_suite_add_1smb2_test(suite, "invalid2", test_compound_invalid2);
    2550        2354 :         torture_suite_add_1smb2_test(suite, "invalid3", test_compound_invalid3);
    2551        2354 :         torture_suite_add_1smb2_test(
    2552             :                 suite, "invalid4", test_compound_invalid4);
    2553        2354 :         torture_suite_add_1smb2_test(suite, "interim1",  test_compound_interim1);
    2554        2354 :         torture_suite_add_1smb2_test(suite, "interim2",  test_compound_interim2);
    2555        2354 :         torture_suite_add_1smb2_test(suite, "compound-break", test_compound_break);
    2556        2354 :         torture_suite_add_1smb2_test(suite, "compound-padding", test_compound_padding);
    2557        2354 :         torture_suite_add_1smb2_test(suite, "create-write-close",
    2558             :                                      test_compound_create_write_close);
    2559             : 
    2560        2354 :         suite->description = talloc_strdup(suite, "SMB2-COMPOUND tests");
    2561             : 
    2562        2354 :         return suite;
    2563             : }
    2564             : 
    2565        2354 : struct torture_suite *torture_smb2_compound_find_init(TALLOC_CTX *ctx)
    2566             : {
    2567        2354 :         struct torture_suite *suite = torture_suite_create(ctx, "compound_find");
    2568             : 
    2569        2354 :         torture_suite_add_1smb2_test(suite, "compound_find_related", test_compound_find_related);
    2570        2354 :         torture_suite_add_1smb2_test(suite, "compound_find_unrelated", test_compound_find_unrelated);
    2571        2354 :         torture_suite_add_1smb2_test(suite, "compound_find_close", test_compound_find_close);
    2572             : 
    2573        2354 :         suite->description = talloc_strdup(suite, "SMB2-COMPOUND-FIND tests");
    2574             : 
    2575        2354 :         return suite;
    2576             : }
    2577             : 
    2578        2354 : struct torture_suite *torture_smb2_compound_async_init(TALLOC_CTX *ctx)
    2579             : {
    2580        2354 :         struct torture_suite *suite = torture_suite_create(ctx,
    2581             :                                         "compound_async");
    2582             : 
    2583        2354 :         torture_suite_add_1smb2_test(suite, "flush_close",
    2584             :                 test_compound_async_flush_close);
    2585        2354 :         torture_suite_add_1smb2_test(suite, "flush_flush",
    2586             :                 test_compound_async_flush_flush);
    2587        2354 :         torture_suite_add_1smb2_test(suite, "write_write",
    2588             :                 test_compound_async_write_write);
    2589        2354 :         torture_suite_add_1smb2_test(suite, "read_read",
    2590             :                 test_compound_async_read_read);
    2591             : 
    2592        2354 :         suite->description = talloc_strdup(suite, "SMB2-COMPOUND-ASYNC tests");
    2593             : 
    2594        2354 :         return suite;
    2595             : }

Generated by: LCOV version 1.14