LCOV - code coverage report
Current view: top level - source4/torture/smb2 - durable_v2_open.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 26 1159 2.2 %
Date: 2024-06-13 04:01:37 Functions: 2 25 8.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           0 : static void torture_oplock_close_callback(struct smb2_request *req)
      59             : {
      60           0 :         smb2_close_recv(req, &break_info.cl);
      61           0 : }
      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           0 : 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           0 :         struct smb2_tree *tree = private_data;
      71             :         struct smb2_request *req;
      72             : 
      73           0 :         break_info.count++;
      74             : 
      75           0 :         ZERO_STRUCT(break_info.cl);
      76           0 :         break_info.cl.in.file.handle = *handle;
      77             : 
      78           0 :         req = smb2_close_send(tree, &break_info.cl);
      79           0 :         req->async.fn = torture_oplock_close_callback;
      80           0 :         req->async.private_data = NULL;
      81           0 :         return true;
      82             : }
      83             : 
      84             : /**
      85             :  * testing various create blob combinations.
      86             :  */
      87           0 : bool test_durable_v2_open_create_blob(struct torture_context *tctx,
      88             :                                       struct smb2_tree *tree)
      89             : {
      90             :         NTSTATUS status;
      91           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
      92             :         char fname[256];
      93             :         struct smb2_handle _h;
      94           0 :         struct smb2_handle *h = NULL;
      95             :         struct smb2_create io;
      96           0 :         struct GUID create_guid = GUID_random();
      97           0 :         bool ret = true;
      98             :         struct smbcli_options options;
      99             : 
     100           0 :         options = tree->session->transport->options;
     101             : 
     102             :         /* Choose a random name in case the state is left a little funky. */
     103           0 :         snprintf(fname, 256, "durable_v2_open_create_blob_%s.dat",
     104             :                  generate_random_str(tctx, 8));
     105             : 
     106           0 :         smb2_util_unlink(tree, fname);
     107             : 
     108           0 :         smb2_oplock_create_share(&io, fname,
     109             :                                  smb2_util_share_access(""),
     110           0 :                                  smb2_util_oplock_level("b"));
     111           0 :         io.in.durable_open = false;
     112           0 :         io.in.durable_open_v2 = true;
     113           0 :         io.in.persistent_open = false;
     114           0 :         io.in.create_guid = create_guid;
     115           0 :         io.in.timeout = UINT32_MAX;
     116             : 
     117           0 :         status = smb2_create(tree, mem_ctx, &io);
     118           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     119           0 :         _h = io.out.file.handle;
     120           0 :         h = &_h;
     121           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     122           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     123           0 :         CHECK_VAL(io.out.durable_open, false);
     124           0 :         CHECK_VAL(io.out.durable_open_v2, true);
     125           0 :         CHECK_VAL(io.out.persistent_open, false);
     126           0 :         CHECK_VAL(io.out.timeout, 300*1000);
     127             : 
     128             :         /* disconnect */
     129           0 :         TALLOC_FREE(tree);
     130             : 
     131             :         /* create a new session (same client_guid) */
     132           0 :         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           0 :         ZERO_STRUCT(io);
     145           0 :         io.in.fname = fname;
     146           0 :         io.in.durable_handle_v2 = h; /* durable v2 reconnect request */
     147           0 :         io.in.durable_open = true;   /* durable v1 handle request */
     148           0 :         io.in.create_guid = create_guid;
     149           0 :         status = smb2_create(tree, mem_ctx, &io);
     150           0 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     151             : 
     152           0 :         ZERO_STRUCT(io);
     153           0 :         io.in.fname = fname;
     154           0 :         io.in.durable_handle = h;     /* durable v1 reconnect request */
     155           0 :         io.in.durable_open_v2 = true; /* durable v2 handle request */
     156           0 :         io.in.create_guid = create_guid;
     157           0 :         status = smb2_create(tree, mem_ctx, &io);
     158           0 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     159             : 
     160           0 :         ZERO_STRUCT(io);
     161           0 :         io.in.fname = fname;
     162           0 :         io.in.durable_handle = h;    /* durable v1 reconnect request */
     163           0 :         io.in.durable_handle_v2 = h; /* durable v2 reconnect request */
     164           0 :         io.in.create_guid = create_guid;
     165           0 :         status = smb2_create(tree, mem_ctx, &io);
     166           0 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     167             : 
     168           0 :         ZERO_STRUCT(io);
     169           0 :         io.in.fname = fname;
     170           0 :         io.in.durable_handle_v2 = h;  /* durable v2 reconnect request */
     171           0 :         io.in.durable_open_v2 = true; /* durable v2 handle request */
     172           0 :         io.in.create_guid = create_guid;
     173           0 :         status = smb2_create(tree, mem_ctx, &io);
     174           0 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     175             : 
     176           0 : done:
     177           0 :         if (h != NULL) {
     178           0 :                 smb2_util_close(tree, *h);
     179             :         }
     180             : 
     181           0 :         smb2_util_unlink(tree, fname);
     182             : 
     183           0 :         talloc_free(tree);
     184             : 
     185           0 :         talloc_free(mem_ctx);
     186             : 
     187           0 :         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           0 : 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             :         NTSTATUS status;
     255           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     256             :         struct smb2_handle _h;
     257           0 :         struct smb2_handle *h = NULL;
     258           0 :         bool ret = true;
     259             :         struct smb2_create io;
     260             : 
     261           0 :         smb2_util_unlink(tree, fname);
     262             : 
     263           0 :         smb2_oplock_create_share(&io, fname,
     264             :                                  smb2_util_share_access(test.share_mode),
     265           0 :                                  smb2_util_oplock_level(test.level));
     266           0 :         io.in.durable_open = false;
     267           0 :         io.in.durable_open_v2 = true;
     268           0 :         io.in.persistent_open = request_persistent;
     269           0 :         io.in.create_guid = GUID_random();
     270             : 
     271           0 :         status = smb2_create(tree, mem_ctx, &io);
     272           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     273           0 :         _h = io.out.file.handle;
     274           0 :         h = &_h;
     275           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     276           0 :         CHECK_VAL(io.out.durable_open, false);
     277           0 :         CHECK_VAL(io.out.durable_open_v2, test.durable);
     278           0 :         CHECK_VAL(io.out.persistent_open, test.persistent);
     279           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(test.level));
     280             : 
     281           0 : done:
     282           0 :         if (h != NULL) {
     283           0 :                 smb2_util_close(tree, *h);
     284             :         }
     285           0 :         smb2_util_unlink(tree, fname);
     286           0 :         talloc_free(mem_ctx);
     287             : 
     288           0 :         return ret;
     289             : }
     290             : 
     291           0 : 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           0 :         bool ret = true;
     299             :         uint8_t i;
     300             : 
     301           0 :         smb2_util_unlink(tree, fname);
     302             : 
     303           0 :         for (i = 0; i < num_tests; i++) {
     304           0 :                 ret = test_one_durable_v2_open_oplock(tctx,
     305             :                                                       tree,
     306             :                                                       fname,
     307             :                                                       request_persistent,
     308           0 :                                                       table[i]);
     309           0 :                 if (ret == false) {
     310           0 :                         goto done;
     311             :                 }
     312             :         }
     313             : 
     314           0 : done:
     315           0 :         smb2_util_unlink(tree, fname);
     316             : 
     317           0 :         return ret;
     318             : }
     319             : 
     320           0 : bool test_durable_v2_open_oplock(struct torture_context *tctx,
     321             :                                  struct smb2_tree *tree)
     322             : {
     323             :         bool ret;
     324             :         char fname[256];
     325             : 
     326             :         /* Choose a random name in case the state is left a little funky. */
     327           0 :         snprintf(fname, 256, "durable_open_oplock_%s.dat",
     328             :                  generate_random_str(tctx, 8));
     329             : 
     330           0 :         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           0 :         talloc_free(tree);
     336             : 
     337           0 :         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           0 : 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             :         NTSTATUS status;
     412           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     413             :         struct smb2_handle _h;
     414           0 :         struct smb2_handle *h = NULL;
     415           0 :         bool ret = true;
     416             :         struct smb2_create io;
     417             :         struct smb2_lease ls;
     418             :         uint64_t lease;
     419             : 
     420           0 :         smb2_util_unlink(tree, fname);
     421             : 
     422           0 :         lease = random();
     423             : 
     424           0 :         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           0 :         io.in.durable_open = false;
     429           0 :         io.in.durable_open_v2 = true;
     430           0 :         io.in.persistent_open = request_persistent;
     431           0 :         io.in.create_guid = GUID_random();
     432             : 
     433           0 :         status = smb2_create(tree, mem_ctx, &io);
     434           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     435           0 :         _h = io.out.file.handle;
     436           0 :         h = &_h;
     437           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     438           0 :         CHECK_VAL(io.out.durable_open, false);
     439           0 :         CHECK_VAL(io.out.durable_open_v2, test.durable);
     440           0 :         CHECK_VAL(io.out.persistent_open, test.persistent);
     441           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
     442           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease);
     443           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease);
     444           0 :         CHECK_VAL(io.out.lease_response.lease_state,
     445             :                   smb2_util_lease_state(test.type));
     446           0 : done:
     447           0 :         if (h != NULL) {
     448           0 :                 smb2_util_close(tree, *h);
     449             :         }
     450           0 :         smb2_util_unlink(tree, fname);
     451           0 :         talloc_free(mem_ctx);
     452             : 
     453           0 :         return ret;
     454             : }
     455             : 
     456           0 : 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           0 :         bool ret = true;
     464             :         uint8_t i;
     465             : 
     466           0 :         smb2_util_unlink(tree, fname);
     467             : 
     468           0 :         for (i = 0; i < num_tests; i++) {
     469           0 :                 ret = test_one_durable_v2_open_lease(tctx,
     470             :                                                      tree,
     471             :                                                      fname,
     472             :                                                      request_persistent,
     473           0 :                                                      table[i]);
     474           0 :                 if (ret == false) {
     475           0 :                         goto done;
     476             :                 }
     477             :         }
     478             : 
     479           0 : done:
     480           0 :         smb2_util_unlink(tree, fname);
     481             : 
     482           0 :         return ret;
     483             : }
     484             : 
     485           0 : bool test_durable_v2_open_lease(struct torture_context *tctx,
     486             :                                 struct smb2_tree *tree)
     487             : {
     488             :         char fname[256];
     489           0 :         bool ret = true;
     490             :         uint32_t caps;
     491             : 
     492           0 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
     493           0 :         if (!(caps & SMB2_CAP_LEASING)) {
     494           0 :                 torture_skip(tctx, "leases are not supported");
     495             :         }
     496             : 
     497             :         /* Choose a random name in case the state is left a little funky. */
     498           0 :         snprintf(fname, 256, "durable_open_lease_%s.dat", generate_random_str(tctx, 8));
     499             : 
     500           0 :         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           0 :         talloc_free(tree);
     506           0 :         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           0 : bool test_durable_v2_open_reopen1(struct torture_context *tctx,
     515             :                                   struct smb2_tree *tree)
     516             : {
     517             :         NTSTATUS status;
     518           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     519             :         char fname[256];
     520             :         struct smb2_handle _h;
     521           0 :         struct smb2_handle *h = NULL;
     522             :         struct smb2_create io;
     523           0 :         struct GUID create_guid = GUID_random();
     524           0 :         bool ret = true;
     525             : 
     526             :         /* Choose a random name in case the state is left a little funky. */
     527           0 :         snprintf(fname, 256, "durable_v2_open_reopen1_%s.dat",
     528             :                  generate_random_str(tctx, 8));
     529             : 
     530           0 :         smb2_util_unlink(tree, fname);
     531             : 
     532           0 :         smb2_oplock_create_share(&io, fname,
     533             :                                  smb2_util_share_access(""),
     534           0 :                                  smb2_util_oplock_level("b"));
     535           0 :         io.in.durable_open = false;
     536           0 :         io.in.durable_open_v2 = true;
     537           0 :         io.in.persistent_open = false;
     538           0 :         io.in.create_guid = create_guid;
     539           0 :         io.in.timeout = UINT32_MAX;
     540             : 
     541           0 :         status = smb2_create(tree, mem_ctx, &io);
     542           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     543           0 :         _h = io.out.file.handle;
     544           0 :         h = &_h;
     545           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     546           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     547           0 :         CHECK_VAL(io.out.durable_open, false);
     548           0 :         CHECK_VAL(io.out.durable_open_v2, true);
     549           0 :         CHECK_VAL(io.out.persistent_open, false);
     550           0 :         CHECK_VAL(io.out.timeout, 300*1000);
     551             : 
     552             :         /* try a durable reconnect while the file is still open */
     553           0 :         ZERO_STRUCT(io);
     554           0 :         io.in.fname = "";
     555           0 :         io.in.durable_handle_v2 = h;
     556           0 :         io.in.create_guid = create_guid;
     557           0 :         status = smb2_create(tree, mem_ctx, &io);
     558           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     559             : 
     560           0 : done:
     561           0 :         if (h != NULL) {
     562           0 :                 smb2_util_close(tree, *h);
     563             :         }
     564             : 
     565           0 :         smb2_util_unlink(tree, fname);
     566             : 
     567           0 :         talloc_free(tree);
     568             : 
     569           0 :         talloc_free(mem_ctx);
     570             : 
     571           0 :         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           0 : bool test_durable_v2_open_reopen1a(struct torture_context *tctx,
     583             :                                    struct smb2_tree *tree)
     584             : {
     585             :         NTSTATUS status;
     586           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     587             :         char fname[256];
     588             :         struct smb2_handle _h;
     589           0 :         struct smb2_handle *h = NULL;
     590             :         struct smb2_create io;
     591           0 :         struct GUID create_guid = GUID_random();
     592           0 :         bool ret = true;
     593           0 :         struct smb2_tree *tree2 = NULL;
     594           0 :         struct smb2_tree *tree3 = NULL;
     595             :         uint64_t previous_session_id;
     596             :         struct smbcli_options options;
     597             :         struct GUID orig_client_guid;
     598             : 
     599           0 :         options = tree->session->transport->options;
     600           0 :         orig_client_guid = options.client_guid;
     601             : 
     602             :         /* Choose a random name in case the state is left a little funky. */
     603           0 :         snprintf(fname, 256, "durable_v2_open_reopen1a_%s.dat",
     604             :                  generate_random_str(tctx, 8));
     605             : 
     606           0 :         smb2_util_unlink(tree, fname);
     607             : 
     608           0 :         smb2_oplock_create_share(&io, fname,
     609             :                                  smb2_util_share_access(""),
     610           0 :                                  smb2_util_oplock_level("b"));
     611           0 :         io.in.durable_open = false;
     612           0 :         io.in.durable_open_v2 = true;
     613           0 :         io.in.persistent_open = false;
     614           0 :         io.in.create_guid = create_guid;
     615           0 :         io.in.timeout = UINT32_MAX;
     616             : 
     617           0 :         status = smb2_create(tree, mem_ctx, &io);
     618           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     619           0 :         _h = io.out.file.handle;
     620           0 :         h = &_h;
     621           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     622           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     623           0 :         CHECK_VAL(io.out.durable_open, false);
     624           0 :         CHECK_VAL(io.out.durable_open_v2, true);
     625           0 :         CHECK_VAL(io.out.persistent_open, false);
     626           0 :         CHECK_VAL(io.out.timeout, 300*1000);
     627             : 
     628             :         /*
     629             :          * a session reconnect on a second tcp connection
     630             :          */
     631             : 
     632           0 :         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
     633             : 
     634             :         /* for oplocks, the client guid can be different: */
     635           0 :         options.client_guid = GUID_random();
     636             : 
     637           0 :         ret = torture_smb2_connection_ext(tctx, previous_session_id,
     638             :                                           &options, &tree2);
     639           0 :         torture_assert_goto(tctx, ret, ret, done, "couldn't reconnect");
     640             : 
     641             :         /*
     642             :          * check that this has deleted the old session
     643             :          */
     644             : 
     645           0 :         ZERO_STRUCT(io);
     646           0 :         io.in.fname = "";
     647           0 :         io.in.durable_handle_v2 = h;
     648           0 :         io.in.create_guid = create_guid;
     649           0 :         status = smb2_create(tree, mem_ctx, &io);
     650           0 :         CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
     651             : 
     652           0 :         TALLOC_FREE(tree);
     653             : 
     654             :         /*
     655             :          * but a durable reconnect on the new session succeeds:
     656             :          */
     657             : 
     658           0 :         ZERO_STRUCT(io);
     659           0 :         io.in.fname = "";
     660           0 :         io.in.durable_handle_v2 = h;
     661           0 :         io.in.create_guid = create_guid;
     662           0 :         status = smb2_create(tree2, mem_ctx, &io);
     663           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     664           0 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     665           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     666           0 :         CHECK_VAL(io.out.durable_open, false);
     667           0 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
     668           0 :         CHECK_VAL(io.out.persistent_open, false);
     669           0 :         CHECK_VAL(io.out.timeout, 0);
     670           0 :         _h = io.out.file.handle;
     671           0 :         h = &_h;
     672             : 
     673             :         /*
     674             :          * a session reconnect on a second tcp connection
     675             :          */
     676             : 
     677           0 :         previous_session_id = smb2cli_session_current_id(tree2->session->smbXcli);
     678             : 
     679             :         /* it works the same with the original guid */
     680           0 :         options.client_guid = orig_client_guid;
     681             : 
     682           0 :         ret = torture_smb2_connection_ext(tctx, previous_session_id,
     683             :                                           &options, &tree3);
     684           0 :         torture_assert_goto(tctx, ret, ret, done, "couldn't reconnect");
     685             : 
     686             :         /*
     687             :          * check that this has deleted the old session
     688             :          */
     689             : 
     690           0 :         ZERO_STRUCT(io);
     691           0 :         io.in.fname = "";
     692           0 :         io.in.durable_handle_v2 = h;
     693           0 :         io.in.create_guid = create_guid;
     694           0 :         status = smb2_create(tree2, mem_ctx, &io);
     695           0 :         CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
     696           0 :         TALLOC_FREE(tree2);
     697             : 
     698             :         /*
     699             :          * but a durable reconnect on the new session succeeds:
     700             :          */
     701             : 
     702           0 :         ZERO_STRUCT(io);
     703           0 :         io.in.fname = "";
     704           0 :         io.in.durable_handle_v2 = h;
     705           0 :         io.in.create_guid = create_guid;
     706           0 :         status = smb2_create(tree3, mem_ctx, &io);
     707           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     708           0 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     709           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     710           0 :         CHECK_VAL(io.out.durable_open, false);
     711           0 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
     712           0 :         CHECK_VAL(io.out.persistent_open, false);
     713           0 :         CHECK_VAL(io.out.timeout, 0);
     714           0 :         _h = io.out.file.handle;
     715           0 :         h = &_h;
     716             : 
     717           0 : done:
     718           0 :         if (tree == NULL) {
     719           0 :                 tree = tree2;
     720             :         }
     721             : 
     722           0 :         if (tree == NULL) {
     723           0 :                 tree = tree3;
     724             :         }
     725             : 
     726           0 :         if (tree != NULL) {
     727           0 :                 if (h != NULL) {
     728           0 :                         smb2_util_close(tree, *h);
     729             :                 }
     730             : 
     731           0 :                 smb2_util_unlink(tree, fname);
     732             : 
     733           0 :                 talloc_free(tree);
     734             :         }
     735             : 
     736           0 :         talloc_free(mem_ctx);
     737             : 
     738           0 :         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           0 : bool test_durable_v2_open_reopen1a_lease(struct torture_context *tctx,
     754             :                                          struct smb2_tree *tree)
     755             : {
     756             :         NTSTATUS status;
     757           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     758             :         char fname[256];
     759             :         struct smb2_handle _h;
     760           0 :         struct smb2_handle *h = NULL;
     761             :         struct smb2_create io;
     762           0 :         struct GUID create_guid = GUID_random();
     763             :         struct smb2_lease ls;
     764             :         uint64_t lease_key;
     765           0 :         bool ret = true;
     766           0 :         struct smb2_tree *tree2 = NULL;
     767           0 :         struct smb2_tree *tree3 = NULL;
     768             :         uint64_t previous_session_id;
     769             :         struct smbcli_options options;
     770             :         struct GUID orig_client_guid;
     771             : 
     772           0 :         options = tree->session->transport->options;
     773           0 :         orig_client_guid = options.client_guid;
     774             : 
     775             :         /* Choose a random name in case the state is left a little funky. */
     776           0 :         snprintf(fname, 256, "durable_v2_open_reopen1a_lease_%s.dat",
     777             :                  generate_random_str(tctx, 8));
     778             : 
     779           0 :         smb2_util_unlink(tree, fname);
     780             : 
     781           0 :         lease_key = random();
     782           0 :         smb2_lease_create(&io, &ls, false /* dir */, fname,
     783             :                           lease_key, smb2_util_lease_state("RWH"));
     784           0 :         io.in.durable_open = false;
     785           0 :         io.in.durable_open_v2 = true;
     786           0 :         io.in.persistent_open = false;
     787           0 :         io.in.create_guid = create_guid;
     788           0 :         io.in.timeout = UINT32_MAX;
     789             : 
     790           0 :         status = smb2_create(tree, mem_ctx, &io);
     791           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     792           0 :         _h = io.out.file.handle;
     793           0 :         h = &_h;
     794           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     795           0 :         CHECK_VAL(io.out.durable_open, false);
     796           0 :         CHECK_VAL(io.out.durable_open_v2, true);
     797           0 :         CHECK_VAL(io.out.persistent_open, false);
     798           0 :         CHECK_VAL(io.out.timeout, 300*1000);
     799           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
     800           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
     801           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
     802           0 :         CHECK_VAL(io.out.lease_response.lease_state,
     803             :                   smb2_util_lease_state("RWH"));
     804           0 :         CHECK_VAL(io.out.lease_response.lease_flags, 0);
     805           0 :         CHECK_VAL(io.out.lease_response.lease_duration, 0);
     806             : 
     807           0 :         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           0 :         options.client_guid = GUID_random();
     816             : 
     817           0 :         ret = torture_smb2_connection_ext(tctx, previous_session_id,
     818             :                                           &options, &tree2);
     819           0 :         torture_assert_goto(tctx, ret, ret, done, "couldn't reconnect");
     820             : 
     821             :         /*
     822             :          * check that this has deleted the old session
     823             :          */
     824             : 
     825           0 :         ZERO_STRUCT(io);
     826           0 :         io.in.fname = fname;
     827           0 :         io.in.durable_handle_v2 = h;
     828           0 :         io.in.create_guid = create_guid;
     829           0 :         io.in.lease_request = &ls;
     830           0 :         status = smb2_create(tree, mem_ctx, &io);
     831           0 :         CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
     832           0 :         TALLOC_FREE(tree);
     833             : 
     834             :         /*
     835             :          * but a durable reconnect on the new session with the wrong
     836             :          * client guid fails
     837             :          */
     838             : 
     839           0 :         ZERO_STRUCT(io);
     840           0 :         io.in.fname = fname;
     841           0 :         io.in.durable_handle_v2 = h;
     842           0 :         io.in.create_guid = create_guid;
     843           0 :         io.in.lease_request = &ls;
     844           0 :         status = smb2_create(tree2, mem_ctx, &io);
     845           0 :         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           0 :         options.client_guid = orig_client_guid;
     854             :         //options.client_guid = GUID_random();
     855             : 
     856           0 :         ret = torture_smb2_connection_ext(tctx, previous_session_id,
     857             :                                           &options, &tree3);
     858           0 :         torture_assert_goto(tctx, ret, ret, done, "couldn't reconnect");
     859             : 
     860             :         /*
     861             :          * check that this has deleted the old session
     862             :          */
     863             : 
     864           0 :         ZERO_STRUCT(io);
     865           0 :         io.in.fname = fname;
     866           0 :         io.in.durable_handle_v2 = h;
     867           0 :         io.in.create_guid = create_guid;
     868           0 :         io.in.lease_request = &ls;
     869           0 :         status = smb2_create(tree2, mem_ctx, &io);
     870           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     871           0 :         TALLOC_FREE(tree2);
     872             : 
     873             :         /*
     874             :          * but a durable reconnect on the new session succeeds:
     875             :          */
     876             : 
     877           0 :         ZERO_STRUCT(io);
     878           0 :         io.in.fname = fname;
     879           0 :         io.in.durable_handle_v2 = h;
     880           0 :         io.in.create_guid = create_guid;
     881           0 :         io.in.lease_request = &ls;
     882           0 :         status = smb2_create(tree3, mem_ctx, &io);
     883           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     884           0 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     885           0 :         CHECK_VAL(io.out.durable_open, false);
     886           0 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
     887           0 :         CHECK_VAL(io.out.persistent_open, false);
     888           0 :         CHECK_VAL(io.out.timeout, 0);
     889           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
     890           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
     891           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
     892           0 :         CHECK_VAL(io.out.lease_response.lease_state,
     893             :                   smb2_util_lease_state("RWH"));
     894           0 :         CHECK_VAL(io.out.lease_response.lease_flags, 0);
     895           0 :         CHECK_VAL(io.out.lease_response.lease_duration, 0);
     896           0 :         _h = io.out.file.handle;
     897           0 :         h = &_h;
     898             : 
     899           0 : done:
     900           0 :         if (tree == NULL) {
     901           0 :                 tree = tree2;
     902             :         }
     903             : 
     904           0 :         if (tree == NULL) {
     905           0 :                 tree = tree3;
     906             :         }
     907             : 
     908           0 :         if (tree != NULL) {
     909           0 :                 if (h != NULL) {
     910           0 :                         smb2_util_close(tree, *h);
     911             :                 }
     912             : 
     913           0 :                 smb2_util_unlink(tree, fname);
     914             : 
     915           0 :                 talloc_free(tree);
     916             :         }
     917             : 
     918           0 :         talloc_free(mem_ctx);
     919             : 
     920           0 :         return ret;
     921             : }
     922             : 
     923             : /**
     924             :  * basic test for doing a durable open
     925             :  * tcp disconnect, reconnect, do a durable reopen (succeeds)
     926             :  */
     927           0 : bool test_durable_v2_open_reopen2(struct torture_context *tctx,
     928             :                                   struct smb2_tree *tree)
     929             : {
     930             :         NTSTATUS status;
     931           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     932             :         char fname[256];
     933             :         struct smb2_handle _h;
     934           0 :         struct smb2_handle *h = NULL;
     935             :         struct smb2_create io;
     936           0 :         struct GUID create_guid = GUID_random();
     937           0 :         struct GUID create_guid_invalid = GUID_random();
     938           0 :         bool ret = true;
     939             : 
     940             :         /* Choose a random name in case the state is left a little funky. */
     941           0 :         snprintf(fname, 256, "durable_v2_open_reopen2_%s.dat",
     942             :                  generate_random_str(tctx, 8));
     943             : 
     944           0 :         smb2_util_unlink(tree, fname);
     945             : 
     946           0 :         smb2_oplock_create_share(&io, fname,
     947             :                                  smb2_util_share_access(""),
     948           0 :                                  smb2_util_oplock_level("b"));
     949           0 :         io.in.durable_open = false;
     950           0 :         io.in.durable_open_v2 = true;
     951           0 :         io.in.persistent_open = false;
     952           0 :         io.in.create_guid = create_guid;
     953           0 :         io.in.timeout = UINT32_MAX;
     954             : 
     955           0 :         status = smb2_create(tree, mem_ctx, &io);
     956           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     957           0 :         _h = io.out.file.handle;
     958           0 :         h = &_h;
     959           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     960           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     961           0 :         CHECK_VAL(io.out.durable_open, false);
     962           0 :         CHECK_VAL(io.out.durable_open_v2, true);
     963           0 :         CHECK_VAL(io.out.persistent_open, false);
     964           0 :         CHECK_VAL(io.out.timeout, 300*1000);
     965             : 
     966             :         /* disconnect, leaving the durable open */
     967           0 :         TALLOC_FREE(tree);
     968             : 
     969           0 :         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           0 :         ZERO_STRUCT(io);
     980           0 :         io.in.fname = "";
     981           0 :         io.in.durable_handle_v2 = h;
     982           0 :         status = smb2_create(tree, mem_ctx, &io);
     983           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     984             : 
     985           0 :         ZERO_STRUCT(io);
     986           0 :         io.in.fname = "__non_existing_fname__";
     987           0 :         io.in.durable_handle_v2 = h;
     988           0 :         status = smb2_create(tree, mem_ctx, &io);
     989           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     990             : 
     991           0 :         ZERO_STRUCT(io);
     992           0 :         io.in.fname = fname;
     993           0 :         io.in.durable_handle_v2 = h;
     994           0 :         status = smb2_create(tree, mem_ctx, &io);
     995           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     996             : 
     997             :         /* a non-zero but non-matching create_guid does not change it: */
     998           0 :         ZERO_STRUCT(io);
     999           0 :         io.in.fname = fname;
    1000           0 :         io.in.durable_handle_v2 = h;
    1001           0 :         io.in.create_guid = create_guid_invalid;
    1002           0 :         status = smb2_create(tree, mem_ctx, &io);
    1003           0 :         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           0 :         ZERO_STRUCT(io);
    1010           0 :         io.in.fname = fname;
    1011           0 :         io.in.durable_open_v2 = false;
    1012           0 :         io.in.durable_handle_v2 = h;
    1013           0 :         io.in.create_guid = create_guid;
    1014           0 :         h = NULL;
    1015             : 
    1016           0 :         status = smb2_create(tree, mem_ctx, &io);
    1017           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1018           0 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1019           0 :         CHECK_VAL(io.out.durable_open, false);
    1020           0 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    1021           0 :         CHECK_VAL(io.out.persistent_open, false);
    1022           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    1023           0 :         _h = io.out.file.handle;
    1024           0 :         h = &_h;
    1025             : 
    1026             :         /* disconnect one more time */
    1027           0 :         TALLOC_FREE(tree);
    1028             : 
    1029           0 :         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           0 :         ZERO_STRUCT(io);
    1036             :         /* These are completely ignored by the server */
    1037           0 :         io.in.security_flags = 0x78;
    1038           0 :         io.in.oplock_level = 0x78;
    1039           0 :         io.in.impersonation_level = 0x12345678;
    1040           0 :         io.in.create_flags = 0x12345678;
    1041           0 :         io.in.reserved = 0x12345678;
    1042           0 :         io.in.desired_access = 0x12345678;
    1043           0 :         io.in.file_attributes = 0x12345678;
    1044           0 :         io.in.share_access = 0x12345678;
    1045           0 :         io.in.create_disposition = 0x12345678;
    1046           0 :         io.in.create_options = 0x12345678;
    1047           0 :         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           0 :         io.in.durable_open_v2 = false;
    1054           0 :         io.in.durable_handle_v2 = h;
    1055           0 :         io.in.create_guid = create_guid;
    1056           0 :         h = NULL;
    1057             : 
    1058           0 :         status = smb2_create(tree, mem_ctx, &io);
    1059           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1060           0 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1061           0 :         CHECK_VAL(io.out.durable_open, false);
    1062           0 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    1063           0 :         CHECK_VAL(io.out.persistent_open, false);
    1064           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    1065           0 :         _h = io.out.file.handle;
    1066           0 :         h = &_h;
    1067             : 
    1068           0 : done:
    1069           0 :         if (h != NULL) {
    1070           0 :                 smb2_util_close(tree, *h);
    1071             :         }
    1072             : 
    1073           0 :         smb2_util_unlink(tree, fname);
    1074             : 
    1075           0 :         talloc_free(tree);
    1076             : 
    1077           0 :         talloc_free(mem_ctx);
    1078             : 
    1079           0 :         return ret;
    1080             : }
    1081             : 
    1082             : /**
    1083             :  * durable reconnect test:
    1084             :  * connect with v2, reconnect with v1
    1085             :  */
    1086           0 : bool test_durable_v2_open_reopen2b(struct torture_context *tctx,
    1087             :                                    struct smb2_tree *tree)
    1088             : {
    1089             :         NTSTATUS status;
    1090           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1091             :         char fname[256];
    1092             :         struct smb2_handle _h;
    1093           0 :         struct smb2_handle *h = NULL;
    1094             :         struct smb2_create io;
    1095           0 :         struct GUID create_guid = GUID_random();
    1096           0 :         bool ret = true;
    1097             :         struct smbcli_options options;
    1098             : 
    1099           0 :         options = tree->session->transport->options;
    1100             : 
    1101             :         /* Choose a random name in case the state is left a little funky. */
    1102           0 :         snprintf(fname, 256, "durable_v2_open_reopen2b_%s.dat",
    1103             :                  generate_random_str(tctx, 8));
    1104             : 
    1105           0 :         smb2_util_unlink(tree, fname);
    1106             : 
    1107           0 :         smb2_oplock_create_share(&io, fname,
    1108             :                                  smb2_util_share_access(""),
    1109           0 :                                  smb2_util_oplock_level("b"));
    1110           0 :         io.in.durable_open = false;
    1111           0 :         io.in.durable_open_v2 = true;
    1112           0 :         io.in.persistent_open = false;
    1113           0 :         io.in.create_guid = create_guid;
    1114           0 :         io.in.timeout = UINT32_MAX;
    1115             : 
    1116           0 :         status = smb2_create(tree, mem_ctx, &io);
    1117           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1118           0 :         _h = io.out.file.handle;
    1119           0 :         h = &_h;
    1120           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1121           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    1122           0 :         CHECK_VAL(io.out.durable_open, false);
    1123           0 :         CHECK_VAL(io.out.durable_open_v2, true);
    1124           0 :         CHECK_VAL(io.out.persistent_open, false);
    1125           0 :         CHECK_VAL(io.out.timeout, 300*1000);
    1126             : 
    1127             :         /* disconnect, leaving the durable open */
    1128           0 :         TALLOC_FREE(tree);
    1129             : 
    1130           0 :         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           0 :         ZERO_STRUCT(io);
    1137           0 :         io.in.fname = fname;
    1138           0 :         io.in.durable_handle_v2 = h;     /* durable v2 reconnect */
    1139           0 :         io.in.create_guid = GUID_zero(); /* but zero create GUID */
    1140           0 :         status = smb2_create(tree, mem_ctx, &io);
    1141           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1142             : 
    1143           0 :         ZERO_STRUCT(io);
    1144           0 :         io.in.fname = fname;
    1145           0 :         io.in.durable_handle = h; /* durable v1 (!) reconnect */
    1146           0 :         h = NULL;
    1147             : 
    1148           0 :         status = smb2_create(tree, mem_ctx, &io);
    1149           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1150           0 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1151           0 :         CHECK_VAL(io.out.durable_open, false);
    1152           0 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    1153           0 :         CHECK_VAL(io.out.persistent_open, false);
    1154           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    1155           0 :         _h = io.out.file.handle;
    1156           0 :         h = &_h;
    1157             : 
    1158           0 : done:
    1159           0 :         if (h != NULL) {
    1160           0 :                 smb2_util_close(tree, *h);
    1161             :         }
    1162             : 
    1163           0 :         smb2_util_unlink(tree, fname);
    1164             : 
    1165           0 :         talloc_free(tree);
    1166             : 
    1167           0 :         talloc_free(mem_ctx);
    1168             : 
    1169           0 :         return ret;
    1170             : }
    1171             : /**
    1172             :  * durable reconnect test:
    1173             :  * connect with v1, reconnect with v2 : fails (no create_guid...)
    1174             :  */
    1175           0 : bool test_durable_v2_open_reopen2c(struct torture_context *tctx,
    1176             :                                    struct smb2_tree *tree)
    1177             : {
    1178             :         NTSTATUS status;
    1179           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1180             :         char fname[256];
    1181             :         struct smb2_handle _h;
    1182           0 :         struct smb2_handle *h = NULL;
    1183             :         struct smb2_create io;
    1184           0 :         struct GUID create_guid = GUID_random();
    1185           0 :         bool ret = true;
    1186             :         struct smbcli_options options;
    1187             : 
    1188           0 :         options = tree->session->transport->options;
    1189             : 
    1190             :         /* Choose a random name in case the state is left a little funky. */
    1191           0 :         snprintf(fname, 256, "durable_v2_open_reopen2c_%s.dat",
    1192             :                  generate_random_str(tctx, 8));
    1193             : 
    1194           0 :         smb2_util_unlink(tree, fname);
    1195             : 
    1196           0 :         smb2_oplock_create_share(&io, fname,
    1197             :                                  smb2_util_share_access(""),
    1198           0 :                                  smb2_util_oplock_level("b"));
    1199           0 :         io.in.durable_open = true;
    1200           0 :         io.in.durable_open_v2 = false;
    1201           0 :         io.in.persistent_open = false;
    1202           0 :         io.in.create_guid = create_guid;
    1203           0 :         io.in.timeout = UINT32_MAX;
    1204             : 
    1205           0 :         status = smb2_create(tree, mem_ctx, &io);
    1206           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1207           0 :         _h = io.out.file.handle;
    1208           0 :         h = &_h;
    1209           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1210           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    1211           0 :         CHECK_VAL(io.out.durable_open, true);
    1212           0 :         CHECK_VAL(io.out.durable_open_v2, false);
    1213           0 :         CHECK_VAL(io.out.persistent_open, false);
    1214           0 :         CHECK_VAL(io.out.timeout, 0);
    1215             : 
    1216             :         /* disconnect, leaving the durable open */
    1217           0 :         TALLOC_FREE(tree);
    1218             : 
    1219           0 :         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           0 :         ZERO_STRUCT(io);
    1226           0 :         io.in.fname = fname;
    1227           0 :         io.in.durable_handle_v2 = h;     /* durable v2 reconnect */
    1228           0 :         io.in.create_guid = create_guid;
    1229           0 :         status = smb2_create(tree, mem_ctx, &io);
    1230           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1231             : 
    1232           0 : done:
    1233           0 :         if (h != NULL) {
    1234           0 :                 smb2_util_close(tree, *h);
    1235             :         }
    1236             : 
    1237           0 :         smb2_util_unlink(tree, fname);
    1238             : 
    1239           0 :         talloc_free(tree);
    1240             : 
    1241           0 :         talloc_free(mem_ctx);
    1242             : 
    1243           0 :         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           0 : bool test_durable_v2_open_reopen2_lease(struct torture_context *tctx,
    1252             :                                         struct smb2_tree *tree)
    1253             : {
    1254             :         NTSTATUS status;
    1255           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1256             :         char fname[256];
    1257             :         struct smb2_handle _h;
    1258           0 :         struct smb2_handle *h = NULL;
    1259             :         struct smb2_create io;
    1260           0 :         struct GUID create_guid = GUID_random();
    1261             :         struct smb2_lease ls;
    1262             :         uint64_t lease_key;
    1263           0 :         bool ret = true;
    1264             :         struct smbcli_options options;
    1265             :         uint32_t caps;
    1266             : 
    1267           0 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
    1268           0 :         if (!(caps & SMB2_CAP_LEASING)) {
    1269           0 :                 torture_skip(tctx, "leases are not supported");
    1270             :         }
    1271             : 
    1272           0 :         options = tree->session->transport->options;
    1273             : 
    1274             :         /* Choose a random name in case the state is left a little funky. */
    1275           0 :         snprintf(fname, 256, "durable_v2_open_reopen2_%s.dat",
    1276             :                  generate_random_str(tctx, 8));
    1277             : 
    1278           0 :         smb2_util_unlink(tree, fname);
    1279             : 
    1280           0 :         lease_key = generate_random_u64();
    1281           0 :         smb2_lease_create(&io, &ls, false /* dir */, fname,
    1282             :                           lease_key, smb2_util_lease_state("RWH"));
    1283           0 :         io.in.durable_open = false;
    1284           0 :         io.in.durable_open_v2 = true;
    1285           0 :         io.in.persistent_open = false;
    1286           0 :         io.in.create_guid = create_guid;
    1287           0 :         io.in.timeout = UINT32_MAX;
    1288             : 
    1289           0 :         status = smb2_create(tree, mem_ctx, &io);
    1290           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1291           0 :         _h = io.out.file.handle;
    1292           0 :         h = &_h;
    1293           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1294           0 :         CHECK_VAL(io.out.durable_open, false);
    1295           0 :         CHECK_VAL(io.out.durable_open_v2, true);
    1296           0 :         CHECK_VAL(io.out.persistent_open, false);
    1297           0 :         CHECK_VAL(io.out.timeout, 300*1000);
    1298           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    1299           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
    1300           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
    1301           0 :         CHECK_VAL(io.out.lease_response.lease_state,
    1302             :                   smb2_util_lease_state("RWH"));
    1303           0 :         CHECK_VAL(io.out.lease_response.lease_flags, 0);
    1304           0 :         CHECK_VAL(io.out.lease_response.lease_duration, 0);
    1305             : 
    1306             :         /* disconnect, reconnect and then do durable reopen */
    1307           0 :         TALLOC_FREE(tree);
    1308             : 
    1309           0 :         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           0 :         ZERO_STRUCT(io);
    1324           0 :         io.in.fname = "";
    1325           0 :         io.in.durable_handle_v2 = h;
    1326           0 :         status = smb2_create(tree, mem_ctx, &io);
    1327           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1328             : 
    1329           0 :         ZERO_STRUCT(io);
    1330           0 :         io.in.fname = "__non_existing_fname__";
    1331           0 :         io.in.durable_handle_v2 = h;
    1332           0 :         status = smb2_create(tree, mem_ctx, &io);
    1333           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1334             : 
    1335           0 :         ZERO_STRUCT(io);
    1336           0 :         io.in.fname = fname;
    1337           0 :         io.in.durable_handle_v2 = h;
    1338           0 :         status = smb2_create(tree, mem_ctx, &io);
    1339           0 :         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           0 :         ZERO_STRUCT(io);
    1346           0 :         io.in.fname = fname;
    1347           0 :         io.in.durable_open_v2 = false;
    1348           0 :         io.in.durable_handle_v2 = h;
    1349           0 :         io.in.create_guid = create_guid;
    1350           0 :         io.in.lease_request = &ls;
    1351           0 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
    1352             :         /* a wrong lease key lets the request fail */
    1353           0 :         ls.lease_key.data[0]++;
    1354             : 
    1355           0 :         status = smb2_create(tree, mem_ctx, &io);
    1356           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1357             : 
    1358             :         /* restore the correct lease key */
    1359           0 :         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           0 :         ZERO_STRUCT(io);
    1368           0 :         io.in.fname = "__non_existing_fname__";
    1369           0 :         io.in.durable_open_v2 = false;
    1370           0 :         io.in.durable_handle_v2 = h;
    1371           0 :         io.in.create_guid = create_guid;
    1372           0 :         io.in.lease_request = &ls;
    1373           0 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
    1374             : 
    1375           0 :         status = smb2_create(tree, mem_ctx, &io);
    1376           0 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
    1377             : 
    1378             :         /*
    1379             :          * Now for a succeeding reconnect:
    1380             :          */
    1381             : 
    1382           0 :         ZERO_STRUCT(io);
    1383           0 :         io.in.fname = fname;
    1384           0 :         io.in.durable_open_v2 = false;
    1385           0 :         io.in.durable_handle_v2 = h;
    1386           0 :         io.in.create_guid = create_guid;
    1387           0 :         io.in.lease_request = &ls;
    1388           0 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
    1389             : 
    1390             :         /* the requested lease state is irrelevant */
    1391           0 :         ls.lease_state = smb2_util_lease_state("");
    1392             : 
    1393           0 :         h = NULL;
    1394             : 
    1395           0 :         status = smb2_create(tree, mem_ctx, &io);
    1396           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1397             : 
    1398           0 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1399           0 :         CHECK_VAL(io.out.durable_open, false);
    1400           0 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    1401           0 :         CHECK_VAL(io.out.persistent_open, false);
    1402           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    1403           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
    1404           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
    1405           0 :         CHECK_VAL(io.out.lease_response.lease_state,
    1406             :                   smb2_util_lease_state("RWH"));
    1407           0 :         CHECK_VAL(io.out.lease_response.lease_flags, 0);
    1408           0 :         CHECK_VAL(io.out.lease_response.lease_duration, 0);
    1409           0 :         _h = io.out.file.handle;
    1410           0 :         h = &_h;
    1411             : 
    1412             :         /* disconnect one more time */
    1413           0 :         TALLOC_FREE(tree);
    1414             : 
    1415           0 :         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           0 :         ZERO_STRUCT(io);
    1427             :         /*
    1428             :          * These are completely ignored by the server
    1429             :          */
    1430           0 :         io.in.security_flags = 0x78;
    1431           0 :         io.in.oplock_level = 0x78;
    1432           0 :         io.in.impersonation_level = 0x12345678;
    1433           0 :         io.in.create_flags = 0x12345678;
    1434           0 :         io.in.reserved = 0x12345678;
    1435           0 :         io.in.desired_access = 0x12345678;
    1436           0 :         io.in.file_attributes = 0x12345678;
    1437           0 :         io.in.share_access = 0x12345678;
    1438           0 :         io.in.create_disposition = 0x12345678;
    1439           0 :         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           0 :         io.in.fname = fname;
    1450           0 :         io.in.durable_open_v2 = false;
    1451           0 :         io.in.durable_handle_v2 = h;
    1452           0 :         io.in.create_guid = create_guid;
    1453           0 :         io.in.lease_request = &ls;
    1454             : 
    1455             :         /* the requested lease state is irrelevant */
    1456           0 :         ls.lease_state = smb2_util_lease_state("");
    1457             : 
    1458           0 :         h = NULL;
    1459             : 
    1460           0 :         status = smb2_create(tree, mem_ctx, &io);
    1461           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1462             : 
    1463           0 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1464           0 :         CHECK_VAL(io.out.durable_open, false);
    1465           0 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    1466           0 :         CHECK_VAL(io.out.persistent_open, false);
    1467           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    1468           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
    1469           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
    1470           0 :         CHECK_VAL(io.out.lease_response.lease_state,
    1471             :                   smb2_util_lease_state("RWH"));
    1472           0 :         CHECK_VAL(io.out.lease_response.lease_flags, 0);
    1473           0 :         CHECK_VAL(io.out.lease_response.lease_duration, 0);
    1474             : 
    1475           0 :         _h = io.out.file.handle;
    1476           0 :         h = &_h;
    1477             : 
    1478           0 : done:
    1479           0 :         if (h != NULL) {
    1480           0 :                 smb2_util_close(tree, *h);
    1481             :         }
    1482             : 
    1483           0 :         smb2_util_unlink(tree, fname);
    1484             : 
    1485           0 :         talloc_free(tree);
    1486             : 
    1487           0 :         talloc_free(mem_ctx);
    1488             : 
    1489           0 :         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           0 : bool test_durable_v2_open_reopen2_lease_v2(struct torture_context *tctx,
    1498             :                                            struct smb2_tree *tree)
    1499             : {
    1500             :         NTSTATUS status;
    1501           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1502             :         char fname[256];
    1503             :         struct smb2_handle _h;
    1504           0 :         struct smb2_handle *h = NULL;
    1505             :         struct smb2_create io;
    1506           0 :         struct GUID create_guid = GUID_random();
    1507             :         struct smb2_lease ls;
    1508             :         uint64_t lease_key;
    1509           0 :         bool ret = true;
    1510             :         struct smbcli_options options;
    1511             :         uint32_t caps;
    1512             : 
    1513           0 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
    1514           0 :         if (!(caps & SMB2_CAP_LEASING)) {
    1515           0 :                 torture_skip(tctx, "leases are not supported");
    1516             :         }
    1517             : 
    1518           0 :         options = tree->session->transport->options;
    1519             : 
    1520           0 :         smb2_deltree(tree, __func__);
    1521           0 :         status = torture_smb2_testdir(tree, __func__, &_h);
    1522           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1523             :                                         "torture_smb2_testdir failed\n");
    1524           0 :         smb2_util_close(tree, _h);
    1525             : 
    1526             :         /* Choose a random name in case the state is left a little funky. */
    1527           0 :         snprintf(fname, 256, "%s\\durable_v2_open_reopen2_%s.dat",
    1528             :                  __func__, generate_random_str(tctx, 8));
    1529             : 
    1530           0 :         smb2_util_unlink(tree, fname);
    1531             : 
    1532           0 :         lease_key = random();
    1533           0 :         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           0 :         io.in.durable_open = false;
    1537           0 :         io.in.durable_open_v2 = true;
    1538           0 :         io.in.persistent_open = false;
    1539           0 :         io.in.create_guid = create_guid;
    1540           0 :         io.in.timeout = UINT32_MAX;
    1541             : 
    1542           0 :         status = smb2_create(tree, mem_ctx, &io);
    1543           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1544           0 :         _h = io.out.file.handle;
    1545           0 :         h = &_h;
    1546           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1547           0 :         CHECK_VAL(io.out.durable_open, false);
    1548           0 :         CHECK_VAL(io.out.durable_open_v2, true);
    1549           0 :         CHECK_VAL(io.out.persistent_open, false);
    1550           0 :         CHECK_VAL(io.out.timeout, 300*1000);
    1551           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    1552           0 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
    1553           0 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
    1554             : 
    1555             :         /* disconnect, reconnect and then do durable reopen */
    1556           0 :         TALLOC_FREE(tree);
    1557             : 
    1558           0 :         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           0 :         ZERO_STRUCT(io);
    1573           0 :         io.in.fname = "";
    1574           0 :         io.in.durable_handle_v2 = h;
    1575           0 :         status = smb2_create(tree, mem_ctx, &io);
    1576           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1577             : 
    1578           0 :         ZERO_STRUCT(io);
    1579           0 :         io.in.fname = "__non_existing_fname__";
    1580           0 :         io.in.durable_handle_v2 = h;
    1581           0 :         status = smb2_create(tree, mem_ctx, &io);
    1582           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1583             : 
    1584           0 :         ZERO_STRUCT(io);
    1585           0 :         io.in.fname = fname;
    1586           0 :         io.in.durable_handle_v2 = h;
    1587           0 :         status = smb2_create(tree, mem_ctx, &io);
    1588           0 :         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           0 :         ZERO_STRUCT(io);
    1595           0 :         io.in.fname = fname;
    1596           0 :         io.in.durable_open_v2 = false;
    1597           0 :         io.in.durable_handle_v2 = h;
    1598           0 :         io.in.create_guid = create_guid;
    1599           0 :         io.in.lease_request_v2 = &ls;
    1600           0 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
    1601             :         /* a wrong lease key lets the request fail */
    1602           0 :         ls.lease_key.data[0]++;
    1603             : 
    1604           0 :         status = smb2_create(tree, mem_ctx, &io);
    1605           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1606             : 
    1607             :         /* restore the correct lease key */
    1608           0 :         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           0 :         ZERO_STRUCT(io);
    1618           0 :         io.in.fname = "__non_existing_fname__";
    1619           0 :         io.in.durable_open_v2 = false;
    1620           0 :         io.in.durable_handle_v2 = h;
    1621           0 :         io.in.create_guid = create_guid;
    1622           0 :         io.in.lease_request_v2 = &ls;
    1623           0 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
    1624             : 
    1625           0 :         status = smb2_create(tree, mem_ctx, &io);
    1626           0 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
    1627             : 
    1628             :         /*
    1629             :          * Now for a succeeding reconnect:
    1630             :          */
    1631             : 
    1632           0 :         ZERO_STRUCT(io);
    1633           0 :         io.in.fname = fname;
    1634           0 :         io.in.durable_open_v2 = false;
    1635           0 :         io.in.durable_handle_v2 = h;
    1636           0 :         io.in.create_guid = create_guid;
    1637           0 :         io.in.lease_request_v2 = &ls;
    1638           0 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
    1639             : 
    1640             :         /* the requested lease state is irrelevant */
    1641           0 :         ls.lease_state = smb2_util_lease_state("");
    1642             : 
    1643           0 :         h = NULL;
    1644             : 
    1645           0 :         status = smb2_create(tree, mem_ctx, &io);
    1646           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1647             : 
    1648           0 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1649           0 :         CHECK_VAL(io.out.durable_open, false);
    1650           0 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    1651           0 :         CHECK_VAL(io.out.persistent_open, false);
    1652           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    1653           0 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
    1654           0 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
    1655           0 :         CHECK_VAL(io.out.lease_response_v2.lease_state,
    1656             :                   smb2_util_lease_state("RWH"));
    1657           0 :         CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
    1658           0 :         CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
    1659           0 :         _h = io.out.file.handle;
    1660           0 :         h = &_h;
    1661             : 
    1662             :         /* disconnect one more time */
    1663           0 :         TALLOC_FREE(tree);
    1664             : 
    1665           0 :         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           0 :         ZERO_STRUCT(io);
    1677             :         /*
    1678             :          * These are completely ignored by the server
    1679             :          */
    1680           0 :         io.in.security_flags = 0x78;
    1681           0 :         io.in.oplock_level = 0x78;
    1682           0 :         io.in.impersonation_level = 0x12345678;
    1683           0 :         io.in.create_flags = 0x12345678;
    1684           0 :         io.in.reserved = 0x12345678;
    1685           0 :         io.in.desired_access = 0x12345678;
    1686           0 :         io.in.file_attributes = 0x12345678;
    1687           0 :         io.in.share_access = 0x12345678;
    1688           0 :         io.in.create_disposition = 0x12345678;
    1689           0 :         io.in.create_options = 0x12345678;
    1690           0 :         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           0 :         io.in.fname = fname;
    1701           0 :         io.in.durable_open_v2 = false;
    1702           0 :         io.in.durable_handle_v2 = h;
    1703           0 :         io.in.create_guid = create_guid;
    1704           0 :         io.in.lease_request_v2 = &ls;
    1705             : 
    1706             :         /* the requested lease state is irrelevant */
    1707           0 :         ls.lease_state = smb2_util_lease_state("");
    1708             : 
    1709           0 :         h = NULL;
    1710             : 
    1711           0 :         status = smb2_create(tree, mem_ctx, &io);
    1712           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1713           0 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1714           0 :         CHECK_VAL(io.out.durable_open, false);
    1715           0 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    1716           0 :         CHECK_VAL(io.out.persistent_open, false);
    1717           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    1718           0 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
    1719           0 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
    1720           0 :         CHECK_VAL(io.out.lease_response_v2.lease_state,
    1721             :                   smb2_util_lease_state("RWH"));
    1722           0 :         CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
    1723           0 :         CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
    1724             : 
    1725           0 :         _h = io.out.file.handle;
    1726           0 :         h = &_h;
    1727             : 
    1728           0 : done:
    1729           0 :         if (h != NULL) {
    1730           0 :                 smb2_util_close(tree, *h);
    1731             :         }
    1732             : 
    1733           0 :         smb2_util_unlink(tree, fname);
    1734           0 :         smb2_deltree(tree, __func__);
    1735             : 
    1736           0 :         talloc_free(tree);
    1737             : 
    1738           0 :         talloc_free(mem_ctx);
    1739             : 
    1740           0 :         return ret;
    1741             : }
    1742             : 
    1743             : /**
    1744             :  * Test durable request / reconnect with AppInstanceId
    1745             :  */
    1746           0 : bool test_durable_v2_open_app_instance(struct torture_context *tctx,
    1747             :                                        struct smb2_tree *tree1,
    1748             :                                        struct smb2_tree *tree2)
    1749             : {
    1750             :         NTSTATUS status;
    1751           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1752             :         char fname[256];
    1753             :         struct smb2_handle _h1, _h2;
    1754           0 :         struct smb2_handle *h1 = NULL, *h2 = NULL;
    1755             :         struct smb2_create io1, io2;
    1756           0 :         bool ret = true;
    1757           0 :         struct GUID create_guid_1 = GUID_random();
    1758           0 :         struct GUID create_guid_2 = GUID_random();
    1759           0 :         struct GUID app_instance_id = GUID_random();
    1760             : 
    1761             :         /* Choose a random name in case the state is left a little funky. */
    1762           0 :         snprintf(fname, 256, "durable_v2_open_app_instance_%s.dat",
    1763             :                  generate_random_str(tctx, 8));
    1764             : 
    1765           0 :         smb2_util_unlink(tree1, fname);
    1766             : 
    1767           0 :         ZERO_STRUCT(break_info);
    1768           0 :         tree1->session->transport->oplock.handler = torture_oplock_handler;
    1769           0 :         tree1->session->transport->oplock.private_data = tree1;
    1770             : 
    1771           0 :         smb2_oplock_create_share(&io1, fname,
    1772             :                                  smb2_util_share_access(""),
    1773           0 :                                  smb2_util_oplock_level("b"));
    1774           0 :         io1.in.durable_open = false;
    1775           0 :         io1.in.durable_open_v2 = true;
    1776           0 :         io1.in.persistent_open = false;
    1777           0 :         io1.in.create_guid = create_guid_1;
    1778           0 :         io1.in.app_instance_id = &app_instance_id;
    1779           0 :         io1.in.timeout = UINT32_MAX;
    1780             : 
    1781           0 :         status = smb2_create(tree1, mem_ctx, &io1);
    1782           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1783           0 :         _h1 = io1.out.file.handle;
    1784           0 :         h1 = &_h1;
    1785           0 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1786           0 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
    1787           0 :         CHECK_VAL(io1.out.durable_open, false);
    1788           0 :         CHECK_VAL(io1.out.durable_open_v2, true);
    1789           0 :         CHECK_VAL(io1.out.persistent_open, false);
    1790           0 :         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           0 :         smb2_oplock_create_share(&io2, fname,
    1799             :                                  smb2_util_share_access(""),
    1800           0 :                                  smb2_util_oplock_level("b"));
    1801           0 :         io2.in.durable_open = false;
    1802           0 :         io2.in.durable_open_v2 = true;
    1803           0 :         io2.in.persistent_open = false;
    1804           0 :         io2.in.create_guid = create_guid_2;
    1805           0 :         io2.in.app_instance_id = &app_instance_id;
    1806           0 :         io2.in.timeout = UINT32_MAX;
    1807             : 
    1808           0 :         status = smb2_create(tree2, mem_ctx, &io2);
    1809           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1810           0 :         _h2 = io2.out.file.handle;
    1811           0 :         h2 = &_h2;
    1812           0 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1813           0 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
    1814           0 :         CHECK_VAL(io2.out.durable_open, false);
    1815           0 :         CHECK_VAL(io2.out.durable_open_v2, true);
    1816           0 :         CHECK_VAL(io2.out.persistent_open, false);
    1817           0 :         CHECK_VAL(io2.out.timeout, 300*1000);
    1818             : 
    1819           0 :         CHECK_VAL(break_info.count, 0);
    1820             : 
    1821           0 :         status = smb2_util_close(tree1, *h1);
    1822           0 :         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
    1823           0 :         h1 = NULL;
    1824             : 
    1825           0 : done:
    1826           0 :         if (h1 != NULL) {
    1827           0 :                 smb2_util_close(tree1, *h1);
    1828             :         }
    1829           0 :         if (h2 != NULL) {
    1830           0 :                 smb2_util_close(tree2, *h2);
    1831             :         }
    1832             : 
    1833           0 :         smb2_util_unlink(tree2, fname);
    1834             : 
    1835           0 :         talloc_free(tree1);
    1836           0 :         talloc_free(tree2);
    1837             : 
    1838           0 :         talloc_free(mem_ctx);
    1839             : 
    1840           0 :         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           0 : bool test_persistent_open_oplock(struct torture_context *tctx,
    1890             :                                  struct smb2_tree *tree)
    1891             : {
    1892             :         char fname[256];
    1893           0 :         bool ret = true;
    1894             :         uint32_t share_capabilities;
    1895           0 :         bool share_is_ca = false;
    1896             :         struct durable_open_vs_oplock *table;
    1897             : 
    1898             :         /* Choose a random name in case the state is left a little funky. */
    1899           0 :         snprintf(fname, 256, "persistent_open_oplock_%s.dat", generate_random_str(tctx, 8));
    1900             : 
    1901           0 :         share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
    1902           0 :         share_is_ca = share_capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY;
    1903             : 
    1904           0 :         if (share_is_ca) {
    1905           0 :                 table = persistent_open_oplock_ca_table;
    1906             :         } else {
    1907           0 :                 table = durable_open_vs_oplock_table;
    1908             :         }
    1909             : 
    1910           0 :         ret = test_durable_v2_open_oplock_table(tctx, tree, fname,
    1911             :                                                 true, /* request_persistent */
    1912             :                                                 table,
    1913             :                                                 NUM_OPLOCK_OPEN_TESTS);
    1914             : 
    1915           0 :         talloc_free(tree);
    1916             : 
    1917           0 :         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           0 : bool test_persistent_open_lease(struct torture_context *tctx,
    1977             :                                 struct smb2_tree *tree)
    1978             : {
    1979             :         char fname[256];
    1980           0 :         bool ret = true;
    1981             :         uint32_t caps;
    1982             :         uint32_t share_capabilities;
    1983             :         bool share_is_ca;
    1984             :         struct durable_open_vs_lease *table;
    1985             : 
    1986           0 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
    1987           0 :         if (!(caps & SMB2_CAP_LEASING)) {
    1988           0 :                 torture_skip(tctx, "leases are not supported");
    1989             :         }
    1990             : 
    1991             :         /* Choose a random name in case the state is left a little funky. */
    1992           0 :         snprintf(fname, 256, "persistent_open_lease_%s.dat", generate_random_str(tctx, 8));
    1993             : 
    1994           0 :         share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
    1995           0 :         share_is_ca = share_capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY;
    1996             : 
    1997           0 :         if (share_is_ca) {
    1998           0 :                 table = persistent_open_lease_ca_table;
    1999             :         } else {
    2000           0 :                 table = durable_open_vs_lease_table;
    2001             :         }
    2002             : 
    2003           0 :         ret = test_durable_v2_open_lease_table(tctx, tree, fname,
    2004             :                                                true, /* request_persistent */
    2005             :                                                table,
    2006             :                                                NUM_LEASE_OPEN_TESTS);
    2007             : 
    2008           0 :         talloc_free(tree);
    2009             : 
    2010           0 :         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           0 : bool test_durable_v2_setinfo(struct torture_context *tctx,
    2022             :                                            struct smb2_tree *tree)
    2023             : {
    2024             :         NTSTATUS status;
    2025           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2026             :         char fname[256];
    2027             :         struct smb2_handle _h;
    2028           0 :         struct smb2_handle *h = NULL;
    2029             :         struct smb2_create io;
    2030             :         union smb_setfileinfo si;
    2031           0 :         struct GUID create_guid = GUID_random();
    2032             :         struct smb2_lease ls;
    2033             :         uint64_t lease_key;
    2034           0 :         bool ret = true;
    2035             :         struct smbcli_options options;
    2036             :         uint32_t caps;
    2037             : 
    2038           0 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
    2039           0 :         if (!(caps & SMB2_CAP_LEASING)) {
    2040           0 :                 torture_skip(tctx, "leases are not supported");
    2041             :         }
    2042             : 
    2043           0 :         options = tree->session->transport->options;
    2044             : 
    2045           0 :         smb2_deltree(tree, __func__);
    2046           0 :         status = torture_smb2_testdir(tree, __func__, &_h);
    2047           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    2048             :                                         "torture_smb2_testdir failed\n");
    2049           0 :         smb2_util_close(tree, _h);
    2050             : 
    2051             :         /* Choose a random name in case the state is left a little funky. */
    2052           0 :         snprintf(fname, 256, "%s\\durable_v2_setinfo%s.dat",
    2053             :                  __func__, generate_random_str(tctx, 8));
    2054             : 
    2055           0 :         smb2_util_unlink(tree, fname);
    2056             : 
    2057           0 :         lease_key = random();
    2058           0 :         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           0 :         io.in.durable_open = false;
    2062           0 :         io.in.durable_open_v2 = true;
    2063           0 :         io.in.persistent_open = false;
    2064           0 :         io.in.create_guid = create_guid;
    2065           0 :         io.in.timeout = UINT32_MAX;
    2066             : 
    2067           0 :         status = smb2_create(tree, mem_ctx, &io);
    2068           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2069           0 :         _h = io.out.file.handle;
    2070           0 :         h = &_h;
    2071           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    2072           0 :         CHECK_VAL(io.out.durable_open, false);
    2073           0 :         CHECK_VAL(io.out.durable_open_v2, true);
    2074           0 :         CHECK_VAL(io.out.persistent_open, false);
    2075           0 :         CHECK_VAL(io.out.timeout, 300*1000);
    2076           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    2077           0 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
    2078           0 :         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           0 :         ZERO_STRUCT(si);
    2086           0 :         si.generic.level = SMB_SFILEINFO_END_OF_FILE_INFORMATION;
    2087           0 :         si.generic.in.file.handle = io.out.file.handle;
    2088           0 :         si.end_of_file_info.in.size = 0x100000;
    2089           0 :         status = smb2_setinfo_file(tree, &si);
    2090           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2091             : 
    2092             :         /* disconnect, reconnect and then do durable reopen */
    2093           0 :         TALLOC_FREE(tree);
    2094             : 
    2095           0 :         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           0 :         ZERO_STRUCT(io);
    2106           0 :         io.in.fname = fname;
    2107           0 :         io.in.durable_open_v2 = false;
    2108           0 :         io.in.durable_handle_v2 = h;
    2109           0 :         io.in.create_guid = create_guid;
    2110           0 :         io.in.lease_request_v2 = &ls;
    2111           0 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
    2112             : 
    2113             :         /* the requested lease state is irrelevant */
    2114           0 :         ls.lease_state = smb2_util_lease_state("");
    2115             : 
    2116           0 :         h = NULL;
    2117             : 
    2118           0 :         status = smb2_create(tree, mem_ctx, &io);
    2119           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2120             : 
    2121           0 :         CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
    2122           0 :         CHECK_VAL(io.out.size, 0x100000);                               \
    2123           0 :         CHECK_VAL(io.out.durable_open, false);
    2124           0 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    2125           0 :         CHECK_VAL(io.out.persistent_open, false);
    2126           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    2127           0 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
    2128           0 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
    2129           0 :         CHECK_VAL(io.out.lease_response_v2.lease_state,
    2130             :                   smb2_util_lease_state("RWH"));
    2131           0 :         CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
    2132           0 :         CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
    2133           0 :         _h = io.out.file.handle;
    2134           0 :         h = &_h;
    2135             : 
    2136           0 : done:
    2137             : 
    2138           0 :         if (h != NULL) {
    2139           0 :                 smb2_util_close(tree, *h);
    2140             :         }
    2141             : 
    2142           0 :         smb2_util_unlink(tree, fname);
    2143           0 :         smb2_deltree(tree, __func__);
    2144             : 
    2145           0 :         talloc_free(tree);
    2146             : 
    2147           0 :         talloc_free(mem_ctx);
    2148             : 
    2149           0 :         return ret;
    2150             : }
    2151             : 
    2152         964 : struct torture_suite *torture_smb2_durable_v2_open_init(TALLOC_CTX *ctx)
    2153             : {
    2154         738 :         struct torture_suite *suite =
    2155         226 :             torture_suite_create(ctx, "durable-v2-open");
    2156             : 
    2157         964 :         torture_suite_add_1smb2_test(suite, "create-blob", test_durable_v2_open_create_blob);
    2158         964 :         torture_suite_add_1smb2_test(suite, "open-oplock", test_durable_v2_open_oplock);
    2159         964 :         torture_suite_add_1smb2_test(suite, "open-lease", test_durable_v2_open_lease);
    2160         964 :         torture_suite_add_1smb2_test(suite, "reopen1", test_durable_v2_open_reopen1);
    2161         964 :         torture_suite_add_1smb2_test(suite, "reopen1a", test_durable_v2_open_reopen1a);
    2162         964 :         torture_suite_add_1smb2_test(suite, "reopen1a-lease", test_durable_v2_open_reopen1a_lease);
    2163         964 :         torture_suite_add_1smb2_test(suite, "reopen2", test_durable_v2_open_reopen2);
    2164         964 :         torture_suite_add_1smb2_test(suite, "reopen2b", test_durable_v2_open_reopen2b);
    2165         964 :         torture_suite_add_1smb2_test(suite, "reopen2c", test_durable_v2_open_reopen2c);
    2166         964 :         torture_suite_add_1smb2_test(suite, "reopen2-lease", test_durable_v2_open_reopen2_lease);
    2167         964 :         torture_suite_add_1smb2_test(suite, "reopen2-lease-v2", test_durable_v2_open_reopen2_lease_v2);
    2168         964 :         torture_suite_add_1smb2_test(suite, "durable-v2-setinfo", test_durable_v2_setinfo);
    2169         964 :         torture_suite_add_2smb2_test(suite, "app-instance", test_durable_v2_open_app_instance);
    2170         964 :         torture_suite_add_1smb2_test(suite, "persistent-open-oplock", test_persistent_open_oplock);
    2171         964 :         torture_suite_add_1smb2_test(suite, "persistent-open-lease", test_persistent_open_lease);
    2172             : 
    2173         964 :         suite->description = talloc_strdup(suite, "SMB2-DURABLE-V2-OPEN tests");
    2174             : 
    2175         964 :         return suite;
    2176             : }
    2177             : 
    2178             : /**
    2179             :  * basic test for doing a durable open
    2180             :  * tcp disconnect, reconnect, do a durable reopen (succeeds)
    2181             :  */
    2182           0 : static bool test_durable_v2_reconnect_delay(struct torture_context *tctx,
    2183             :                                             struct smb2_tree *tree,
    2184             :                                             struct smb2_tree *tree2)
    2185             : {
    2186             :         NTSTATUS status;
    2187           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2188             :         char fname[256];
    2189             :         struct smb2_handle _h;
    2190           0 :         struct smb2_handle *h = NULL;
    2191             :         struct smb2_create io;
    2192           0 :         struct GUID create_guid = GUID_random();
    2193             :         struct smbcli_options options;
    2194             :         uint64_t previous_session_id;
    2195           0 :         uint8_t b = 0;
    2196           0 :         bool ret = true;
    2197             :         bool ok;
    2198             : 
    2199           0 :         options = tree->session->transport->options;
    2200           0 :         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           0 :         snprintf(fname,
    2204             :                  sizeof(fname),
    2205             :                  "durable_v2_reconnect_delay_%s.dat",
    2206             :                  generate_random_str(tctx, 8));
    2207             : 
    2208           0 :         smb2_util_unlink(tree, fname);
    2209             : 
    2210           0 :         smb2_oplock_create_share(&io, fname,
    2211             :                                  smb2_util_share_access(""),
    2212           0 :                                  smb2_util_oplock_level("b"));
    2213           0 :         io.in.durable_open = false;
    2214           0 :         io.in.durable_open_v2 = true;
    2215           0 :         io.in.persistent_open = false;
    2216           0 :         io.in.create_guid = create_guid;
    2217           0 :         io.in.timeout = 0;
    2218             : 
    2219           0 :         status = smb2_create(tree, mem_ctx, &io);
    2220           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2221             : 
    2222           0 :         _h = io.out.file.handle;
    2223           0 :         h = &_h;
    2224           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    2225           0 :         CHECK_VAL(io.out.durable_open_v2, true);
    2226             : 
    2227           0 :         status = smb2_util_write(tree, *h, &b, 0, 1);
    2228           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2229             : 
    2230             :         /* disconnect, leaving the durable open */
    2231           0 :         TALLOC_FREE(tree);
    2232           0 :         h = NULL;
    2233             : 
    2234           0 :         ok = torture_smb2_connection_ext(tctx, previous_session_id,
    2235             :                                          &options, &tree);
    2236           0 :         torture_assert_goto(tctx, ok, ret, done, "couldn't reconnect, bailing\n");
    2237             : 
    2238           0 :         ZERO_STRUCT(io);
    2239           0 :         io.in.fname = fname;
    2240           0 :         io.in.durable_open_v2 = false;
    2241           0 :         io.in.durable_handle_v2 = &_h;
    2242           0 :         io.in.create_guid = create_guid;
    2243             : 
    2244           0 :         status = smb2_create(tree, mem_ctx, &io);
    2245           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2246           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    2247           0 :         _h = io.out.file.handle;
    2248           0 :         h = &_h;
    2249             : 
    2250           0 : done:
    2251           0 :         if (h != NULL) {
    2252           0 :                 smb2_util_close(tree, *h);
    2253             :         }
    2254           0 :         TALLOC_FREE(tree);
    2255             : 
    2256           0 :         smb2_util_unlink(tree2, fname);
    2257             : 
    2258           0 :         TALLOC_FREE(tree2);
    2259             : 
    2260           0 :         talloc_free(mem_ctx);
    2261             : 
    2262           0 :         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           0 : static bool test_durable_v2_reconnect_delay_msec(struct torture_context *tctx,
    2270             :                                                  struct smb2_tree *tree,
    2271             :                                                  struct smb2_tree *tree2)
    2272             : {
    2273             :         NTSTATUS status;
    2274           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2275             :         char fname[256];
    2276             :         struct smb2_handle _h;
    2277           0 :         struct smb2_handle *h = NULL;
    2278             :         struct smb2_create io;
    2279             :         struct smb2_lease ls;
    2280           0 :         struct GUID create_guid = GUID_random();
    2281             :         struct smbcli_options options;
    2282             :         uint64_t previous_session_id;
    2283           0 :         uint8_t b = 0;
    2284           0 :         bool ret = true;
    2285             :         bool ok;
    2286             : 
    2287           0 :         options = tree->session->transport->options;
    2288           0 :         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           0 :         snprintf(fname,
    2292             :                  sizeof(fname),
    2293             :                  "durable_v2_reconnect_delay_%s.dat",
    2294             :                  generate_random_str(tctx, 8));
    2295             : 
    2296           0 :         smb2_util_unlink(tree, fname);
    2297             : 
    2298           0 :         smb2_lease_create(
    2299             :                 &io,
    2300             :                 &ls,
    2301             :                 false /* dir */,
    2302             :                 fname,
    2303             :                 generate_random_u64(),
    2304             :                 smb2_util_lease_state("RWH"));
    2305           0 :         io.in.durable_open = false;
    2306           0 :         io.in.durable_open_v2 = true;
    2307           0 :         io.in.persistent_open = false;
    2308           0 :         io.in.create_guid = create_guid;
    2309           0 :         io.in.timeout = 1;
    2310             : 
    2311           0 :         status = smb2_create(tree, mem_ctx, &io);
    2312           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2313             : 
    2314           0 :         _h = io.out.file.handle;
    2315           0 :         h = &_h;
    2316           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    2317           0 :         CHECK_VAL(io.out.durable_open_v2, true);
    2318             : 
    2319           0 :         status = smb2_util_write(tree, *h, &b, 0, 1);
    2320           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2321             : 
    2322             :         /* disconnect, leaving the durable open */
    2323           0 :         TALLOC_FREE(tree);
    2324           0 :         h = NULL;
    2325             : 
    2326           0 :         ok = torture_smb2_connection_ext(tctx, previous_session_id,
    2327             :                                          &options, &tree);
    2328           0 :         torture_assert_goto(tctx, ok, ret, done, "couldn't reconnect, bailing\n");
    2329             : 
    2330           0 :         sleep(10);
    2331             : 
    2332           0 :         ZERO_STRUCT(io);
    2333           0 :         io.in.fname = fname;
    2334           0 :         io.in.durable_open_v2 = false;
    2335           0 :         io.in.durable_handle_v2 = &_h;
    2336           0 :         io.in.create_guid = create_guid;
    2337             : 
    2338           0 :         status = smb2_create(tree, mem_ctx, &io);
    2339           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    2340           0 :         _h = io.out.file.handle;
    2341           0 :         h = &_h;
    2342             : 
    2343           0 : done:
    2344           0 :         if (h != NULL) {
    2345           0 :                 smb2_util_close(tree, *h);
    2346             :         }
    2347           0 :         TALLOC_FREE(tree);
    2348             : 
    2349           0 :         smb2_util_unlink(tree2, fname);
    2350             : 
    2351           0 :         TALLOC_FREE(tree2);
    2352             : 
    2353           0 :         talloc_free(mem_ctx);
    2354             : 
    2355           0 :         return ret;
    2356             : }
    2357             : 
    2358         964 : struct torture_suite *torture_smb2_durable_v2_delay_init(TALLOC_CTX *ctx)
    2359             : {
    2360         738 :         struct torture_suite *suite =
    2361         226 :             torture_suite_create(ctx, "durable-v2-delay");
    2362             : 
    2363         964 :         torture_suite_add_2smb2_test(suite,
    2364             :                                      "durable_v2_reconnect_delay",
    2365             :                                      test_durable_v2_reconnect_delay);
    2366         964 :         torture_suite_add_2smb2_test(suite,
    2367             :                                      "durable_v2_reconnect_delay_msec",
    2368             :                                      test_durable_v2_reconnect_delay_msec);
    2369             : 
    2370         964 :         return suite;
    2371             : }

Generated by: LCOV version 1.13