LCOV - code coverage report
Current view: top level - source4/torture/smb2 - durable_v2_open.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 1124 1265 88.9 %
Date: 2024-04-21 15:09:00 Functions: 25 25 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    test suite for SMB2 version two of durable opens
       5             : 
       6             :    Copyright (C) Michael Adam 2012
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "libcli/smb2/smb2.h"
      24             : #include "libcli/smb2/smb2_calls.h"
      25             : #include "../libcli/smb/smbXcli_base.h"
      26             : #include "torture/torture.h"
      27             : #include "torture/smb2/proto.h"
      28             : #include "librpc/ndr/libndr.h"
      29             : 
      30             : #define CHECK_VAL(v, correct) do { \
      31             :         if ((v) != (correct)) { \
      32             :                 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
      33             :                                 __location__, #v, (int)v, (int)correct); \
      34             :                 ret = false; \
      35             :         }} while (0)
      36             : 
      37             : #define CHECK_STATUS(status, correct) do { \
      38             :         if (!NT_STATUS_EQUAL(status, correct)) { \
      39             :                 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
      40             :                        nt_errstr(status), nt_errstr(correct)); \
      41             :                 ret = false; \
      42             :                 goto done; \
      43             :         }} while (0)
      44             : 
      45             : #define CHECK_CREATED(__io, __created, __attribute)                     \
      46             :         do {                                                            \
      47             :                 CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
      48             :                 CHECK_VAL((__io)->out.size, 0);                              \
      49             :                 CHECK_VAL((__io)->out.file_attr, (__attribute));     \
      50             :                 CHECK_VAL((__io)->out.reserved2, 0);                 \
      51             :         } while(0)
      52             : 
      53             : static struct {
      54             :         int count;
      55             :         struct smb2_close cl;
      56             : } break_info;
      57             : 
      58           4 : static void torture_oplock_close_callback(struct smb2_request *req)
      59             : {
      60           4 :         smb2_close_recv(req, &break_info.cl);
      61           4 : }
      62             : 
      63             : /* A general oplock break notification handler.  This should be used when a
      64             :  * test expects to break from batch or exclusive to a lower level. */
      65           4 : static bool torture_oplock_handler(struct smb2_transport *transport,
      66             :                                    const struct smb2_handle *handle,
      67             :                                    uint8_t level,
      68             :                                    void *private_data)
      69             : {
      70           4 :         struct smb2_tree *tree = private_data;
      71           0 :         struct smb2_request *req;
      72             : 
      73           4 :         break_info.count++;
      74             : 
      75           4 :         ZERO_STRUCT(break_info.cl);
      76           4 :         break_info.cl.in.file.handle = *handle;
      77             : 
      78           4 :         req = smb2_close_send(tree, &break_info.cl);
      79           4 :         req->async.fn = torture_oplock_close_callback;
      80           4 :         req->async.private_data = NULL;
      81           4 :         return true;
      82             : }
      83             : 
      84             : /**
      85             :  * testing various create blob combinations.
      86             :  */
      87           4 : bool test_durable_v2_open_create_blob(struct torture_context *tctx,
      88             :                                       struct smb2_tree *tree)
      89             : {
      90           0 :         NTSTATUS status;
      91           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
      92           0 :         char fname[256];
      93           0 :         struct smb2_handle _h;
      94           4 :         struct smb2_handle *h = NULL;
      95           0 :         struct smb2_create io;
      96           4 :         struct GUID create_guid = GUID_random();
      97           4 :         bool ret = true;
      98           0 :         struct smbcli_options options;
      99             : 
     100           4 :         options = tree->session->transport->options;
     101             : 
     102             :         /* Choose a random name in case the state is left a little funky. */
     103           4 :         snprintf(fname, 256, "durable_v2_open_create_blob_%s.dat",
     104             :                  generate_random_str(tctx, 8));
     105             : 
     106           4 :         smb2_util_unlink(tree, fname);
     107             : 
     108           4 :         smb2_oplock_create_share(&io, fname,
     109             :                                  smb2_util_share_access(""),
     110           4 :                                  smb2_util_oplock_level("b"));
     111           4 :         io.in.durable_open = false;
     112           4 :         io.in.durable_open_v2 = true;
     113           4 :         io.in.persistent_open = false;
     114           4 :         io.in.create_guid = create_guid;
     115           4 :         io.in.timeout = UINT32_MAX;
     116             : 
     117           4 :         status = smb2_create(tree, mem_ctx, &io);
     118           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     119           4 :         _h = io.out.file.handle;
     120           4 :         h = &_h;
     121           4 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     122           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     123           4 :         CHECK_VAL(io.out.durable_open, false);
     124           4 :         CHECK_VAL(io.out.durable_open_v2, true);
     125           4 :         CHECK_VAL(io.out.persistent_open, false);
     126           4 :         CHECK_VAL(io.out.timeout, 300*1000);
     127             : 
     128             :         /* disconnect */
     129           4 :         TALLOC_FREE(tree);
     130             : 
     131             :         /* create a new session (same client_guid) */
     132           4 :         if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
     133           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
     134           0 :                 ret = false;
     135           0 :                 goto done;
     136             :         }
     137             : 
     138             :         /*
     139             :          * check invalid combinations of durable handle
     140             :          * request and reconnect blobs
     141             :          * See MS-SMB2: 3.3.5.9.12
     142             :          * Handling the SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 Create Context
     143             :          */
     144           4 :         ZERO_STRUCT(io);
     145           4 :         io.in.fname = fname;
     146           4 :         io.in.durable_handle_v2 = h; /* durable v2 reconnect request */
     147           4 :         io.in.durable_open = true;   /* durable v1 handle request */
     148           4 :         io.in.create_guid = create_guid;
     149           4 :         status = smb2_create(tree, mem_ctx, &io);
     150           4 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     151             : 
     152           4 :         ZERO_STRUCT(io);
     153           4 :         io.in.fname = fname;
     154           4 :         io.in.durable_handle = h;     /* durable v1 reconnect request */
     155           4 :         io.in.durable_open_v2 = true; /* durable v2 handle request */
     156           4 :         io.in.create_guid = create_guid;
     157           4 :         status = smb2_create(tree, mem_ctx, &io);
     158           4 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     159             : 
     160           4 :         ZERO_STRUCT(io);
     161           4 :         io.in.fname = fname;
     162           4 :         io.in.durable_handle = h;    /* durable v1 reconnect request */
     163           4 :         io.in.durable_handle_v2 = h; /* durable v2 reconnect request */
     164           4 :         io.in.create_guid = create_guid;
     165           4 :         status = smb2_create(tree, mem_ctx, &io);
     166           4 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     167             : 
     168           4 :         ZERO_STRUCT(io);
     169           4 :         io.in.fname = fname;
     170           4 :         io.in.durable_handle_v2 = h;  /* durable v2 reconnect request */
     171           4 :         io.in.durable_open_v2 = true; /* durable v2 handle request */
     172           4 :         io.in.create_guid = create_guid;
     173           4 :         status = smb2_create(tree, mem_ctx, &io);
     174           4 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     175             : 
     176           4 : done:
     177           4 :         if (h != NULL) {
     178           4 :                 smb2_util_close(tree, *h);
     179             :         }
     180             : 
     181           4 :         smb2_util_unlink(tree, fname);
     182             : 
     183           4 :         talloc_free(tree);
     184             : 
     185           4 :         talloc_free(mem_ctx);
     186             : 
     187           4 :         return ret;
     188             : }
     189             : 
     190             : 
     191             : /**
     192             :  * basic durable_open test.
     193             :  * durable state should only be granted when requested
     194             :  * along with a batch oplock or a handle lease.
     195             :  *
     196             :  * This test tests durable open with all possible oplock types.
     197             :  */
     198             : 
     199             : struct durable_open_vs_oplock {
     200             :         const char *level;
     201             :         const char *share_mode;
     202             :         bool durable;
     203             :         bool persistent;
     204             : };
     205             : 
     206             : #define NUM_OPLOCK_TYPES 4
     207             : #define NUM_SHARE_MODES 8
     208             : #define NUM_OPLOCK_OPEN_TESTS ( NUM_OPLOCK_TYPES * NUM_SHARE_MODES )
     209             : static struct durable_open_vs_oplock durable_open_vs_oplock_table[NUM_OPLOCK_OPEN_TESTS] =
     210             : {
     211             :         { "", "", false, false },
     212             :         { "", "R", false, false },
     213             :         { "", "W", false, false },
     214             :         { "", "D", false, false },
     215             :         { "", "RD", false, false },
     216             :         { "", "RW", false, false },
     217             :         { "", "WD", false, false },
     218             :         { "", "RWD", false, false },
     219             : 
     220             :         { "s", "", false, false },
     221             :         { "s", "R", false, false },
     222             :         { "s", "W", false, false },
     223             :         { "s", "D", false, false },
     224             :         { "s", "RD", false, false },
     225             :         { "s", "RW", false, false },
     226             :         { "s", "WD", false, false },
     227             :         { "s", "RWD", false, false },
     228             : 
     229             :         { "x", "", false, false },
     230             :         { "x", "R", false, false },
     231             :         { "x", "W", false, false },
     232             :         { "x", "D", false, false },
     233             :         { "x", "RD", false, false },
     234             :         { "x", "RW", false, false },
     235             :         { "x", "WD", false, false },
     236             :         { "x", "RWD", false, false },
     237             : 
     238             :         { "b", "", true, false },
     239             :         { "b", "R", true, false },
     240             :         { "b", "W", true, false },
     241             :         { "b", "D", true, false },
     242             :         { "b", "RD", true, false },
     243             :         { "b", "RW", true, false },
     244             :         { "b", "WD", true, false },
     245             :         { "b", "RWD", true, false },
     246             : };
     247             : 
     248         256 : static bool test_one_durable_v2_open_oplock(struct torture_context *tctx,
     249             :                                             struct smb2_tree *tree,
     250             :                                             const char *fname,
     251             :                                             bool request_persistent,
     252             :                                             struct durable_open_vs_oplock test)
     253             : {
     254           0 :         NTSTATUS status;
     255         256 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     256           0 :         struct smb2_handle _h;
     257         256 :         struct smb2_handle *h = NULL;
     258         256 :         bool ret = true;
     259           0 :         struct smb2_create io;
     260             : 
     261         256 :         smb2_util_unlink(tree, fname);
     262             : 
     263         256 :         smb2_oplock_create_share(&io, fname,
     264             :                                  smb2_util_share_access(test.share_mode),
     265         256 :                                  smb2_util_oplock_level(test.level));
     266         256 :         io.in.durable_open = false;
     267         256 :         io.in.durable_open_v2 = true;
     268         256 :         io.in.persistent_open = request_persistent;
     269         256 :         io.in.create_guid = GUID_random();
     270             : 
     271         256 :         status = smb2_create(tree, mem_ctx, &io);
     272         256 :         CHECK_STATUS(status, NT_STATUS_OK);
     273         256 :         _h = io.out.file.handle;
     274         256 :         h = &_h;
     275         256 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     276         256 :         CHECK_VAL(io.out.durable_open, false);
     277         256 :         CHECK_VAL(io.out.durable_open_v2, test.durable);
     278         256 :         CHECK_VAL(io.out.persistent_open, test.persistent);
     279         256 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(test.level));
     280             : 
     281         256 : done:
     282         256 :         if (h != NULL) {
     283         256 :                 smb2_util_close(tree, *h);
     284             :         }
     285         256 :         smb2_util_unlink(tree, fname);
     286         256 :         talloc_free(mem_ctx);
     287             : 
     288         256 :         return ret;
     289             : }
     290             : 
     291           8 : static bool test_durable_v2_open_oplock_table(struct torture_context *tctx,
     292             :                                               struct smb2_tree *tree,
     293             :                                               const char *fname,
     294             :                                               bool request_persistent,
     295             :                                               struct durable_open_vs_oplock *table,
     296             :                                               uint8_t num_tests)
     297             : {
     298           8 :         bool ret = true;
     299           0 :         uint8_t i;
     300             : 
     301           8 :         smb2_util_unlink(tree, fname);
     302             : 
     303         264 :         for (i = 0; i < num_tests; i++) {
     304         256 :                 ret = test_one_durable_v2_open_oplock(tctx,
     305             :                                                       tree,
     306             :                                                       fname,
     307             :                                                       request_persistent,
     308         256 :                                                       table[i]);
     309         256 :                 if (ret == false) {
     310           0 :                         goto done;
     311             :                 }
     312             :         }
     313             : 
     314           8 : done:
     315           8 :         smb2_util_unlink(tree, fname);
     316             : 
     317           8 :         return ret;
     318             : }
     319             : 
     320           4 : bool test_durable_v2_open_oplock(struct torture_context *tctx,
     321             :                                  struct smb2_tree *tree)
     322             : {
     323           0 :         bool ret;
     324           0 :         char fname[256];
     325             : 
     326             :         /* Choose a random name in case the state is left a little funky. */
     327           4 :         snprintf(fname, 256, "durable_open_oplock_%s.dat",
     328             :                  generate_random_str(tctx, 8));
     329             : 
     330           4 :         ret = test_durable_v2_open_oplock_table(tctx, tree, fname,
     331             :                                                 false, /* request_persistent */
     332             :                                                 durable_open_vs_oplock_table,
     333             :                                                 NUM_OPLOCK_OPEN_TESTS);
     334             : 
     335           4 :         talloc_free(tree);
     336             : 
     337           4 :         return ret;
     338             : }
     339             : 
     340             : /**
     341             :  * basic durable handle open test.
     342             :  * persistent state should only be granted when requested
     343             :  * along with a batch oplock or a handle lease.
     344             :  *
     345             :  * This test tests persistent open with all valid lease types.
     346             :  */
     347             : 
     348             : struct durable_open_vs_lease {
     349             :         const char *type;
     350             :         const char *share_mode;
     351             :         bool durable;
     352             :         bool persistent;
     353             : };
     354             : 
     355             : #define NUM_LEASE_TYPES 5
     356             : #define NUM_LEASE_OPEN_TESTS ( NUM_LEASE_TYPES * NUM_SHARE_MODES )
     357             : static struct durable_open_vs_lease durable_open_vs_lease_table[NUM_LEASE_OPEN_TESTS] =
     358             : {
     359             :         { "", "", false, false },
     360             :         { "", "R", false, false },
     361             :         { "", "W", false, false },
     362             :         { "", "D", false, false },
     363             :         { "", "RW", false, false },
     364             :         { "", "RD", false, false },
     365             :         { "", "WD", false, false },
     366             :         { "", "RWD", false, false },
     367             : 
     368             :         { "R", "", false, false },
     369             :         { "R", "R", false, false },
     370             :         { "R", "W", false, false },
     371             :         { "R", "D", false, false },
     372             :         { "R", "RW", false, false },
     373             :         { "R", "RD", false, false },
     374             :         { "R", "DW", false, false },
     375             :         { "R", "RWD", false, false },
     376             : 
     377             :         { "RW", "", false, false },
     378             :         { "RW", "R", false, false },
     379             :         { "RW", "W", false, false },
     380             :         { "RW", "D", false, false },
     381             :         { "RW", "RW", false, false },
     382             :         { "RW", "RD", false, false },
     383             :         { "RW", "WD", false, false },
     384             :         { "RW", "RWD", false, false },
     385             : 
     386             :         { "RH", "", true, false },
     387             :         { "RH", "R", true, false },
     388             :         { "RH", "W", true, false },
     389             :         { "RH", "D", true, false },
     390             :         { "RH", "RW", true, false },
     391             :         { "RH", "RD", true, false },
     392             :         { "RH", "WD", true, false },
     393             :         { "RH", "RWD", true, false },
     394             : 
     395             :         { "RHW", "", true, false },
     396             :         { "RHW", "R", true, false },
     397             :         { "RHW", "W", true, false },
     398             :         { "RHW", "D", true, false },
     399             :         { "RHW", "RW", true, false },
     400             :         { "RHW", "RD", true, false },
     401             :         { "RHW", "WD", true, false },
     402             :         { "RHW", "RWD", true, false },
     403             : };
     404             : 
     405         160 : static bool test_one_durable_v2_open_lease(struct torture_context *tctx,
     406             :                                            struct smb2_tree *tree,
     407             :                                            const char *fname,
     408             :                                            bool request_persistent,
     409             :                                            struct durable_open_vs_lease test)
     410             : {
     411           0 :         NTSTATUS status;
     412         160 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     413           0 :         struct smb2_handle _h;
     414         160 :         struct smb2_handle *h = NULL;
     415         160 :         bool ret = true;
     416           0 :         struct smb2_create io;
     417           0 :         struct smb2_lease ls;
     418           0 :         uint64_t lease;
     419             : 
     420         160 :         smb2_util_unlink(tree, fname);
     421             : 
     422         160 :         lease = random();
     423             : 
     424         160 :         smb2_lease_create_share(&io, &ls, false /* dir */, fname,
     425             :                                 smb2_util_share_access(test.share_mode),
     426             :                                 lease,
     427             :                                 smb2_util_lease_state(test.type));
     428         160 :         io.in.durable_open = false;
     429         160 :         io.in.durable_open_v2 = true;
     430         160 :         io.in.persistent_open = request_persistent;
     431         160 :         io.in.create_guid = GUID_random();
     432             : 
     433         160 :         status = smb2_create(tree, mem_ctx, &io);
     434         160 :         CHECK_STATUS(status, NT_STATUS_OK);
     435         160 :         _h = io.out.file.handle;
     436         160 :         h = &_h;
     437         160 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     438         160 :         CHECK_VAL(io.out.durable_open, false);
     439         160 :         CHECK_VAL(io.out.durable_open_v2, test.durable);
     440         160 :         CHECK_VAL(io.out.persistent_open, test.persistent);
     441         160 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
     442         160 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease);
     443         160 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease);
     444         160 :         CHECK_VAL(io.out.lease_response.lease_state,
     445             :                   smb2_util_lease_state(test.type));
     446         160 : done:
     447         160 :         if (h != NULL) {
     448         160 :                 smb2_util_close(tree, *h);
     449             :         }
     450         160 :         smb2_util_unlink(tree, fname);
     451         160 :         talloc_free(mem_ctx);
     452             : 
     453         160 :         return ret;
     454             : }
     455             : 
     456           4 : static bool test_durable_v2_open_lease_table(struct torture_context *tctx,
     457             :                                              struct smb2_tree *tree,
     458             :                                              const char *fname,
     459             :                                              bool request_persistent,
     460             :                                              struct durable_open_vs_lease *table,
     461             :                                              uint8_t num_tests)
     462             : {
     463           4 :         bool ret = true;
     464           0 :         uint8_t i;
     465             : 
     466           4 :         smb2_util_unlink(tree, fname);
     467             : 
     468         164 :         for (i = 0; i < num_tests; i++) {
     469         160 :                 ret = test_one_durable_v2_open_lease(tctx,
     470             :                                                      tree,
     471             :                                                      fname,
     472             :                                                      request_persistent,
     473         160 :                                                      table[i]);
     474         160 :                 if (ret == false) {
     475           0 :                         goto done;
     476             :                 }
     477             :         }
     478             : 
     479           4 : done:
     480           4 :         smb2_util_unlink(tree, fname);
     481             : 
     482           4 :         return ret;
     483             : }
     484             : 
     485           4 : bool test_durable_v2_open_lease(struct torture_context *tctx,
     486             :                                 struct smb2_tree *tree)
     487             : {
     488           0 :         char fname[256];
     489           4 :         bool ret = true;
     490           0 :         uint32_t caps;
     491             : 
     492           4 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
     493           4 :         if (!(caps & SMB2_CAP_LEASING)) {
     494           2 :                 torture_skip(tctx, "leases are not supported");
     495             :         }
     496             : 
     497             :         /* Choose a random name in case the state is left a little funky. */
     498           2 :         snprintf(fname, 256, "durable_open_lease_%s.dat", generate_random_str(tctx, 8));
     499             : 
     500           2 :         ret = test_durable_v2_open_lease_table(tctx, tree, fname,
     501             :                                                false, /* request_persistent */
     502             :                                                durable_open_vs_lease_table,
     503             :                                                NUM_LEASE_OPEN_TESTS);
     504             : 
     505           2 :         talloc_free(tree);
     506           2 :         return ret;
     507             : }
     508             : 
     509             : /**
     510             :  * basic test for doing a durable open
     511             :  * and do a durable reopen on the same connection
     512             :  * while the first open is still active (fails)
     513             :  */
     514           4 : bool test_durable_v2_open_reopen1(struct torture_context *tctx,
     515             :                                   struct smb2_tree *tree)
     516             : {
     517           0 :         NTSTATUS status;
     518           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     519           0 :         char fname[256];
     520           0 :         struct smb2_handle _h;
     521           4 :         struct smb2_handle *h = NULL;
     522           0 :         struct smb2_create io;
     523           4 :         struct GUID create_guid = GUID_random();
     524           4 :         bool ret = true;
     525             : 
     526             :         /* Choose a random name in case the state is left a little funky. */
     527           4 :         snprintf(fname, 256, "durable_v2_open_reopen1_%s.dat",
     528             :                  generate_random_str(tctx, 8));
     529             : 
     530           4 :         smb2_util_unlink(tree, fname);
     531             : 
     532           4 :         smb2_oplock_create_share(&io, fname,
     533             :                                  smb2_util_share_access(""),
     534           4 :                                  smb2_util_oplock_level("b"));
     535           4 :         io.in.durable_open = false;
     536           4 :         io.in.durable_open_v2 = true;
     537           4 :         io.in.persistent_open = false;
     538           4 :         io.in.create_guid = create_guid;
     539           4 :         io.in.timeout = UINT32_MAX;
     540             : 
     541           4 :         status = smb2_create(tree, mem_ctx, &io);
     542           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     543           4 :         _h = io.out.file.handle;
     544           4 :         h = &_h;
     545           4 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     546           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     547           4 :         CHECK_VAL(io.out.durable_open, false);
     548           4 :         CHECK_VAL(io.out.durable_open_v2, true);
     549           4 :         CHECK_VAL(io.out.persistent_open, false);
     550           4 :         CHECK_VAL(io.out.timeout, 300*1000);
     551             : 
     552             :         /* try a durable reconnect while the file is still open */
     553           4 :         ZERO_STRUCT(io);
     554           4 :         io.in.fname = "";
     555           4 :         io.in.durable_handle_v2 = h;
     556           4 :         io.in.create_guid = create_guid;
     557           4 :         status = smb2_create(tree, mem_ctx, &io);
     558           4 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     559             : 
     560           4 : done:
     561           4 :         if (h != NULL) {
     562           4 :                 smb2_util_close(tree, *h);
     563             :         }
     564             : 
     565           4 :         smb2_util_unlink(tree, fname);
     566             : 
     567           4 :         talloc_free(tree);
     568             : 
     569           4 :         talloc_free(mem_ctx);
     570             : 
     571           4 :         return ret;
     572             : }
     573             : 
     574             : /**
     575             :  * Basic test for doing a durable open
     576             :  * and do a session reconnect while the first
     577             :  * session is still active and the handle is
     578             :  * still open in the client.
     579             :  * This closes the original session and  a
     580             :  * durable reconnect on the new session succeeds.
     581             :  */
     582           4 : bool test_durable_v2_open_reopen1a(struct torture_context *tctx,
     583             :                                    struct smb2_tree *tree)
     584             : {
     585           0 :         NTSTATUS status;
     586           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     587           0 :         char fname[256];
     588           0 :         struct smb2_handle _h;
     589           4 :         struct smb2_handle *h = NULL;
     590           0 :         struct smb2_create io;
     591           4 :         struct GUID create_guid = GUID_random();
     592           4 :         bool ret = true;
     593           4 :         struct smb2_tree *tree2 = NULL;
     594           4 :         struct smb2_tree *tree3 = NULL;
     595           0 :         uint64_t previous_session_id;
     596           0 :         struct smbcli_options options;
     597           0 :         struct GUID orig_client_guid;
     598             : 
     599           4 :         options = tree->session->transport->options;
     600           4 :         orig_client_guid = options.client_guid;
     601             : 
     602             :         /* Choose a random name in case the state is left a little funky. */
     603           4 :         snprintf(fname, 256, "durable_v2_open_reopen1a_%s.dat",
     604             :                  generate_random_str(tctx, 8));
     605             : 
     606           4 :         smb2_util_unlink(tree, fname);
     607             : 
     608           4 :         smb2_oplock_create_share(&io, fname,
     609             :                                  smb2_util_share_access(""),
     610           4 :                                  smb2_util_oplock_level("b"));
     611           4 :         io.in.durable_open = false;
     612           4 :         io.in.durable_open_v2 = true;
     613           4 :         io.in.persistent_open = false;
     614           4 :         io.in.create_guid = create_guid;
     615           4 :         io.in.timeout = UINT32_MAX;
     616             : 
     617           4 :         status = smb2_create(tree, mem_ctx, &io);
     618           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     619           4 :         _h = io.out.file.handle;
     620           4 :         h = &_h;
     621           4 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     622           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     623           4 :         CHECK_VAL(io.out.durable_open, false);
     624           4 :         CHECK_VAL(io.out.durable_open_v2, true);
     625           4 :         CHECK_VAL(io.out.persistent_open, false);
     626           4 :         CHECK_VAL(io.out.timeout, 300*1000);
     627             : 
     628             :         /*
     629             :          * a session reconnect on a second tcp connection
     630             :          */
     631             : 
     632           4 :         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
     633             : 
     634             :         /* for oplocks, the client guid can be different: */
     635           4 :         options.client_guid = GUID_random();
     636             : 
     637           4 :         ret = torture_smb2_connection_ext(tctx, previous_session_id,
     638             :                                           &options, &tree2);
     639           4 :         torture_assert_goto(tctx, ret, ret, done, "couldn't reconnect");
     640             : 
     641             :         /*
     642             :          * check that this has deleted the old session
     643             :          */
     644             : 
     645           4 :         ZERO_STRUCT(io);
     646           4 :         io.in.fname = "";
     647           4 :         io.in.durable_handle_v2 = h;
     648           4 :         io.in.create_guid = create_guid;
     649           4 :         status = smb2_create(tree, mem_ctx, &io);
     650           4 :         CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
     651             : 
     652           4 :         TALLOC_FREE(tree);
     653             : 
     654             :         /*
     655             :          * but a durable reconnect on the new session succeeds:
     656             :          */
     657             : 
     658           4 :         ZERO_STRUCT(io);
     659           4 :         io.in.fname = "";
     660           4 :         io.in.durable_handle_v2 = h;
     661           4 :         io.in.create_guid = create_guid;
     662           4 :         status = smb2_create(tree2, mem_ctx, &io);
     663           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     664           4 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     665           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     666           4 :         CHECK_VAL(io.out.durable_open, false);
     667           4 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
     668           4 :         CHECK_VAL(io.out.persistent_open, false);
     669           4 :         CHECK_VAL(io.out.timeout, 0);
     670           4 :         _h = io.out.file.handle;
     671           4 :         h = &_h;
     672             : 
     673             :         /*
     674             :          * a session reconnect on a second tcp connection
     675             :          */
     676             : 
     677           4 :         previous_session_id = smb2cli_session_current_id(tree2->session->smbXcli);
     678             : 
     679             :         /* it works the same with the original guid */
     680           4 :         options.client_guid = orig_client_guid;
     681             : 
     682           4 :         ret = torture_smb2_connection_ext(tctx, previous_session_id,
     683             :                                           &options, &tree3);
     684           4 :         torture_assert_goto(tctx, ret, ret, done, "couldn't reconnect");
     685             : 
     686             :         /*
     687             :          * check that this has deleted the old session
     688             :          */
     689             : 
     690           4 :         ZERO_STRUCT(io);
     691           4 :         io.in.fname = "";
     692           4 :         io.in.durable_handle_v2 = h;
     693           4 :         io.in.create_guid = create_guid;
     694           4 :         status = smb2_create(tree2, mem_ctx, &io);
     695           4 :         CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
     696           4 :         TALLOC_FREE(tree2);
     697             : 
     698             :         /*
     699             :          * but a durable reconnect on the new session succeeds:
     700             :          */
     701             : 
     702           4 :         ZERO_STRUCT(io);
     703           4 :         io.in.fname = "";
     704           4 :         io.in.durable_handle_v2 = h;
     705           4 :         io.in.create_guid = create_guid;
     706           4 :         status = smb2_create(tree3, mem_ctx, &io);
     707           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     708           4 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     709           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     710           4 :         CHECK_VAL(io.out.durable_open, false);
     711           4 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
     712           4 :         CHECK_VAL(io.out.persistent_open, false);
     713           4 :         CHECK_VAL(io.out.timeout, 0);
     714           4 :         _h = io.out.file.handle;
     715           4 :         h = &_h;
     716             : 
     717           4 : done:
     718           4 :         if (tree == NULL) {
     719           4 :                 tree = tree2;
     720             :         }
     721             : 
     722           4 :         if (tree == NULL) {
     723           4 :                 tree = tree3;
     724             :         }
     725             : 
     726           4 :         if (tree != NULL) {
     727           4 :                 if (h != NULL) {
     728           4 :                         smb2_util_close(tree, *h);
     729             :                 }
     730             : 
     731           4 :                 smb2_util_unlink(tree, fname);
     732             : 
     733           4 :                 talloc_free(tree);
     734             :         }
     735             : 
     736           4 :         talloc_free(mem_ctx);
     737             : 
     738           4 :         return ret;
     739             : }
     740             : 
     741             : /**
     742             :  * lease variant of reopen1a
     743             :  *
     744             :  * Basic test for doing a durable open and doing a session
     745             :  * reconnect while the first session is still active and the
     746             :  * handle is still open in the client.
     747             :  * This closes the original session and  a durable reconnect on
     748             :  * the new session succeeds depending on the client guid:
     749             :  *
     750             :  * Durable reconnect on a session with a different client guid fails.
     751             :  * Durable reconnect on a session with the original client guid succeeds.
     752             :  */
     753           4 : bool test_durable_v2_open_reopen1a_lease(struct torture_context *tctx,
     754             :                                          struct smb2_tree *tree)
     755             : {
     756           0 :         NTSTATUS status;
     757           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     758           0 :         char fname[256];
     759           0 :         struct smb2_handle _h;
     760           4 :         struct smb2_handle *h = NULL;
     761           0 :         struct smb2_create io;
     762           4 :         struct GUID create_guid = GUID_random();
     763           0 :         struct smb2_lease ls;
     764           0 :         uint64_t lease_key;
     765           4 :         bool ret = true;
     766           4 :         struct smb2_tree *tree2 = NULL;
     767           4 :         struct smb2_tree *tree3 = NULL;
     768           0 :         uint64_t previous_session_id;
     769           0 :         struct smbcli_options options;
     770           0 :         struct GUID orig_client_guid;
     771             : 
     772           4 :         options = tree->session->transport->options;
     773           4 :         orig_client_guid = options.client_guid;
     774             : 
     775             :         /* Choose a random name in case the state is left a little funky. */
     776           4 :         snprintf(fname, 256, "durable_v2_open_reopen1a_lease_%s.dat",
     777             :                  generate_random_str(tctx, 8));
     778             : 
     779           4 :         smb2_util_unlink(tree, fname);
     780             : 
     781           4 :         lease_key = random();
     782           4 :         smb2_lease_create(&io, &ls, false /* dir */, fname,
     783             :                           lease_key, smb2_util_lease_state("RWH"));
     784           4 :         io.in.durable_open = false;
     785           4 :         io.in.durable_open_v2 = true;
     786           4 :         io.in.persistent_open = false;
     787           4 :         io.in.create_guid = create_guid;
     788           4 :         io.in.timeout = UINT32_MAX;
     789             : 
     790           4 :         status = smb2_create(tree, mem_ctx, &io);
     791           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     792           4 :         _h = io.out.file.handle;
     793           4 :         h = &_h;
     794           4 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     795           4 :         CHECK_VAL(io.out.durable_open, false);
     796           4 :         CHECK_VAL(io.out.durable_open_v2, true);
     797           4 :         CHECK_VAL(io.out.persistent_open, false);
     798           4 :         CHECK_VAL(io.out.timeout, 300*1000);
     799           4 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
     800           4 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
     801           4 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
     802           4 :         CHECK_VAL(io.out.lease_response.lease_state,
     803             :                   smb2_util_lease_state("RWH"));
     804           4 :         CHECK_VAL(io.out.lease_response.lease_flags, 0);
     805           4 :         CHECK_VAL(io.out.lease_response.lease_duration, 0);
     806             : 
     807           4 :         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
     808             : 
     809             :         /*
     810             :          * a session reconnect on a second tcp connection
     811             :          * with a different client_guid does not allow
     812             :          * the durable reconnect.
     813             :          */
     814             : 
     815           4 :         options.client_guid = GUID_random();
     816             : 
     817           4 :         ret = torture_smb2_connection_ext(tctx, previous_session_id,
     818             :                                           &options, &tree2);
     819           4 :         torture_assert_goto(tctx, ret, ret, done, "couldn't reconnect");
     820             : 
     821             :         /*
     822             :          * check that this has deleted the old session
     823             :          */
     824             : 
     825           4 :         ZERO_STRUCT(io);
     826           4 :         io.in.fname = fname;
     827           4 :         io.in.durable_handle_v2 = h;
     828           4 :         io.in.create_guid = create_guid;
     829           4 :         io.in.lease_request = &ls;
     830           4 :         status = smb2_create(tree, mem_ctx, &io);
     831           4 :         CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
     832           4 :         TALLOC_FREE(tree);
     833             : 
     834             :         /*
     835             :          * but a durable reconnect on the new session with the wrong
     836             :          * client guid fails
     837             :          */
     838             : 
     839           4 :         ZERO_STRUCT(io);
     840           4 :         io.in.fname = fname;
     841           4 :         io.in.durable_handle_v2 = h;
     842           4 :         io.in.create_guid = create_guid;
     843           4 :         io.in.lease_request = &ls;
     844           4 :         status = smb2_create(tree2, mem_ctx, &io);
     845           4 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     846             : 
     847             : 
     848             :         /*
     849             :          * now a session reconnect on a second tcp connection
     850             :          * with original client_guid allows the durable reconnect.
     851             :          */
     852             : 
     853           4 :         options.client_guid = orig_client_guid;
     854             :         //options.client_guid = GUID_random();
     855             : 
     856           4 :         ret = torture_smb2_connection_ext(tctx, previous_session_id,
     857             :                                           &options, &tree3);
     858           4 :         torture_assert_goto(tctx, ret, ret, done, "couldn't reconnect");
     859             : 
     860             :         /*
     861             :          * check that this has deleted the old session
     862             :          */
     863             : 
     864           4 :         ZERO_STRUCT(io);
     865           4 :         io.in.fname = fname;
     866           4 :         io.in.durable_handle_v2 = h;
     867           4 :         io.in.create_guid = create_guid;
     868           4 :         io.in.lease_request = &ls;
     869           4 :         status = smb2_create(tree2, mem_ctx, &io);
     870           4 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     871           4 :         TALLOC_FREE(tree2);
     872             : 
     873             :         /*
     874             :          * but a durable reconnect on the new session succeeds:
     875             :          */
     876             : 
     877           4 :         ZERO_STRUCT(io);
     878           4 :         io.in.fname = fname;
     879           4 :         io.in.durable_handle_v2 = h;
     880           4 :         io.in.create_guid = create_guid;
     881           4 :         io.in.lease_request = &ls;
     882           4 :         status = smb2_create(tree3, mem_ctx, &io);
     883           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     884           2 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     885           2 :         CHECK_VAL(io.out.durable_open, false);
     886           2 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
     887           2 :         CHECK_VAL(io.out.persistent_open, false);
     888           2 :         CHECK_VAL(io.out.timeout, 0);
     889           2 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
     890           2 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
     891           2 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
     892           2 :         CHECK_VAL(io.out.lease_response.lease_state,
     893             :                   smb2_util_lease_state("RWH"));
     894           2 :         CHECK_VAL(io.out.lease_response.lease_flags, 0);
     895           2 :         CHECK_VAL(io.out.lease_response.lease_duration, 0);
     896           2 :         _h = io.out.file.handle;
     897           2 :         h = &_h;
     898             : 
     899           4 : done:
     900           4 :         if (tree == NULL) {
     901           4 :                 tree = tree2;
     902             :         }
     903             : 
     904           4 :         if (tree == NULL) {
     905           4 :                 tree = tree3;
     906             :         }
     907             : 
     908           4 :         if (tree != NULL) {
     909           4 :                 if (h != NULL) {
     910           4 :                         smb2_util_close(tree, *h);
     911             :                 }
     912             : 
     913           4 :                 smb2_util_unlink(tree, fname);
     914             : 
     915           4 :                 talloc_free(tree);
     916             :         }
     917             : 
     918           4 :         talloc_free(mem_ctx);
     919             : 
     920           4 :         return ret;
     921             : }
     922             : 
     923             : /**
     924             :  * basic test for doing a durable open
     925             :  * tcp disconnect, reconnect, do a durable reopen (succeeds)
     926             :  */
     927           4 : bool test_durable_v2_open_reopen2(struct torture_context *tctx,
     928             :                                   struct smb2_tree *tree)
     929             : {
     930           0 :         NTSTATUS status;
     931           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     932           0 :         char fname[256];
     933           0 :         struct smb2_handle _h;
     934           4 :         struct smb2_handle *h = NULL;
     935           0 :         struct smb2_create io;
     936           4 :         struct GUID create_guid = GUID_random();
     937           4 :         struct GUID create_guid_invalid = GUID_random();
     938           4 :         bool ret = true;
     939             : 
     940             :         /* Choose a random name in case the state is left a little funky. */
     941           4 :         snprintf(fname, 256, "durable_v2_open_reopen2_%s.dat",
     942             :                  generate_random_str(tctx, 8));
     943             : 
     944           4 :         smb2_util_unlink(tree, fname);
     945             : 
     946           4 :         smb2_oplock_create_share(&io, fname,
     947             :                                  smb2_util_share_access(""),
     948           4 :                                  smb2_util_oplock_level("b"));
     949           4 :         io.in.durable_open = false;
     950           4 :         io.in.durable_open_v2 = true;
     951           4 :         io.in.persistent_open = false;
     952           4 :         io.in.create_guid = create_guid;
     953           4 :         io.in.timeout = UINT32_MAX;
     954             : 
     955           4 :         status = smb2_create(tree, mem_ctx, &io);
     956           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     957           4 :         _h = io.out.file.handle;
     958           4 :         h = &_h;
     959           4 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     960           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     961           4 :         CHECK_VAL(io.out.durable_open, false);
     962           4 :         CHECK_VAL(io.out.durable_open_v2, true);
     963           4 :         CHECK_VAL(io.out.persistent_open, false);
     964           4 :         CHECK_VAL(io.out.timeout, 300*1000);
     965             : 
     966             :         /* disconnect, leaving the durable open */
     967           4 :         TALLOC_FREE(tree);
     968             : 
     969           4 :         if (!torture_smb2_connection(tctx, &tree)) {
     970           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
     971           0 :                 ret = false;
     972           0 :                 goto done;
     973             :         }
     974             : 
     975             :         /*
     976             :          * first a few failure cases
     977             :          */
     978             : 
     979           4 :         ZERO_STRUCT(io);
     980           4 :         io.in.fname = "";
     981           4 :         io.in.durable_handle_v2 = h;
     982           4 :         status = smb2_create(tree, mem_ctx, &io);
     983           4 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     984             : 
     985           4 :         ZERO_STRUCT(io);
     986           4 :         io.in.fname = "__non_existing_fname__";
     987           4 :         io.in.durable_handle_v2 = h;
     988           4 :         status = smb2_create(tree, mem_ctx, &io);
     989           4 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     990             : 
     991           4 :         ZERO_STRUCT(io);
     992           4 :         io.in.fname = fname;
     993           4 :         io.in.durable_handle_v2 = h;
     994           4 :         status = smb2_create(tree, mem_ctx, &io);
     995           4 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     996             : 
     997             :         /* a non-zero but non-matching create_guid does not change it: */
     998           4 :         ZERO_STRUCT(io);
     999           4 :         io.in.fname = fname;
    1000           4 :         io.in.durable_handle_v2 = h;
    1001           4 :         io.in.create_guid = create_guid_invalid;
    1002           4 :         status = smb2_create(tree, mem_ctx, &io);
    1003           4 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1004             : 
    1005             :         /*
    1006             :          * now success:
    1007             :          * The important difference is that the create_guid is provided.
    1008             :          */
    1009           4 :         ZERO_STRUCT(io);
    1010           4 :         io.in.fname = fname;
    1011           4 :         io.in.durable_open_v2 = false;
    1012           4 :         io.in.durable_handle_v2 = h;
    1013           4 :         io.in.create_guid = create_guid;
    1014           4 :         h = NULL;
    1015             : 
    1016           4 :         status = smb2_create(tree, mem_ctx, &io);
    1017           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1018           4 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1019           4 :         CHECK_VAL(io.out.durable_open, false);
    1020           4 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    1021           4 :         CHECK_VAL(io.out.persistent_open, false);
    1022           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    1023           4 :         _h = io.out.file.handle;
    1024           4 :         h = &_h;
    1025             : 
    1026             :         /* disconnect one more time */
    1027           4 :         TALLOC_FREE(tree);
    1028             : 
    1029           4 :         if (!torture_smb2_connection(tctx, &tree)) {
    1030           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
    1031           0 :                 ret = false;
    1032           0 :                 goto done;
    1033             :         }
    1034             : 
    1035           4 :         ZERO_STRUCT(io);
    1036             :         /* These are completely ignored by the server */
    1037           4 :         io.in.security_flags = 0x78;
    1038           4 :         io.in.oplock_level = 0x78;
    1039           4 :         io.in.impersonation_level = 0x12345678;
    1040           4 :         io.in.create_flags = 0x12345678;
    1041           4 :         io.in.reserved = 0x12345678;
    1042           4 :         io.in.desired_access = 0x12345678;
    1043           4 :         io.in.file_attributes = 0x12345678;
    1044           4 :         io.in.share_access = 0x12345678;
    1045           4 :         io.in.create_disposition = 0x12345678;
    1046           4 :         io.in.create_options = 0x12345678;
    1047           4 :         io.in.fname = "__non_existing_fname__";
    1048             : 
    1049             :         /*
    1050             :          * only io.in.durable_handle_v2 and
    1051             :          * io.in.create_guid are checked
    1052             :          */
    1053           4 :         io.in.durable_open_v2 = false;
    1054           4 :         io.in.durable_handle_v2 = h;
    1055           4 :         io.in.create_guid = create_guid;
    1056           4 :         h = NULL;
    1057             : 
    1058           4 :         status = smb2_create(tree, mem_ctx, &io);
    1059           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1060           4 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1061           4 :         CHECK_VAL(io.out.durable_open, false);
    1062           4 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    1063           4 :         CHECK_VAL(io.out.persistent_open, false);
    1064           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    1065           4 :         _h = io.out.file.handle;
    1066           4 :         h = &_h;
    1067             : 
    1068           4 : done:
    1069           4 :         if (h != NULL) {
    1070           4 :                 smb2_util_close(tree, *h);
    1071             :         }
    1072             : 
    1073           4 :         smb2_util_unlink(tree, fname);
    1074             : 
    1075           4 :         talloc_free(tree);
    1076             : 
    1077           4 :         talloc_free(mem_ctx);
    1078             : 
    1079           4 :         return ret;
    1080             : }
    1081             : 
    1082             : /**
    1083             :  * durable reconnect test:
    1084             :  * connect with v2, reconnect with v1
    1085             :  */
    1086           4 : bool test_durable_v2_open_reopen2b(struct torture_context *tctx,
    1087             :                                    struct smb2_tree *tree)
    1088             : {
    1089           0 :         NTSTATUS status;
    1090           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1091           0 :         char fname[256];
    1092           0 :         struct smb2_handle _h;
    1093           4 :         struct smb2_handle *h = NULL;
    1094           0 :         struct smb2_create io;
    1095           4 :         struct GUID create_guid = GUID_random();
    1096           4 :         bool ret = true;
    1097           0 :         struct smbcli_options options;
    1098             : 
    1099           4 :         options = tree->session->transport->options;
    1100             : 
    1101             :         /* Choose a random name in case the state is left a little funky. */
    1102           4 :         snprintf(fname, 256, "durable_v2_open_reopen2b_%s.dat",
    1103             :                  generate_random_str(tctx, 8));
    1104             : 
    1105           4 :         smb2_util_unlink(tree, fname);
    1106             : 
    1107           4 :         smb2_oplock_create_share(&io, fname,
    1108             :                                  smb2_util_share_access(""),
    1109           4 :                                  smb2_util_oplock_level("b"));
    1110           4 :         io.in.durable_open = false;
    1111           4 :         io.in.durable_open_v2 = true;
    1112           4 :         io.in.persistent_open = false;
    1113           4 :         io.in.create_guid = create_guid;
    1114           4 :         io.in.timeout = UINT32_MAX;
    1115             : 
    1116           4 :         status = smb2_create(tree, mem_ctx, &io);
    1117           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1118           4 :         _h = io.out.file.handle;
    1119           4 :         h = &_h;
    1120           4 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1121           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    1122           4 :         CHECK_VAL(io.out.durable_open, false);
    1123           4 :         CHECK_VAL(io.out.durable_open_v2, true);
    1124           4 :         CHECK_VAL(io.out.persistent_open, false);
    1125           4 :         CHECK_VAL(io.out.timeout, 300*1000);
    1126             : 
    1127             :         /* disconnect, leaving the durable open */
    1128           4 :         TALLOC_FREE(tree);
    1129             : 
    1130           4 :         if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
    1131           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
    1132           0 :                 ret = false;
    1133           0 :                 goto done;
    1134             :         }
    1135             : 
    1136           4 :         ZERO_STRUCT(io);
    1137           4 :         io.in.fname = fname;
    1138           4 :         io.in.durable_handle_v2 = h;     /* durable v2 reconnect */
    1139           4 :         io.in.create_guid = GUID_zero(); /* but zero create GUID */
    1140           4 :         status = smb2_create(tree, mem_ctx, &io);
    1141           4 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1142             : 
    1143           4 :         ZERO_STRUCT(io);
    1144           4 :         io.in.fname = fname;
    1145           4 :         io.in.durable_handle = h; /* durable v1 (!) reconnect */
    1146           4 :         h = NULL;
    1147             : 
    1148           4 :         status = smb2_create(tree, mem_ctx, &io);
    1149           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1150           4 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1151           4 :         CHECK_VAL(io.out.durable_open, false);
    1152           4 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    1153           4 :         CHECK_VAL(io.out.persistent_open, false);
    1154           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    1155           4 :         _h = io.out.file.handle;
    1156           4 :         h = &_h;
    1157             : 
    1158           4 : done:
    1159           4 :         if (h != NULL) {
    1160           4 :                 smb2_util_close(tree, *h);
    1161             :         }
    1162             : 
    1163           4 :         smb2_util_unlink(tree, fname);
    1164             : 
    1165           4 :         talloc_free(tree);
    1166             : 
    1167           4 :         talloc_free(mem_ctx);
    1168             : 
    1169           4 :         return ret;
    1170             : }
    1171             : /**
    1172             :  * durable reconnect test:
    1173             :  * connect with v1, reconnect with v2 : fails (no create_guid...)
    1174             :  */
    1175           4 : bool test_durable_v2_open_reopen2c(struct torture_context *tctx,
    1176             :                                    struct smb2_tree *tree)
    1177             : {
    1178           0 :         NTSTATUS status;
    1179           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1180           0 :         char fname[256];
    1181           0 :         struct smb2_handle _h;
    1182           4 :         struct smb2_handle *h = NULL;
    1183           0 :         struct smb2_create io;
    1184           4 :         struct GUID create_guid = GUID_random();
    1185           4 :         bool ret = true;
    1186           0 :         struct smbcli_options options;
    1187             : 
    1188           4 :         options = tree->session->transport->options;
    1189             : 
    1190             :         /* Choose a random name in case the state is left a little funky. */
    1191           4 :         snprintf(fname, 256, "durable_v2_open_reopen2c_%s.dat",
    1192             :                  generate_random_str(tctx, 8));
    1193             : 
    1194           4 :         smb2_util_unlink(tree, fname);
    1195             : 
    1196           4 :         smb2_oplock_create_share(&io, fname,
    1197             :                                  smb2_util_share_access(""),
    1198           4 :                                  smb2_util_oplock_level("b"));
    1199           4 :         io.in.durable_open = true;
    1200           4 :         io.in.durable_open_v2 = false;
    1201           4 :         io.in.persistent_open = false;
    1202           4 :         io.in.create_guid = create_guid;
    1203           4 :         io.in.timeout = UINT32_MAX;
    1204             : 
    1205           4 :         status = smb2_create(tree, mem_ctx, &io);
    1206           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1207           4 :         _h = io.out.file.handle;
    1208           4 :         h = &_h;
    1209           4 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1210           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    1211           4 :         CHECK_VAL(io.out.durable_open, true);
    1212           4 :         CHECK_VAL(io.out.durable_open_v2, false);
    1213           4 :         CHECK_VAL(io.out.persistent_open, false);
    1214           4 :         CHECK_VAL(io.out.timeout, 0);
    1215             : 
    1216             :         /* disconnect, leaving the durable open */
    1217           4 :         TALLOC_FREE(tree);
    1218             : 
    1219           4 :         if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
    1220           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
    1221           0 :                 ret = false;
    1222           0 :                 goto done;
    1223             :         }
    1224             : 
    1225           4 :         ZERO_STRUCT(io);
    1226           4 :         io.in.fname = fname;
    1227           4 :         io.in.durable_handle_v2 = h;     /* durable v2 reconnect */
    1228           4 :         io.in.create_guid = create_guid;
    1229           4 :         status = smb2_create(tree, mem_ctx, &io);
    1230           4 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1231             : 
    1232           4 : done:
    1233           4 :         if (h != NULL) {
    1234           4 :                 smb2_util_close(tree, *h);
    1235             :         }
    1236             : 
    1237           4 :         smb2_util_unlink(tree, fname);
    1238             : 
    1239           4 :         talloc_free(tree);
    1240             : 
    1241           4 :         talloc_free(mem_ctx);
    1242             : 
    1243           4 :         return ret;
    1244             : }
    1245             : 
    1246             : /**
    1247             :  * lease variant of reopen2
    1248             :  * basic test for doing a durable open
    1249             :  * tcp disconnect, reconnect, do a durable reopen (succeeds)
    1250             :  */
    1251           4 : bool test_durable_v2_open_reopen2_lease(struct torture_context *tctx,
    1252             :                                         struct smb2_tree *tree)
    1253             : {
    1254           0 :         NTSTATUS status;
    1255           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1256           0 :         char fname[256];
    1257           0 :         struct smb2_handle _h;
    1258           4 :         struct smb2_handle *h = NULL;
    1259           0 :         struct smb2_create io;
    1260           4 :         struct GUID create_guid = GUID_random();
    1261           0 :         struct smb2_lease ls;
    1262           0 :         uint64_t lease_key;
    1263           4 :         bool ret = true;
    1264           0 :         struct smbcli_options options;
    1265           0 :         uint32_t caps;
    1266             : 
    1267           4 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
    1268           4 :         if (!(caps & SMB2_CAP_LEASING)) {
    1269           2 :                 torture_skip(tctx, "leases are not supported");
    1270             :         }
    1271             : 
    1272           2 :         options = tree->session->transport->options;
    1273             : 
    1274             :         /* Choose a random name in case the state is left a little funky. */
    1275           2 :         snprintf(fname, 256, "durable_v2_open_reopen2_%s.dat",
    1276             :                  generate_random_str(tctx, 8));
    1277             : 
    1278           2 :         smb2_util_unlink(tree, fname);
    1279             : 
    1280           2 :         lease_key = generate_random_u64();
    1281           2 :         smb2_lease_create(&io, &ls, false /* dir */, fname,
    1282             :                           lease_key, smb2_util_lease_state("RWH"));
    1283           2 :         io.in.durable_open = false;
    1284           2 :         io.in.durable_open_v2 = true;
    1285           2 :         io.in.persistent_open = false;
    1286           2 :         io.in.create_guid = create_guid;
    1287           2 :         io.in.timeout = UINT32_MAX;
    1288             : 
    1289           2 :         status = smb2_create(tree, mem_ctx, &io);
    1290           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1291           2 :         _h = io.out.file.handle;
    1292           2 :         h = &_h;
    1293           2 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1294           2 :         CHECK_VAL(io.out.durable_open, false);
    1295           2 :         CHECK_VAL(io.out.durable_open_v2, true);
    1296           2 :         CHECK_VAL(io.out.persistent_open, false);
    1297           2 :         CHECK_VAL(io.out.timeout, 300*1000);
    1298           2 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    1299           2 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
    1300           2 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
    1301           2 :         CHECK_VAL(io.out.lease_response.lease_state,
    1302             :                   smb2_util_lease_state("RWH"));
    1303           2 :         CHECK_VAL(io.out.lease_response.lease_flags, 0);
    1304           2 :         CHECK_VAL(io.out.lease_response.lease_duration, 0);
    1305             : 
    1306             :         /* disconnect, reconnect and then do durable reopen */
    1307           2 :         TALLOC_FREE(tree);
    1308             : 
    1309           2 :         if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
    1310           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
    1311           0 :                 ret = false;
    1312           0 :                 goto done;
    1313             :         }
    1314             : 
    1315             :         /* a few failure tests: */
    1316             : 
    1317             :         /*
    1318             :          * several attempts without lease attached:
    1319             :          * all fail with NT_STATUS_OBJECT_NAME_NOT_FOUND
    1320             :          * irrespective of file name provided
    1321             :          */
    1322             : 
    1323           2 :         ZERO_STRUCT(io);
    1324           2 :         io.in.fname = "";
    1325           2 :         io.in.durable_handle_v2 = h;
    1326           2 :         status = smb2_create(tree, mem_ctx, &io);
    1327           2 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1328             : 
    1329           2 :         ZERO_STRUCT(io);
    1330           2 :         io.in.fname = "__non_existing_fname__";
    1331           2 :         io.in.durable_handle_v2 = h;
    1332           2 :         status = smb2_create(tree, mem_ctx, &io);
    1333           2 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1334             : 
    1335           2 :         ZERO_STRUCT(io);
    1336           2 :         io.in.fname = fname;
    1337           2 :         io.in.durable_handle_v2 = h;
    1338           2 :         status = smb2_create(tree, mem_ctx, &io);
    1339           2 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1340             : 
    1341             :         /*
    1342             :          * attempt with lease provided, but
    1343             :          * with a changed lease key. => fails
    1344             :          */
    1345           2 :         ZERO_STRUCT(io);
    1346           2 :         io.in.fname = fname;
    1347           2 :         io.in.durable_open_v2 = false;
    1348           2 :         io.in.durable_handle_v2 = h;
    1349           2 :         io.in.create_guid = create_guid;
    1350           2 :         io.in.lease_request = &ls;
    1351           2 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
    1352             :         /* a wrong lease key lets the request fail */
    1353           2 :         ls.lease_key.data[0]++;
    1354             : 
    1355           2 :         status = smb2_create(tree, mem_ctx, &io);
    1356           2 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1357             : 
    1358             :         /* restore the correct lease key */
    1359           2 :         ls.lease_key.data[0]--;
    1360             : 
    1361             :         /*
    1362             :          * this last failing attempt is almost correct:
    1363             :          * only problem is: we use the wrong filename...
    1364             :          * Note that this gives INVALID_PARAMETER.
    1365             :          * This is different from oplocks!
    1366             :          */
    1367           2 :         ZERO_STRUCT(io);
    1368           2 :         io.in.fname = "__non_existing_fname__";
    1369           2 :         io.in.durable_open_v2 = false;
    1370           2 :         io.in.durable_handle_v2 = h;
    1371           2 :         io.in.create_guid = create_guid;
    1372           2 :         io.in.lease_request = &ls;
    1373           2 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
    1374             : 
    1375           2 :         status = smb2_create(tree, mem_ctx, &io);
    1376           2 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
    1377             : 
    1378             :         /*
    1379             :          * Now for a succeeding reconnect:
    1380             :          */
    1381             : 
    1382           2 :         ZERO_STRUCT(io);
    1383           2 :         io.in.fname = fname;
    1384           2 :         io.in.durable_open_v2 = false;
    1385           2 :         io.in.durable_handle_v2 = h;
    1386           2 :         io.in.create_guid = create_guid;
    1387           2 :         io.in.lease_request = &ls;
    1388           2 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
    1389             : 
    1390             :         /* the requested lease state is irrelevant */
    1391           2 :         ls.lease_state = smb2_util_lease_state("");
    1392             : 
    1393           2 :         h = NULL;
    1394             : 
    1395           2 :         status = smb2_create(tree, mem_ctx, &io);
    1396           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1397             : 
    1398           2 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1399           2 :         CHECK_VAL(io.out.durable_open, false);
    1400           2 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    1401           2 :         CHECK_VAL(io.out.persistent_open, false);
    1402           2 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    1403           2 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
    1404           2 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
    1405           2 :         CHECK_VAL(io.out.lease_response.lease_state,
    1406             :                   smb2_util_lease_state("RWH"));
    1407           2 :         CHECK_VAL(io.out.lease_response.lease_flags, 0);
    1408           2 :         CHECK_VAL(io.out.lease_response.lease_duration, 0);
    1409           2 :         _h = io.out.file.handle;
    1410           2 :         h = &_h;
    1411             : 
    1412             :         /* disconnect one more time */
    1413           2 :         TALLOC_FREE(tree);
    1414             : 
    1415           2 :         if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
    1416           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
    1417           0 :                 ret = false;
    1418           0 :                 goto done;
    1419             :         }
    1420             : 
    1421             :         /*
    1422             :          * demonstrate that various parameters are ignored
    1423             :          * in the reconnect
    1424             :          */
    1425             : 
    1426           2 :         ZERO_STRUCT(io);
    1427             :         /*
    1428             :          * These are completely ignored by the server
    1429             :          */
    1430           2 :         io.in.security_flags = 0x78;
    1431           2 :         io.in.oplock_level = 0x78;
    1432           2 :         io.in.impersonation_level = 0x12345678;
    1433           2 :         io.in.create_flags = 0x12345678;
    1434           2 :         io.in.reserved = 0x12345678;
    1435           2 :         io.in.desired_access = 0x12345678;
    1436           2 :         io.in.file_attributes = 0x12345678;
    1437           2 :         io.in.share_access = 0x12345678;
    1438           2 :         io.in.create_disposition = 0x12345678;
    1439           2 :         io.in.create_options = 0x12345678;
    1440             : 
    1441             :         /*
    1442             :          * only these are checked:
    1443             :          * - io.in.fname
    1444             :          * - io.in.durable_handle_v2,
    1445             :          * - io.in.create_guid
    1446             :          * - io.in.lease_request->lease_key
    1447             :          */
    1448             : 
    1449           2 :         io.in.fname = fname;
    1450           2 :         io.in.durable_open_v2 = false;
    1451           2 :         io.in.durable_handle_v2 = h;
    1452           2 :         io.in.create_guid = create_guid;
    1453           2 :         io.in.lease_request = &ls;
    1454             : 
    1455             :         /* the requested lease state is irrelevant */
    1456           2 :         ls.lease_state = smb2_util_lease_state("");
    1457             : 
    1458           2 :         h = NULL;
    1459             : 
    1460           2 :         status = smb2_create(tree, mem_ctx, &io);
    1461           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1462             : 
    1463           2 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1464           2 :         CHECK_VAL(io.out.durable_open, false);
    1465           2 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    1466           2 :         CHECK_VAL(io.out.persistent_open, false);
    1467           2 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    1468           2 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
    1469           2 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
    1470           2 :         CHECK_VAL(io.out.lease_response.lease_state,
    1471             :                   smb2_util_lease_state("RWH"));
    1472           2 :         CHECK_VAL(io.out.lease_response.lease_flags, 0);
    1473           2 :         CHECK_VAL(io.out.lease_response.lease_duration, 0);
    1474             : 
    1475           2 :         _h = io.out.file.handle;
    1476           2 :         h = &_h;
    1477             : 
    1478           2 : done:
    1479           2 :         if (h != NULL) {
    1480           2 :                 smb2_util_close(tree, *h);
    1481             :         }
    1482             : 
    1483           2 :         smb2_util_unlink(tree, fname);
    1484             : 
    1485           2 :         talloc_free(tree);
    1486             : 
    1487           2 :         talloc_free(mem_ctx);
    1488             : 
    1489           2 :         return ret;
    1490             : }
    1491             : 
    1492             : /**
    1493             :  * lease_v2 variant of reopen2
    1494             :  * basic test for doing a durable open
    1495             :  * tcp disconnect, reconnect, do a durable reopen (succeeds)
    1496             :  */
    1497           4 : bool test_durable_v2_open_reopen2_lease_v2(struct torture_context *tctx,
    1498             :                                            struct smb2_tree *tree)
    1499             : {
    1500           0 :         NTSTATUS status;
    1501           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1502           0 :         char fname[256];
    1503           0 :         struct smb2_handle _h;
    1504           4 :         struct smb2_handle *h = NULL;
    1505           0 :         struct smb2_create io;
    1506           4 :         struct GUID create_guid = GUID_random();
    1507           0 :         struct smb2_lease ls;
    1508           0 :         uint64_t lease_key;
    1509           4 :         bool ret = true;
    1510           0 :         struct smbcli_options options;
    1511           0 :         uint32_t caps;
    1512             : 
    1513           4 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
    1514           4 :         if (!(caps & SMB2_CAP_LEASING)) {
    1515           2 :                 torture_skip(tctx, "leases are not supported");
    1516             :         }
    1517             : 
    1518           2 :         options = tree->session->transport->options;
    1519             : 
    1520           2 :         smb2_deltree(tree, __func__);
    1521           2 :         status = torture_smb2_testdir(tree, __func__, &_h);
    1522           2 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1523             :                                         "torture_smb2_testdir failed\n");
    1524           2 :         smb2_util_close(tree, _h);
    1525             : 
    1526             :         /* Choose a random name in case the state is left a little funky. */
    1527           2 :         snprintf(fname, 256, "%s\\durable_v2_open_reopen2_%s.dat",
    1528             :                  __func__, generate_random_str(tctx, 8));
    1529             : 
    1530           2 :         smb2_util_unlink(tree, fname);
    1531             : 
    1532           2 :         lease_key = random();
    1533           2 :         smb2_lease_v2_create(&io, &ls, false /* dir */, fname,
    1534             :                              lease_key, 0, /* parent lease key */
    1535             :                              smb2_util_lease_state("RWH"), 0 /* lease epoch */);
    1536           2 :         io.in.durable_open = false;
    1537           2 :         io.in.durable_open_v2 = true;
    1538           2 :         io.in.persistent_open = false;
    1539           2 :         io.in.create_guid = create_guid;
    1540           2 :         io.in.timeout = UINT32_MAX;
    1541             : 
    1542           2 :         status = smb2_create(tree, mem_ctx, &io);
    1543           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1544           2 :         _h = io.out.file.handle;
    1545           2 :         h = &_h;
    1546           2 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1547           2 :         CHECK_VAL(io.out.durable_open, false);
    1548           2 :         CHECK_VAL(io.out.durable_open_v2, true);
    1549           2 :         CHECK_VAL(io.out.persistent_open, false);
    1550           2 :         CHECK_VAL(io.out.timeout, 300*1000);
    1551           2 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    1552           2 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
    1553           2 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
    1554             : 
    1555             :         /* disconnect, reconnect and then do durable reopen */
    1556           2 :         TALLOC_FREE(tree);
    1557             : 
    1558           2 :         if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
    1559           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
    1560           0 :                 ret = false;
    1561           0 :                 goto done;
    1562             :         }
    1563             : 
    1564             :         /* a few failure tests: */
    1565             : 
    1566             :         /*
    1567             :          * several attempts without lease attached:
    1568             :          * all fail with NT_STATUS_OBJECT_NAME_NOT_FOUND
    1569             :          * irrespective of file name provided
    1570             :          */
    1571             : 
    1572           2 :         ZERO_STRUCT(io);
    1573           2 :         io.in.fname = "";
    1574           2 :         io.in.durable_handle_v2 = h;
    1575           2 :         status = smb2_create(tree, mem_ctx, &io);
    1576           2 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1577             : 
    1578           2 :         ZERO_STRUCT(io);
    1579           2 :         io.in.fname = "__non_existing_fname__";
    1580           2 :         io.in.durable_handle_v2 = h;
    1581           2 :         status = smb2_create(tree, mem_ctx, &io);
    1582           2 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1583             : 
    1584           2 :         ZERO_STRUCT(io);
    1585           2 :         io.in.fname = fname;
    1586           2 :         io.in.durable_handle_v2 = h;
    1587           2 :         status = smb2_create(tree, mem_ctx, &io);
    1588           2 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1589             : 
    1590             :         /*
    1591             :          * attempt with lease provided, but
    1592             :          * with a changed lease key. => fails
    1593             :          */
    1594           2 :         ZERO_STRUCT(io);
    1595           2 :         io.in.fname = fname;
    1596           2 :         io.in.durable_open_v2 = false;
    1597           2 :         io.in.durable_handle_v2 = h;
    1598           2 :         io.in.create_guid = create_guid;
    1599           2 :         io.in.lease_request_v2 = &ls;
    1600           2 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
    1601             :         /* a wrong lease key lets the request fail */
    1602           2 :         ls.lease_key.data[0]++;
    1603             : 
    1604           2 :         status = smb2_create(tree, mem_ctx, &io);
    1605           2 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1606             : 
    1607             :         /* restore the correct lease key */
    1608           2 :         ls.lease_key.data[0]--;
    1609             : 
    1610             : 
    1611             :         /*
    1612             :          * this last failing attempt is almost correct:
    1613             :          * only problem is: we use the wrong filename...
    1614             :          * Note that this gives INVALID_PARAMETER.
    1615             :          * This is different from oplocks!
    1616             :          */
    1617           2 :         ZERO_STRUCT(io);
    1618           2 :         io.in.fname = "__non_existing_fname__";
    1619           2 :         io.in.durable_open_v2 = false;
    1620           2 :         io.in.durable_handle_v2 = h;
    1621           2 :         io.in.create_guid = create_guid;
    1622           2 :         io.in.lease_request_v2 = &ls;
    1623           2 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
    1624             : 
    1625           2 :         status = smb2_create(tree, mem_ctx, &io);
    1626           2 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
    1627             : 
    1628             :         /*
    1629             :          * Now for a succeeding reconnect:
    1630             :          */
    1631             : 
    1632           2 :         ZERO_STRUCT(io);
    1633           2 :         io.in.fname = fname;
    1634           2 :         io.in.durable_open_v2 = false;
    1635           2 :         io.in.durable_handle_v2 = h;
    1636           2 :         io.in.create_guid = create_guid;
    1637           2 :         io.in.lease_request_v2 = &ls;
    1638           2 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
    1639             : 
    1640             :         /* the requested lease state is irrelevant */
    1641           2 :         ls.lease_state = smb2_util_lease_state("");
    1642             : 
    1643           2 :         h = NULL;
    1644             : 
    1645           2 :         status = smb2_create(tree, mem_ctx, &io);
    1646           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1647             : 
    1648           2 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1649           2 :         CHECK_VAL(io.out.durable_open, false);
    1650           2 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    1651           2 :         CHECK_VAL(io.out.persistent_open, false);
    1652           2 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    1653           2 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
    1654           2 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
    1655           2 :         CHECK_VAL(io.out.lease_response_v2.lease_state,
    1656             :                   smb2_util_lease_state("RWH"));
    1657           2 :         CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
    1658           2 :         CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
    1659           2 :         _h = io.out.file.handle;
    1660           2 :         h = &_h;
    1661             : 
    1662             :         /* disconnect one more time */
    1663           2 :         TALLOC_FREE(tree);
    1664             : 
    1665           2 :         if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
    1666           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
    1667           0 :                 ret = false;
    1668           0 :                 goto done;
    1669             :         }
    1670             : 
    1671             :         /*
    1672             :          * demonstrate that various parameters are ignored
    1673             :          * in the reconnect
    1674             :          */
    1675             : 
    1676           2 :         ZERO_STRUCT(io);
    1677             :         /*
    1678             :          * These are completely ignored by the server
    1679             :          */
    1680           2 :         io.in.security_flags = 0x78;
    1681           2 :         io.in.oplock_level = 0x78;
    1682           2 :         io.in.impersonation_level = 0x12345678;
    1683           2 :         io.in.create_flags = 0x12345678;
    1684           2 :         io.in.reserved = 0x12345678;
    1685           2 :         io.in.desired_access = 0x12345678;
    1686           2 :         io.in.file_attributes = 0x12345678;
    1687           2 :         io.in.share_access = 0x12345678;
    1688           2 :         io.in.create_disposition = 0x12345678;
    1689           2 :         io.in.create_options = 0x12345678;
    1690           2 :         io.in.fname = "__non_existing_fname__";
    1691             : 
    1692             :         /*
    1693             :          * only these are checked:
    1694             :          * - io.in.fname
    1695             :          * - io.in.durable_handle_v2,
    1696             :          * - io.in.create_guid
    1697             :          * - io.in.lease_request_v2->lease_key
    1698             :          */
    1699             : 
    1700           2 :         io.in.fname = fname;
    1701           2 :         io.in.durable_open_v2 = false;
    1702           2 :         io.in.durable_handle_v2 = h;
    1703           2 :         io.in.create_guid = create_guid;
    1704           2 :         io.in.lease_request_v2 = &ls;
    1705             : 
    1706             :         /* the requested lease state is irrelevant */
    1707           2 :         ls.lease_state = smb2_util_lease_state("");
    1708             : 
    1709           2 :         h = NULL;
    1710             : 
    1711           2 :         status = smb2_create(tree, mem_ctx, &io);
    1712           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1713           2 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1714           2 :         CHECK_VAL(io.out.durable_open, false);
    1715           2 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    1716           2 :         CHECK_VAL(io.out.persistent_open, false);
    1717           2 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    1718           2 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
    1719           2 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
    1720           2 :         CHECK_VAL(io.out.lease_response_v2.lease_state,
    1721             :                   smb2_util_lease_state("RWH"));
    1722           2 :         CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
    1723           2 :         CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
    1724             : 
    1725           2 :         _h = io.out.file.handle;
    1726           2 :         h = &_h;
    1727             : 
    1728           2 : done:
    1729           2 :         if (h != NULL) {
    1730           2 :                 smb2_util_close(tree, *h);
    1731             :         }
    1732             : 
    1733           2 :         smb2_util_unlink(tree, fname);
    1734           2 :         smb2_deltree(tree, __func__);
    1735             : 
    1736           2 :         talloc_free(tree);
    1737             : 
    1738           2 :         talloc_free(mem_ctx);
    1739             : 
    1740           2 :         return ret;
    1741             : }
    1742             : 
    1743             : /**
    1744             :  * Test durable request / reconnect with AppInstanceId
    1745             :  */
    1746           4 : bool test_durable_v2_open_app_instance(struct torture_context *tctx,
    1747             :                                        struct smb2_tree *tree1,
    1748             :                                        struct smb2_tree *tree2)
    1749             : {
    1750           0 :         NTSTATUS status;
    1751           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1752           0 :         char fname[256];
    1753           0 :         struct smb2_handle _h1, _h2;
    1754           4 :         struct smb2_handle *h1 = NULL, *h2 = NULL;
    1755           0 :         struct smb2_create io1, io2;
    1756           4 :         bool ret = true;
    1757           4 :         struct GUID create_guid_1 = GUID_random();
    1758           4 :         struct GUID create_guid_2 = GUID_random();
    1759           4 :         struct GUID app_instance_id = GUID_random();
    1760             : 
    1761             :         /* Choose a random name in case the state is left a little funky. */
    1762           4 :         snprintf(fname, 256, "durable_v2_open_app_instance_%s.dat",
    1763             :                  generate_random_str(tctx, 8));
    1764             : 
    1765           4 :         smb2_util_unlink(tree1, fname);
    1766             : 
    1767           4 :         ZERO_STRUCT(break_info);
    1768           4 :         tree1->session->transport->oplock.handler = torture_oplock_handler;
    1769           4 :         tree1->session->transport->oplock.private_data = tree1;
    1770             : 
    1771           4 :         smb2_oplock_create_share(&io1, fname,
    1772             :                                  smb2_util_share_access(""),
    1773           4 :                                  smb2_util_oplock_level("b"));
    1774           4 :         io1.in.durable_open = false;
    1775           4 :         io1.in.durable_open_v2 = true;
    1776           4 :         io1.in.persistent_open = false;
    1777           4 :         io1.in.create_guid = create_guid_1;
    1778           4 :         io1.in.app_instance_id = &app_instance_id;
    1779           4 :         io1.in.timeout = UINT32_MAX;
    1780             : 
    1781           4 :         status = smb2_create(tree1, mem_ctx, &io1);
    1782           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1783           4 :         _h1 = io1.out.file.handle;
    1784           4 :         h1 = &_h1;
    1785           4 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1786           4 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
    1787           4 :         CHECK_VAL(io1.out.durable_open, false);
    1788           4 :         CHECK_VAL(io1.out.durable_open_v2, true);
    1789           4 :         CHECK_VAL(io1.out.persistent_open, false);
    1790           4 :         CHECK_VAL(io1.out.timeout, 300*1000);
    1791             : 
    1792             :         /*
    1793             :          * try to open the file as durable from a second tree with
    1794             :          * a different create guid but the same app_instance_id
    1795             :          * while the first handle is still open.
    1796             :          */
    1797             : 
    1798           4 :         smb2_oplock_create_share(&io2, fname,
    1799             :                                  smb2_util_share_access(""),
    1800           4 :                                  smb2_util_oplock_level("b"));
    1801           4 :         io2.in.durable_open = false;
    1802           4 :         io2.in.durable_open_v2 = true;
    1803           4 :         io2.in.persistent_open = false;
    1804           4 :         io2.in.create_guid = create_guid_2;
    1805           4 :         io2.in.app_instance_id = &app_instance_id;
    1806           4 :         io2.in.timeout = UINT32_MAX;
    1807             : 
    1808           4 :         status = smb2_create(tree2, mem_ctx, &io2);
    1809           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1810           4 :         _h2 = io2.out.file.handle;
    1811           4 :         h2 = &_h2;
    1812           4 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1813           4 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
    1814           4 :         CHECK_VAL(io2.out.durable_open, false);
    1815           4 :         CHECK_VAL(io2.out.durable_open_v2, true);
    1816           4 :         CHECK_VAL(io2.out.persistent_open, false);
    1817           4 :         CHECK_VAL(io2.out.timeout, 300*1000);
    1818             : 
    1819           4 :         CHECK_VAL(break_info.count, 0);
    1820             : 
    1821           4 :         status = smb2_util_close(tree1, *h1);
    1822           4 :         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
    1823           4 :         h1 = NULL;
    1824             : 
    1825           4 : done:
    1826           4 :         if (h1 != NULL) {
    1827           0 :                 smb2_util_close(tree1, *h1);
    1828             :         }
    1829           4 :         if (h2 != NULL) {
    1830           4 :                 smb2_util_close(tree2, *h2);
    1831             :         }
    1832             : 
    1833           4 :         smb2_util_unlink(tree2, fname);
    1834             : 
    1835           4 :         talloc_free(tree1);
    1836           4 :         talloc_free(tree2);
    1837             : 
    1838           4 :         talloc_free(mem_ctx);
    1839             : 
    1840           4 :         return ret;
    1841             : }
    1842             : 
    1843             : 
    1844             : /**
    1845             :  * basic persistent open test.
    1846             :  *
    1847             :  * This test tests durable open with all possible oplock types.
    1848             :  */
    1849             : 
    1850             : struct durable_open_vs_oplock persistent_open_oplock_ca_table[NUM_OPLOCK_OPEN_TESTS] =
    1851             : {
    1852             :         { "", "", true, true },
    1853             :         { "", "R", true, true },
    1854             :         { "", "W", true, true },
    1855             :         { "", "D", true, true },
    1856             :         { "", "RD", true, true },
    1857             :         { "", "RW", true, true },
    1858             :         { "", "WD", true, true },
    1859             :         { "", "RWD", true, true },
    1860             : 
    1861             :         { "s", "", true, true },
    1862             :         { "s", "R", true, true },
    1863             :         { "s", "W", true, true },
    1864             :         { "s", "D", true, true },
    1865             :         { "s", "RD", true, true },
    1866             :         { "s", "RW", true, true },
    1867             :         { "s", "WD", true, true },
    1868             :         { "s", "RWD", true, true },
    1869             : 
    1870             :         { "x", "", true, true },
    1871             :         { "x", "R", true, true },
    1872             :         { "x", "W", true, true },
    1873             :         { "x", "D", true, true },
    1874             :         { "x", "RD", true, true },
    1875             :         { "x", "RW", true, true },
    1876             :         { "x", "WD", true, true },
    1877             :         { "x", "RWD", true, true },
    1878             : 
    1879             :         { "b", "", true, true },
    1880             :         { "b", "R", true, true },
    1881             :         { "b", "W", true, true },
    1882             :         { "b", "D", true, true },
    1883             :         { "b", "RD", true, true },
    1884             :         { "b", "RW", true, true },
    1885             :         { "b", "WD", true, true },
    1886             :         { "b", "RWD", true, true },
    1887             : };
    1888             : 
    1889           4 : bool test_persistent_open_oplock(struct torture_context *tctx,
    1890             :                                  struct smb2_tree *tree)
    1891             : {
    1892           0 :         char fname[256];
    1893           4 :         bool ret = true;
    1894           0 :         uint32_t share_capabilities;
    1895           4 :         bool share_is_ca = false;
    1896           0 :         struct durable_open_vs_oplock *table;
    1897             : 
    1898             :         /* Choose a random name in case the state is left a little funky. */
    1899           4 :         snprintf(fname, 256, "persistent_open_oplock_%s.dat", generate_random_str(tctx, 8));
    1900             : 
    1901           4 :         share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
    1902           4 :         share_is_ca = share_capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY;
    1903             : 
    1904           4 :         if (share_is_ca) {
    1905           0 :                 table = persistent_open_oplock_ca_table;
    1906             :         } else {
    1907           4 :                 table = durable_open_vs_oplock_table;
    1908             :         }
    1909             : 
    1910           4 :         ret = test_durable_v2_open_oplock_table(tctx, tree, fname,
    1911             :                                                 true, /* request_persistent */
    1912             :                                                 table,
    1913             :                                                 NUM_OPLOCK_OPEN_TESTS);
    1914             : 
    1915           4 :         talloc_free(tree);
    1916             : 
    1917           4 :         return ret;
    1918             : }
    1919             : 
    1920             : /**
    1921             :  * basic persistent handle open test.
    1922             :  * persistent state should only be granted when requested
    1923             :  * along with a batch oplock or a handle lease.
    1924             :  *
    1925             :  * This test tests persistent open with all valid lease types.
    1926             :  */
    1927             : 
    1928             : struct durable_open_vs_lease persistent_open_lease_ca_table[NUM_LEASE_OPEN_TESTS] =
    1929             : {
    1930             :         { "", "", true, true },
    1931             :         { "", "R", true, true },
    1932             :         { "", "W", true, true },
    1933             :         { "", "D", true, true },
    1934             :         { "", "RW", true, true },
    1935             :         { "", "RD", true, true },
    1936             :         { "", "WD", true, true },
    1937             :         { "", "RWD", true, true },
    1938             : 
    1939             :         { "R", "", true, true },
    1940             :         { "R", "R", true, true },
    1941             :         { "R", "W", true, true },
    1942             :         { "R", "D", true, true },
    1943             :         { "R", "RW", true, true },
    1944             :         { "R", "RD", true, true },
    1945             :         { "R", "DW", true, true },
    1946             :         { "R", "RWD", true, true },
    1947             : 
    1948             :         { "RW", "", true, true },
    1949             :         { "RW", "R", true, true },
    1950             :         { "RW", "W", true, true },
    1951             :         { "RW", "D", true, true },
    1952             :         { "RW", "RW", true, true },
    1953             :         { "RW", "RD", true, true },
    1954             :         { "RW", "WD", true, true },
    1955             :         { "RW", "RWD", true, true },
    1956             : 
    1957             :         { "RH", "", true, true },
    1958             :         { "RH", "R", true, true },
    1959             :         { "RH", "W", true, true },
    1960             :         { "RH", "D", true, true },
    1961             :         { "RH", "RW", true, true },
    1962             :         { "RH", "RD", true, true },
    1963             :         { "RH", "WD", true, true },
    1964             :         { "RH", "RWD", true, true },
    1965             : 
    1966             :         { "RHW", "", true, true },
    1967             :         { "RHW", "R", true, true },
    1968             :         { "RHW", "W", true, true },
    1969             :         { "RHW", "D", true, true },
    1970             :         { "RHW", "RW", true, true },
    1971             :         { "RHW", "RD", true, true },
    1972             :         { "RHW", "WD", true, true },
    1973             :         { "RHW", "RWD", true, true },
    1974             : };
    1975             : 
    1976           4 : bool test_persistent_open_lease(struct torture_context *tctx,
    1977             :                                 struct smb2_tree *tree)
    1978             : {
    1979           0 :         char fname[256];
    1980           4 :         bool ret = true;
    1981           0 :         uint32_t caps;
    1982           0 :         uint32_t share_capabilities;
    1983           0 :         bool share_is_ca;
    1984           0 :         struct durable_open_vs_lease *table;
    1985             : 
    1986           4 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
    1987           4 :         if (!(caps & SMB2_CAP_LEASING)) {
    1988           2 :                 torture_skip(tctx, "leases are not supported");
    1989             :         }
    1990             : 
    1991             :         /* Choose a random name in case the state is left a little funky. */
    1992           2 :         snprintf(fname, 256, "persistent_open_lease_%s.dat", generate_random_str(tctx, 8));
    1993             : 
    1994           2 :         share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
    1995           2 :         share_is_ca = share_capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY;
    1996             : 
    1997           2 :         if (share_is_ca) {
    1998           0 :                 table = persistent_open_lease_ca_table;
    1999             :         } else {
    2000           2 :                 table = durable_open_vs_lease_table;
    2001             :         }
    2002             : 
    2003           2 :         ret = test_durable_v2_open_lease_table(tctx, tree, fname,
    2004             :                                                true, /* request_persistent */
    2005             :                                                table,
    2006             :                                                NUM_LEASE_OPEN_TESTS);
    2007             : 
    2008           2 :         talloc_free(tree);
    2009             : 
    2010           2 :         return ret;
    2011             : }
    2012             : 
    2013             : /**
    2014             :  * setfileinfo test for doing a durable open
    2015             :  * create the file with lease and durable handle,
    2016             :  * write to it (via set end-of-file), tcp disconnect,
    2017             :  * reconnect, do a durable reopen - should succeed.
    2018             :  *
    2019             :  * BUG: https://bugzilla.samba.org/show_bug.cgi?id=15022
    2020             :  */
    2021           4 : bool test_durable_v2_setinfo(struct torture_context *tctx,
    2022             :                                            struct smb2_tree *tree)
    2023             : {
    2024           0 :         NTSTATUS status;
    2025           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2026           0 :         char fname[256];
    2027           0 :         struct smb2_handle _h;
    2028           4 :         struct smb2_handle *h = NULL;
    2029           0 :         struct smb2_create io;
    2030           0 :         union smb_setfileinfo si;
    2031           4 :         struct GUID create_guid = GUID_random();
    2032           0 :         struct smb2_lease ls;
    2033           0 :         uint64_t lease_key;
    2034           4 :         bool ret = true;
    2035           0 :         struct smbcli_options options;
    2036           0 :         uint32_t caps;
    2037             : 
    2038           4 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
    2039           4 :         if (!(caps & SMB2_CAP_LEASING)) {
    2040           2 :                 torture_skip(tctx, "leases are not supported");
    2041             :         }
    2042             : 
    2043           2 :         options = tree->session->transport->options;
    2044             : 
    2045           2 :         smb2_deltree(tree, __func__);
    2046           2 :         status = torture_smb2_testdir(tree, __func__, &_h);
    2047           2 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2048             :                                         "torture_smb2_testdir failed\n");
    2049           2 :         smb2_util_close(tree, _h);
    2050             : 
    2051             :         /* Choose a random name in case the state is left a little funky. */
    2052           2 :         snprintf(fname, 256, "%s\\durable_v2_setinfo%s.dat",
    2053             :                  __func__, generate_random_str(tctx, 8));
    2054             : 
    2055           2 :         smb2_util_unlink(tree, fname);
    2056             : 
    2057           2 :         lease_key = random();
    2058           2 :         smb2_lease_v2_create(&io, &ls, false /* dir */, fname,
    2059             :                              lease_key, 0, /* parent lease key */
    2060             :                              smb2_util_lease_state("RWH"), 0 /* lease epoch */);
    2061           2 :         io.in.durable_open = false;
    2062           2 :         io.in.durable_open_v2 = true;
    2063           2 :         io.in.persistent_open = false;
    2064           2 :         io.in.create_guid = create_guid;
    2065           2 :         io.in.timeout = UINT32_MAX;
    2066             : 
    2067           2 :         status = smb2_create(tree, mem_ctx, &io);
    2068           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2069           2 :         _h = io.out.file.handle;
    2070           2 :         h = &_h;
    2071           2 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    2072           2 :         CHECK_VAL(io.out.durable_open, false);
    2073           2 :         CHECK_VAL(io.out.durable_open_v2, true);
    2074           2 :         CHECK_VAL(io.out.persistent_open, false);
    2075           2 :         CHECK_VAL(io.out.timeout, 300*1000);
    2076           2 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    2077           2 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
    2078           2 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
    2079             : 
    2080             :         /*
    2081             :          * Set EOF to 0x100000.
    2082             :          * Mimics an Apple client test, but most importantly
    2083             :          * causes the mtime timestamp on disk to be updated.
    2084             :          */
    2085           2 :         ZERO_STRUCT(si);
    2086           2 :         si.generic.level = SMB_SFILEINFO_END_OF_FILE_INFORMATION;
    2087           2 :         si.generic.in.file.handle = io.out.file.handle;
    2088           2 :         si.end_of_file_info.in.size = 0x100000;
    2089           2 :         status = smb2_setinfo_file(tree, &si);
    2090           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2091             : 
    2092             :         /* disconnect, reconnect and then do durable reopen */
    2093           2 :         TALLOC_FREE(tree);
    2094             : 
    2095           2 :         if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
    2096           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
    2097           0 :                 ret = false;
    2098           0 :                 goto done;
    2099             :         }
    2100             : 
    2101             :         /*
    2102             :          * Now for a succeeding reconnect:
    2103             :          */
    2104             : 
    2105           2 :         ZERO_STRUCT(io);
    2106           2 :         io.in.fname = fname;
    2107           2 :         io.in.durable_open_v2 = false;
    2108           2 :         io.in.durable_handle_v2 = h;
    2109           2 :         io.in.create_guid = create_guid;
    2110           2 :         io.in.lease_request_v2 = &ls;
    2111           2 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
    2112             : 
    2113             :         /* the requested lease state is irrelevant */
    2114           2 :         ls.lease_state = smb2_util_lease_state("");
    2115             : 
    2116           2 :         h = NULL;
    2117             : 
    2118           2 :         status = smb2_create(tree, mem_ctx, &io);
    2119           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2120             : 
    2121           2 :         CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
    2122           2 :         CHECK_VAL(io.out.size, 0x100000);                               \
    2123           2 :         CHECK_VAL(io.out.durable_open, false);
    2124           2 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    2125           2 :         CHECK_VAL(io.out.persistent_open, false);
    2126           2 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    2127           2 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
    2128           2 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
    2129           2 :         CHECK_VAL(io.out.lease_response_v2.lease_state,
    2130             :                   smb2_util_lease_state("RWH"));
    2131           2 :         CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
    2132           2 :         CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
    2133           2 :         _h = io.out.file.handle;
    2134           2 :         h = &_h;
    2135             : 
    2136           2 : done:
    2137             : 
    2138           2 :         if (h != NULL) {
    2139           2 :                 smb2_util_close(tree, *h);
    2140             :         }
    2141             : 
    2142           2 :         smb2_util_unlink(tree, fname);
    2143           2 :         smb2_deltree(tree, __func__);
    2144             : 
    2145           2 :         talloc_free(tree);
    2146             : 
    2147           2 :         talloc_free(mem_ctx);
    2148             : 
    2149           2 :         return ret;
    2150             : }
    2151             : 
    2152        2354 : struct torture_suite *torture_smb2_durable_v2_open_init(TALLOC_CTX *ctx)
    2153             : {
    2154         125 :         struct torture_suite *suite =
    2155        2354 :             torture_suite_create(ctx, "durable-v2-open");
    2156             : 
    2157        2354 :         torture_suite_add_1smb2_test(suite, "create-blob", test_durable_v2_open_create_blob);
    2158        2354 :         torture_suite_add_1smb2_test(suite, "open-oplock", test_durable_v2_open_oplock);
    2159        2354 :         torture_suite_add_1smb2_test(suite, "open-lease", test_durable_v2_open_lease);
    2160        2354 :         torture_suite_add_1smb2_test(suite, "reopen1", test_durable_v2_open_reopen1);
    2161        2354 :         torture_suite_add_1smb2_test(suite, "reopen1a", test_durable_v2_open_reopen1a);
    2162        2354 :         torture_suite_add_1smb2_test(suite, "reopen1a-lease", test_durable_v2_open_reopen1a_lease);
    2163        2354 :         torture_suite_add_1smb2_test(suite, "reopen2", test_durable_v2_open_reopen2);
    2164        2354 :         torture_suite_add_1smb2_test(suite, "reopen2b", test_durable_v2_open_reopen2b);
    2165        2354 :         torture_suite_add_1smb2_test(suite, "reopen2c", test_durable_v2_open_reopen2c);
    2166        2354 :         torture_suite_add_1smb2_test(suite, "reopen2-lease", test_durable_v2_open_reopen2_lease);
    2167        2354 :         torture_suite_add_1smb2_test(suite, "reopen2-lease-v2", test_durable_v2_open_reopen2_lease_v2);
    2168        2354 :         torture_suite_add_1smb2_test(suite, "durable-v2-setinfo", test_durable_v2_setinfo);
    2169        2354 :         torture_suite_add_2smb2_test(suite, "app-instance", test_durable_v2_open_app_instance);
    2170        2354 :         torture_suite_add_1smb2_test(suite, "persistent-open-oplock", test_persistent_open_oplock);
    2171        2354 :         torture_suite_add_1smb2_test(suite, "persistent-open-lease", test_persistent_open_lease);
    2172             : 
    2173        2354 :         suite->description = talloc_strdup(suite, "SMB2-DURABLE-V2-OPEN tests");
    2174             : 
    2175        2354 :         return suite;
    2176             : }
    2177             : 
    2178             : /**
    2179             :  * basic test for doing a durable open
    2180             :  * tcp disconnect, reconnect, do a durable reopen (succeeds)
    2181             :  */
    2182           6 : static bool test_durable_v2_reconnect_delay(struct torture_context *tctx,
    2183             :                                             struct smb2_tree *tree,
    2184             :                                             struct smb2_tree *tree2)
    2185             : {
    2186           0 :         NTSTATUS status;
    2187           6 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2188           0 :         char fname[256];
    2189           0 :         struct smb2_handle _h;
    2190           6 :         struct smb2_handle *h = NULL;
    2191           0 :         struct smb2_create io;
    2192           6 :         struct GUID create_guid = GUID_random();
    2193           0 :         struct smbcli_options options;
    2194           0 :         uint64_t previous_session_id;
    2195           6 :         uint8_t b = 0;
    2196           6 :         bool ret = true;
    2197           0 :         bool ok;
    2198             : 
    2199           6 :         options = tree->session->transport->options;
    2200           6 :         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
    2201             : 
    2202             :         /* Choose a random name in case the state is left a little funky. */
    2203           6 :         snprintf(fname,
    2204             :                  sizeof(fname),
    2205             :                  "durable_v2_reconnect_delay_%s.dat",
    2206             :                  generate_random_str(tctx, 8));
    2207             : 
    2208           6 :         smb2_util_unlink(tree, fname);
    2209             : 
    2210           6 :         smb2_oplock_create_share(&io, fname,
    2211             :                                  smb2_util_share_access(""),
    2212           6 :                                  smb2_util_oplock_level("b"));
    2213           6 :         io.in.durable_open = false;
    2214           6 :         io.in.durable_open_v2 = true;
    2215           6 :         io.in.persistent_open = false;
    2216           6 :         io.in.create_guid = create_guid;
    2217           6 :         io.in.timeout = 0;
    2218             : 
    2219           6 :         status = smb2_create(tree, mem_ctx, &io);
    2220           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    2221             : 
    2222           6 :         _h = io.out.file.handle;
    2223           6 :         h = &_h;
    2224           6 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    2225           6 :         CHECK_VAL(io.out.durable_open_v2, true);
    2226             : 
    2227           6 :         status = smb2_util_write(tree, *h, &b, 0, 1);
    2228           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    2229             : 
    2230             :         /* disconnect, leaving the durable open */
    2231           6 :         TALLOC_FREE(tree);
    2232           6 :         h = NULL;
    2233             : 
    2234           6 :         ok = torture_smb2_connection_ext(tctx, previous_session_id,
    2235             :                                          &options, &tree);
    2236           6 :         torture_assert_goto(tctx, ok, ret, done, "couldn't reconnect, bailing\n");
    2237             : 
    2238           6 :         ZERO_STRUCT(io);
    2239           6 :         io.in.fname = fname;
    2240           6 :         io.in.durable_open_v2 = false;
    2241           6 :         io.in.durable_handle_v2 = &_h;
    2242           6 :         io.in.create_guid = create_guid;
    2243             : 
    2244           6 :         status = smb2_create(tree, mem_ctx, &io);
    2245           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    2246           6 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    2247           6 :         _h = io.out.file.handle;
    2248           6 :         h = &_h;
    2249             : 
    2250           6 : done:
    2251           6 :         if (h != NULL) {
    2252           6 :                 smb2_util_close(tree, *h);
    2253             :         }
    2254           6 :         TALLOC_FREE(tree);
    2255             : 
    2256           6 :         smb2_util_unlink(tree2, fname);
    2257             : 
    2258           6 :         TALLOC_FREE(tree2);
    2259             : 
    2260           6 :         talloc_free(mem_ctx);
    2261             : 
    2262           6 :         return ret;
    2263             : }
    2264             : 
    2265             : /**
    2266             :  * basic test for doing a durable open with 1msec cleanup time
    2267             :  * tcp disconnect, wait a bit, reconnect, do a durable reopen (fails)
    2268             :  */
    2269           6 : static bool test_durable_v2_reconnect_delay_msec(struct torture_context *tctx,
    2270             :                                                  struct smb2_tree *tree,
    2271             :                                                  struct smb2_tree *tree2)
    2272             : {
    2273           0 :         NTSTATUS status;
    2274           6 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2275           0 :         char fname[256];
    2276           0 :         struct smb2_handle _h;
    2277           6 :         struct smb2_handle *h = NULL;
    2278           0 :         struct smb2_create io;
    2279           0 :         struct smb2_lease ls;
    2280           6 :         struct GUID create_guid = GUID_random();
    2281           0 :         struct smbcli_options options;
    2282           0 :         uint64_t previous_session_id;
    2283           6 :         uint8_t b = 0;
    2284           6 :         bool ret = true;
    2285           0 :         bool ok;
    2286             : 
    2287           6 :         options = tree->session->transport->options;
    2288           6 :         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
    2289             : 
    2290             :         /* Choose a random name in case the state is left a little funky. */
    2291           6 :         snprintf(fname,
    2292             :                  sizeof(fname),
    2293             :                  "durable_v2_reconnect_delay_%s.dat",
    2294             :                  generate_random_str(tctx, 8));
    2295             : 
    2296           6 :         smb2_util_unlink(tree, fname);
    2297             : 
    2298           6 :         smb2_lease_create(
    2299             :                 &io,
    2300             :                 &ls,
    2301             :                 false /* dir */,
    2302             :                 fname,
    2303             :                 generate_random_u64(),
    2304             :                 smb2_util_lease_state("RWH"));
    2305           6 :         io.in.durable_open = false;
    2306           6 :         io.in.durable_open_v2 = true;
    2307           6 :         io.in.persistent_open = false;
    2308           6 :         io.in.create_guid = create_guid;
    2309           6 :         io.in.timeout = 1;
    2310             : 
    2311           6 :         status = smb2_create(tree, mem_ctx, &io);
    2312           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    2313             : 
    2314           6 :         _h = io.out.file.handle;
    2315           6 :         h = &_h;
    2316           6 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    2317           6 :         CHECK_VAL(io.out.durable_open_v2, true);
    2318             : 
    2319           6 :         status = smb2_util_write(tree, *h, &b, 0, 1);
    2320           6 :         CHECK_STATUS(status, NT_STATUS_OK);
    2321             : 
    2322             :         /* disconnect, leaving the durable open */
    2323           6 :         TALLOC_FREE(tree);
    2324           6 :         h = NULL;
    2325             : 
    2326           6 :         ok = torture_smb2_connection_ext(tctx, previous_session_id,
    2327             :                                          &options, &tree);
    2328           6 :         torture_assert_goto(tctx, ok, ret, done, "couldn't reconnect, bailing\n");
    2329             : 
    2330           6 :         sleep(10);
    2331             : 
    2332           6 :         ZERO_STRUCT(io);
    2333           6 :         io.in.fname = fname;
    2334           6 :         io.in.durable_open_v2 = false;
    2335           6 :         io.in.durable_handle_v2 = &_h;
    2336           6 :         io.in.create_guid = create_guid;
    2337             : 
    2338           6 :         status = smb2_create(tree, mem_ctx, &io);
    2339           6 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    2340           6 :         _h = io.out.file.handle;
    2341           6 :         h = &_h;
    2342             : 
    2343           6 : done:
    2344           6 :         if (h != NULL) {
    2345           6 :                 smb2_util_close(tree, *h);
    2346             :         }
    2347           6 :         TALLOC_FREE(tree);
    2348             : 
    2349           6 :         smb2_util_unlink(tree2, fname);
    2350             : 
    2351           6 :         TALLOC_FREE(tree2);
    2352             : 
    2353           6 :         talloc_free(mem_ctx);
    2354             : 
    2355           6 :         return ret;
    2356             : }
    2357             : 
    2358        2354 : struct torture_suite *torture_smb2_durable_v2_delay_init(TALLOC_CTX *ctx)
    2359             : {
    2360         125 :         struct torture_suite *suite =
    2361        2354 :             torture_suite_create(ctx, "durable-v2-delay");
    2362             : 
    2363        2354 :         torture_suite_add_2smb2_test(suite,
    2364             :                                      "durable_v2_reconnect_delay",
    2365             :                                      test_durable_v2_reconnect_delay);
    2366        2354 :         torture_suite_add_2smb2_test(suite,
    2367             :                                      "durable_v2_reconnect_delay_msec",
    2368             :                                      test_durable_v2_reconnect_delay_msec);
    2369             : 
    2370        2354 :         return suite;
    2371             : }

Generated by: LCOV version 1.14