LCOV - code coverage report
Current view: top level - source4/torture/smb2 - durable_open.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 34 1417 2.4 %
Date: 2024-06-13 04:01:37 Functions: 2 28 7.1 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    test suite for SMB2 durable opens
       5             : 
       6             :    Copyright (C) Stefan Metzmacher 2008
       7             :    Copyright (C) Michael Adam 2011-2012
       8             : 
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : #include "includes.h"
      24             : #include "libcli/smb2/smb2.h"
      25             : #include "libcli/smb2/smb2_calls.h"
      26             : #include "../libcli/smb/smbXcli_base.h"
      27             : #include "torture/torture.h"
      28             : #include "torture/smb2/proto.h"
      29             : #include "../libcli/smb/smbXcli_base.h"
      30             : 
      31             : #define CHECK_VAL(v, correct) do { \
      32             :         if ((v) != (correct)) { \
      33             :                 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%llx - should be 0x%llx\n", \
      34             :                                 __location__, #v, (unsigned long long)v, (unsigned long long)correct); \
      35             :                 ret = false; \
      36             :         }} while (0)
      37             : 
      38             : #define CHECK_NOT_VAL(v, incorrect) do { \
      39             :         if ((v) == (incorrect)) { \
      40             :                 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%llx - should not be 0x%llx\n", \
      41             :                                 __location__, #v, (unsigned long long)v, (unsigned long long)incorrect); \
      42             :                 ret = false; \
      43             :         }} while (0)
      44             : 
      45             : #define CHECK_NOT_NULL(p) do { \
      46             :         if ((p) == NULL) { \
      47             :                 torture_result(tctx, TORTURE_FAIL, "(%s): %s is NULL but it should not be.\n", \
      48             :                                 __location__, #p); \
      49             :                 ret = false; \
      50             :         }} while (0)
      51             : 
      52             : #define CHECK_STATUS(status, correct) do { \
      53             :         if (!NT_STATUS_EQUAL(status, correct)) { \
      54             :                 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
      55             :                        nt_errstr(status), nt_errstr(correct)); \
      56             :                 ret = false; \
      57             :                 goto done; \
      58             :         }} while (0)
      59             : 
      60             : #define CHECK_CREATED(__io, __created, __attribute)                     \
      61             :         do {                                                            \
      62             :                 CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
      63             :                 CHECK_VAL((__io)->out.size, 0);                              \
      64             :                 CHECK_VAL((__io)->out.file_attr, (__attribute));     \
      65             :                 CHECK_VAL((__io)->out.reserved2, 0);                 \
      66             :         } while(0)
      67             : 
      68             : #define CHECK_CREATED_SIZE(__io, __created, __attribute, __alloc_size, __size)  \
      69             :         do {                                                                    \
      70             :                 CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
      71             :                 CHECK_VAL((__io)->out.alloc_size, (__alloc_size));           \
      72             :                 CHECK_VAL((__io)->out.size, (__size));                               \
      73             :                 CHECK_VAL((__io)->out.file_attr, (__attribute));             \
      74             :                 CHECK_VAL((__io)->out.reserved2, 0);                         \
      75             :         } while(0)
      76             : 
      77             : 
      78             : 
      79             : /**
      80             :  * basic durable_open test.
      81             :  * durable state should only be granted when requested
      82             :  * along with a batch oplock or a handle lease.
      83             :  *
      84             :  * This test tests durable open with all possible oplock types.
      85             :  */
      86             : 
      87             : struct durable_open_vs_oplock {
      88             :         const char *level;
      89             :         const char *share_mode;
      90             :         bool expected;
      91             : };
      92             : 
      93             : #define NUM_OPLOCK_TYPES 4
      94             : #define NUM_SHARE_MODES 8
      95             : #define NUM_OPLOCK_OPEN_TESTS ( NUM_OPLOCK_TYPES * NUM_SHARE_MODES )
      96             : static struct durable_open_vs_oplock durable_open_vs_oplock_table[NUM_OPLOCK_OPEN_TESTS] =
      97             : {
      98             :         { "", "", false },
      99             :         { "", "R", false },
     100             :         { "", "W", false },
     101             :         { "", "D", false },
     102             :         { "", "RD", false },
     103             :         { "", "RW", false },
     104             :         { "", "WD", false },
     105             :         { "", "RWD", false },
     106             : 
     107             :         { "s", "", false },
     108             :         { "s", "R", false },
     109             :         { "s", "W", false },
     110             :         { "s", "D", false },
     111             :         { "s", "RD", false },
     112             :         { "s", "RW", false },
     113             :         { "s", "WD", false },
     114             :         { "s", "RWD", false },
     115             : 
     116             :         { "x", "", false },
     117             :         { "x", "R", false },
     118             :         { "x", "W", false },
     119             :         { "x", "D", false },
     120             :         { "x", "RD", false },
     121             :         { "x", "RW", false },
     122             :         { "x", "WD", false },
     123             :         { "x", "RWD", false },
     124             : 
     125             :         { "b", "", true },
     126             :         { "b", "R", true },
     127             :         { "b", "W", true },
     128             :         { "b", "D", true },
     129             :         { "b", "RD", true },
     130             :         { "b", "RW", true },
     131             :         { "b", "WD", true },
     132             :         { "b", "RWD", true },
     133             : };
     134             : 
     135           0 : static bool test_one_durable_open_open_oplock(struct torture_context *tctx,
     136             :                                               struct smb2_tree *tree,
     137             :                                               const char *fname,
     138             :                                               struct durable_open_vs_oplock test)
     139             : {
     140             :         NTSTATUS status;
     141           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     142             :         struct smb2_handle _h;
     143           0 :         struct smb2_handle *h = NULL;
     144           0 :         bool ret = true;
     145             :         struct smb2_create io;
     146             : 
     147           0 :         smb2_util_unlink(tree, fname);
     148             : 
     149           0 :         smb2_oplock_create_share(&io, fname,
     150             :                                  smb2_util_share_access(test.share_mode),
     151           0 :                                  smb2_util_oplock_level(test.level));
     152           0 :         io.in.durable_open = true;
     153             : 
     154           0 :         status = smb2_create(tree, mem_ctx, &io);
     155           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     156           0 :         _h = io.out.file.handle;
     157           0 :         h = &_h;
     158           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     159           0 :         CHECK_VAL(io.out.durable_open, test.expected);
     160           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(test.level));
     161             : 
     162           0 : done:
     163           0 :         if (h != NULL) {
     164           0 :                 smb2_util_close(tree, *h);
     165             :         }
     166           0 :         smb2_util_unlink(tree, fname);
     167           0 :         talloc_free(mem_ctx);
     168             : 
     169           0 :         return ret;
     170             : }
     171             : 
     172           0 : static bool test_durable_open_open_oplock(struct torture_context *tctx,
     173             :                                           struct smb2_tree *tree)
     174             : {
     175           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     176             :         char fname[256];
     177           0 :         bool ret = true;
     178             :         int i;
     179             : 
     180             :         /* Choose a random name in case the state is left a little funky. */
     181           0 :         snprintf(fname, 256, "durable_open_open_oplock_%s.dat", generate_random_str(tctx, 8));
     182             : 
     183           0 :         smb2_util_unlink(tree, fname);
     184             : 
     185             :         /* test various oplock levels with durable open */
     186             : 
     187           0 :         for (i = 0; i < NUM_OPLOCK_OPEN_TESTS; i++) {
     188           0 :                 ret = test_one_durable_open_open_oplock(tctx,
     189             :                                                         tree,
     190             :                                                         fname,
     191             :                                                         durable_open_vs_oplock_table[i]);
     192           0 :                 if (ret == false) {
     193           0 :                         goto done;
     194             :                 }
     195             :         }
     196             : 
     197           0 : done:
     198           0 :         smb2_util_unlink(tree, fname);
     199           0 :         talloc_free(tree);
     200           0 :         talloc_free(mem_ctx);
     201             : 
     202           0 :         return ret;
     203             : }
     204             : 
     205             : /**
     206             :  * basic durable_open test.
     207             :  * durable state should only be granted when requested
     208             :  * along with a batch oplock or a handle lease.
     209             :  *
     210             :  * This test tests durable open with all valid lease types.
     211             :  */
     212             : 
     213             : struct durable_open_vs_lease {
     214             :         const char *type;
     215             :         const char *share_mode;
     216             :         bool expected;
     217             : };
     218             : 
     219             : #define NUM_LEASE_TYPES 5
     220             : #define NUM_LEASE_OPEN_TESTS ( NUM_LEASE_TYPES * NUM_SHARE_MODES )
     221             : static struct durable_open_vs_lease durable_open_vs_lease_table[NUM_LEASE_OPEN_TESTS] =
     222             : {
     223             :         { "", "", false },
     224             :         { "", "R", false },
     225             :         { "", "W", false },
     226             :         { "", "D", false },
     227             :         { "", "RW", false },
     228             :         { "", "RD", false },
     229             :         { "", "WD", false },
     230             :         { "", "RWD", false },
     231             : 
     232             :         { "R", "", false },
     233             :         { "R", "R", false },
     234             :         { "R", "W", false },
     235             :         { "R", "D", false },
     236             :         { "R", "RW", false },
     237             :         { "R", "RD", false },
     238             :         { "R", "DW", false },
     239             :         { "R", "RWD", false },
     240             : 
     241             :         { "RW", "", false },
     242             :         { "RW", "R", false },
     243             :         { "RW", "W", false },
     244             :         { "RW", "D", false },
     245             :         { "RW", "RW", false },
     246             :         { "RW", "RD", false },
     247             :         { "RW", "WD", false },
     248             :         { "RW", "RWD", false },
     249             : 
     250             :         { "RH", "", true },
     251             :         { "RH", "R", true },
     252             :         { "RH", "W", true },
     253             :         { "RH", "D", true },
     254             :         { "RH", "RW", true },
     255             :         { "RH", "RD", true },
     256             :         { "RH", "WD", true },
     257             :         { "RH", "RWD", true },
     258             : 
     259             :         { "RHW", "", true },
     260             :         { "RHW", "R", true },
     261             :         { "RHW", "W", true },
     262             :         { "RHW", "D", true },
     263             :         { "RHW", "RW", true },
     264             :         { "RHW", "RD", true },
     265             :         { "RHW", "WD", true },
     266             :         { "RHW", "RWD", true },
     267             : };
     268             : 
     269           0 : static bool test_one_durable_open_open_lease(struct torture_context *tctx,
     270             :                                              struct smb2_tree *tree,
     271             :                                              const char *fname,
     272             :                                              struct durable_open_vs_lease test)
     273             : {
     274             :         NTSTATUS status;
     275           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     276             :         struct smb2_handle _h;
     277           0 :         struct smb2_handle *h = NULL;
     278           0 :         bool ret = true;
     279             :         struct smb2_create io;
     280             :         struct smb2_lease ls;
     281             :         uint64_t lease;
     282             :         uint32_t caps;
     283             : 
     284           0 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
     285           0 :         if (!(caps & SMB2_CAP_LEASING)) {
     286           0 :                 torture_skip(tctx, "leases are not supported");
     287             :         }
     288             : 
     289           0 :         smb2_util_unlink(tree, fname);
     290             : 
     291           0 :         lease = random();
     292             : 
     293           0 :         smb2_lease_create_share(&io, &ls, false /* dir */, fname,
     294             :                                 smb2_util_share_access(test.share_mode),
     295             :                                 lease,
     296             :                                 smb2_util_lease_state(test.type));
     297           0 :         io.in.durable_open = true;
     298             : 
     299           0 :         status = smb2_create(tree, mem_ctx, &io);
     300           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     301           0 :         _h = io.out.file.handle;
     302           0 :         h = &_h;
     303           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     304           0 :         CHECK_VAL(io.out.durable_open, test.expected);
     305           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
     306           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease);
     307           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease);
     308           0 :         CHECK_VAL(io.out.lease_response.lease_state,
     309             :                   smb2_util_lease_state(test.type));
     310           0 : done:
     311           0 :         if (h != NULL) {
     312           0 :                 smb2_util_close(tree, *h);
     313             :         }
     314           0 :         smb2_util_unlink(tree, fname);
     315           0 :         talloc_free(mem_ctx);
     316             : 
     317           0 :         return ret;
     318             : }
     319             : 
     320           0 : static bool test_durable_open_open_lease(struct torture_context *tctx,
     321             :                                          struct smb2_tree *tree)
     322             : {
     323           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     324             :         char fname[256];
     325           0 :         bool ret = true;
     326             :         int i;
     327             :         uint32_t caps;
     328             : 
     329           0 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
     330           0 :         if (!(caps & SMB2_CAP_LEASING)) {
     331           0 :                 torture_skip(tctx, "leases are not supported");
     332             :         }
     333             : 
     334             :         /* Choose a random name in case the state is left a little funky. */
     335           0 :         snprintf(fname, 256, "durable_open_open_lease_%s.dat", generate_random_str(tctx, 8));
     336             : 
     337           0 :         smb2_util_unlink(tree, fname);
     338             : 
     339             : 
     340             :         /* test various oplock levels with durable open */
     341             : 
     342           0 :         for (i = 0; i < NUM_LEASE_OPEN_TESTS; i++) {
     343           0 :                 ret = test_one_durable_open_open_lease(tctx,
     344             :                                                        tree,
     345             :                                                        fname,
     346             :                                                        durable_open_vs_lease_table[i]);
     347           0 :                 if (ret == false) {
     348           0 :                         goto done;
     349             :                 }
     350             :         }
     351             : 
     352           0 : done:
     353           0 :         smb2_util_unlink(tree, fname);
     354           0 :         talloc_free(tree);
     355           0 :         talloc_free(mem_ctx);
     356             : 
     357           0 :         return ret;
     358             : }
     359             : 
     360             : /**
     361             :  * basic test for doing a durable open
     362             :  * and do a durable reopen on the same connection
     363             :  * while the first open is still active (fails)
     364             :  */
     365           0 : static bool test_durable_open_reopen1(struct torture_context *tctx,
     366             :                                       struct smb2_tree *tree)
     367             : {
     368             :         NTSTATUS status;
     369           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     370             :         char fname[256];
     371             :         struct smb2_handle _h;
     372           0 :         struct smb2_handle *h = NULL;
     373             :         struct smb2_create io1, io2;
     374           0 :         bool ret = true;
     375             : 
     376             :         /* Choose a random name in case the state is left a little funky. */
     377           0 :         snprintf(fname, 256, "durable_open_reopen1_%s.dat",
     378             :                  generate_random_str(tctx, 8));
     379             : 
     380           0 :         smb2_util_unlink(tree, fname);
     381             : 
     382           0 :         smb2_oplock_create_share(&io1, fname,
     383             :                                  smb2_util_share_access(""),
     384           0 :                                  smb2_util_oplock_level("b"));
     385           0 :         io1.in.durable_open = true;
     386             : 
     387           0 :         status = smb2_create(tree, mem_ctx, &io1);
     388           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     389           0 :         _h = io1.out.file.handle;
     390           0 :         h = &_h;
     391           0 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     392           0 :         CHECK_VAL(io1.out.durable_open, true);
     393           0 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
     394             : 
     395             :         /* try a durable reconnect while the file is still open */
     396           0 :         ZERO_STRUCT(io2);
     397           0 :         io2.in.fname = fname;
     398           0 :         io2.in.durable_handle = h;
     399             : 
     400           0 :         status = smb2_create(tree, mem_ctx, &io2);
     401           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     402             : 
     403           0 : done:
     404           0 :         if (h != NULL) {
     405           0 :                 smb2_util_close(tree, *h);
     406             :         }
     407             : 
     408           0 :         smb2_util_unlink(tree, fname);
     409             : 
     410           0 :         talloc_free(tree);
     411             : 
     412           0 :         talloc_free(mem_ctx);
     413             : 
     414           0 :         return ret;
     415             : }
     416             : 
     417             : /**
     418             :  * Basic test for doing a durable open
     419             :  * and do a session reconnect while the first
     420             :  * session is still active and the handle is
     421             :  * still open in the client.
     422             :  * This closes the original session and  a
     423             :  * durable reconnect on the new session succeeds.
     424             :  */
     425           0 : static bool test_durable_open_reopen1a(struct torture_context *tctx,
     426             :                                        struct smb2_tree *tree)
     427             : {
     428             :         NTSTATUS status;
     429           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     430             :         char fname[256];
     431             :         struct smb2_handle _h;
     432           0 :         struct smb2_handle *h = NULL;
     433             :         struct smb2_create io;
     434           0 :         bool ret = true;
     435           0 :         struct smb2_tree *tree2 = NULL;
     436           0 :         struct smb2_tree *tree3 = NULL;
     437             :         uint64_t previous_session_id;
     438             :         struct smbcli_options options;
     439             :         struct GUID orig_client_guid;
     440             : 
     441           0 :         options = tree->session->transport->options;
     442           0 :         orig_client_guid = options.client_guid;
     443             : 
     444             :         /* Choose a random name in case the state is left a little funky. */
     445           0 :         snprintf(fname, 256, "durable_open_reopen1a_%s.dat",
     446             :                  generate_random_str(tctx, 8));
     447             : 
     448           0 :         smb2_util_unlink(tree, fname);
     449             : 
     450           0 :         smb2_oplock_create_share(&io, fname,
     451             :                                  smb2_util_share_access(""),
     452           0 :                                  smb2_util_oplock_level("b"));
     453           0 :         io.in.durable_open = true;
     454             : 
     455           0 :         status = smb2_create(tree, mem_ctx, &io);
     456           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     457           0 :         _h = io.out.file.handle;
     458           0 :         h = &_h;
     459           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     460           0 :         CHECK_VAL(io.out.durable_open, true);
     461           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     462             : 
     463             :         /*
     464             :          * a session reconnect on a second tcp connection
     465             :          */
     466             : 
     467           0 :         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
     468             : 
     469             :         /* for oplocks, the client guid can be different: */
     470           0 :         options.client_guid = GUID_random();
     471             : 
     472           0 :         ret = torture_smb2_connection_ext(tctx, previous_session_id,
     473             :                                           &options, &tree2);
     474           0 :         torture_assert_goto(tctx, ret, ret, done, "could not reconnect");
     475             : 
     476             :         /*
     477             :          * check that this has deleted the old session
     478             :          */
     479             : 
     480           0 :         ZERO_STRUCT(io);
     481           0 :         io.in.fname = fname;
     482           0 :         io.in.durable_handle = h;
     483             : 
     484           0 :         status = smb2_create(tree, mem_ctx, &io);
     485           0 :         CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
     486             : 
     487           0 :         TALLOC_FREE(tree);
     488             : 
     489             :         /*
     490             :          * but a durable reconnect on the new session succeeds:
     491             :          */
     492             : 
     493           0 :         ZERO_STRUCT(io);
     494           0 :         io.in.fname = fname;
     495           0 :         io.in.durable_handle = h;
     496             : 
     497           0 :         status = smb2_create(tree2, mem_ctx, &io);
     498           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     499           0 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     500           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     501           0 :         _h = io.out.file.handle;
     502           0 :         h = &_h;
     503             : 
     504             :         /*
     505             :          * a session reconnect on a second tcp connection
     506             :          */
     507             : 
     508           0 :         previous_session_id = smb2cli_session_current_id(tree2->session->smbXcli);
     509             : 
     510             :         /* the original client_guid works just the same */
     511           0 :         options.client_guid = orig_client_guid;
     512             : 
     513           0 :         ret = torture_smb2_connection_ext(tctx, previous_session_id,
     514             :                                           &options, &tree3);
     515           0 :         torture_assert_goto(tctx, ret, ret, done, "could not reconnect");
     516             : 
     517             :         /*
     518             :          * check that this has deleted the old session
     519             :          */
     520             : 
     521           0 :         ZERO_STRUCT(io);
     522           0 :         io.in.fname = fname;
     523           0 :         io.in.durable_handle = h;
     524             : 
     525           0 :         status = smb2_create(tree2, mem_ctx, &io);
     526           0 :         CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
     527             : 
     528           0 :         TALLOC_FREE(tree2);
     529             : 
     530             :         /*
     531             :          * but a durable reconnect on the new session succeeds:
     532             :          */
     533             : 
     534           0 :         ZERO_STRUCT(io);
     535           0 :         io.in.fname = fname;
     536           0 :         io.in.durable_handle = h;
     537             : 
     538           0 :         status = smb2_create(tree3, mem_ctx, &io);
     539           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     540           0 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     541           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     542           0 :         _h = io.out.file.handle;
     543           0 :         h = &_h;
     544             : 
     545           0 : done:
     546           0 :         if (tree == NULL) {
     547           0 :                 tree = tree2;
     548             :         }
     549             : 
     550           0 :         if (tree == NULL) {
     551           0 :                 tree = tree3;
     552             :         }
     553             : 
     554           0 :         if (tree != NULL) {
     555           0 :                 if (h != NULL) {
     556           0 :                         smb2_util_close(tree, *h);
     557           0 :                         h = NULL;
     558             :                 }
     559           0 :                 smb2_util_unlink(tree, fname);
     560             : 
     561           0 :                 talloc_free(tree);
     562             :         }
     563             : 
     564           0 :         talloc_free(mem_ctx);
     565             : 
     566           0 :         return ret;
     567             : }
     568             : 
     569             : /**
     570             :  * lease variant of reopen1a
     571             :  *
     572             :  * Basic test for doing a durable open and doing a session
     573             :  * reconnect while the first session is still active and the
     574             :  * handle is still open in the client.
     575             :  * This closes the original session and  a durable reconnect on
     576             :  * the new session succeeds depending on the client guid:
     577             :  *
     578             :  * Durable reconnect on a session with a different client guid fails.
     579             :  * Durable reconnect on a session with the original client guid succeeds.
     580             :  */
     581           0 : bool test_durable_open_reopen1a_lease(struct torture_context *tctx,
     582             :                                       struct smb2_tree *tree)
     583             : {
     584             :         NTSTATUS status;
     585           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     586             :         char fname[256];
     587             :         struct smb2_handle _h;
     588           0 :         struct smb2_handle *h = NULL;
     589             :         struct smb2_create io;
     590             :         struct smb2_lease ls;
     591             :         uint64_t lease_key;
     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_lease_%s.dat",
     604             :                  generate_random_str(tctx, 8));
     605             : 
     606           0 :         smb2_util_unlink(tree, fname);
     607             : 
     608           0 :         lease_key = random();
     609           0 :         smb2_lease_create(&io, &ls, false /* dir */, fname,
     610             :                           lease_key, smb2_util_lease_state("RWH"));
     611           0 :         io.in.durable_open = true;
     612             : 
     613           0 :         status = smb2_create(tree, mem_ctx, &io);
     614           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     615           0 :         _h = io.out.file.handle;
     616           0 :         h = &_h;
     617           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     618           0 :         CHECK_VAL(io.out.durable_open, true);
     619           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
     620           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
     621           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
     622           0 :         CHECK_VAL(io.out.lease_response.lease_state,
     623             :                   smb2_util_lease_state("RWH"));
     624           0 :         CHECK_VAL(io.out.lease_response.lease_flags, 0);
     625           0 :         CHECK_VAL(io.out.lease_response.lease_duration, 0);
     626             : 
     627           0 :         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
     628             : 
     629             :         /*
     630             :          * a session reconnect on a second tcp connection
     631             :          * with a different client_guid does not allow
     632             :          * the durable reconnect.
     633             :          */
     634             : 
     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 = fname;
     647           0 :         io.in.durable_handle = h;
     648           0 :         io.in.lease_request = &ls;
     649           0 :         status = smb2_create(tree, mem_ctx, &io);
     650           0 :         CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
     651           0 :         TALLOC_FREE(tree);
     652             : 
     653             : 
     654             :         /*
     655             :          * but a durable reconnect on the new session with the wrong
     656             :          * client guid fails
     657             :          */
     658             : 
     659           0 :         ZERO_STRUCT(io);
     660           0 :         io.in.fname = fname;
     661           0 :         io.in.durable_handle = h;
     662           0 :         io.in.lease_request = &ls;
     663           0 :         status = smb2_create(tree2, mem_ctx, &io);
     664           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     665             : 
     666             :         /*
     667             :          * now a session reconnect on a second tcp connection
     668             :          * with original client_guid allows the durable reconnect.
     669             :          */
     670             : 
     671           0 :         options.client_guid = orig_client_guid;
     672             : 
     673           0 :         ret = torture_smb2_connection_ext(tctx, previous_session_id,
     674             :                                           &options, &tree3);
     675           0 :         torture_assert_goto(tctx, ret, ret, done, "couldn't reconnect");
     676             : 
     677             :         /*
     678             :          * check that this has deleted the old session
     679             :          * In this case, a durable reconnect attempt with the
     680             :          * correct client_guid yields a different error code.
     681             :          */
     682             : 
     683           0 :         ZERO_STRUCT(io);
     684           0 :         io.in.fname = fname;
     685           0 :         io.in.durable_handle = h;
     686           0 :         io.in.lease_request = &ls;
     687           0 :         status = smb2_create(tree2, mem_ctx, &io);
     688           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     689           0 :         TALLOC_FREE(tree2);
     690             : 
     691             :         /*
     692             :          * but a durable reconnect on the new session succeeds:
     693             :          */
     694             : 
     695           0 :         ZERO_STRUCT(io);
     696           0 :         io.in.fname = fname;
     697           0 :         io.in.durable_handle = h;
     698           0 :         io.in.lease_request = &ls;
     699           0 :         status = smb2_create(tree3, mem_ctx, &io);
     700           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     701           0 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     702           0 :         CHECK_VAL(io.out.durable_open, false); /* no dh response context... */
     703           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
     704           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
     705           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
     706           0 :         CHECK_VAL(io.out.lease_response.lease_state,
     707             :                   smb2_util_lease_state("RWH"));
     708           0 :         CHECK_VAL(io.out.lease_response.lease_flags, 0);
     709           0 :         CHECK_VAL(io.out.lease_response.lease_duration, 0);
     710           0 :         _h = io.out.file.handle;
     711           0 :         h = &_h;
     712             : 
     713           0 : done:
     714           0 :         if (tree == NULL) {
     715           0 :                 tree = tree2;
     716             :         }
     717             : 
     718           0 :         if (tree == NULL) {
     719           0 :                 tree = tree3;
     720             :         }
     721             : 
     722           0 :         if (tree != NULL) {
     723           0 :                 if (h != NULL) {
     724           0 :                         smb2_util_close(tree, *h);
     725             :                 }
     726             : 
     727           0 :                 smb2_util_unlink(tree, fname);
     728             : 
     729           0 :                 talloc_free(tree);
     730             :         }
     731             : 
     732           0 :         talloc_free(mem_ctx);
     733             : 
     734           0 :         return ret;
     735             : }
     736             : 
     737             : 
     738             : /**
     739             :  * basic test for doing a durable open
     740             :  * tcp disconnect, reconnect, do a durable reopen (succeeds)
     741             :  */
     742           0 : static bool test_durable_open_reopen2(struct torture_context *tctx,
     743             :                                       struct smb2_tree *tree)
     744             : {
     745             :         NTSTATUS status;
     746           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     747             :         char fname[256];
     748             :         struct smb2_handle _h;
     749           0 :         struct smb2_handle *h = NULL;
     750             :         struct smb2_create io;
     751           0 :         bool ret = true;
     752             : 
     753             :         /* Choose a random name in case the state is left a little funky. */
     754           0 :         snprintf(fname, 256, "durable_open_reopen2_%s.dat",
     755             :                  generate_random_str(tctx, 8));
     756             : 
     757           0 :         smb2_util_unlink(tree, fname);
     758             : 
     759           0 :         smb2_oplock_create_share(&io, fname,
     760             :                                  smb2_util_share_access(""),
     761           0 :                                  smb2_util_oplock_level("b"));
     762           0 :         io.in.durable_open = true;
     763             : 
     764           0 :         status = smb2_create(tree, mem_ctx, &io);
     765           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     766           0 :         _h = io.out.file.handle;
     767           0 :         h = &_h;
     768           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     769           0 :         CHECK_VAL(io.out.durable_open, true);
     770           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     771             : 
     772             :         /* disconnect, leaving the durable in place */
     773           0 :         TALLOC_FREE(tree);
     774             : 
     775           0 :         if (!torture_smb2_connection(tctx, &tree)) {
     776           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
     777           0 :                 ret = false;
     778           0 :                 goto done;
     779             :         }
     780             : 
     781           0 :         ZERO_STRUCT(io);
     782             :         /* the path name is ignored by the server */
     783           0 :         io.in.fname = fname;
     784           0 :         io.in.durable_handle = h; /* durable v1 reconnect request */
     785           0 :         h = NULL;
     786             : 
     787           0 :         status = smb2_create(tree, mem_ctx, &io);
     788           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     789           0 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     790           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     791           0 :         _h = io.out.file.handle;
     792           0 :         h = &_h;
     793             : 
     794             :         /* disconnect again, leaving the durable in place */
     795           0 :         TALLOC_FREE(tree);
     796             : 
     797           0 :         if (!torture_smb2_connection(tctx, &tree)) {
     798           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
     799           0 :                 ret = false;
     800           0 :                 goto done;
     801             :         }
     802             : 
     803             :         /*
     804             :          * show that the filename and many other fields
     805             :          * are ignored. only the reconnect request blob
     806             :          * is important.
     807             :          */
     808           0 :         ZERO_STRUCT(io);
     809             :         /* the path name is ignored by the server */
     810           0 :         io.in.security_flags = 0x78;
     811           0 :         io.in.oplock_level = 0x78;
     812           0 :         io.in.impersonation_level = 0x12345678;
     813           0 :         io.in.create_flags = 0x12345678;
     814           0 :         io.in.reserved = 0x12345678;
     815           0 :         io.in.desired_access = 0x12345678;
     816           0 :         io.in.file_attributes = 0x12345678;
     817           0 :         io.in.share_access = 0x12345678;
     818           0 :         io.in.create_disposition = 0x12345678;
     819           0 :         io.in.create_options = 0x12345678;
     820           0 :         io.in.fname = "__non_existing_fname__";
     821           0 :         io.in.durable_handle = h; /* durable v1 reconnect request */
     822           0 :         h = NULL;
     823             : 
     824           0 :         status = smb2_create(tree, mem_ctx, &io);
     825           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     826           0 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     827           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     828           0 :         _h = io.out.file.handle;
     829           0 :         h = &_h;
     830             : 
     831             :         /* disconnect, leaving the durable in place */
     832           0 :         TALLOC_FREE(tree);
     833             : 
     834           0 :         if (!torture_smb2_connection(tctx, &tree)) {
     835           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
     836           0 :                 ret = false;
     837           0 :                 goto done;
     838             :         }
     839             : 
     840             :         /*
     841             :          * show that an additionally specified durable v1 request
     842             :          * is ignored by the server.
     843             :          * See MS-SMB2, 3.3.5.9.7
     844             :          * Handling the SMB2_CREATE_DURABLE_HANDLE_RECONNECT Create Context
     845             :          */
     846           0 :         ZERO_STRUCT(io);
     847             :         /* the path name is ignored by the server */
     848           0 :         io.in.fname = fname;
     849           0 :         io.in.durable_handle = h;  /* durable v1 reconnect request */
     850           0 :         io.in.durable_open = true; /* durable v1 handle request */
     851           0 :         h = NULL;
     852             : 
     853           0 :         status = smb2_create(tree, mem_ctx, &io);
     854           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     855           0 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     856           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     857           0 :         _h = io.out.file.handle;
     858           0 :         h = &_h;
     859             : 
     860           0 : done:
     861           0 :         if (tree != NULL) {
     862           0 :                 if (h != NULL) {
     863           0 :                         smb2_util_close(tree, *h);
     864             :                 }
     865             : 
     866           0 :                 smb2_util_unlink(tree, fname);
     867             : 
     868           0 :                 talloc_free(tree);
     869             :         }
     870             : 
     871           0 :         talloc_free(mem_ctx);
     872             : 
     873           0 :         return ret;
     874             : }
     875             : 
     876             : /**
     877             :  * lease variant of reopen2
     878             :  * basic test for doing a durable open
     879             :  * tcp disconnect, reconnect, do a durable reopen (succeeds)
     880             :  */
     881           0 : static bool test_durable_open_reopen2_lease(struct torture_context *tctx,
     882             :                                             struct smb2_tree *tree)
     883             : {
     884             :         NTSTATUS status;
     885           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     886             :         char fname[256];
     887             :         struct smb2_handle _h;
     888           0 :         struct smb2_handle *h = NULL;
     889             :         struct smb2_create io;
     890             :         struct smb2_lease ls;
     891             :         uint64_t lease_key;
     892           0 :         bool ret = true;
     893             :         struct smbcli_options options;
     894             :         uint32_t caps;
     895             : 
     896           0 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
     897           0 :         if (!(caps & SMB2_CAP_LEASING)) {
     898           0 :                 torture_skip(tctx, "leases are not supported");
     899             :         }
     900             : 
     901           0 :         options = tree->session->transport->options;
     902             : 
     903             :         /* Choose a random name in case the state is left a little funky. */
     904           0 :         snprintf(fname, 256, "durable_open_reopen2_%s.dat",
     905             :                  generate_random_str(tctx, 8));
     906             : 
     907           0 :         smb2_util_unlink(tree, fname);
     908             : 
     909           0 :         lease_key = random();
     910           0 :         smb2_lease_create(&io, &ls, false /* dir */, fname, lease_key,
     911             :                           smb2_util_lease_state("RWH"));
     912           0 :         io.in.durable_open = true;
     913             : 
     914           0 :         status = smb2_create(tree, mem_ctx, &io);
     915           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     916           0 :         _h = io.out.file.handle;
     917           0 :         h = &_h;
     918           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     919             : 
     920           0 :         CHECK_VAL(io.out.durable_open, true);
     921           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
     922           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
     923           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
     924           0 :         CHECK_VAL(io.out.lease_response.lease_state,
     925             :                   smb2_util_lease_state("RWH"));
     926           0 :         CHECK_VAL(io.out.lease_response.lease_flags, 0);
     927           0 :         CHECK_VAL(io.out.lease_response.lease_duration, 0);
     928             : 
     929             :         /* disconnect, reconnect and then do durable reopen */
     930           0 :         TALLOC_FREE(tree);
     931             : 
     932           0 :         if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
     933           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
     934           0 :                 ret = false;
     935           0 :                 goto done;
     936             :         }
     937             : 
     938             : 
     939             :         /* a few failure tests: */
     940             : 
     941             :         /*
     942             :          * several attempts without lease attached:
     943             :          * all fail with NT_STATUS_OBJECT_NAME_NOT_FOUND
     944             :          * irrespective of file name provided
     945             :          */
     946             : 
     947           0 :         ZERO_STRUCT(io);
     948           0 :         io.in.fname = "";
     949           0 :         io.in.durable_handle = h;
     950           0 :         status = smb2_create(tree, mem_ctx, &io);
     951           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     952             : 
     953           0 :         ZERO_STRUCT(io);
     954           0 :         io.in.fname = "__non_existing_fname__";
     955           0 :         io.in.durable_handle = h;
     956           0 :         status = smb2_create(tree, mem_ctx, &io);
     957           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     958             : 
     959           0 :         ZERO_STRUCT(io);
     960           0 :         io.in.fname = fname;
     961           0 :         io.in.durable_handle = h;
     962           0 :         status = smb2_create(tree, mem_ctx, &io);
     963           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     964             : 
     965             :         /*
     966             :          * attempt with lease provided, but
     967             :          * with a changed lease key. => fails
     968             :          */
     969           0 :         ZERO_STRUCT(io);
     970           0 :         io.in.fname = fname;
     971           0 :         io.in.durable_open = false;
     972           0 :         io.in.durable_handle = h;
     973           0 :         io.in.lease_request = &ls;
     974           0 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
     975             :         /* a wrong lease key lets the request fail */
     976           0 :         ls.lease_key.data[0]++;
     977             : 
     978           0 :         status = smb2_create(tree, mem_ctx, &io);
     979           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     980             : 
     981             :         /* restore the correct lease key */
     982           0 :         ls.lease_key.data[0]--;
     983             : 
     984             :         /*
     985             :          * this last failing attempt is almost correct:
     986             :          * only problem is: we use the wrong filename...
     987             :          * Note that this gives INVALID_PARAMETER.
     988             :          * This is different from oplocks!
     989             :          */
     990           0 :         ZERO_STRUCT(io);
     991           0 :         io.in.fname = "__non_existing_fname__";
     992           0 :         io.in.durable_open = false;
     993           0 :         io.in.durable_handle = h;
     994           0 :         io.in.lease_request = &ls;
     995           0 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
     996             : 
     997           0 :         status = smb2_create(tree, mem_ctx, &io);
     998           0 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     999             : 
    1000             :         /*
    1001             :          * Now for a succeeding reconnect:
    1002             :          */
    1003             : 
    1004           0 :         ZERO_STRUCT(io);
    1005           0 :         io.in.fname = fname;
    1006           0 :         io.in.durable_open = false;
    1007           0 :         io.in.durable_handle = h;
    1008           0 :         io.in.lease_request = &ls;
    1009           0 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
    1010             : 
    1011             :         /* the requested lease state is irrelevant */
    1012           0 :         ls.lease_state = smb2_util_lease_state("");
    1013             : 
    1014           0 :         h = NULL;
    1015             : 
    1016           0 :         status = smb2_create(tree, mem_ctx, &io);
    1017           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1018             : 
    1019           0 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1020           0 :         CHECK_VAL(io.out.durable_open, false);
    1021           0 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    1022           0 :         CHECK_VAL(io.out.persistent_open, false);
    1023           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    1024           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
    1025           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
    1026           0 :         CHECK_VAL(io.out.lease_response.lease_state,
    1027             :                   smb2_util_lease_state("RWH"));
    1028           0 :         CHECK_VAL(io.out.lease_response.lease_flags, 0);
    1029           0 :         CHECK_VAL(io.out.lease_response.lease_duration, 0);
    1030           0 :         _h = io.out.file.handle;
    1031           0 :         h = &_h;
    1032             : 
    1033             :         /* disconnect one more time */
    1034           0 :         TALLOC_FREE(tree);
    1035             : 
    1036           0 :         if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
    1037           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
    1038           0 :                 ret = false;
    1039           0 :                 goto done;
    1040             :         }
    1041             : 
    1042             :         /*
    1043             :          * demonstrate that various parameters are ignored
    1044             :          * in the reconnect
    1045             :          */
    1046             : 
    1047           0 :         ZERO_STRUCT(io);
    1048             :         /*
    1049             :          * These are completely ignored by the server
    1050             :          */
    1051           0 :         io.in.security_flags = 0x78;
    1052           0 :         io.in.oplock_level = 0x78;
    1053           0 :         io.in.impersonation_level = 0x12345678;
    1054           0 :         io.in.create_flags = 0x12345678;
    1055           0 :         io.in.reserved = 0x12345678;
    1056           0 :         io.in.desired_access = 0x12345678;
    1057           0 :         io.in.file_attributes = 0x12345678;
    1058           0 :         io.in.share_access = 0x12345678;
    1059           0 :         io.in.create_disposition = 0x12345678;
    1060           0 :         io.in.create_options = 0x12345678;
    1061             : 
    1062             :         /*
    1063             :          * only these are checked:
    1064             :          * - io.in.fname
    1065             :          * - io.in.durable_handle,
    1066             :          * - io.in.lease_request->lease_key
    1067             :          */
    1068             : 
    1069           0 :         io.in.fname = fname;
    1070           0 :         io.in.durable_open_v2 = false;
    1071           0 :         io.in.durable_handle_v2 = h;
    1072           0 :         io.in.lease_request = &ls;
    1073             : 
    1074             :         /* the requested lease state is irrelevant */
    1075           0 :         ls.lease_state = smb2_util_lease_state("");
    1076             : 
    1077           0 :         h = NULL;
    1078             : 
    1079           0 :         status = smb2_create(tree, mem_ctx, &io);
    1080           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1081             : 
    1082           0 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1083           0 :         CHECK_VAL(io.out.durable_open, false);
    1084           0 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    1085           0 :         CHECK_VAL(io.out.persistent_open, false);
    1086           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    1087           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
    1088           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
    1089           0 :         CHECK_VAL(io.out.lease_response.lease_state,
    1090             :                   smb2_util_lease_state("RWH"));
    1091           0 :         CHECK_VAL(io.out.lease_response.lease_flags, 0);
    1092           0 :         CHECK_VAL(io.out.lease_response.lease_duration, 0);
    1093             : 
    1094           0 :         _h = io.out.file.handle;
    1095           0 :         h = &_h;
    1096             : 
    1097           0 : done:
    1098           0 :         if (tree != NULL) {
    1099           0 :                 if (h != NULL) {
    1100           0 :                         smb2_util_close(tree, *h);
    1101             :                 }
    1102             : 
    1103           0 :                 smb2_util_unlink(tree, fname);
    1104             : 
    1105           0 :                 talloc_free(tree);
    1106             :         }
    1107             : 
    1108           0 :         talloc_free(mem_ctx);
    1109             : 
    1110           0 :         return ret;
    1111             : }
    1112             : 
    1113             : /**
    1114             :  * lease v2 variant of reopen2
    1115             :  * basic test for doing a durable open
    1116             :  * tcp disconnect, reconnect, do a durable reopen (succeeds)
    1117             :  */
    1118           0 : static bool test_durable_open_reopen2_lease_v2(struct torture_context *tctx,
    1119             :                                                struct smb2_tree *tree)
    1120             : {
    1121             :         NTSTATUS status;
    1122           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1123             :         char fname[256];
    1124             :         struct smb2_handle _h;
    1125           0 :         struct smb2_handle *h = NULL;
    1126             :         struct smb2_create io;
    1127             :         struct smb2_lease ls;
    1128             :         uint64_t lease_key;
    1129           0 :         bool ret = true;
    1130             :         struct smbcli_options options;
    1131             :         uint32_t caps;
    1132             : 
    1133           0 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
    1134           0 :         if (!(caps & SMB2_CAP_LEASING)) {
    1135           0 :                 torture_skip(tctx, "leases are not supported");
    1136             :         }
    1137             : 
    1138           0 :         options = tree->session->transport->options;
    1139             : 
    1140             :         /* Choose a random name in case the state is left a little funky. */
    1141           0 :         snprintf(fname, 256, "durable_open_reopen2_%s.dat",
    1142             :                  generate_random_str(tctx, 8));
    1143             : 
    1144           0 :         smb2_util_unlink(tree, fname);
    1145             : 
    1146           0 :         lease_key = random();
    1147           0 :         smb2_lease_v2_create(&io, &ls, false /* dir */, fname,
    1148             :                              lease_key, 0, /* parent lease key */
    1149             :                              smb2_util_lease_state("RWH"), 0 /* lease epoch */);
    1150           0 :         io.in.durable_open = true;
    1151             : 
    1152           0 :         status = smb2_create(tree, mem_ctx, &io);
    1153           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1154           0 :         _h = io.out.file.handle;
    1155           0 :         h = &_h;
    1156           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1157             : 
    1158           0 :         CHECK_VAL(io.out.durable_open, true);
    1159           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    1160           0 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
    1161           0 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
    1162           0 :         CHECK_VAL(io.out.lease_response_v2.lease_state,
    1163             :                   smb2_util_lease_state("RWH"));
    1164           0 :         CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
    1165           0 :         CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
    1166             : 
    1167             :         /* disconnect, reconnect and then do durable reopen */
    1168           0 :         TALLOC_FREE(tree);
    1169             : 
    1170           0 :         if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
    1171           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
    1172           0 :                 ret = false;
    1173           0 :                 goto done;
    1174             :         }
    1175             : 
    1176             :         /* a few failure tests: */
    1177             : 
    1178             :         /*
    1179             :          * several attempts without lease attached:
    1180             :          * all fail with NT_STATUS_OBJECT_NAME_NOT_FOUND
    1181             :          * irrespective of file name provided
    1182             :          */
    1183             : 
    1184           0 :         ZERO_STRUCT(io);
    1185           0 :         io.in.fname = "";
    1186           0 :         io.in.durable_handle = h;
    1187           0 :         status = smb2_create(tree, mem_ctx, &io);
    1188           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1189             : 
    1190           0 :         ZERO_STRUCT(io);
    1191           0 :         io.in.fname = "__non_existing_fname__";
    1192           0 :         io.in.durable_handle = h;
    1193           0 :         status = smb2_create(tree, mem_ctx, &io);
    1194           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1195             : 
    1196           0 :         ZERO_STRUCT(io);
    1197           0 :         io.in.fname = fname;
    1198           0 :         io.in.durable_handle = h;
    1199           0 :         status = smb2_create(tree, mem_ctx, &io);
    1200           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1201             : 
    1202             :         /*
    1203             :          * attempt with lease provided, but
    1204             :          * with a changed lease key. => fails
    1205             :          */
    1206           0 :         ZERO_STRUCT(io);
    1207           0 :         io.in.fname = fname;
    1208           0 :         io.in.durable_open = false;
    1209           0 :         io.in.durable_handle = h;
    1210           0 :         io.in.lease_request_v2 = &ls;
    1211           0 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
    1212             :         /* a wrong lease key lets the request fail */
    1213           0 :         ls.lease_key.data[0]++;
    1214             : 
    1215           0 :         status = smb2_create(tree, mem_ctx, &io);
    1216           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1217             : 
    1218             :         /* restore the correct lease key */
    1219           0 :         ls.lease_key.data[0]--;
    1220             : 
    1221             :         /*
    1222             :          * this last failing attempt is almost correct:
    1223             :          * only problem is: we use the wrong filename...
    1224             :          * Note that this gives INVALID_PARAMETER.
    1225             :          * This is different from oplocks!
    1226             :          */
    1227           0 :         ZERO_STRUCT(io);
    1228           0 :         io.in.fname = "__non_existing_fname__";
    1229           0 :         io.in.durable_open = false;
    1230           0 :         io.in.durable_handle = h;
    1231           0 :         io.in.lease_request_v2 = &ls;
    1232           0 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
    1233             : 
    1234           0 :         status = smb2_create(tree, mem_ctx, &io);
    1235           0 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
    1236             : 
    1237             :         /*
    1238             :          * Now for a succeeding reconnect:
    1239             :          */
    1240             : 
    1241           0 :         ZERO_STRUCT(io);
    1242           0 :         io.in.fname = fname;
    1243           0 :         io.in.durable_open = false;
    1244           0 :         io.in.durable_handle = h;
    1245           0 :         io.in.lease_request_v2 = &ls;
    1246           0 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
    1247             : 
    1248             :         /* the requested lease state is irrelevant */
    1249           0 :         ls.lease_state = smb2_util_lease_state("");
    1250             : 
    1251           0 :         h = NULL;
    1252             : 
    1253           0 :         status = smb2_create(tree, mem_ctx, &io);
    1254           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1255             : 
    1256           0 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1257           0 :         CHECK_VAL(io.out.durable_open, false);
    1258           0 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    1259           0 :         CHECK_VAL(io.out.persistent_open, false);
    1260           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    1261           0 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
    1262           0 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
    1263           0 :         CHECK_VAL(io.out.lease_response_v2.lease_state,
    1264             :                   smb2_util_lease_state("RWH"));
    1265           0 :         CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
    1266           0 :         CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
    1267           0 :         _h = io.out.file.handle;
    1268           0 :         h = &_h;
    1269             : 
    1270             :         /* disconnect one more time */
    1271           0 :         TALLOC_FREE(tree);
    1272             : 
    1273           0 :         if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
    1274           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
    1275           0 :                 ret = false;
    1276           0 :                 goto done;
    1277             :         }
    1278             : 
    1279             :         /*
    1280             :          * demonstrate that various parameters are ignored
    1281             :          * in the reconnect
    1282             :          */
    1283             : 
    1284           0 :         ZERO_STRUCT(io);
    1285             :         /*
    1286             :          * These are completely ignored by the server
    1287             :          */
    1288           0 :         io.in.security_flags = 0x78;
    1289           0 :         io.in.oplock_level = 0x78;
    1290           0 :         io.in.impersonation_level = 0x12345678;
    1291           0 :         io.in.create_flags = 0x12345678;
    1292           0 :         io.in.reserved = 0x12345678;
    1293           0 :         io.in.desired_access = 0x12345678;
    1294           0 :         io.in.file_attributes = 0x12345678;
    1295           0 :         io.in.share_access = 0x12345678;
    1296           0 :         io.in.create_disposition = 0x12345678;
    1297           0 :         io.in.create_options = 0x12345678;
    1298             : 
    1299             :         /*
    1300             :          * only these are checked:
    1301             :          * - io.in.fname
    1302             :          * - io.in.durable_handle,
    1303             :          * - io.in.lease_request->lease_key
    1304             :          */
    1305             : 
    1306           0 :         io.in.fname = fname;
    1307           0 :         io.in.durable_open_v2 = false;
    1308           0 :         io.in.durable_handle_v2 = h;
    1309           0 :         io.in.lease_request_v2 = &ls;
    1310             : 
    1311             :         /* the requested lease state is irrelevant */
    1312           0 :         ls.lease_state = smb2_util_lease_state("");
    1313             : 
    1314           0 :         h = NULL;
    1315             : 
    1316           0 :         status = smb2_create(tree, mem_ctx, &io);
    1317           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1318             : 
    1319           0 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1320           0 :         CHECK_VAL(io.out.durable_open, false);
    1321           0 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    1322           0 :         CHECK_VAL(io.out.persistent_open, false);
    1323           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    1324           0 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
    1325           0 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
    1326           0 :         CHECK_VAL(io.out.lease_response_v2.lease_state,
    1327             :                   smb2_util_lease_state("RWH"));
    1328           0 :         CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
    1329           0 :         CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
    1330             : 
    1331           0 :         _h = io.out.file.handle;
    1332           0 :         h = &_h;
    1333             : 
    1334           0 : done:
    1335           0 :         if (tree != NULL) {
    1336           0 :                 if (h != NULL) {
    1337           0 :                         smb2_util_close(tree, *h);
    1338             :                 }
    1339             : 
    1340           0 :                 smb2_util_unlink(tree, fname);
    1341             : 
    1342           0 :                 talloc_free(tree);
    1343             :         }
    1344             : 
    1345           0 :         talloc_free(mem_ctx);
    1346             : 
    1347           0 :         return ret;
    1348             : }
    1349             : 
    1350             : /**
    1351             :  * basic test for doing a durable open
    1352             :  * tcp disconnect, reconnect with a session reconnect and
    1353             :  * do a durable reopen (succeeds)
    1354             :  */
    1355           0 : static bool test_durable_open_reopen2a(struct torture_context *tctx,
    1356             :                                        struct smb2_tree *tree)
    1357             : {
    1358             :         NTSTATUS status;
    1359           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1360             :         char fname[256];
    1361             :         struct smb2_handle _h;
    1362           0 :         struct smb2_handle *h = NULL;
    1363             :         struct smb2_create io1, io2;
    1364             :         uint64_t previous_session_id;
    1365           0 :         bool ret = true;
    1366             :         struct smbcli_options options;
    1367             : 
    1368           0 :         options = tree->session->transport->options;
    1369             : 
    1370             :         /* Choose a random name in case the state is left a little funky. */
    1371           0 :         snprintf(fname, 256, "durable_open_reopen2_%s.dat",
    1372             :                  generate_random_str(tctx, 8));
    1373             : 
    1374           0 :         smb2_util_unlink(tree, fname);
    1375             : 
    1376           0 :         smb2_oplock_create_share(&io1, fname,
    1377             :                                  smb2_util_share_access(""),
    1378           0 :                                  smb2_util_oplock_level("b"));
    1379           0 :         io1.in.durable_open = true;
    1380             : 
    1381           0 :         status = smb2_create(tree, mem_ctx, &io1);
    1382           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1383           0 :         _h = io1.out.file.handle;
    1384           0 :         h = &_h;
    1385           0 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1386           0 :         CHECK_VAL(io1.out.durable_open, true);
    1387           0 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
    1388             : 
    1389             :         /* disconnect, reconnect and then do durable reopen */
    1390           0 :         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
    1391           0 :         talloc_free(tree);
    1392           0 :         tree = NULL;
    1393             : 
    1394           0 :         if (!torture_smb2_connection_ext(tctx, previous_session_id,
    1395             :                                          &options, &tree))
    1396             :         {
    1397           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
    1398           0 :                 ret = false;
    1399           0 :                 goto done;
    1400             :         }
    1401             : 
    1402           0 :         ZERO_STRUCT(io2);
    1403           0 :         io2.in.fname = fname;
    1404           0 :         io2.in.durable_handle = h;
    1405           0 :         h = NULL;
    1406             : 
    1407           0 :         status = smb2_create(tree, mem_ctx, &io2);
    1408           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1409           0 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1410           0 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
    1411           0 :         _h = io2.out.file.handle;
    1412           0 :         h = &_h;
    1413             : 
    1414           0 : done:
    1415           0 :         if (tree != NULL) {
    1416           0 :                 if (h != NULL) {
    1417           0 :                         smb2_util_close(tree, *h);
    1418             :                 }
    1419             : 
    1420           0 :                 smb2_util_unlink(tree, fname);
    1421             : 
    1422           0 :                 talloc_free(tree);
    1423             :         }
    1424             : 
    1425           0 :         talloc_free(mem_ctx);
    1426             : 
    1427           0 :         return ret;
    1428             : }
    1429             : 
    1430             : 
    1431             : /**
    1432             :  * basic test for doing a durable open:
    1433             :  * tdis, new tcon, try durable reopen (fails)
    1434             :  */
    1435           0 : static bool test_durable_open_reopen3(struct torture_context *tctx,
    1436             :                                       struct smb2_tree *tree)
    1437             : {
    1438             :         NTSTATUS status;
    1439           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1440             :         char fname[256];
    1441             :         struct smb2_handle _h;
    1442           0 :         struct smb2_handle *h = NULL;
    1443             :         struct smb2_create io1, io2;
    1444           0 :         bool ret = true;
    1445             :         struct smb2_tree *tree2;
    1446             : 
    1447             :         /* Choose a random name in case the state is left a little funky. */
    1448           0 :         snprintf(fname, 256, "durable_open_reopen3_%s.dat",
    1449             :                  generate_random_str(tctx, 8));
    1450             : 
    1451           0 :         smb2_util_unlink(tree, fname);
    1452             : 
    1453           0 :         smb2_oplock_create_share(&io1, fname,
    1454             :                                  smb2_util_share_access(""),
    1455           0 :                                  smb2_util_oplock_level("b"));
    1456           0 :         io1.in.durable_open = true;
    1457             : 
    1458           0 :         status = smb2_create(tree, mem_ctx, &io1);
    1459           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1460           0 :         _h = io1.out.file.handle;
    1461           0 :         h = &_h;
    1462           0 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1463           0 :         CHECK_VAL(io1.out.durable_open, true);
    1464           0 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
    1465             : 
    1466             :         /* disconnect, reconnect and then do durable reopen */
    1467           0 :         status = smb2_tdis(tree);
    1468           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1469             : 
    1470           0 :         if (!torture_smb2_tree_connect(tctx, tree->session, mem_ctx, &tree2)) {
    1471           0 :                 torture_warning(tctx, "couldn't reconnect to share, bailing\n");
    1472           0 :                 ret = false;
    1473           0 :                 goto done;
    1474             :         }
    1475             : 
    1476             : 
    1477           0 :         ZERO_STRUCT(io2);
    1478           0 :         io2.in.fname = fname;
    1479           0 :         io2.in.durable_handle = h;
    1480             : 
    1481           0 :         status = smb2_create(tree2, mem_ctx, &io2);
    1482           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1483             : 
    1484           0 : done:
    1485           0 :         if (tree != NULL) {
    1486           0 :                 if (h != NULL) {
    1487           0 :                         smb2_util_close(tree, *h);
    1488             :                 }
    1489             : 
    1490           0 :                 smb2_util_unlink(tree2, fname);
    1491             : 
    1492           0 :                 talloc_free(tree);
    1493             :         }
    1494             : 
    1495           0 :         talloc_free(mem_ctx);
    1496             : 
    1497           0 :         return ret;
    1498             : }
    1499             : 
    1500             : /**
    1501             :  * basic test for doing a durable open:
    1502             :  * logoff, create a new session, do a durable reopen (succeeds)
    1503             :  */
    1504           0 : static bool test_durable_open_reopen4(struct torture_context *tctx,
    1505             :                                       struct smb2_tree *tree)
    1506             : {
    1507             :         NTSTATUS status;
    1508           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1509             :         char fname[256];
    1510             :         struct smb2_handle _h;
    1511           0 :         struct smb2_handle *h = NULL;
    1512             :         struct smb2_create io1, io2;
    1513           0 :         bool ret = true;
    1514             :         struct smb2_transport *transport;
    1515             :         struct smb2_session *session2;
    1516             :         struct smb2_tree *tree2;
    1517             : 
    1518             :         /* Choose a random name in case the state is left a little funky. */
    1519           0 :         snprintf(fname, 256, "durable_open_reopen4_%s.dat",
    1520             :                  generate_random_str(tctx, 8));
    1521             : 
    1522           0 :         smb2_util_unlink(tree, fname);
    1523             : 
    1524           0 :         smb2_oplock_create_share(&io1, fname,
    1525             :                                  smb2_util_share_access(""),
    1526           0 :                                  smb2_util_oplock_level("b"));
    1527           0 :         io1.in.durable_open = true;
    1528             : 
    1529           0 :         status = smb2_create(tree, mem_ctx, &io1);
    1530           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1531           0 :         _h = io1.out.file.handle;
    1532           0 :         h = &_h;
    1533           0 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1534           0 :         CHECK_VAL(io1.out.durable_open, true);
    1535           0 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
    1536             : 
    1537             :         /*
    1538             :          * do a session logoff, establish a new session and tree
    1539             :          * connect on the same transport, and try a durable reopen
    1540             :          */
    1541           0 :         transport = tree->session->transport;
    1542           0 :         status = smb2_logoff(tree->session);
    1543           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1544             : 
    1545           0 :         if (!torture_smb2_session_setup(tctx, transport,
    1546             :                                         0, /* previous_session_id */
    1547             :                                         mem_ctx, &session2))
    1548             :         {
    1549           0 :                 torture_warning(tctx, "session setup failed.\n");
    1550           0 :                 ret = false;
    1551           0 :                 goto done;
    1552             :         }
    1553             : 
    1554             :         /*
    1555             :          * the session setup has talloc-stolen the transport,
    1556             :          * so we can safely free the old tree+session for clarity
    1557             :          */
    1558           0 :         TALLOC_FREE(tree);
    1559             : 
    1560           0 :         if (!torture_smb2_tree_connect(tctx, session2, mem_ctx, &tree2)) {
    1561           0 :                 torture_warning(tctx, "tree connect failed.\n");
    1562           0 :                 ret = false;
    1563           0 :                 goto done;
    1564             :         }
    1565             : 
    1566           0 :         ZERO_STRUCT(io2);
    1567           0 :         io2.in.fname = fname;
    1568           0 :         io2.in.durable_handle = h;
    1569           0 :         h = NULL;
    1570             : 
    1571           0 :         status = smb2_create(tree2, mem_ctx, &io2);
    1572           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1573             : 
    1574           0 :         _h = io2.out.file.handle;
    1575           0 :         h = &_h;
    1576           0 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1577           0 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
    1578             : 
    1579           0 : done:
    1580           0 :         if (tree != NULL) {
    1581           0 :                 if (h != NULL) {
    1582           0 :                         smb2_util_close(tree2, *h);
    1583             :                 }
    1584             : 
    1585           0 :                 smb2_util_unlink(tree2, fname);
    1586             : 
    1587           0 :                 talloc_free(tree);
    1588             :         }
    1589             : 
    1590           0 :         talloc_free(mem_ctx);
    1591             : 
    1592           0 :         return ret;
    1593             : }
    1594             : 
    1595           0 : static bool test_durable_open_delete_on_close1(struct torture_context *tctx,
    1596             :                                                struct smb2_tree *tree)
    1597             : {
    1598             :         NTSTATUS status;
    1599           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1600             :         char fname[256];
    1601             :         struct smb2_handle _h;
    1602           0 :         struct smb2_handle *h = NULL;
    1603             :         struct smb2_create io1, io2;
    1604           0 :         bool ret = true;
    1605           0 :         uint8_t b = 0;
    1606             : 
    1607             :         /* Choose a random name in case the state is left a little funky. */
    1608           0 :         snprintf(fname, 256, "durable_open_delete_on_close1_%s.dat",
    1609             :                  generate_random_str(tctx, 8));
    1610             : 
    1611           0 :         smb2_util_unlink(tree, fname);
    1612             : 
    1613           0 :         smb2_oplock_create_share(&io1, fname,
    1614             :                                  smb2_util_share_access(""),
    1615           0 :                                  smb2_util_oplock_level("b"));
    1616           0 :         io1.in.durable_open = true;
    1617           0 :         io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
    1618             : 
    1619           0 :         status = smb2_create(tree, mem_ctx, &io1);
    1620           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1621           0 :         _h = io1.out.file.handle;
    1622           0 :         h = &_h;
    1623           0 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1624           0 :         CHECK_VAL(io1.out.durable_open, true);
    1625           0 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
    1626             : 
    1627           0 :         status = smb2_util_write(tree, *h, &b, 0, 1);
    1628           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1629             : 
    1630             :         /* disconnect, leaving the durable handle in place */
    1631           0 :         TALLOC_FREE(tree);
    1632             : 
    1633           0 :         if (!torture_smb2_connection(tctx, &tree)) {
    1634           0 :                 torture_warning(tctx, "could not reconnect, bailing\n");
    1635           0 :                 ret = false;
    1636           0 :                 goto done;
    1637             :         }
    1638             : 
    1639             :         /*
    1640             :          * Open the file on the new connection again
    1641             :          * and check that it has been newly created,
    1642             :          * i.e. delete on close was effective on the disconnected handle.
    1643             :          * Also check that the file is really empty,
    1644             :          * the previously written byte gone.
    1645             :          */
    1646           0 :         smb2_oplock_create_share(&io2, fname,
    1647             :                                  smb2_util_share_access(""),
    1648           0 :                                  smb2_util_oplock_level("b"));
    1649           0 :         io2.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
    1650             : 
    1651           0 :         status = smb2_create(tree, mem_ctx, &io2);
    1652           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1653           0 :         _h = io2.out.file.handle;
    1654           0 :         h = &_h;
    1655           0 :         CHECK_CREATED_SIZE(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE, 0, 0);
    1656           0 :         CHECK_VAL(io2.out.durable_open, false);
    1657           0 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
    1658             : 
    1659           0 : done:
    1660           0 :         if (tree != NULL) {
    1661           0 :                 if (h != NULL) {
    1662           0 :                         smb2_util_close(tree, *h);
    1663             :                 }
    1664             : 
    1665           0 :                 smb2_util_unlink(tree, fname);
    1666             : 
    1667           0 :                 talloc_free(tree);
    1668             :         }
    1669             : 
    1670           0 :         talloc_free(mem_ctx);
    1671             : 
    1672           0 :         return ret;
    1673             : }
    1674             : 
    1675             : 
    1676           0 : static bool test_durable_open_delete_on_close2(struct torture_context *tctx,
    1677             :                                                struct smb2_tree *tree)
    1678             : {
    1679             :         NTSTATUS status;
    1680           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1681             :         char fname[256];
    1682             :         struct smb2_handle _h;
    1683           0 :         struct smb2_handle *h = NULL;
    1684             :         struct smb2_create io;
    1685           0 :         bool ret = true;
    1686           0 :         uint8_t b = 0;
    1687             :         uint64_t previous_session_id;
    1688             :         uint64_t alloc_size_step;
    1689             :         struct smbcli_options options;
    1690             : 
    1691           0 :         options = tree->session->transport->options;
    1692             : 
    1693             :         /* Choose a random name in case the state is left a little funky. */
    1694           0 :         snprintf(fname, 256, "durable_open_delete_on_close2_%s.dat",
    1695             :                  generate_random_str(tctx, 8));
    1696             : 
    1697           0 :         smb2_util_unlink(tree, fname);
    1698             : 
    1699           0 :         smb2_oplock_create_share(&io, fname,
    1700             :                                  smb2_util_share_access(""),
    1701           0 :                                  smb2_util_oplock_level("b"));
    1702           0 :         io.in.durable_open = true;
    1703           0 :         io.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
    1704             : 
    1705           0 :         status = smb2_create(tree, mem_ctx, &io);
    1706           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1707           0 :         _h = io.out.file.handle;
    1708           0 :         h = &_h;
    1709           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1710           0 :         CHECK_VAL(io.out.durable_open, true);
    1711           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    1712             : 
    1713           0 :         status = smb2_util_write(tree, *h, &b, 0, 1);
    1714           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1715             : 
    1716           0 :         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
    1717             : 
    1718             :         /* disconnect, leaving the durable handle in place */
    1719           0 :         TALLOC_FREE(tree);
    1720             : 
    1721           0 :         if (!torture_smb2_connection_ext(tctx, previous_session_id,
    1722             :                                          &options, &tree))
    1723             :         {
    1724           0 :                 torture_warning(tctx, "could not reconnect, bailing\n");
    1725           0 :                 ret = false;
    1726           0 :                 goto done;
    1727             :         }
    1728             : 
    1729           0 :         ZERO_STRUCT(io);
    1730           0 :         io.in.fname = fname;
    1731           0 :         io.in.durable_handle = h;
    1732             : 
    1733           0 :         status = smb2_create(tree, mem_ctx, &io);
    1734           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1735           0 :         _h = io.out.file.handle;
    1736           0 :         h = &_h;
    1737           0 :         alloc_size_step = io.out.alloc_size;
    1738           0 :         CHECK_CREATED_SIZE(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE, alloc_size_step, 1);
    1739           0 :         CHECK_VAL(io.out.durable_open, false);
    1740           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    1741             : 
    1742             :         /* close the file, thereby deleting it */
    1743           0 :         smb2_util_close(tree, *h);
    1744           0 :         status = smb2_logoff(tree->session);
    1745           0 :         TALLOC_FREE(tree);
    1746             : 
    1747           0 :         if (!torture_smb2_connection(tctx, &tree)) {
    1748           0 :                 torture_warning(tctx, "could not reconnect, bailing\n");
    1749           0 :                 ret = false;
    1750           0 :                 goto done;
    1751             :         }
    1752             : 
    1753             :         /*
    1754             :          * Open the file on the new connection again
    1755             :          * and check that it has been newly created,
    1756             :          * i.e. delete on close was effective on the reconnected handle.
    1757             :          * Also check that the file is really empty,
    1758             :          * the previously written byte gone.
    1759             :          */
    1760           0 :         smb2_oplock_create_share(&io, fname,
    1761             :                                  smb2_util_share_access(""),
    1762           0 :                                  smb2_util_oplock_level("b"));
    1763           0 :         io.in.durable_open = true;
    1764           0 :         io.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
    1765             : 
    1766           0 :         status = smb2_create(tree, mem_ctx, &io);
    1767           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1768           0 :         _h = io.out.file.handle;
    1769           0 :         h = &_h;
    1770           0 :         CHECK_CREATED_SIZE(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE, 0, 0);
    1771           0 :         CHECK_VAL(io.out.durable_open, true);
    1772           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    1773             : 
    1774           0 : done:
    1775           0 :         if (tree != NULL) {
    1776           0 :                 if (h != NULL) {
    1777           0 :                         smb2_util_close(tree, *h);
    1778             :                 }
    1779             : 
    1780           0 :                 smb2_util_unlink(tree, fname);
    1781             : 
    1782           0 :                 talloc_free(tree);
    1783             :         }
    1784             : 
    1785           0 :         talloc_free(mem_ctx);
    1786             : 
    1787           0 :         return ret;
    1788             : }
    1789             : 
    1790             : /*
    1791             :    basic testing of SMB2 durable opens
    1792             :    regarding the position information on the handle
    1793             : */
    1794           0 : static bool test_durable_open_file_position(struct torture_context *tctx,
    1795             :                                             struct smb2_tree *tree)
    1796             : {
    1797           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1798             :         struct smb2_handle h;
    1799             :         struct smb2_create io;
    1800             :         NTSTATUS status;
    1801           0 :         const char *fname = "durable_open_position.dat";
    1802             :         union smb_fileinfo qfinfo;
    1803             :         union smb_setfileinfo sfinfo;
    1804           0 :         bool ret = true;
    1805             :         uint64_t pos;
    1806             :         uint64_t previous_session_id;
    1807             :         struct smbcli_options options;
    1808             : 
    1809           0 :         options = tree->session->transport->options;
    1810             : 
    1811           0 :         smb2_util_unlink(tree, fname);
    1812             : 
    1813           0 :         smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_BATCH);
    1814           0 :         io.in.durable_open = true;
    1815             : 
    1816           0 :         status = smb2_create(tree, mem_ctx, &io);
    1817           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1818           0 :         h = io.out.file.handle;
    1819           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1820           0 :         CHECK_VAL(io.out.durable_open, true);
    1821           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
    1822             : 
    1823             :         /* TODO: check extra blob content */
    1824             : 
    1825           0 :         ZERO_STRUCT(qfinfo);
    1826           0 :         qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
    1827           0 :         qfinfo.generic.in.file.handle = h;
    1828           0 :         status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
    1829           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1830           0 :         CHECK_VAL(qfinfo.position_information.out.position, 0);
    1831           0 :         pos = qfinfo.position_information.out.position;
    1832           0 :         torture_comment(tctx, "position: %llu\n",
    1833             :                         (unsigned long long)pos);
    1834             : 
    1835           0 :         ZERO_STRUCT(sfinfo);
    1836           0 :         sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
    1837           0 :         sfinfo.generic.in.file.handle = h;
    1838           0 :         sfinfo.position_information.in.position = 0x1000;
    1839           0 :         status = smb2_setinfo_file(tree, &sfinfo);
    1840           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1841             : 
    1842           0 :         ZERO_STRUCT(qfinfo);
    1843           0 :         qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
    1844           0 :         qfinfo.generic.in.file.handle = h;
    1845           0 :         status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
    1846           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1847           0 :         CHECK_VAL(qfinfo.position_information.out.position, 0x1000);
    1848           0 :         pos = qfinfo.position_information.out.position;
    1849           0 :         torture_comment(tctx, "position: %llu\n",
    1850             :                         (unsigned long long)pos);
    1851             : 
    1852           0 :         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
    1853             : 
    1854             :         /* tcp disconnect */
    1855           0 :         talloc_free(tree);
    1856           0 :         tree = NULL;
    1857             : 
    1858             :         /* do a session reconnect */
    1859           0 :         if (!torture_smb2_connection_ext(tctx, previous_session_id,
    1860             :                                          &options, &tree))
    1861             :         {
    1862           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
    1863           0 :                 ret = false;
    1864           0 :                 goto done;
    1865             :         }
    1866             : 
    1867           0 :         ZERO_STRUCT(qfinfo);
    1868           0 :         qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
    1869           0 :         qfinfo.generic.in.file.handle = h;
    1870           0 :         status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
    1871           0 :         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
    1872             : 
    1873           0 :         ZERO_STRUCT(io);
    1874           0 :         io.in.fname = fname;
    1875           0 :         io.in.durable_handle = &h;
    1876             : 
    1877           0 :         status = smb2_create(tree, mem_ctx, &io);
    1878           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1879           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
    1880           0 :         CHECK_VAL(io.out.reserved, 0x00);
    1881           0 :         CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
    1882           0 :         CHECK_VAL(io.out.alloc_size, 0);
    1883           0 :         CHECK_VAL(io.out.size, 0);
    1884           0 :         CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
    1885           0 :         CHECK_VAL(io.out.reserved2, 0);
    1886             : 
    1887           0 :         h = io.out.file.handle;
    1888             : 
    1889           0 :         ZERO_STRUCT(qfinfo);
    1890           0 :         qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
    1891           0 :         qfinfo.generic.in.file.handle = h;
    1892           0 :         status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
    1893           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1894           0 :         CHECK_VAL(qfinfo.position_information.out.position, 0x1000);
    1895           0 :         pos = qfinfo.position_information.out.position;
    1896           0 :         torture_comment(tctx, "position: %llu\n",
    1897             :                         (unsigned long long)pos);
    1898             : 
    1899           0 :         smb2_util_close(tree, h);
    1900             : 
    1901           0 :         talloc_free(mem_ctx);
    1902             : 
    1903           0 :         smb2_util_unlink(tree, fname);
    1904             : 
    1905           0 : done:
    1906           0 :         talloc_free(tree);
    1907             : 
    1908           0 :         return ret;
    1909             : }
    1910             : 
    1911             : /*
    1912             :   Open, disconnect, oplock break, reconnect.
    1913             : */
    1914           0 : static bool test_durable_open_oplock(struct torture_context *tctx,
    1915             :                                      struct smb2_tree *tree1,
    1916             :                                      struct smb2_tree *tree2)
    1917             : {
    1918           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1919             :         struct smb2_create io1, io2;
    1920           0 :         struct smb2_handle h1 = {{0}};
    1921           0 :         struct smb2_handle h2 = {{0}};
    1922             :         NTSTATUS status;
    1923             :         char fname[256];
    1924           0 :         bool ret = true;
    1925             : 
    1926             :         /* Choose a random name in case the state is left a little funky. */
    1927           0 :         snprintf(fname, 256, "durable_open_oplock_%s.dat", generate_random_str(tctx, 8));
    1928             : 
    1929             :         /* Clean slate */
    1930           0 :         smb2_util_unlink(tree1, fname);
    1931             : 
    1932             :         /* Create with batch oplock */
    1933           0 :         smb2_oplock_create(&io1, fname, SMB2_OPLOCK_LEVEL_BATCH);
    1934           0 :         io1.in.durable_open = true;
    1935             : 
    1936           0 :         io2 = io1;
    1937           0 :         io2.in.create_disposition = NTCREATEX_DISP_OPEN;
    1938             : 
    1939           0 :         status = smb2_create(tree1, mem_ctx, &io1);
    1940           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1941           0 :         h1 = io1.out.file.handle;
    1942           0 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1943           0 :         CHECK_VAL(io1.out.durable_open, true);
    1944           0 :         CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
    1945             : 
    1946             :         /* Disconnect after getting the batch */
    1947           0 :         talloc_free(tree1);
    1948           0 :         tree1 = NULL;
    1949             : 
    1950             :         /*
    1951             :          * Windows7 (build 7000) will break a batch oplock immediately if the
    1952             :          * original client is gone. (ZML: This seems like a bug. It should give
    1953             :          * some time for the client to reconnect!)
    1954             :          */
    1955           0 :         status = smb2_create(tree2, mem_ctx, &io2);
    1956           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1957           0 :         h2 = io2.out.file.handle;
    1958           0 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1959           0 :         CHECK_VAL(io2.out.durable_open, true);
    1960           0 :         CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
    1961             : 
    1962             :         /* What if tree1 tries to come back and reclaim? */
    1963           0 :         if (!torture_smb2_connection(tctx, &tree1)) {
    1964           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
    1965           0 :                 ret = false;
    1966           0 :                 goto done;
    1967             :         }
    1968             : 
    1969           0 :         ZERO_STRUCT(io1);
    1970           0 :         io1.in.fname = fname;
    1971           0 :         io1.in.durable_handle = &h1;
    1972             : 
    1973           0 :         status = smb2_create(tree1, mem_ctx, &io1);
    1974           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1975             : 
    1976           0 :  done:
    1977           0 :         smb2_util_close(tree2, h2);
    1978           0 :         smb2_util_unlink(tree2, fname);
    1979             : 
    1980           0 :         talloc_free(tree1);
    1981           0 :         talloc_free(tree2);
    1982             : 
    1983           0 :         return ret;
    1984             : }
    1985             : 
    1986             : /*
    1987             :   Open, disconnect, lease break, reconnect.
    1988             : */
    1989           0 : static bool test_durable_open_lease(struct torture_context *tctx,
    1990             :                                     struct smb2_tree *tree1,
    1991             :                                     struct smb2_tree *tree2)
    1992             : {
    1993           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1994             :         struct smb2_create io1, io2;
    1995             :         struct smb2_lease ls1, ls2;
    1996           0 :         struct smb2_handle h1 = {{0}};
    1997           0 :         struct smb2_handle h2 = {{0}};
    1998             :         NTSTATUS status;
    1999             :         char fname[256];
    2000           0 :         bool ret = true;
    2001             :         uint64_t lease1, lease2;
    2002             :         uint32_t caps;
    2003             : 
    2004           0 :         caps = smb2cli_conn_server_capabilities(tree1->session->transport->conn);
    2005           0 :         if (!(caps & SMB2_CAP_LEASING)) {
    2006           0 :                 torture_skip(tctx, "leases are not supported");
    2007             :         }
    2008             : 
    2009             :         /*
    2010             :          * Choose a random name and random lease in case the state is left a
    2011             :          * little funky.
    2012             :          */
    2013           0 :         lease1 = random();
    2014           0 :         lease2 = random();
    2015           0 :         snprintf(fname, 256, "durable_open_lease_%s.dat", generate_random_str(tctx, 8));
    2016             : 
    2017             :         /* Clean slate */
    2018           0 :         smb2_util_unlink(tree1, fname);
    2019             : 
    2020             :         /* Create with lease */
    2021           0 :         smb2_lease_create(&io1, &ls1, false /* dir */, fname,
    2022             :                           lease1, smb2_util_lease_state("RHW"));
    2023           0 :         io1.in.durable_open = true;
    2024             : 
    2025           0 :         smb2_lease_create(&io2, &ls2, false /* dir */, fname,
    2026             :                           lease2, smb2_util_lease_state("RHW"));
    2027           0 :         io2.in.durable_open = true;
    2028           0 :         io2.in.create_disposition = NTCREATEX_DISP_OPEN;
    2029             : 
    2030           0 :         status = smb2_create(tree1, mem_ctx, &io1);
    2031           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2032           0 :         h1 = io1.out.file.handle;
    2033           0 :         CHECK_VAL(io1.out.durable_open, true);
    2034           0 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    2035             : 
    2036           0 :         CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    2037           0 :         CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease1);
    2038           0 :         CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease1);
    2039           0 :         CHECK_VAL(io1.out.lease_response.lease_state,
    2040             :             SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
    2041             : 
    2042             :         /* Disconnect after getting the lease */
    2043           0 :         talloc_free(tree1);
    2044           0 :         tree1 = NULL;
    2045             : 
    2046             :         /*
    2047             :          * Windows7 (build 7000) will grant an RH lease immediate (not an RHW?)
    2048             :          * even if the original client is gone. (ZML: This seems like a bug. It
    2049             :          * should give some time for the client to reconnect! And why RH?)
    2050             :          * 
    2051             :          * obnox: Current windows 7 and w2k8r2 grant RHW instead of RH.
    2052             :          * Test is adapted accordingly.
    2053             :          */
    2054           0 :         status = smb2_create(tree2, mem_ctx, &io2);
    2055           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2056           0 :         h2 = io2.out.file.handle;
    2057           0 :         CHECK_VAL(io2.out.durable_open, true);
    2058           0 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    2059             : 
    2060           0 :         CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    2061           0 :         CHECK_VAL(io2.out.lease_response.lease_key.data[0], lease2);
    2062           0 :         CHECK_VAL(io2.out.lease_response.lease_key.data[1], ~lease2);
    2063           0 :         CHECK_VAL(io2.out.lease_response.lease_state,
    2064             :             SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
    2065             : 
    2066             :         /* What if tree1 tries to come back and reclaim? */
    2067           0 :         if (!torture_smb2_connection(tctx, &tree1)) {
    2068           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
    2069           0 :                 ret = false;
    2070           0 :                 goto done;
    2071             :         }
    2072             : 
    2073           0 :         ZERO_STRUCT(io1);
    2074           0 :         io1.in.fname = fname;
    2075           0 :         io1.in.durable_handle = &h1;
    2076           0 :         io1.in.lease_request = &ls1;
    2077             : 
    2078           0 :         status = smb2_create(tree1, mem_ctx, &io1);
    2079           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    2080             : 
    2081           0 :  done:
    2082           0 :         smb2_util_close(tree2, h2);
    2083           0 :         smb2_util_unlink(tree2, fname);
    2084             : 
    2085           0 :         talloc_free(tree1);
    2086           0 :         talloc_free(tree2);
    2087             : 
    2088           0 :         return ret;
    2089             : }
    2090             : 
    2091           0 : static bool test_durable_open_lock_oplock(struct torture_context *tctx,
    2092             :                                           struct smb2_tree *tree)
    2093             : {
    2094           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2095             :         struct smb2_create io;
    2096           0 :         struct smb2_handle h = {{0}};
    2097             :         struct smb2_lock lck;
    2098             :         struct smb2_lock_element el[2];
    2099             :         NTSTATUS status;
    2100             :         char fname[256];
    2101           0 :         bool ret = true;
    2102             : 
    2103             :         /*
    2104             :          */
    2105           0 :         snprintf(fname, 256, "durable_open_oplock_lock_%s.dat", generate_random_str(tctx, 8));
    2106             : 
    2107             :         /* Clean slate */
    2108           0 :         smb2_util_unlink(tree, fname);
    2109             : 
    2110             :         /* Create with oplock */
    2111             : 
    2112           0 :         smb2_oplock_create_share(&io, fname,
    2113             :                                  smb2_util_share_access(""),
    2114           0 :                                  smb2_util_oplock_level("b"));
    2115           0 :         io.in.durable_open = true;
    2116             : 
    2117           0 :         status = smb2_create(tree, mem_ctx, &io);
    2118           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2119           0 :         h = io.out.file.handle;
    2120           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    2121             : 
    2122           0 :         CHECK_VAL(io.out.durable_open, true);
    2123           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    2124             : 
    2125           0 :         ZERO_STRUCT(lck);
    2126           0 :         ZERO_STRUCT(el);
    2127           0 :         lck.in.locks            = el;
    2128           0 :         lck.in.lock_count       = 0x0001;
    2129           0 :         lck.in.lock_sequence    = 0x00000000;
    2130           0 :         lck.in.file.handle      = h;
    2131           0 :         el[0].offset            = 0;
    2132           0 :         el[0].length            = 1;
    2133           0 :         el[0].reserved          = 0x00000000;
    2134           0 :         el[0].flags             = SMB2_LOCK_FLAG_EXCLUSIVE;
    2135           0 :         status = smb2_lock(tree, &lck);
    2136           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2137             : 
    2138             :         /* Disconnect/Reconnect. */
    2139           0 :         talloc_free(tree);
    2140           0 :         tree = NULL;
    2141             : 
    2142           0 :         if (!torture_smb2_connection(tctx, &tree)) {
    2143           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
    2144           0 :                 ret = false;
    2145           0 :                 goto done;
    2146             :         }
    2147             : 
    2148           0 :         ZERO_STRUCT(io);
    2149           0 :         io.in.fname = fname;
    2150           0 :         io.in.durable_handle = &h;
    2151             : 
    2152           0 :         status = smb2_create(tree, mem_ctx, &io);
    2153           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2154           0 :         h = io.out.file.handle;
    2155             : 
    2156           0 :         lck.in.file.handle      = h;
    2157           0 :         el[0].flags             = SMB2_LOCK_FLAG_UNLOCK;
    2158           0 :         status = smb2_lock(tree, &lck);
    2159           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2160             : 
    2161           0 :  done:
    2162           0 :         smb2_util_close(tree, h);
    2163           0 :         smb2_util_unlink(tree, fname);
    2164           0 :         talloc_free(tree);
    2165             : 
    2166           0 :         return ret;
    2167             : }
    2168             : 
    2169             : /*
    2170             :   Open, take BRL, disconnect, reconnect.
    2171             : */
    2172           0 : static bool test_durable_open_lock_lease(struct torture_context *tctx,
    2173             :                                          struct smb2_tree *tree)
    2174             : {
    2175           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2176             :         struct smb2_create io;
    2177             :         struct smb2_lease ls;
    2178           0 :         struct smb2_handle h = {{0}};
    2179             :         struct smb2_lock lck;
    2180             :         struct smb2_lock_element el[2];
    2181             :         NTSTATUS status;
    2182             :         char fname[256];
    2183           0 :         bool ret = true;
    2184             :         uint64_t lease;
    2185             :         uint32_t caps;
    2186             :         struct smbcli_options options;
    2187             : 
    2188           0 :         options = tree->session->transport->options;
    2189             : 
    2190           0 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
    2191           0 :         if (!(caps & SMB2_CAP_LEASING)) {
    2192           0 :                 torture_skip(tctx, "leases are not supported");
    2193             :         }
    2194             : 
    2195             :         /*
    2196             :          * Choose a random name and random lease in case the state is left a
    2197             :          * little funky.
    2198             :          */
    2199           0 :         lease = random();
    2200           0 :         snprintf(fname, 256, "durable_open_lease_lock_%s.dat", generate_random_str(tctx, 8));
    2201             : 
    2202             :         /* Clean slate */
    2203           0 :         smb2_util_unlink(tree, fname);
    2204             : 
    2205             :         /* Create with lease */
    2206             : 
    2207           0 :         smb2_lease_create(&io, &ls, false /* dir */, fname, lease,
    2208             :                           smb2_util_lease_state("RWH"));
    2209           0 :         io.in.durable_open              = true;
    2210             : 
    2211           0 :         status = smb2_create(tree, mem_ctx, &io);
    2212           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2213           0 :         h = io.out.file.handle;
    2214           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    2215             : 
    2216           0 :         CHECK_VAL(io.out.durable_open, true);
    2217           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    2218           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease);
    2219           0 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease);
    2220           0 :         CHECK_VAL(io.out.lease_response.lease_state,
    2221             :             SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
    2222             : 
    2223           0 :         ZERO_STRUCT(lck);
    2224           0 :         ZERO_STRUCT(el);
    2225           0 :         lck.in.locks            = el;
    2226           0 :         lck.in.lock_count       = 0x0001;
    2227           0 :         lck.in.lock_sequence    = 0x00000000;
    2228           0 :         lck.in.file.handle      = h;
    2229           0 :         el[0].offset            = 0;
    2230           0 :         el[0].length            = 1;
    2231           0 :         el[0].reserved          = 0x00000000;
    2232           0 :         el[0].flags             = SMB2_LOCK_FLAG_EXCLUSIVE;
    2233           0 :         status = smb2_lock(tree, &lck);
    2234           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2235             : 
    2236             :         /* Disconnect/Reconnect. */
    2237           0 :         talloc_free(tree);
    2238           0 :         tree = NULL;
    2239             : 
    2240           0 :         if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
    2241           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
    2242           0 :                 ret = false;
    2243           0 :                 goto done;
    2244             :         }
    2245             : 
    2246           0 :         ZERO_STRUCT(io);
    2247           0 :         io.in.fname = fname;
    2248           0 :         io.in.durable_handle = &h;
    2249           0 :         io.in.lease_request = &ls;
    2250             : 
    2251           0 :         status = smb2_create(tree, mem_ctx, &io);
    2252           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2253           0 :         h = io.out.file.handle;
    2254             : 
    2255           0 :         lck.in.file.handle      = h;
    2256           0 :         el[0].flags             = SMB2_LOCK_FLAG_UNLOCK;
    2257           0 :         status = smb2_lock(tree, &lck);
    2258           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2259             : 
    2260           0 :  done:
    2261           0 :         smb2_util_close(tree, h);
    2262           0 :         smb2_util_unlink(tree, fname);
    2263           0 :         talloc_free(tree);
    2264             : 
    2265           0 :         return ret;
    2266             : }
    2267             : 
    2268             : /**
    2269             :  * Open with a RH lease, disconnect, open in another tree, reconnect.
    2270             :  *
    2271             :  * This test actually demonstrates a minimum level of respect for the durable
    2272             :  * open in the face of another open. As long as this test shows an inability to
    2273             :  * reconnect after an open, the oplock/lease tests above will certainly
    2274             :  * demonstrate an error on reconnect.
    2275             :  */
    2276           0 : static bool test_durable_open_open2_lease(struct torture_context *tctx,
    2277             :                                           struct smb2_tree *tree1,
    2278             :                                           struct smb2_tree *tree2)
    2279             : {
    2280           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2281             :         struct smb2_create io1, io2;
    2282             :         struct smb2_lease ls;
    2283           0 :         struct smb2_handle h1 = {{0}};
    2284           0 :         struct smb2_handle h2 = {{0}};
    2285             :         NTSTATUS status;
    2286             :         char fname[256];
    2287           0 :         bool ret = true;
    2288             :         uint64_t lease;
    2289             :         uint32_t caps;
    2290             :         struct smbcli_options options;
    2291             : 
    2292           0 :         options = tree1->session->transport->options;
    2293             : 
    2294           0 :         caps = smb2cli_conn_server_capabilities(tree1->session->transport->conn);
    2295           0 :         if (!(caps & SMB2_CAP_LEASING)) {
    2296           0 :                 torture_skip(tctx, "leases are not supported");
    2297             :         }
    2298             : 
    2299             :         /*
    2300             :          * Choose a random name and random lease in case the state is left a
    2301             :          * little funky.
    2302             :          */
    2303           0 :         lease = random();
    2304           0 :         snprintf(fname, 256, "durable_open_open2_lease_%s.dat",
    2305             :                  generate_random_str(tctx, 8));
    2306             : 
    2307             :         /* Clean slate */
    2308           0 :         smb2_util_unlink(tree1, fname);
    2309             : 
    2310             :         /* Create with lease */
    2311           0 :         smb2_lease_create_share(&io1, &ls, false /* dir */, fname,
    2312             :                                 smb2_util_share_access(""),
    2313             :                                 lease,
    2314             :                                 smb2_util_lease_state("RH"));
    2315           0 :         io1.in.durable_open = true;
    2316             : 
    2317           0 :         status = smb2_create(tree1, mem_ctx, &io1);
    2318           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2319           0 :         h1 = io1.out.file.handle;
    2320           0 :         CHECK_VAL(io1.out.durable_open, true);
    2321           0 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    2322             : 
    2323           0 :         CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    2324           0 :         CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease);
    2325           0 :         CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease);
    2326           0 :         CHECK_VAL(io1.out.lease_response.lease_state,
    2327             :                   smb2_util_lease_state("RH"));
    2328             : 
    2329             :         /* Disconnect */
    2330           0 :         talloc_free(tree1);
    2331           0 :         tree1 = NULL;
    2332             : 
    2333             :         /* Open the file in tree2 */
    2334           0 :         smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
    2335             : 
    2336           0 :         status = smb2_create(tree2, mem_ctx, &io2);
    2337           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2338           0 :         h2 = io2.out.file.handle;
    2339           0 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    2340             : 
    2341             :         /* Reconnect */
    2342           0 :         if (!torture_smb2_connection_ext(tctx, 0, &options, &tree1)) {
    2343           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
    2344           0 :                 ret = false;
    2345           0 :                 goto done;
    2346             :         }
    2347             : 
    2348           0 :         ZERO_STRUCT(io1);
    2349           0 :         io1.in.fname = fname;
    2350           0 :         io1.in.durable_handle = &h1;
    2351           0 :         io1.in.lease_request = &ls;
    2352             : 
    2353             :         /*
    2354             :          * Windows7 (build 7000) will give away an open immediately if the
    2355             :          * original client is gone. (ZML: This seems like a bug. It should give
    2356             :          * some time for the client to reconnect!)
    2357             :          */
    2358           0 :         status = smb2_create(tree1, mem_ctx, &io1);
    2359           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    2360           0 :         h1 = io1.out.file.handle;
    2361             : 
    2362           0 :  done:
    2363           0 :         if (tree1 != NULL){
    2364           0 :                 smb2_util_close(tree1, h1);
    2365           0 :                 smb2_util_unlink(tree1, fname);
    2366           0 :                 talloc_free(tree1);
    2367             :         }
    2368             : 
    2369           0 :         smb2_util_close(tree2, h2);
    2370           0 :         smb2_util_unlink(tree2, fname);
    2371           0 :         talloc_free(tree2);
    2372             : 
    2373           0 :         return ret;
    2374             : }
    2375             : 
    2376             : /**
    2377             :  * Open with a batch oplock, disconnect, open in another tree, reconnect.
    2378             :  *
    2379             :  * This test actually demonstrates a minimum level of respect for the durable
    2380             :  * open in the face of another open. As long as this test shows an inability to
    2381             :  * reconnect after an open, the oplock/lease tests above will certainly
    2382             :  * demonstrate an error on reconnect.
    2383             :  */
    2384           0 : static bool test_durable_open_open2_oplock(struct torture_context *tctx,
    2385             :                                            struct smb2_tree *tree1,
    2386             :                                            struct smb2_tree *tree2)
    2387             : {
    2388           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2389             :         struct smb2_create io1, io2;
    2390           0 :         struct smb2_handle h1 = {{0}};
    2391           0 :         struct smb2_handle h2 = {{0}};
    2392             :         NTSTATUS status;
    2393             :         char fname[256];
    2394           0 :         bool ret = true;
    2395             : 
    2396             :         /*
    2397             :          * Choose a random name and random lease in case the state is left a
    2398             :          * little funky.
    2399             :          */
    2400           0 :         snprintf(fname, 256, "durable_open_open2_oplock_%s.dat",
    2401             :                  generate_random_str(tctx, 8));
    2402             : 
    2403             :         /* Clean slate */
    2404           0 :         smb2_util_unlink(tree1, fname);
    2405             : 
    2406             :         /* Create with batch oplock */
    2407           0 :         smb2_oplock_create(&io1, fname, SMB2_OPLOCK_LEVEL_BATCH);
    2408           0 :         io1.in.durable_open = true;
    2409             : 
    2410           0 :         status = smb2_create(tree1, mem_ctx, &io1);
    2411           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2412           0 :         h1 = io1.out.file.handle;
    2413           0 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    2414           0 :         CHECK_VAL(io1.out.durable_open, true);
    2415           0 :         CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
    2416             : 
    2417             :         /* Disconnect */
    2418           0 :         talloc_free(tree1);
    2419           0 :         tree1 = NULL;
    2420             : 
    2421             :         /* Open the file in tree2 */
    2422           0 :         smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
    2423             : 
    2424           0 :         status = smb2_create(tree2, mem_ctx, &io2);
    2425           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2426           0 :         h2 = io2.out.file.handle;
    2427           0 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    2428             : 
    2429             :         /* Reconnect */
    2430           0 :         if (!torture_smb2_connection(tctx, &tree1)) {
    2431           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
    2432           0 :                 ret = false;
    2433           0 :                 goto done;
    2434             :         }
    2435             : 
    2436           0 :         ZERO_STRUCT(io1);
    2437           0 :         io1.in.fname = fname;
    2438           0 :         io1.in.durable_handle = &h1;
    2439             : 
    2440           0 :         status = smb2_create(tree1, mem_ctx, &io1);
    2441           0 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    2442           0 :         h1 = io1.out.file.handle;
    2443             : 
    2444           0 :  done:
    2445           0 :         smb2_util_close(tree2, h2);
    2446           0 :         smb2_util_unlink(tree2, fname);
    2447           0 :         if (tree1 != NULL) {
    2448           0 :                 smb2_util_close(tree1, h1);
    2449           0 :                 smb2_util_unlink(tree1, fname);
    2450             :         }
    2451             : 
    2452           0 :         talloc_free(tree1);
    2453           0 :         talloc_free(tree2);
    2454             : 
    2455           0 :         return ret;
    2456             : }
    2457             : 
    2458             : /**
    2459             :  * test behaviour with initial allocation size
    2460             :  */
    2461           0 : static bool test_durable_open_alloc_size(struct torture_context *tctx,
    2462             :                                          struct smb2_tree *tree)
    2463             : {
    2464             :         NTSTATUS status;
    2465           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2466             :         char fname[256];
    2467             :         struct smb2_handle _h;
    2468           0 :         struct smb2_handle *h = NULL;
    2469             :         struct smb2_create io;
    2470           0 :         bool ret = true;
    2471             :         uint64_t previous_session_id;
    2472             :         uint64_t alloc_size_step;
    2473           0 :         uint64_t initial_alloc_size = 0x1000;
    2474           0 :         const uint8_t *b = NULL;
    2475             :         struct smbcli_options options;
    2476             : 
    2477           0 :         options = tree->session->transport->options;
    2478             : 
    2479             :         /* Choose a random name in case the state is left a little funky. */
    2480           0 :         snprintf(fname, 256, "durable_open_alloc_size_%s.dat",
    2481             :                  generate_random_str(tctx, 8));
    2482             : 
    2483           0 :         smb2_util_unlink(tree, fname);
    2484             : 
    2485           0 :         smb2_oplock_create_share(&io, fname,
    2486             :                                  smb2_util_share_access(""),
    2487           0 :                                  smb2_util_oplock_level("b"));
    2488           0 :         io.in.durable_open = true;
    2489           0 :         io.in.alloc_size = initial_alloc_size;
    2490             : 
    2491           0 :         status = smb2_create(tree, mem_ctx, &io);
    2492           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2493           0 :         _h = io.out.file.handle;
    2494           0 :         h = &_h;
    2495           0 :         CHECK_NOT_VAL(io.out.alloc_size, 0);
    2496           0 :         alloc_size_step = io.out.alloc_size;
    2497           0 :         CHECK_CREATED_SIZE(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE,
    2498             :                            alloc_size_step, 0);
    2499           0 :         CHECK_VAL(io.out.durable_open, true);
    2500           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    2501             : 
    2502             :         /* prepare buffer */
    2503           0 :         b = talloc_zero_size(mem_ctx, alloc_size_step);
    2504           0 :         CHECK_NOT_NULL(b);
    2505             : 
    2506           0 :         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
    2507             : 
    2508             :         /* disconnect, reconnect and then do durable reopen */
    2509           0 :         talloc_free(tree);
    2510           0 :         tree = NULL;
    2511             : 
    2512           0 :         if (!torture_smb2_connection_ext(tctx, previous_session_id,
    2513             :                                          &options, &tree))
    2514             :         {
    2515           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
    2516           0 :                 ret = false;
    2517           0 :                 goto done;
    2518             :         }
    2519             : 
    2520           0 :         ZERO_STRUCT(io);
    2521           0 :         io.in.fname = fname;
    2522           0 :         io.in.durable_handle = h;
    2523           0 :         h = NULL;
    2524             : 
    2525           0 :         status = smb2_create(tree, mem_ctx, &io);
    2526           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2527           0 :         CHECK_CREATED_SIZE(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE,
    2528             :                            alloc_size_step, 0);
    2529           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    2530           0 :         _h = io.out.file.handle;
    2531           0 :         h = &_h;
    2532             : 
    2533           0 :         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
    2534             : 
    2535             :         /* write one byte */
    2536           0 :         status = smb2_util_write(tree, *h, b, 0, 1);
    2537           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2538             : 
    2539             :         /* disconnect, reconnect and then do durable reopen */
    2540           0 :         talloc_free(tree);
    2541           0 :         tree = NULL;
    2542             : 
    2543           0 :         if (!torture_smb2_connection_ext(tctx, previous_session_id,
    2544             :                                          &options, &tree))
    2545             :         {
    2546           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
    2547           0 :                 ret = false;
    2548           0 :                 goto done;
    2549             :         }
    2550             : 
    2551           0 :         ZERO_STRUCT(io);
    2552           0 :         io.in.fname = fname;
    2553           0 :         io.in.durable_handle = h;
    2554           0 :         h = NULL;
    2555             : 
    2556           0 :         status = smb2_create(tree, mem_ctx, &io);
    2557           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2558           0 :         CHECK_CREATED_SIZE(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE,
    2559             :                            alloc_size_step, 1);
    2560           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    2561           0 :         _h = io.out.file.handle;
    2562           0 :         h = &_h;
    2563             : 
    2564           0 :         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
    2565             : 
    2566             :         /* write more byte than initial allocation size */
    2567           0 :         status = smb2_util_write(tree, *h, b, 1, alloc_size_step);
    2568             : 
    2569             :         /* disconnect, reconnect and then do durable reopen */
    2570           0 :         talloc_free(tree);
    2571           0 :         tree = NULL;
    2572             : 
    2573           0 :         if (!torture_smb2_connection_ext(tctx, previous_session_id,
    2574             :                                          &options, &tree))
    2575             :         {
    2576           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
    2577           0 :                 ret = false;
    2578           0 :                 goto done;
    2579             :         }
    2580             : 
    2581           0 :         ZERO_STRUCT(io);
    2582           0 :         io.in.fname = fname;
    2583           0 :         io.in.durable_handle = h;
    2584           0 :         h = NULL;
    2585             : 
    2586           0 :         status = smb2_create(tree, mem_ctx, &io);
    2587           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2588           0 :         CHECK_CREATED_SIZE(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE,
    2589             :                            alloc_size_step * 2, alloc_size_step + 1);
    2590           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    2591           0 :         _h = io.out.file.handle;
    2592           0 :         h = &_h;
    2593             : 
    2594           0 : done:
    2595           0 :         if (h != NULL) {
    2596           0 :                 smb2_util_close(tree, *h);
    2597             :         }
    2598             : 
    2599           0 :         smb2_util_unlink(tree, fname);
    2600             : 
    2601           0 :         talloc_free(tree);
    2602             : 
    2603           0 :         talloc_free(mem_ctx);
    2604             : 
    2605           0 :         return ret;
    2606             : }
    2607             : 
    2608             : /**
    2609             :  * test behaviour when a disconnect happens while creating a read-only file
    2610             :  */
    2611           0 : static bool test_durable_open_read_only(struct torture_context *tctx,
    2612             :                                         struct smb2_tree *tree)
    2613             : {
    2614             :         NTSTATUS status;
    2615           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2616             :         char fname[256];
    2617             :         struct smb2_handle _h;
    2618           0 :         struct smb2_handle *h = NULL;
    2619             :         struct smb2_create io;
    2620           0 :         bool ret = true;
    2621             :         uint64_t previous_session_id;
    2622           0 :         const uint8_t b = 0;
    2623           0 :         uint64_t alloc_size = 0;
    2624             :         struct smbcli_options options;
    2625             : 
    2626           0 :         options = tree->session->transport->options;
    2627             : 
    2628             :         /* Choose a random name in case the state is left a little funky. */
    2629           0 :         snprintf(fname, 256, "durable_open_initial_alloc_%s.dat",
    2630             :                  generate_random_str(tctx, 8));
    2631             : 
    2632           0 :         smb2_util_unlink(tree, fname);
    2633             : 
    2634           0 :         smb2_oplock_create_share(&io, fname,
    2635             :                                  smb2_util_share_access(""),
    2636           0 :                                  smb2_util_oplock_level("b"));
    2637           0 :         io.in.durable_open = true;
    2638           0 :         io.in.file_attributes = FILE_ATTRIBUTE_READONLY;
    2639             : 
    2640           0 :         status = smb2_create(tree, mem_ctx, &io);
    2641           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2642           0 :         _h = io.out.file.handle;
    2643           0 :         h = &_h;
    2644           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_ARCHIVE);
    2645           0 :         CHECK_VAL(io.out.durable_open, true);
    2646           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    2647             : 
    2648           0 :         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
    2649             : 
    2650             :         /* write one byte */
    2651           0 :         status = smb2_util_write(tree, *h, &b, 0, 1);
    2652           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2653             : 
    2654             :         /* disconnect, reconnect and then do durable reopen */
    2655           0 :         talloc_free(tree);
    2656           0 :         tree = NULL;
    2657             : 
    2658           0 :         if (!torture_smb2_connection_ext(tctx, previous_session_id,
    2659             :                                          &options, &tree))
    2660             :         {
    2661           0 :                 torture_warning(tctx, "couldn't reconnect, bailing\n");
    2662           0 :                 ret = false;
    2663           0 :                 goto done;
    2664             :         }
    2665             : 
    2666           0 :         ZERO_STRUCT(io);
    2667           0 :         io.in.fname = fname;
    2668           0 :         io.in.durable_handle = h;
    2669           0 :         h = NULL;
    2670             : 
    2671           0 :         status = smb2_create(tree, mem_ctx, &io);
    2672           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2673           0 :         alloc_size = io.out.alloc_size;
    2674           0 :         CHECK_CREATED_SIZE(&io, EXISTED,
    2675             :                            FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_ARCHIVE,
    2676             :                            alloc_size, 1);
    2677           0 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    2678           0 :         _h = io.out.file.handle;
    2679           0 :         h = &_h;
    2680             : 
    2681             :         /* write one byte */
    2682           0 :         status = smb2_util_write(tree, *h, &b, 1, 1);
    2683           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2684             : 
    2685           0 : done:
    2686           0 :         if (h != NULL) {
    2687             :                 union smb_setfileinfo sfinfo;
    2688             : 
    2689           0 :                 ZERO_STRUCT(sfinfo);
    2690           0 :                 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
    2691           0 :                 sfinfo.basic_info.in.file.handle = *h;
    2692           0 :                 sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL;
    2693           0 :                 smb2_setinfo_file(tree, &sfinfo);
    2694             : 
    2695           0 :                 smb2_util_close(tree, *h);
    2696             :         }
    2697             : 
    2698           0 :         smb2_util_unlink(tree, fname);
    2699             : 
    2700           0 :         talloc_free(tree);
    2701             : 
    2702           0 :         talloc_free(mem_ctx);
    2703             : 
    2704           0 :         return ret;
    2705             : }
    2706             : 
    2707             : /**
    2708             :  * durable open with oplock, disconnect, exit
    2709             :  */
    2710           0 : static bool test_durable_open_oplock_disconnect(struct torture_context *tctx,
    2711             :                                                 struct smb2_tree *tree)
    2712             : {
    2713           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2714             :         struct smb2_create io;
    2715             :         struct smb2_handle _h;
    2716           0 :         struct smb2_handle *h = NULL;
    2717             :         NTSTATUS status;
    2718             :         char fname[256];
    2719           0 :         bool ret = true;
    2720             : 
    2721           0 :         snprintf(fname, 256, "durable_open_oplock_disconnect_%s.dat",
    2722             :                  generate_random_str(mem_ctx, 8));
    2723             : 
    2724           0 :         smb2_util_unlink(tree, fname);
    2725             : 
    2726           0 :         smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_BATCH);
    2727           0 :         io.in.durable_open = true;
    2728             : 
    2729           0 :         status = smb2_create(tree, mem_ctx, &io);
    2730           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2731             : 
    2732           0 :         _h = io.out.file.handle;
    2733           0 :         h = &_h;
    2734             : 
    2735           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    2736           0 :         CHECK_VAL(io.out.durable_open, true);
    2737           0 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
    2738             : 
    2739             :         /* disconnect */
    2740           0 :         talloc_free(tree);
    2741           0 :         tree = NULL;
    2742             : 
    2743           0 : done:
    2744           0 :         if (tree != NULL) {
    2745           0 :                 if (h != NULL) {
    2746           0 :                         smb2_util_close(tree, *h);
    2747             :                 }
    2748           0 :                 smb2_util_unlink(tree, fname);
    2749             :         }
    2750           0 :         talloc_free(mem_ctx);
    2751           0 :         return ret;
    2752             : }
    2753             : 
    2754             : /**
    2755             :  * durable stat open with lease.
    2756             :  */
    2757           0 : static bool test_durable_open_stat_open(struct torture_context *tctx,
    2758             :                                         struct smb2_tree *tree)
    2759             : {
    2760           0 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2761             :         struct smb2_create io;
    2762             :         struct smb2_handle _h;
    2763           0 :         struct smb2_handle *h = NULL;
    2764             :         struct smb2_lease ls;
    2765             :         NTSTATUS status;
    2766             :         char fname[256];
    2767           0 :         bool ret = true;
    2768             :         uint64_t lease;
    2769             : 
    2770           0 :         snprintf(fname, 256, "durable_open_stat_open_%s.dat",
    2771             :                  generate_random_str(mem_ctx, 8));
    2772             : 
    2773             :         /* Ensure file doesn't exist. */
    2774           0 :         smb2_util_unlink(tree, fname);
    2775             : 
    2776             :         /* Create a normal file. */
    2777           0 :         smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_NONE);
    2778           0 :         status = smb2_create(tree, mem_ctx, &io);
    2779           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2780           0 :         _h = io.out.file.handle;
    2781           0 :         h = &_h;
    2782           0 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    2783             :         /* Close. */
    2784           0 :         smb2_util_close(tree, *h);
    2785           0 :         h = NULL;
    2786             : 
    2787             :         /* Now try a leased, durable handle stat open. */
    2788           0 :         lease = random();
    2789             :         /* Create with lease */
    2790           0 :         smb2_lease_create(&io,
    2791             :                           &ls,
    2792             :                           false /* dir */,
    2793             :                           fname,
    2794             :                           lease,
    2795             :                           smb2_util_lease_state("RH"));
    2796           0 :         io.in.durable_open = true;
    2797           0 :         io.in.desired_access = SEC_FILE_READ_ATTRIBUTE;
    2798           0 :         io.in.create_disposition = NTCREATEX_DISP_OPEN;
    2799             : 
    2800           0 :         status = smb2_create(tree, mem_ctx, &io);
    2801           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    2802           0 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    2803           0 :         CHECK_VAL(io.out.durable_open, true);
    2804           0 :         _h = io.out.file.handle;
    2805           0 :         h = &_h;
    2806             : 
    2807           0 : done:
    2808           0 :         if (h != NULL) {
    2809           0 :                 smb2_util_close(tree, *h);
    2810             :         }
    2811           0 :         smb2_util_unlink(tree, fname);
    2812           0 :         talloc_free(mem_ctx);
    2813           0 :         return ret;
    2814             : }
    2815             : 
    2816         964 : struct torture_suite *torture_smb2_durable_open_init(TALLOC_CTX *ctx)
    2817             : {
    2818         738 :         struct torture_suite *suite =
    2819         226 :             torture_suite_create(ctx, "durable-open");
    2820             : 
    2821         964 :         torture_suite_add_1smb2_test(suite, "open-oplock", test_durable_open_open_oplock);
    2822         964 :         torture_suite_add_1smb2_test(suite, "open-lease", test_durable_open_open_lease);
    2823         964 :         torture_suite_add_1smb2_test(suite, "reopen1", test_durable_open_reopen1);
    2824         964 :         torture_suite_add_1smb2_test(suite, "reopen1a", test_durable_open_reopen1a);
    2825         964 :         torture_suite_add_1smb2_test(suite, "reopen1a-lease", test_durable_open_reopen1a_lease);
    2826         964 :         torture_suite_add_1smb2_test(suite, "reopen2", test_durable_open_reopen2);
    2827         964 :         torture_suite_add_1smb2_test(suite, "reopen2-lease", test_durable_open_reopen2_lease);
    2828         964 :         torture_suite_add_1smb2_test(suite, "reopen2-lease-v2", test_durable_open_reopen2_lease_v2);
    2829         964 :         torture_suite_add_1smb2_test(suite, "reopen2a", test_durable_open_reopen2a);
    2830         964 :         torture_suite_add_1smb2_test(suite, "reopen3", test_durable_open_reopen3);
    2831         964 :         torture_suite_add_1smb2_test(suite, "reopen4", test_durable_open_reopen4);
    2832         964 :         torture_suite_add_1smb2_test(suite, "delete_on_close1",
    2833             :                                      test_durable_open_delete_on_close1);
    2834         964 :         torture_suite_add_1smb2_test(suite, "delete_on_close2",
    2835             :                                      test_durable_open_delete_on_close2);
    2836         964 :         torture_suite_add_1smb2_test(suite, "file-position",
    2837             :             test_durable_open_file_position);
    2838         964 :         torture_suite_add_2smb2_test(suite, "oplock", test_durable_open_oplock);
    2839         964 :         torture_suite_add_2smb2_test(suite, "lease", test_durable_open_lease);
    2840         964 :         torture_suite_add_1smb2_test(suite, "lock-oplock", test_durable_open_lock_oplock);
    2841         964 :         torture_suite_add_1smb2_test(suite, "lock-lease", test_durable_open_lock_lease);
    2842         964 :         torture_suite_add_2smb2_test(suite, "open2-lease",
    2843             :                                      test_durable_open_open2_lease);
    2844         964 :         torture_suite_add_2smb2_test(suite, "open2-oplock",
    2845             :                                      test_durable_open_open2_oplock);
    2846         964 :         torture_suite_add_1smb2_test(suite, "alloc-size",
    2847             :                                      test_durable_open_alloc_size);
    2848         964 :         torture_suite_add_1smb2_test(suite, "read-only",
    2849             :                                      test_durable_open_read_only);
    2850         964 :         torture_suite_add_1smb2_test(suite, "stat-open",
    2851             :                                      test_durable_open_stat_open);
    2852             : 
    2853         964 :         suite->description = talloc_strdup(suite, "SMB2-DURABLE-OPEN tests");
    2854             : 
    2855         964 :         return suite;
    2856             : }
    2857             : 
    2858         964 : struct torture_suite *torture_smb2_durable_open_disconnect_init(TALLOC_CTX *ctx)
    2859             : {
    2860         738 :         struct torture_suite *suite =
    2861         226 :             torture_suite_create(ctx,
    2862             :                                  "durable-open-disconnect");
    2863             : 
    2864         964 :         torture_suite_add_1smb2_test(suite, "open-oplock-disconnect",
    2865             :                                      test_durable_open_oplock_disconnect);
    2866             : 
    2867         964 :         suite->description = talloc_strdup(suite,
    2868             :                                         "SMB2-DURABLE-OPEN-DISCONNECT tests");
    2869             : 
    2870         964 :         return suite;
    2871             : }

Generated by: LCOV version 1.13