LCOV - code coverage report
Current view: top level - source4/torture/smb2 - durable_open.c (source / functions) Hit Total Coverage
Test: coverage report for master 6248eab5 Lines: 1256 1383 90.8 %
Date: 2021-08-25 13:27:56 Functions: 26 29 89.7 %

          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         128 : 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         128 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     142             :         struct smb2_handle _h;
     143         128 :         struct smb2_handle *h = NULL;
     144         128 :         bool ret = true;
     145             :         struct smb2_create io;
     146             : 
     147         128 :         smb2_util_unlink(tree, fname);
     148             : 
     149         128 :         smb2_oplock_create_share(&io, fname,
     150             :                                  smb2_util_share_access(test.share_mode),
     151         128 :                                  smb2_util_oplock_level(test.level));
     152         128 :         io.in.durable_open = true;
     153             : 
     154         128 :         status = smb2_create(tree, mem_ctx, &io);
     155         128 :         CHECK_STATUS(status, NT_STATUS_OK);
     156         128 :         _h = io.out.file.handle;
     157         128 :         h = &_h;
     158         128 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     159         128 :         CHECK_VAL(io.out.durable_open, test.expected);
     160         128 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(test.level));
     161             : 
     162         256 : done:
     163         128 :         if (h != NULL) {
     164         128 :                 smb2_util_close(tree, *h);
     165             :         }
     166         128 :         smb2_util_unlink(tree, fname);
     167         128 :         talloc_free(mem_ctx);
     168             : 
     169         128 :         return ret;
     170             : }
     171             : 
     172           4 : static bool test_durable_open_open_oplock(struct torture_context *tctx,
     173             :                                           struct smb2_tree *tree)
     174             : {
     175           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     176             :         char fname[256];
     177           4 :         bool ret = true;
     178             :         int i;
     179             : 
     180             :         /* Choose a random name in case the state is left a little funky. */
     181           4 :         snprintf(fname, 256, "durable_open_open_oplock_%s.dat", generate_random_str(tctx, 8));
     182             : 
     183           4 :         smb2_util_unlink(tree, fname);
     184             : 
     185             :         /* test various oplock levels with durable open */
     186             : 
     187         132 :         for (i = 0; i < NUM_OPLOCK_OPEN_TESTS; i++) {
     188         128 :                 ret = test_one_durable_open_open_oplock(tctx,
     189             :                                                         tree,
     190             :                                                         fname,
     191             :                                                         durable_open_vs_oplock_table[i]);
     192         128 :                 if (ret == false) {
     193           0 :                         goto done;
     194             :                 }
     195             :         }
     196             : 
     197           4 : done:
     198           4 :         smb2_util_unlink(tree, fname);
     199           4 :         talloc_free(tree);
     200           4 :         talloc_free(mem_ctx);
     201             : 
     202           4 :         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          80 : 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          80 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     276             :         struct smb2_handle _h;
     277          80 :         struct smb2_handle *h = NULL;
     278          80 :         bool ret = true;
     279             :         struct smb2_create io;
     280             :         struct smb2_lease ls;
     281             :         uint64_t lease;
     282             :         uint32_t caps;
     283             : 
     284          80 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
     285          80 :         if (!(caps & SMB2_CAP_LEASING)) {
     286           0 :                 torture_skip(tctx, "leases are not supported");
     287             :         }
     288             : 
     289          80 :         smb2_util_unlink(tree, fname);
     290             : 
     291          80 :         lease = random();
     292             : 
     293          80 :         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          80 :         io.in.durable_open = true;
     298             : 
     299          80 :         status = smb2_create(tree, mem_ctx, &io);
     300          80 :         CHECK_STATUS(status, NT_STATUS_OK);
     301          80 :         _h = io.out.file.handle;
     302          80 :         h = &_h;
     303          80 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     304          80 :         CHECK_VAL(io.out.durable_open, test.expected);
     305          80 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
     306          80 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease);
     307          80 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease);
     308          80 :         CHECK_VAL(io.out.lease_response.lease_state,
     309             :                   smb2_util_lease_state(test.type));
     310         160 : done:
     311          80 :         if (h != NULL) {
     312          80 :                 smb2_util_close(tree, *h);
     313             :         }
     314          80 :         smb2_util_unlink(tree, fname);
     315          80 :         talloc_free(mem_ctx);
     316             : 
     317          80 :         return ret;
     318             : }
     319             : 
     320           4 : static bool test_durable_open_open_lease(struct torture_context *tctx,
     321             :                                          struct smb2_tree *tree)
     322             : {
     323           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     324             :         char fname[256];
     325           4 :         bool ret = true;
     326             :         int i;
     327             :         uint32_t caps;
     328             : 
     329           4 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
     330           4 :         if (!(caps & SMB2_CAP_LEASING)) {
     331           2 :                 torture_skip(tctx, "leases are not supported");
     332             :         }
     333             : 
     334             :         /* Choose a random name in case the state is left a little funky. */
     335           2 :         snprintf(fname, 256, "durable_open_open_lease_%s.dat", generate_random_str(tctx, 8));
     336             : 
     337           2 :         smb2_util_unlink(tree, fname);
     338             : 
     339             : 
     340             :         /* test various oplock levels with durable open */
     341             : 
     342          82 :         for (i = 0; i < NUM_LEASE_OPEN_TESTS; i++) {
     343          80 :                 ret = test_one_durable_open_open_lease(tctx,
     344             :                                                        tree,
     345             :                                                        fname,
     346             :                                                        durable_open_vs_lease_table[i]);
     347          80 :                 if (ret == false) {
     348           0 :                         goto done;
     349             :                 }
     350             :         }
     351             : 
     352           2 : done:
     353           2 :         smb2_util_unlink(tree, fname);
     354           2 :         talloc_free(tree);
     355           2 :         talloc_free(mem_ctx);
     356             : 
     357           2 :         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           4 : static bool test_durable_open_reopen1(struct torture_context *tctx,
     366             :                                       struct smb2_tree *tree)
     367             : {
     368             :         NTSTATUS status;
     369           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     370             :         char fname[256];
     371             :         struct smb2_handle _h;
     372           4 :         struct smb2_handle *h = NULL;
     373             :         struct smb2_create io1, io2;
     374           4 :         bool ret = true;
     375             : 
     376             :         /* Choose a random name in case the state is left a little funky. */
     377           4 :         snprintf(fname, 256, "durable_open_reopen1_%s.dat",
     378             :                  generate_random_str(tctx, 8));
     379             : 
     380           4 :         smb2_util_unlink(tree, fname);
     381             : 
     382           4 :         smb2_oplock_create_share(&io1, fname,
     383             :                                  smb2_util_share_access(""),
     384           4 :                                  smb2_util_oplock_level("b"));
     385           4 :         io1.in.durable_open = true;
     386             : 
     387           4 :         status = smb2_create(tree, mem_ctx, &io1);
     388           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     389           4 :         _h = io1.out.file.handle;
     390           4 :         h = &_h;
     391           4 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     392           4 :         CHECK_VAL(io1.out.durable_open, true);
     393           4 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
     394             : 
     395             :         /* try a durable reconnect while the file is still open */
     396           4 :         ZERO_STRUCT(io2);
     397           4 :         io2.in.fname = fname;
     398           4 :         io2.in.durable_handle = h;
     399             : 
     400           4 :         status = smb2_create(tree, mem_ctx, &io2);
     401           4 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     402             : 
     403           8 : done:
     404           4 :         if (h != NULL) {
     405           4 :                 smb2_util_close(tree, *h);
     406             :         }
     407             : 
     408           4 :         smb2_util_unlink(tree, fname);
     409             : 
     410           4 :         talloc_free(tree);
     411             : 
     412           4 :         talloc_free(mem_ctx);
     413             : 
     414           4 :         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           4 : static bool test_durable_open_reopen1a(struct torture_context *tctx,
     426             :                                        struct smb2_tree *tree)
     427             : {
     428             :         NTSTATUS status;
     429           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     430             :         char fname[256];
     431             :         struct smb2_handle _h;
     432           4 :         struct smb2_handle *h = NULL;
     433             :         struct smb2_create io;
     434           4 :         bool ret = true;
     435           4 :         struct smb2_tree *tree2 = NULL;
     436           4 :         struct smb2_tree *tree3 = NULL;
     437             :         uint64_t previous_session_id;
     438             :         struct smbcli_options options;
     439             :         struct GUID orig_client_guid;
     440             : 
     441           4 :         options = tree->session->transport->options;
     442           4 :         orig_client_guid = options.client_guid;
     443             : 
     444             :         /* Choose a random name in case the state is left a little funky. */
     445           4 :         snprintf(fname, 256, "durable_open_reopen1a_%s.dat",
     446             :                  generate_random_str(tctx, 8));
     447             : 
     448           4 :         smb2_util_unlink(tree, fname);
     449             : 
     450           4 :         smb2_oplock_create_share(&io, fname,
     451             :                                  smb2_util_share_access(""),
     452           4 :                                  smb2_util_oplock_level("b"));
     453           4 :         io.in.durable_open = true;
     454             : 
     455           4 :         status = smb2_create(tree, mem_ctx, &io);
     456           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     457           4 :         _h = io.out.file.handle;
     458           4 :         h = &_h;
     459           4 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     460           4 :         CHECK_VAL(io.out.durable_open, true);
     461           4 :         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           4 :         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
     468             : 
     469             :         /* for oplocks, the client guid can be different: */
     470           4 :         options.client_guid = GUID_random();
     471             : 
     472           4 :         ret = torture_smb2_connection_ext(tctx, previous_session_id,
     473             :                                           &options, &tree2);
     474           4 :         torture_assert_goto(tctx, ret, ret, done, "could not reconnect");
     475             : 
     476             :         /*
     477             :          * check that this has deleted the old session
     478             :          */
     479             : 
     480           4 :         ZERO_STRUCT(io);
     481           4 :         io.in.fname = fname;
     482           4 :         io.in.durable_handle = h;
     483             : 
     484           4 :         status = smb2_create(tree, mem_ctx, &io);
     485           4 :         CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
     486             : 
     487           4 :         TALLOC_FREE(tree);
     488             : 
     489             :         /*
     490             :          * but a durable reconnect on the new session succeeds:
     491             :          */
     492             : 
     493           4 :         ZERO_STRUCT(io);
     494           4 :         io.in.fname = fname;
     495           4 :         io.in.durable_handle = h;
     496             : 
     497           4 :         status = smb2_create(tree2, mem_ctx, &io);
     498           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     499           4 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     500           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     501           4 :         _h = io.out.file.handle;
     502           4 :         h = &_h;
     503             : 
     504             :         /*
     505             :          * a session reconnect on a second tcp connection
     506             :          */
     507             : 
     508           4 :         previous_session_id = smb2cli_session_current_id(tree2->session->smbXcli);
     509             : 
     510             :         /* the original client_guid works just the same */
     511           4 :         options.client_guid = orig_client_guid;
     512             : 
     513           4 :         ret = torture_smb2_connection_ext(tctx, previous_session_id,
     514             :                                           &options, &tree3);
     515           4 :         torture_assert_goto(tctx, ret, ret, done, "could not reconnect");
     516             : 
     517             :         /*
     518             :          * check that this has deleted the old session
     519             :          */
     520             : 
     521           4 :         ZERO_STRUCT(io);
     522           4 :         io.in.fname = fname;
     523           4 :         io.in.durable_handle = h;
     524             : 
     525           4 :         status = smb2_create(tree2, mem_ctx, &io);
     526           4 :         CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
     527             : 
     528           4 :         TALLOC_FREE(tree2);
     529             : 
     530             :         /*
     531             :          * but a durable reconnect on the new session succeeds:
     532             :          */
     533             : 
     534           4 :         ZERO_STRUCT(io);
     535           4 :         io.in.fname = fname;
     536           4 :         io.in.durable_handle = h;
     537             : 
     538           4 :         status = smb2_create(tree3, mem_ctx, &io);
     539           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     540           4 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     541           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     542           4 :         _h = io.out.file.handle;
     543           4 :         h = &_h;
     544             : 
     545           4 : done:
     546           4 :         if (tree == NULL) {
     547           4 :                 tree = tree2;
     548             :         }
     549             : 
     550           4 :         if (tree == NULL) {
     551           4 :                 tree = tree3;
     552             :         }
     553             : 
     554           4 :         if (tree != NULL) {
     555           4 :                 if (h != NULL) {
     556           4 :                         smb2_util_close(tree, *h);
     557           4 :                         h = NULL;
     558             :                 }
     559           4 :                 smb2_util_unlink(tree, fname);
     560             : 
     561           4 :                 talloc_free(tree);
     562             :         }
     563             : 
     564           4 :         talloc_free(mem_ctx);
     565             : 
     566           4 :         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           4 : bool test_durable_open_reopen1a_lease(struct torture_context *tctx,
     582             :                                       struct smb2_tree *tree)
     583             : {
     584             :         NTSTATUS status;
     585           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     586             :         char fname[256];
     587             :         struct smb2_handle _h;
     588           4 :         struct smb2_handle *h = NULL;
     589             :         struct smb2_create io;
     590             :         struct smb2_lease ls;
     591             :         uint64_t lease_key;
     592           4 :         bool ret = true;
     593           4 :         struct smb2_tree *tree2 = NULL;
     594           4 :         struct smb2_tree *tree3 = NULL;
     595             :         uint64_t previous_session_id;
     596             :         struct smbcli_options options;
     597             :         struct GUID orig_client_guid;
     598             : 
     599           4 :         options = tree->session->transport->options;
     600           4 :         orig_client_guid = options.client_guid;
     601             : 
     602             :         /* Choose a random name in case the state is left a little funky. */
     603           4 :         snprintf(fname, 256, "durable_v2_open_reopen1a_lease_%s.dat",
     604             :                  generate_random_str(tctx, 8));
     605             : 
     606           4 :         smb2_util_unlink(tree, fname);
     607             : 
     608           4 :         lease_key = random();
     609           4 :         smb2_lease_create(&io, &ls, false /* dir */, fname,
     610             :                           lease_key, smb2_util_lease_state("RWH"));
     611           4 :         io.in.durable_open = true;
     612             : 
     613           4 :         status = smb2_create(tree, mem_ctx, &io);
     614           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     615           4 :         _h = io.out.file.handle;
     616           4 :         h = &_h;
     617           4 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     618           4 :         CHECK_VAL(io.out.durable_open, true);
     619           4 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
     620           4 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
     621           4 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
     622           4 :         CHECK_VAL(io.out.lease_response.lease_state,
     623             :                   smb2_util_lease_state("RWH"));
     624           4 :         CHECK_VAL(io.out.lease_response.lease_flags, 0);
     625           4 :         CHECK_VAL(io.out.lease_response.lease_duration, 0);
     626             : 
     627           4 :         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           4 :         options.client_guid = GUID_random();
     636             : 
     637           4 :         ret = torture_smb2_connection_ext(tctx, previous_session_id,
     638             :                                           &options, &tree2);
     639           4 :         torture_assert_goto(tctx, ret, ret, done, "couldn't reconnect");
     640             : 
     641             :         /*
     642             :          * check that this has deleted the old session
     643             :          */
     644             : 
     645           4 :         ZERO_STRUCT(io);
     646           4 :         io.in.fname = fname;
     647           4 :         io.in.durable_handle = h;
     648           4 :         io.in.lease_request = &ls;
     649           4 :         status = smb2_create(tree, mem_ctx, &io);
     650           4 :         CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
     651           4 :         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           4 :         ZERO_STRUCT(io);
     660           4 :         io.in.fname = fname;
     661           4 :         io.in.durable_handle = h;
     662           4 :         io.in.lease_request = &ls;
     663           4 :         status = smb2_create(tree2, mem_ctx, &io);
     664           4 :         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           4 :         options.client_guid = orig_client_guid;
     672             : 
     673           4 :         ret = torture_smb2_connection_ext(tctx, previous_session_id,
     674             :                                           &options, &tree3);
     675           4 :         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           4 :         ZERO_STRUCT(io);
     684           4 :         io.in.fname = fname;
     685           4 :         io.in.durable_handle = h;
     686           4 :         io.in.lease_request = &ls;
     687           4 :         status = smb2_create(tree2, mem_ctx, &io);
     688           4 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     689           4 :         TALLOC_FREE(tree2);
     690             : 
     691             :         /*
     692             :          * but a durable reconnect on the new session succeeds:
     693             :          */
     694             : 
     695           4 :         ZERO_STRUCT(io);
     696           4 :         io.in.fname = fname;
     697           4 :         io.in.durable_handle = h;
     698           4 :         io.in.lease_request = &ls;
     699           4 :         status = smb2_create(tree3, mem_ctx, &io);
     700           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     701           2 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     702           2 :         CHECK_VAL(io.out.durable_open, false); /* no dh response context... */
     703           2 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
     704           2 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
     705           2 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
     706           2 :         CHECK_VAL(io.out.lease_response.lease_state,
     707             :                   smb2_util_lease_state("RWH"));
     708           2 :         CHECK_VAL(io.out.lease_response.lease_flags, 0);
     709           2 :         CHECK_VAL(io.out.lease_response.lease_duration, 0);
     710           2 :         _h = io.out.file.handle;
     711           2 :         h = &_h;
     712             : 
     713           4 : done:
     714           4 :         if (tree == NULL) {
     715           4 :                 tree = tree2;
     716             :         }
     717             : 
     718           4 :         if (tree == NULL) {
     719           4 :                 tree = tree3;
     720             :         }
     721             : 
     722           4 :         if (tree != NULL) {
     723           4 :                 if (h != NULL) {
     724           4 :                         smb2_util_close(tree, *h);
     725             :                 }
     726             : 
     727           4 :                 smb2_util_unlink(tree, fname);
     728             : 
     729           4 :                 talloc_free(tree);
     730             :         }
     731             : 
     732           4 :         talloc_free(mem_ctx);
     733             : 
     734           4 :         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           4 : static bool test_durable_open_reopen2(struct torture_context *tctx,
     743             :                                       struct smb2_tree *tree)
     744             : {
     745             :         NTSTATUS status;
     746           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     747             :         char fname[256];
     748             :         struct smb2_handle _h;
     749           4 :         struct smb2_handle *h = NULL;
     750             :         struct smb2_create io;
     751           4 :         bool ret = true;
     752             : 
     753             :         /* Choose a random name in case the state is left a little funky. */
     754           4 :         snprintf(fname, 256, "durable_open_reopen2_%s.dat",
     755             :                  generate_random_str(tctx, 8));
     756             : 
     757           4 :         smb2_util_unlink(tree, fname);
     758             : 
     759           4 :         smb2_oplock_create_share(&io, fname,
     760             :                                  smb2_util_share_access(""),
     761           4 :                                  smb2_util_oplock_level("b"));
     762           4 :         io.in.durable_open = true;
     763             : 
     764           4 :         status = smb2_create(tree, mem_ctx, &io);
     765           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     766           4 :         _h = io.out.file.handle;
     767           4 :         h = &_h;
     768           4 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     769           4 :         CHECK_VAL(io.out.durable_open, true);
     770           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     771             : 
     772             :         /* disconnect, leaving the durable in place */
     773           4 :         TALLOC_FREE(tree);
     774             : 
     775           4 :         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           4 :         ZERO_STRUCT(io);
     782             :         /* the path name is ignored by the server */
     783           4 :         io.in.fname = fname;
     784           4 :         io.in.durable_handle = h; /* durable v1 reconnect request */
     785           4 :         h = NULL;
     786             : 
     787           4 :         status = smb2_create(tree, mem_ctx, &io);
     788           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     789           4 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     790           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     791           4 :         _h = io.out.file.handle;
     792           4 :         h = &_h;
     793             : 
     794             :         /* disconnect again, leaving the durable in place */
     795           4 :         TALLOC_FREE(tree);
     796             : 
     797           4 :         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           4 :         ZERO_STRUCT(io);
     809             :         /* the path name is ignored by the server */
     810           4 :         io.in.security_flags = 0x78;
     811           4 :         io.in.oplock_level = 0x78;
     812           4 :         io.in.impersonation_level = 0x12345678;
     813           4 :         io.in.create_flags = 0x12345678;
     814           4 :         io.in.reserved = 0x12345678;
     815           4 :         io.in.desired_access = 0x12345678;
     816           4 :         io.in.file_attributes = 0x12345678;
     817           4 :         io.in.share_access = 0x12345678;
     818           4 :         io.in.create_disposition = 0x12345678;
     819           4 :         io.in.create_options = 0x12345678;
     820           4 :         io.in.fname = "__non_existing_fname__";
     821           4 :         io.in.durable_handle = h; /* durable v1 reconnect request */
     822           4 :         h = NULL;
     823             : 
     824           4 :         status = smb2_create(tree, mem_ctx, &io);
     825           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     826           4 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     827           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     828           4 :         _h = io.out.file.handle;
     829           4 :         h = &_h;
     830             : 
     831             :         /* disconnect, leaving the durable in place */
     832           4 :         TALLOC_FREE(tree);
     833             : 
     834           4 :         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           4 :         ZERO_STRUCT(io);
     847             :         /* the path name is ignored by the server */
     848           4 :         io.in.fname = fname;
     849           4 :         io.in.durable_handle = h;  /* durable v1 reconnect request */
     850           4 :         io.in.durable_open = true; /* durable v1 handle request */
     851           4 :         h = NULL;
     852             : 
     853           4 :         status = smb2_create(tree, mem_ctx, &io);
     854           4 :         CHECK_STATUS(status, NT_STATUS_OK);
     855           4 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
     856           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
     857           4 :         _h = io.out.file.handle;
     858           4 :         h = &_h;
     859             : 
     860           4 : done:
     861           4 :         if (tree != NULL) {
     862           4 :                 if (h != NULL) {
     863           4 :                         smb2_util_close(tree, *h);
     864             :                 }
     865             : 
     866           4 :                 smb2_util_unlink(tree, fname);
     867             : 
     868           4 :                 talloc_free(tree);
     869             :         }
     870             : 
     871           4 :         talloc_free(mem_ctx);
     872             : 
     873           4 :         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           4 : static bool test_durable_open_reopen2_lease(struct torture_context *tctx,
     882             :                                             struct smb2_tree *tree)
     883             : {
     884             :         NTSTATUS status;
     885           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
     886             :         char fname[256];
     887             :         struct smb2_handle _h;
     888           4 :         struct smb2_handle *h = NULL;
     889             :         struct smb2_create io;
     890             :         struct smb2_lease ls;
     891             :         uint64_t lease_key;
     892           4 :         bool ret = true;
     893             :         struct smbcli_options options;
     894             :         uint32_t caps;
     895             : 
     896           4 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
     897           4 :         if (!(caps & SMB2_CAP_LEASING)) {
     898           2 :                 torture_skip(tctx, "leases are not supported");
     899             :         }
     900             : 
     901           2 :         options = tree->session->transport->options;
     902             : 
     903             :         /* Choose a random name in case the state is left a little funky. */
     904           2 :         snprintf(fname, 256, "durable_open_reopen2_%s.dat",
     905             :                  generate_random_str(tctx, 8));
     906             : 
     907           2 :         smb2_util_unlink(tree, fname);
     908             : 
     909           2 :         lease_key = random();
     910           2 :         smb2_lease_create(&io, &ls, false /* dir */, fname, lease_key,
     911             :                           smb2_util_lease_state("RWH"));
     912           2 :         io.in.durable_open = true;
     913             : 
     914           2 :         status = smb2_create(tree, mem_ctx, &io);
     915           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     916           2 :         _h = io.out.file.handle;
     917           2 :         h = &_h;
     918           2 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
     919             : 
     920           2 :         CHECK_VAL(io.out.durable_open, true);
     921           2 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
     922           2 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
     923           2 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
     924           2 :         CHECK_VAL(io.out.lease_response.lease_state,
     925             :                   smb2_util_lease_state("RWH"));
     926           2 :         CHECK_VAL(io.out.lease_response.lease_flags, 0);
     927           2 :         CHECK_VAL(io.out.lease_response.lease_duration, 0);
     928             : 
     929             :         /* disconnect, reconnect and then do durable reopen */
     930           2 :         TALLOC_FREE(tree);
     931             : 
     932           2 :         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           2 :         ZERO_STRUCT(io);
     948           2 :         io.in.fname = "";
     949           2 :         io.in.durable_handle = h;
     950           2 :         status = smb2_create(tree, mem_ctx, &io);
     951           2 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     952             : 
     953           2 :         ZERO_STRUCT(io);
     954           2 :         io.in.fname = "__non_existing_fname__";
     955           2 :         io.in.durable_handle = h;
     956           2 :         status = smb2_create(tree, mem_ctx, &io);
     957           2 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     958             : 
     959           2 :         ZERO_STRUCT(io);
     960           2 :         io.in.fname = fname;
     961           2 :         io.in.durable_handle = h;
     962           2 :         status = smb2_create(tree, mem_ctx, &io);
     963           2 :         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           2 :         ZERO_STRUCT(io);
     970           2 :         io.in.fname = fname;
     971           2 :         io.in.durable_open = false;
     972           2 :         io.in.durable_handle = h;
     973           2 :         io.in.lease_request = &ls;
     974           2 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
     975             :         /* a wrong lease key lets the request fail */
     976           2 :         ls.lease_key.data[0]++;
     977             : 
     978           2 :         status = smb2_create(tree, mem_ctx, &io);
     979           2 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     980             : 
     981             :         /* restore the correct lease key */
     982           2 :         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           2 :         ZERO_STRUCT(io);
     991           2 :         io.in.fname = "__non_existing_fname__";
     992           2 :         io.in.durable_open = false;
     993           2 :         io.in.durable_handle = h;
     994           2 :         io.in.lease_request = &ls;
     995           2 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
     996             : 
     997           2 :         status = smb2_create(tree, mem_ctx, &io);
     998           2 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     999             : 
    1000             :         /*
    1001             :          * Now for a succeeding reconnect:
    1002             :          */
    1003             : 
    1004           2 :         ZERO_STRUCT(io);
    1005           2 :         io.in.fname = fname;
    1006           2 :         io.in.durable_open = false;
    1007           2 :         io.in.durable_handle = h;
    1008           2 :         io.in.lease_request = &ls;
    1009           2 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
    1010             : 
    1011             :         /* the requested lease state is irrelevant */
    1012           2 :         ls.lease_state = smb2_util_lease_state("");
    1013             : 
    1014           2 :         h = NULL;
    1015             : 
    1016           2 :         status = smb2_create(tree, mem_ctx, &io);
    1017           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1018             : 
    1019           2 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1020           2 :         CHECK_VAL(io.out.durable_open, false);
    1021           2 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    1022           2 :         CHECK_VAL(io.out.persistent_open, false);
    1023           2 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    1024           2 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
    1025           2 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
    1026           2 :         CHECK_VAL(io.out.lease_response.lease_state,
    1027             :                   smb2_util_lease_state("RWH"));
    1028           2 :         CHECK_VAL(io.out.lease_response.lease_flags, 0);
    1029           2 :         CHECK_VAL(io.out.lease_response.lease_duration, 0);
    1030           2 :         _h = io.out.file.handle;
    1031           2 :         h = &_h;
    1032             : 
    1033             :         /* disconnect one more time */
    1034           2 :         TALLOC_FREE(tree);
    1035             : 
    1036           2 :         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           2 :         ZERO_STRUCT(io);
    1048             :         /*
    1049             :          * These are completely ignored by the server
    1050             :          */
    1051           2 :         io.in.security_flags = 0x78;
    1052           2 :         io.in.oplock_level = 0x78;
    1053           2 :         io.in.impersonation_level = 0x12345678;
    1054           2 :         io.in.create_flags = 0x12345678;
    1055           2 :         io.in.reserved = 0x12345678;
    1056           2 :         io.in.desired_access = 0x12345678;
    1057           2 :         io.in.file_attributes = 0x12345678;
    1058           2 :         io.in.share_access = 0x12345678;
    1059           2 :         io.in.create_disposition = 0x12345678;
    1060           2 :         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           2 :         io.in.fname = fname;
    1070           2 :         io.in.durable_open_v2 = false;
    1071           2 :         io.in.durable_handle_v2 = h;
    1072           2 :         io.in.lease_request = &ls;
    1073             : 
    1074             :         /* the requested lease state is irrelevant */
    1075           2 :         ls.lease_state = smb2_util_lease_state("");
    1076             : 
    1077           2 :         h = NULL;
    1078             : 
    1079           2 :         status = smb2_create(tree, mem_ctx, &io);
    1080           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1081             : 
    1082           2 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1083           2 :         CHECK_VAL(io.out.durable_open, false);
    1084           2 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    1085           2 :         CHECK_VAL(io.out.persistent_open, false);
    1086           2 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    1087           2 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
    1088           2 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
    1089           2 :         CHECK_VAL(io.out.lease_response.lease_state,
    1090             :                   smb2_util_lease_state("RWH"));
    1091           2 :         CHECK_VAL(io.out.lease_response.lease_flags, 0);
    1092           2 :         CHECK_VAL(io.out.lease_response.lease_duration, 0);
    1093             : 
    1094           2 :         _h = io.out.file.handle;
    1095           2 :         h = &_h;
    1096             : 
    1097           2 : done:
    1098           2 :         if (tree != NULL) {
    1099           2 :                 if (h != NULL) {
    1100           2 :                         smb2_util_close(tree, *h);
    1101             :                 }
    1102             : 
    1103           2 :                 smb2_util_unlink(tree, fname);
    1104             : 
    1105           2 :                 talloc_free(tree);
    1106             :         }
    1107             : 
    1108           2 :         talloc_free(mem_ctx);
    1109             : 
    1110           2 :         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           4 : static bool test_durable_open_reopen2_lease_v2(struct torture_context *tctx,
    1119             :                                                struct smb2_tree *tree)
    1120             : {
    1121             :         NTSTATUS status;
    1122           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1123             :         char fname[256];
    1124             :         struct smb2_handle _h;
    1125           4 :         struct smb2_handle *h = NULL;
    1126             :         struct smb2_create io;
    1127             :         struct smb2_lease ls;
    1128             :         uint64_t lease_key;
    1129           4 :         bool ret = true;
    1130             :         struct smbcli_options options;
    1131             :         uint32_t caps;
    1132             : 
    1133           4 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
    1134           4 :         if (!(caps & SMB2_CAP_LEASING)) {
    1135           2 :                 torture_skip(tctx, "leases are not supported");
    1136             :         }
    1137             : 
    1138           2 :         options = tree->session->transport->options;
    1139             : 
    1140             :         /* Choose a random name in case the state is left a little funky. */
    1141           2 :         snprintf(fname, 256, "durable_open_reopen2_%s.dat",
    1142             :                  generate_random_str(tctx, 8));
    1143             : 
    1144           2 :         smb2_util_unlink(tree, fname);
    1145             : 
    1146           2 :         lease_key = random();
    1147           2 :         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           2 :         io.in.durable_open = true;
    1151             : 
    1152           2 :         status = smb2_create(tree, mem_ctx, &io);
    1153           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1154           2 :         _h = io.out.file.handle;
    1155           2 :         h = &_h;
    1156           2 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1157             : 
    1158           2 :         CHECK_VAL(io.out.durable_open, true);
    1159           2 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    1160           2 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
    1161           2 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
    1162           2 :         CHECK_VAL(io.out.lease_response_v2.lease_state,
    1163             :                   smb2_util_lease_state("RWH"));
    1164           2 :         CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
    1165           2 :         CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
    1166             : 
    1167             :         /* disconnect, reconnect and then do durable reopen */
    1168           2 :         TALLOC_FREE(tree);
    1169             : 
    1170           2 :         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           2 :         ZERO_STRUCT(io);
    1185           2 :         io.in.fname = "";
    1186           2 :         io.in.durable_handle = h;
    1187           2 :         status = smb2_create(tree, mem_ctx, &io);
    1188           2 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1189             : 
    1190           2 :         ZERO_STRUCT(io);
    1191           2 :         io.in.fname = "__non_existing_fname__";
    1192           2 :         io.in.durable_handle = h;
    1193           2 :         status = smb2_create(tree, mem_ctx, &io);
    1194           2 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1195             : 
    1196           2 :         ZERO_STRUCT(io);
    1197           2 :         io.in.fname = fname;
    1198           2 :         io.in.durable_handle = h;
    1199           2 :         status = smb2_create(tree, mem_ctx, &io);
    1200           2 :         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           2 :         ZERO_STRUCT(io);
    1207           2 :         io.in.fname = fname;
    1208           2 :         io.in.durable_open = false;
    1209           2 :         io.in.durable_handle = h;
    1210           2 :         io.in.lease_request_v2 = &ls;
    1211           2 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
    1212             :         /* a wrong lease key lets the request fail */
    1213           2 :         ls.lease_key.data[0]++;
    1214             : 
    1215           2 :         status = smb2_create(tree, mem_ctx, &io);
    1216           2 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1217             : 
    1218             :         /* restore the correct lease key */
    1219           2 :         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           2 :         ZERO_STRUCT(io);
    1228           2 :         io.in.fname = "__non_existing_fname__";
    1229           2 :         io.in.durable_open = false;
    1230           2 :         io.in.durable_handle = h;
    1231           2 :         io.in.lease_request_v2 = &ls;
    1232           2 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
    1233             : 
    1234           2 :         status = smb2_create(tree, mem_ctx, &io);
    1235           2 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
    1236             : 
    1237             :         /*
    1238             :          * Now for a succeeding reconnect:
    1239             :          */
    1240             : 
    1241           2 :         ZERO_STRUCT(io);
    1242           2 :         io.in.fname = fname;
    1243           2 :         io.in.durable_open = false;
    1244           2 :         io.in.durable_handle = h;
    1245           2 :         io.in.lease_request_v2 = &ls;
    1246           2 :         io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
    1247             : 
    1248             :         /* the requested lease state is irrelevant */
    1249           2 :         ls.lease_state = smb2_util_lease_state("");
    1250             : 
    1251           2 :         h = NULL;
    1252             : 
    1253           2 :         status = smb2_create(tree, mem_ctx, &io);
    1254           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1255             : 
    1256           2 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1257           2 :         CHECK_VAL(io.out.durable_open, false);
    1258           2 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    1259           2 :         CHECK_VAL(io.out.persistent_open, false);
    1260           2 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    1261           2 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
    1262           2 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
    1263           2 :         CHECK_VAL(io.out.lease_response_v2.lease_state,
    1264             :                   smb2_util_lease_state("RWH"));
    1265           2 :         CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
    1266           2 :         CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
    1267           2 :         _h = io.out.file.handle;
    1268           2 :         h = &_h;
    1269             : 
    1270             :         /* disconnect one more time */
    1271           2 :         TALLOC_FREE(tree);
    1272             : 
    1273           2 :         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           2 :         ZERO_STRUCT(io);
    1285             :         /*
    1286             :          * These are completely ignored by the server
    1287             :          */
    1288           2 :         io.in.security_flags = 0x78;
    1289           2 :         io.in.oplock_level = 0x78;
    1290           2 :         io.in.impersonation_level = 0x12345678;
    1291           2 :         io.in.create_flags = 0x12345678;
    1292           2 :         io.in.reserved = 0x12345678;
    1293           2 :         io.in.desired_access = 0x12345678;
    1294           2 :         io.in.file_attributes = 0x12345678;
    1295           2 :         io.in.share_access = 0x12345678;
    1296           2 :         io.in.create_disposition = 0x12345678;
    1297           2 :         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           2 :         io.in.fname = fname;
    1307           2 :         io.in.durable_open_v2 = false;
    1308           2 :         io.in.durable_handle_v2 = h;
    1309           2 :         io.in.lease_request_v2 = &ls;
    1310             : 
    1311             :         /* the requested lease state is irrelevant */
    1312           2 :         ls.lease_state = smb2_util_lease_state("");
    1313             : 
    1314           2 :         h = NULL;
    1315             : 
    1316           2 :         status = smb2_create(tree, mem_ctx, &io);
    1317           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1318             : 
    1319           2 :         CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1320           2 :         CHECK_VAL(io.out.durable_open, false);
    1321           2 :         CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
    1322           2 :         CHECK_VAL(io.out.persistent_open, false);
    1323           2 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    1324           2 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
    1325           2 :         CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
    1326           2 :         CHECK_VAL(io.out.lease_response_v2.lease_state,
    1327             :                   smb2_util_lease_state("RWH"));
    1328           2 :         CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
    1329           2 :         CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
    1330             : 
    1331           2 :         _h = io.out.file.handle;
    1332           2 :         h = &_h;
    1333             : 
    1334           2 : done:
    1335           2 :         if (tree != NULL) {
    1336           2 :                 if (h != NULL) {
    1337           2 :                         smb2_util_close(tree, *h);
    1338             :                 }
    1339             : 
    1340           2 :                 smb2_util_unlink(tree, fname);
    1341             : 
    1342           2 :                 talloc_free(tree);
    1343             :         }
    1344             : 
    1345           2 :         talloc_free(mem_ctx);
    1346             : 
    1347           2 :         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           4 : static bool test_durable_open_reopen2a(struct torture_context *tctx,
    1356             :                                        struct smb2_tree *tree)
    1357             : {
    1358             :         NTSTATUS status;
    1359           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1360             :         char fname[256];
    1361             :         struct smb2_handle _h;
    1362           4 :         struct smb2_handle *h = NULL;
    1363             :         struct smb2_create io1, io2;
    1364             :         uint64_t previous_session_id;
    1365           4 :         bool ret = true;
    1366             :         struct smbcli_options options;
    1367             : 
    1368           4 :         options = tree->session->transport->options;
    1369             : 
    1370             :         /* Choose a random name in case the state is left a little funky. */
    1371           4 :         snprintf(fname, 256, "durable_open_reopen2_%s.dat",
    1372             :                  generate_random_str(tctx, 8));
    1373             : 
    1374           4 :         smb2_util_unlink(tree, fname);
    1375             : 
    1376           4 :         smb2_oplock_create_share(&io1, fname,
    1377             :                                  smb2_util_share_access(""),
    1378           4 :                                  smb2_util_oplock_level("b"));
    1379           4 :         io1.in.durable_open = true;
    1380             : 
    1381           4 :         status = smb2_create(tree, mem_ctx, &io1);
    1382           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1383           4 :         _h = io1.out.file.handle;
    1384           4 :         h = &_h;
    1385           4 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1386           4 :         CHECK_VAL(io1.out.durable_open, true);
    1387           4 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
    1388             : 
    1389             :         /* disconnect, reconnect and then do durable reopen */
    1390           4 :         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
    1391           4 :         talloc_free(tree);
    1392           4 :         tree = NULL;
    1393             : 
    1394           4 :         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           4 :         ZERO_STRUCT(io2);
    1403           4 :         io2.in.fname = fname;
    1404           4 :         io2.in.durable_handle = h;
    1405           4 :         h = NULL;
    1406             : 
    1407           4 :         status = smb2_create(tree, mem_ctx, &io2);
    1408           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1409           4 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1410           4 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
    1411           4 :         _h = io2.out.file.handle;
    1412           4 :         h = &_h;
    1413             : 
    1414           4 : done:
    1415           4 :         if (tree != NULL) {
    1416           4 :                 if (h != NULL) {
    1417           4 :                         smb2_util_close(tree, *h);
    1418             :                 }
    1419             : 
    1420           4 :                 smb2_util_unlink(tree, fname);
    1421             : 
    1422           4 :                 talloc_free(tree);
    1423             :         }
    1424             : 
    1425           4 :         talloc_free(mem_ctx);
    1426             : 
    1427           4 :         return ret;
    1428             : }
    1429             : 
    1430             : 
    1431             : /**
    1432             :  * basic test for doing a durable open:
    1433             :  * tdis, new tcon, try durable reopen (fails)
    1434             :  */
    1435           4 : static bool test_durable_open_reopen3(struct torture_context *tctx,
    1436             :                                       struct smb2_tree *tree)
    1437             : {
    1438             :         NTSTATUS status;
    1439           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1440             :         char fname[256];
    1441             :         struct smb2_handle _h;
    1442           4 :         struct smb2_handle *h = NULL;
    1443             :         struct smb2_create io1, io2;
    1444           4 :         bool ret = true;
    1445             :         struct smb2_tree *tree2;
    1446             : 
    1447             :         /* Choose a random name in case the state is left a little funky. */
    1448           4 :         snprintf(fname, 256, "durable_open_reopen3_%s.dat",
    1449             :                  generate_random_str(tctx, 8));
    1450             : 
    1451           4 :         smb2_util_unlink(tree, fname);
    1452             : 
    1453           4 :         smb2_oplock_create_share(&io1, fname,
    1454             :                                  smb2_util_share_access(""),
    1455           4 :                                  smb2_util_oplock_level("b"));
    1456           4 :         io1.in.durable_open = true;
    1457             : 
    1458           4 :         status = smb2_create(tree, mem_ctx, &io1);
    1459           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1460           4 :         _h = io1.out.file.handle;
    1461           4 :         h = &_h;
    1462           4 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1463           4 :         CHECK_VAL(io1.out.durable_open, true);
    1464           4 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
    1465             : 
    1466             :         /* disconnect, reconnect and then do durable reopen */
    1467           4 :         status = smb2_tdis(tree);
    1468           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1469             : 
    1470           4 :         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           4 :         ZERO_STRUCT(io2);
    1478           4 :         io2.in.fname = fname;
    1479           4 :         io2.in.durable_handle = h;
    1480             : 
    1481           4 :         status = smb2_create(tree2, mem_ctx, &io2);
    1482           4 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1483             : 
    1484           8 : done:
    1485           4 :         if (tree != NULL) {
    1486           4 :                 if (h != NULL) {
    1487           4 :                         smb2_util_close(tree, *h);
    1488             :                 }
    1489             : 
    1490           4 :                 smb2_util_unlink(tree2, fname);
    1491             : 
    1492           4 :                 talloc_free(tree);
    1493             :         }
    1494             : 
    1495           4 :         talloc_free(mem_ctx);
    1496             : 
    1497           4 :         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           4 : static bool test_durable_open_reopen4(struct torture_context *tctx,
    1505             :                                       struct smb2_tree *tree)
    1506             : {
    1507             :         NTSTATUS status;
    1508           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1509             :         char fname[256];
    1510             :         struct smb2_handle _h;
    1511           4 :         struct smb2_handle *h = NULL;
    1512             :         struct smb2_create io1, io2;
    1513           4 :         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           4 :         snprintf(fname, 256, "durable_open_reopen4_%s.dat",
    1520             :                  generate_random_str(tctx, 8));
    1521             : 
    1522           4 :         smb2_util_unlink(tree, fname);
    1523             : 
    1524           4 :         smb2_oplock_create_share(&io1, fname,
    1525             :                                  smb2_util_share_access(""),
    1526           4 :                                  smb2_util_oplock_level("b"));
    1527           4 :         io1.in.durable_open = true;
    1528             : 
    1529           4 :         status = smb2_create(tree, mem_ctx, &io1);
    1530           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1531           4 :         _h = io1.out.file.handle;
    1532           4 :         h = &_h;
    1533           4 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1534           4 :         CHECK_VAL(io1.out.durable_open, true);
    1535           4 :         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           4 :         transport = tree->session->transport;
    1542           4 :         status = smb2_logoff(tree->session);
    1543           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1544             : 
    1545           4 :         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           4 :         TALLOC_FREE(tree);
    1559             : 
    1560           4 :         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           4 :         ZERO_STRUCT(io2);
    1567           4 :         io2.in.fname = fname;
    1568           4 :         io2.in.durable_handle = h;
    1569           4 :         h = NULL;
    1570             : 
    1571           4 :         status = smb2_create(tree2, mem_ctx, &io2);
    1572           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1573             : 
    1574           4 :         _h = io2.out.file.handle;
    1575           4 :         h = &_h;
    1576           4 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1577           4 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
    1578             : 
    1579           8 : done:
    1580           4 :         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           4 :         talloc_free(mem_ctx);
    1591             : 
    1592           4 :         return ret;
    1593             : }
    1594             : 
    1595           4 : static bool test_durable_open_delete_on_close1(struct torture_context *tctx,
    1596             :                                                struct smb2_tree *tree)
    1597             : {
    1598             :         NTSTATUS status;
    1599           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1600             :         char fname[256];
    1601             :         struct smb2_handle _h;
    1602           4 :         struct smb2_handle *h = NULL;
    1603             :         struct smb2_create io1, io2;
    1604           4 :         bool ret = true;
    1605           4 :         uint8_t b = 0;
    1606             : 
    1607             :         /* Choose a random name in case the state is left a little funky. */
    1608           4 :         snprintf(fname, 256, "durable_open_delete_on_close1_%s.dat",
    1609             :                  generate_random_str(tctx, 8));
    1610             : 
    1611           4 :         smb2_util_unlink(tree, fname);
    1612             : 
    1613           4 :         smb2_oplock_create_share(&io1, fname,
    1614             :                                  smb2_util_share_access(""),
    1615           4 :                                  smb2_util_oplock_level("b"));
    1616           4 :         io1.in.durable_open = true;
    1617           4 :         io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
    1618             : 
    1619           4 :         status = smb2_create(tree, mem_ctx, &io1);
    1620           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1621           4 :         _h = io1.out.file.handle;
    1622           4 :         h = &_h;
    1623           4 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1624           4 :         CHECK_VAL(io1.out.durable_open, true);
    1625           4 :         CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
    1626             : 
    1627           4 :         status = smb2_util_write(tree, *h, &b, 0, 1);
    1628           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1629             : 
    1630             :         /* disconnect, leaving the durable handle in place */
    1631           4 :         TALLOC_FREE(tree);
    1632             : 
    1633           4 :         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           4 :         smb2_oplock_create_share(&io2, fname,
    1647             :                                  smb2_util_share_access(""),
    1648           4 :                                  smb2_util_oplock_level("b"));
    1649           4 :         io2.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
    1650             : 
    1651           4 :         status = smb2_create(tree, mem_ctx, &io2);
    1652           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1653           4 :         _h = io2.out.file.handle;
    1654           4 :         h = &_h;
    1655           4 :         CHECK_CREATED_SIZE(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE, 0, 0);
    1656           4 :         CHECK_VAL(io2.out.durable_open, false);
    1657           4 :         CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
    1658             : 
    1659           8 : done:
    1660           4 :         if (tree != NULL) {
    1661           4 :                 if (h != NULL) {
    1662           4 :                         smb2_util_close(tree, *h);
    1663             :                 }
    1664             : 
    1665           4 :                 smb2_util_unlink(tree, fname);
    1666             : 
    1667           4 :                 talloc_free(tree);
    1668             :         }
    1669             : 
    1670           4 :         talloc_free(mem_ctx);
    1671             : 
    1672           4 :         return ret;
    1673             : }
    1674             : 
    1675             : 
    1676           4 : static bool test_durable_open_delete_on_close2(struct torture_context *tctx,
    1677             :                                                struct smb2_tree *tree)
    1678             : {
    1679             :         NTSTATUS status;
    1680           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1681             :         char fname[256];
    1682             :         struct smb2_handle _h;
    1683           4 :         struct smb2_handle *h = NULL;
    1684             :         struct smb2_create io;
    1685           4 :         bool ret = true;
    1686           4 :         uint8_t b = 0;
    1687             :         uint64_t previous_session_id;
    1688             :         uint64_t alloc_size_step;
    1689             :         struct smbcli_options options;
    1690             : 
    1691           4 :         options = tree->session->transport->options;
    1692             : 
    1693             :         /* Choose a random name in case the state is left a little funky. */
    1694           4 :         snprintf(fname, 256, "durable_open_delete_on_close2_%s.dat",
    1695             :                  generate_random_str(tctx, 8));
    1696             : 
    1697           4 :         smb2_util_unlink(tree, fname);
    1698             : 
    1699           4 :         smb2_oplock_create_share(&io, fname,
    1700             :                                  smb2_util_share_access(""),
    1701           4 :                                  smb2_util_oplock_level("b"));
    1702           4 :         io.in.durable_open = true;
    1703           4 :         io.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
    1704             : 
    1705           4 :         status = smb2_create(tree, mem_ctx, &io);
    1706           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1707           4 :         _h = io.out.file.handle;
    1708           4 :         h = &_h;
    1709           4 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1710           4 :         CHECK_VAL(io.out.durable_open, true);
    1711           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    1712             : 
    1713           4 :         status = smb2_util_write(tree, *h, &b, 0, 1);
    1714           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1715             : 
    1716           4 :         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
    1717             : 
    1718             :         /* disconnect, leaving the durable handle in place */
    1719           4 :         TALLOC_FREE(tree);
    1720             : 
    1721           4 :         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           4 :         ZERO_STRUCT(io);
    1730           4 :         io.in.fname = fname;
    1731           4 :         io.in.durable_handle = h;
    1732             : 
    1733           4 :         status = smb2_create(tree, mem_ctx, &io);
    1734           4 :         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           4 : done:
    1775           4 :         if (tree != NULL) {
    1776           4 :                 if (h != NULL) {
    1777           4 :                         smb2_util_close(tree, *h);
    1778             :                 }
    1779             : 
    1780           4 :                 smb2_util_unlink(tree, fname);
    1781             : 
    1782           4 :                 talloc_free(tree);
    1783             :         }
    1784             : 
    1785           4 :         talloc_free(mem_ctx);
    1786             : 
    1787           4 :         return ret;
    1788             : }
    1789             : 
    1790             : /*
    1791             :    basic testing of SMB2 durable opens
    1792             :    regarding the position information on the handle
    1793             : */
    1794           4 : static bool test_durable_open_file_position(struct torture_context *tctx,
    1795             :                                             struct smb2_tree *tree)
    1796             : {
    1797           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1798             :         struct smb2_handle h;
    1799             :         struct smb2_create io;
    1800             :         NTSTATUS status;
    1801           4 :         const char *fname = "durable_open_position.dat";
    1802             :         union smb_fileinfo qfinfo;
    1803             :         union smb_setfileinfo sfinfo;
    1804           4 :         bool ret = true;
    1805             :         uint64_t pos;
    1806             :         uint64_t previous_session_id;
    1807             :         struct smbcli_options options;
    1808             : 
    1809           4 :         options = tree->session->transport->options;
    1810             : 
    1811           4 :         smb2_util_unlink(tree, fname);
    1812             : 
    1813           4 :         smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_BATCH);
    1814           4 :         io.in.durable_open = true;
    1815             : 
    1816           4 :         status = smb2_create(tree, mem_ctx, &io);
    1817           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1818           4 :         h = io.out.file.handle;
    1819           4 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1820           4 :         CHECK_VAL(io.out.durable_open, true);
    1821           4 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
    1822             : 
    1823             :         /* TODO: check extra blob content */
    1824             : 
    1825           4 :         ZERO_STRUCT(qfinfo);
    1826           4 :         qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
    1827           4 :         qfinfo.generic.in.file.handle = h;
    1828           4 :         status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
    1829           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1830           4 :         CHECK_VAL(qfinfo.position_information.out.position, 0);
    1831           4 :         pos = qfinfo.position_information.out.position;
    1832           4 :         torture_comment(tctx, "position: %llu\n",
    1833             :                         (unsigned long long)pos);
    1834             : 
    1835           4 :         ZERO_STRUCT(sfinfo);
    1836           4 :         sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
    1837           4 :         sfinfo.generic.in.file.handle = h;
    1838           4 :         sfinfo.position_information.in.position = 0x1000;
    1839           4 :         status = smb2_setinfo_file(tree, &sfinfo);
    1840           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1841             : 
    1842           4 :         ZERO_STRUCT(qfinfo);
    1843           4 :         qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
    1844           4 :         qfinfo.generic.in.file.handle = h;
    1845           4 :         status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
    1846           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1847           4 :         CHECK_VAL(qfinfo.position_information.out.position, 0x1000);
    1848           4 :         pos = qfinfo.position_information.out.position;
    1849           4 :         torture_comment(tctx, "position: %llu\n",
    1850             :                         (unsigned long long)pos);
    1851             : 
    1852           4 :         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
    1853             : 
    1854             :         /* tcp disconnect */
    1855           4 :         talloc_free(tree);
    1856           4 :         tree = NULL;
    1857             : 
    1858             :         /* do a session reconnect */
    1859           4 :         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           4 :         ZERO_STRUCT(qfinfo);
    1868           4 :         qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
    1869           4 :         qfinfo.generic.in.file.handle = h;
    1870           4 :         status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
    1871           4 :         CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
    1872             : 
    1873           4 :         ZERO_STRUCT(io);
    1874           4 :         io.in.fname = fname;
    1875           4 :         io.in.durable_handle = &h;
    1876             : 
    1877           4 :         status = smb2_create(tree, mem_ctx, &io);
    1878           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1879           4 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
    1880           4 :         CHECK_VAL(io.out.reserved, 0x00);
    1881           4 :         CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
    1882           4 :         CHECK_VAL(io.out.alloc_size, 0);
    1883           4 :         CHECK_VAL(io.out.size, 0);
    1884           4 :         CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
    1885           4 :         CHECK_VAL(io.out.reserved2, 0);
    1886             : 
    1887           4 :         h = io.out.file.handle;
    1888             : 
    1889           4 :         ZERO_STRUCT(qfinfo);
    1890           4 :         qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
    1891           4 :         qfinfo.generic.in.file.handle = h;
    1892           4 :         status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
    1893           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1894           4 :         CHECK_VAL(qfinfo.position_information.out.position, 0x1000);
    1895           4 :         pos = qfinfo.position_information.out.position;
    1896           4 :         torture_comment(tctx, "position: %llu\n",
    1897             :                         (unsigned long long)pos);
    1898             : 
    1899           4 :         smb2_util_close(tree, h);
    1900             : 
    1901           4 :         talloc_free(mem_ctx);
    1902             : 
    1903           4 :         smb2_util_unlink(tree, fname);
    1904             : 
    1905           4 : done:
    1906           4 :         talloc_free(tree);
    1907             : 
    1908           4 :         return ret;
    1909             : }
    1910             : 
    1911             : /*
    1912             :   Open, disconnect, oplock break, reconnect.
    1913             : */
    1914           4 : static bool test_durable_open_oplock(struct torture_context *tctx,
    1915             :                                      struct smb2_tree *tree1,
    1916             :                                      struct smb2_tree *tree2)
    1917             : {
    1918           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1919             :         struct smb2_create io1, io2;
    1920           4 :         struct smb2_handle h1 = {{0}};
    1921           4 :         struct smb2_handle h2 = {{0}};
    1922             :         NTSTATUS status;
    1923             :         char fname[256];
    1924           4 :         bool ret = true;
    1925             : 
    1926             :         /* Choose a random name in case the state is left a little funky. */
    1927           4 :         snprintf(fname, 256, "durable_open_oplock_%s.dat", generate_random_str(tctx, 8));
    1928             : 
    1929             :         /* Clean slate */
    1930           4 :         smb2_util_unlink(tree1, fname);
    1931             : 
    1932             :         /* Create with batch oplock */
    1933           4 :         smb2_oplock_create(&io1, fname, SMB2_OPLOCK_LEVEL_BATCH);
    1934           4 :         io1.in.durable_open = true;
    1935             : 
    1936           4 :         io2 = io1;
    1937           4 :         io2.in.create_disposition = NTCREATEX_DISP_OPEN;
    1938             : 
    1939           4 :         status = smb2_create(tree1, mem_ctx, &io1);
    1940           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1941           4 :         h1 = io1.out.file.handle;
    1942           4 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    1943           4 :         CHECK_VAL(io1.out.durable_open, true);
    1944           4 :         CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
    1945             : 
    1946             :         /* Disconnect after getting the batch */
    1947           4 :         talloc_free(tree1);
    1948           4 :         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           4 :         status = smb2_create(tree2, mem_ctx, &io2);
    1956           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    1957           4 :         h2 = io2.out.file.handle;
    1958           4 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    1959           4 :         CHECK_VAL(io2.out.durable_open, true);
    1960           4 :         CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
    1961             : 
    1962             :         /* What if tree1 tries to come back and reclaim? */
    1963           4 :         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           4 :         ZERO_STRUCT(io1);
    1970           4 :         io1.in.fname = fname;
    1971           4 :         io1.in.durable_handle = &h1;
    1972             : 
    1973           4 :         status = smb2_create(tree1, mem_ctx, &io1);
    1974           4 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    1975             : 
    1976           8 :  done:
    1977           4 :         smb2_util_close(tree2, h2);
    1978           4 :         smb2_util_unlink(tree2, fname);
    1979             : 
    1980           4 :         talloc_free(tree1);
    1981           4 :         talloc_free(tree2);
    1982             : 
    1983           4 :         return ret;
    1984             : }
    1985             : 
    1986             : /*
    1987             :   Open, disconnect, lease break, reconnect.
    1988             : */
    1989           4 : static bool test_durable_open_lease(struct torture_context *tctx,
    1990             :                                     struct smb2_tree *tree1,
    1991             :                                     struct smb2_tree *tree2)
    1992             : {
    1993           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    1994             :         struct smb2_create io1, io2;
    1995             :         struct smb2_lease ls1, ls2;
    1996           4 :         struct smb2_handle h1 = {{0}};
    1997           4 :         struct smb2_handle h2 = {{0}};
    1998             :         NTSTATUS status;
    1999             :         char fname[256];
    2000           4 :         bool ret = true;
    2001             :         uint64_t lease1, lease2;
    2002             :         uint32_t caps;
    2003             : 
    2004           4 :         caps = smb2cli_conn_server_capabilities(tree1->session->transport->conn);
    2005           4 :         if (!(caps & SMB2_CAP_LEASING)) {
    2006           2 :                 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           2 :         lease1 = random();
    2014           2 :         lease2 = random();
    2015           2 :         snprintf(fname, 256, "durable_open_lease_%s.dat", generate_random_str(tctx, 8));
    2016             : 
    2017             :         /* Clean slate */
    2018           2 :         smb2_util_unlink(tree1, fname);
    2019             : 
    2020             :         /* Create with lease */
    2021           2 :         smb2_lease_create(&io1, &ls1, false /* dir */, fname,
    2022             :                           lease1, smb2_util_lease_state("RHW"));
    2023           2 :         io1.in.durable_open = true;
    2024             : 
    2025           2 :         smb2_lease_create(&io2, &ls2, false /* dir */, fname,
    2026             :                           lease2, smb2_util_lease_state("RHW"));
    2027           2 :         io2.in.durable_open = true;
    2028           2 :         io2.in.create_disposition = NTCREATEX_DISP_OPEN;
    2029             : 
    2030           2 :         status = smb2_create(tree1, mem_ctx, &io1);
    2031           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2032           2 :         h1 = io1.out.file.handle;
    2033           2 :         CHECK_VAL(io1.out.durable_open, true);
    2034           2 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    2035             : 
    2036           2 :         CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    2037           2 :         CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease1);
    2038           2 :         CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease1);
    2039           2 :         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           2 :         talloc_free(tree1);
    2044           2 :         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           2 :         status = smb2_create(tree2, mem_ctx, &io2);
    2055           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2056           2 :         h2 = io2.out.file.handle;
    2057           2 :         CHECK_VAL(io2.out.durable_open, true);
    2058           2 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    2059             : 
    2060           2 :         CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    2061           2 :         CHECK_VAL(io2.out.lease_response.lease_key.data[0], lease2);
    2062           2 :         CHECK_VAL(io2.out.lease_response.lease_key.data[1], ~lease2);
    2063           2 :         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           2 :         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           2 :         ZERO_STRUCT(io1);
    2074           2 :         io1.in.fname = fname;
    2075           2 :         io1.in.durable_handle = &h1;
    2076           2 :         io1.in.lease_request = &ls1;
    2077             : 
    2078           2 :         status = smb2_create(tree1, mem_ctx, &io1);
    2079           2 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    2080             : 
    2081           4 :  done:
    2082           2 :         smb2_util_close(tree2, h2);
    2083           2 :         smb2_util_unlink(tree2, fname);
    2084             : 
    2085           2 :         talloc_free(tree1);
    2086           2 :         talloc_free(tree2);
    2087             : 
    2088           2 :         return ret;
    2089             : }
    2090             : 
    2091           4 : static bool test_durable_open_lock_oplock(struct torture_context *tctx,
    2092             :                                           struct smb2_tree *tree)
    2093             : {
    2094           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2095             :         struct smb2_create io;
    2096           4 :         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           4 :         bool ret = true;
    2102             : 
    2103             :         /*
    2104             :          */
    2105           4 :         snprintf(fname, 256, "durable_open_oplock_lock_%s.dat", generate_random_str(tctx, 8));
    2106             : 
    2107             :         /* Clean slate */
    2108           4 :         smb2_util_unlink(tree, fname);
    2109             : 
    2110             :         /* Create with oplock */
    2111             : 
    2112           4 :         smb2_oplock_create_share(&io, fname,
    2113             :                                  smb2_util_share_access(""),
    2114           4 :                                  smb2_util_oplock_level("b"));
    2115           4 :         io.in.durable_open = true;
    2116             : 
    2117           4 :         status = smb2_create(tree, mem_ctx, &io);
    2118           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    2119           4 :         h = io.out.file.handle;
    2120           4 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    2121             : 
    2122           4 :         CHECK_VAL(io.out.durable_open, true);
    2123           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    2124             : 
    2125           4 :         ZERO_STRUCT(lck);
    2126           4 :         ZERO_STRUCT(el);
    2127           4 :         lck.in.locks            = el;
    2128           4 :         lck.in.lock_count       = 0x0001;
    2129           4 :         lck.in.lock_sequence    = 0x00000000;
    2130           4 :         lck.in.file.handle      = h;
    2131           4 :         el[0].offset            = 0;
    2132           4 :         el[0].length            = 1;
    2133           4 :         el[0].reserved          = 0x00000000;
    2134           4 :         el[0].flags             = SMB2_LOCK_FLAG_EXCLUSIVE;
    2135           4 :         status = smb2_lock(tree, &lck);
    2136           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    2137             : 
    2138             :         /* Disconnect/Reconnect. */
    2139           4 :         talloc_free(tree);
    2140           4 :         tree = NULL;
    2141             : 
    2142           4 :         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           4 :         ZERO_STRUCT(io);
    2149           4 :         io.in.fname = fname;
    2150           4 :         io.in.durable_handle = &h;
    2151             : 
    2152           4 :         status = smb2_create(tree, mem_ctx, &io);
    2153           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    2154           4 :         h = io.out.file.handle;
    2155             : 
    2156           4 :         lck.in.file.handle      = h;
    2157           4 :         el[0].flags             = SMB2_LOCK_FLAG_UNLOCK;
    2158           4 :         status = smb2_lock(tree, &lck);
    2159           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    2160             : 
    2161           8 :  done:
    2162           4 :         smb2_util_close(tree, h);
    2163           4 :         smb2_util_unlink(tree, fname);
    2164           4 :         talloc_free(tree);
    2165             : 
    2166           4 :         return ret;
    2167             : }
    2168             : 
    2169             : /*
    2170             :   Open, take BRL, disconnect, reconnect.
    2171             : */
    2172           4 : static bool test_durable_open_lock_lease(struct torture_context *tctx,
    2173             :                                          struct smb2_tree *tree)
    2174             : {
    2175           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2176             :         struct smb2_create io;
    2177             :         struct smb2_lease ls;
    2178           4 :         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           4 :         bool ret = true;
    2184             :         uint64_t lease;
    2185             :         uint32_t caps;
    2186             :         struct smbcli_options options;
    2187             : 
    2188           4 :         options = tree->session->transport->options;
    2189             : 
    2190           4 :         caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
    2191           4 :         if (!(caps & SMB2_CAP_LEASING)) {
    2192           2 :                 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           2 :         lease = random();
    2200           2 :         snprintf(fname, 256, "durable_open_lease_lock_%s.dat", generate_random_str(tctx, 8));
    2201             : 
    2202             :         /* Clean slate */
    2203           2 :         smb2_util_unlink(tree, fname);
    2204             : 
    2205             :         /* Create with lease */
    2206             : 
    2207           2 :         smb2_lease_create(&io, &ls, false /* dir */, fname, lease,
    2208             :                           smb2_util_lease_state("RWH"));
    2209           2 :         io.in.durable_open              = true;
    2210             : 
    2211           2 :         status = smb2_create(tree, mem_ctx, &io);
    2212           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2213           2 :         h = io.out.file.handle;
    2214           2 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    2215             : 
    2216           2 :         CHECK_VAL(io.out.durable_open, true);
    2217           2 :         CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    2218           2 :         CHECK_VAL(io.out.lease_response.lease_key.data[0], lease);
    2219           2 :         CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease);
    2220           2 :         CHECK_VAL(io.out.lease_response.lease_state,
    2221             :             SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
    2222             : 
    2223           2 :         ZERO_STRUCT(lck);
    2224           2 :         ZERO_STRUCT(el);
    2225           2 :         lck.in.locks            = el;
    2226           2 :         lck.in.lock_count       = 0x0001;
    2227           2 :         lck.in.lock_sequence    = 0x00000000;
    2228           2 :         lck.in.file.handle      = h;
    2229           2 :         el[0].offset            = 0;
    2230           2 :         el[0].length            = 1;
    2231           2 :         el[0].reserved          = 0x00000000;
    2232           2 :         el[0].flags             = SMB2_LOCK_FLAG_EXCLUSIVE;
    2233           2 :         status = smb2_lock(tree, &lck);
    2234           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2235             : 
    2236             :         /* Disconnect/Reconnect. */
    2237           2 :         talloc_free(tree);
    2238           2 :         tree = NULL;
    2239             : 
    2240           2 :         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           2 :         ZERO_STRUCT(io);
    2247           2 :         io.in.fname = fname;
    2248           2 :         io.in.durable_handle = &h;
    2249           2 :         io.in.lease_request = &ls;
    2250             : 
    2251           2 :         status = smb2_create(tree, mem_ctx, &io);
    2252           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2253           2 :         h = io.out.file.handle;
    2254             : 
    2255           2 :         lck.in.file.handle      = h;
    2256           2 :         el[0].flags             = SMB2_LOCK_FLAG_UNLOCK;
    2257           2 :         status = smb2_lock(tree, &lck);
    2258           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2259             : 
    2260           4 :  done:
    2261           2 :         smb2_util_close(tree, h);
    2262           2 :         smb2_util_unlink(tree, fname);
    2263           2 :         talloc_free(tree);
    2264             : 
    2265           2 :         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           4 : static bool test_durable_open_open2_lease(struct torture_context *tctx,
    2277             :                                           struct smb2_tree *tree1,
    2278             :                                           struct smb2_tree *tree2)
    2279             : {
    2280           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2281             :         struct smb2_create io1, io2;
    2282             :         struct smb2_lease ls;
    2283           4 :         struct smb2_handle h1 = {{0}};
    2284           4 :         struct smb2_handle h2 = {{0}};
    2285             :         NTSTATUS status;
    2286             :         char fname[256];
    2287           4 :         bool ret = true;
    2288             :         uint64_t lease;
    2289             :         uint32_t caps;
    2290             :         struct smbcli_options options;
    2291             : 
    2292           4 :         options = tree1->session->transport->options;
    2293             : 
    2294           4 :         caps = smb2cli_conn_server_capabilities(tree1->session->transport->conn);
    2295           4 :         if (!(caps & SMB2_CAP_LEASING)) {
    2296           2 :                 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           2 :         lease = random();
    2304           2 :         snprintf(fname, 256, "durable_open_open2_lease_%s.dat",
    2305             :                  generate_random_str(tctx, 8));
    2306             : 
    2307             :         /* Clean slate */
    2308           2 :         smb2_util_unlink(tree1, fname);
    2309             : 
    2310             :         /* Create with lease */
    2311           2 :         smb2_lease_create_share(&io1, &ls, false /* dir */, fname,
    2312             :                                 smb2_util_share_access(""),
    2313             :                                 lease,
    2314             :                                 smb2_util_lease_state("RH"));
    2315           2 :         io1.in.durable_open = true;
    2316             : 
    2317           2 :         status = smb2_create(tree1, mem_ctx, &io1);
    2318           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2319           2 :         h1 = io1.out.file.handle;
    2320           2 :         CHECK_VAL(io1.out.durable_open, true);
    2321           2 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    2322             : 
    2323           2 :         CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
    2324           2 :         CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease);
    2325           2 :         CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease);
    2326           2 :         CHECK_VAL(io1.out.lease_response.lease_state,
    2327             :                   smb2_util_lease_state("RH"));
    2328             : 
    2329             :         /* Disconnect */
    2330           2 :         talloc_free(tree1);
    2331           2 :         tree1 = NULL;
    2332             : 
    2333             :         /* Open the file in tree2 */
    2334           2 :         smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
    2335             : 
    2336           2 :         status = smb2_create(tree2, mem_ctx, &io2);
    2337           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2338           2 :         h2 = io2.out.file.handle;
    2339           2 :         CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
    2340             : 
    2341             :         /* Reconnect */
    2342           2 :         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           2 :         ZERO_STRUCT(io1);
    2349           2 :         io1.in.fname = fname;
    2350           2 :         io1.in.durable_handle = &h1;
    2351           2 :         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           2 :         status = smb2_create(tree1, mem_ctx, &io1);
    2359           2 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    2360           2 :         h1 = io1.out.file.handle;
    2361             : 
    2362           2 :  done:
    2363           2 :         if (tree1 != NULL){
    2364           2 :                 smb2_util_close(tree1, h1);
    2365           2 :                 smb2_util_unlink(tree1, fname);
    2366           2 :                 talloc_free(tree1);
    2367             :         }
    2368             : 
    2369           2 :         smb2_util_close(tree2, h2);
    2370           2 :         smb2_util_unlink(tree2, fname);
    2371           2 :         talloc_free(tree2);
    2372             : 
    2373           2 :         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           4 : static bool test_durable_open_open2_oplock(struct torture_context *tctx,
    2385             :                                            struct smb2_tree *tree1,
    2386             :                                            struct smb2_tree *tree2)
    2387             : {
    2388           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2389             :         struct smb2_create io1, io2;
    2390           4 :         struct smb2_handle h1 = {{0}};
    2391           4 :         struct smb2_handle h2 = {{0}};
    2392             :         NTSTATUS status;
    2393             :         char fname[256];
    2394           4 :         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           4 :         snprintf(fname, 256, "durable_open_open2_oplock_%s.dat",
    2401             :                  generate_random_str(tctx, 8));
    2402             : 
    2403             :         /* Clean slate */
    2404           4 :         smb2_util_unlink(tree1, fname);
    2405             : 
    2406             :         /* Create with batch oplock */
    2407           4 :         smb2_oplock_create(&io1, fname, SMB2_OPLOCK_LEVEL_BATCH);
    2408           4 :         io1.in.durable_open = true;
    2409             : 
    2410           4 :         status = smb2_create(tree1, mem_ctx, &io1);
    2411           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    2412           4 :         h1 = io1.out.file.handle;
    2413           4 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    2414           4 :         CHECK_VAL(io1.out.durable_open, true);
    2415           4 :         CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
    2416             : 
    2417             :         /* Disconnect */
    2418           4 :         talloc_free(tree1);
    2419           4 :         tree1 = NULL;
    2420             : 
    2421             :         /* Open the file in tree2 */
    2422           4 :         smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
    2423             : 
    2424           4 :         status = smb2_create(tree2, mem_ctx, &io2);
    2425           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    2426           4 :         h2 = io2.out.file.handle;
    2427           4 :         CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
    2428             : 
    2429             :         /* Reconnect */
    2430           4 :         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           4 :         ZERO_STRUCT(io1);
    2437           4 :         io1.in.fname = fname;
    2438           4 :         io1.in.durable_handle = &h1;
    2439             : 
    2440           4 :         status = smb2_create(tree1, mem_ctx, &io1);
    2441           4 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    2442           4 :         h1 = io1.out.file.handle;
    2443             : 
    2444           4 :  done:
    2445           4 :         smb2_util_close(tree2, h2);
    2446           4 :         smb2_util_unlink(tree2, fname);
    2447           4 :         if (tree1 != NULL) {
    2448           4 :                 smb2_util_close(tree1, h1);
    2449           4 :                 smb2_util_unlink(tree1, fname);
    2450             :         }
    2451             : 
    2452           4 :         talloc_free(tree1);
    2453           4 :         talloc_free(tree2);
    2454             : 
    2455           4 :         return ret;
    2456             : }
    2457             : 
    2458             : /**
    2459             :  * test behaviour with initial allocation size
    2460             :  */
    2461           4 : static bool test_durable_open_alloc_size(struct torture_context *tctx,
    2462             :                                          struct smb2_tree *tree)
    2463             : {
    2464             :         NTSTATUS status;
    2465           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2466             :         char fname[256];
    2467             :         struct smb2_handle _h;
    2468           4 :         struct smb2_handle *h = NULL;
    2469             :         struct smb2_create io;
    2470           4 :         bool ret = true;
    2471             :         uint64_t previous_session_id;
    2472             :         uint64_t alloc_size_step;
    2473           4 :         uint64_t initial_alloc_size = 0x1000;
    2474           4 :         const uint8_t *b = NULL;
    2475             :         struct smbcli_options options;
    2476             : 
    2477           4 :         options = tree->session->transport->options;
    2478             : 
    2479             :         /* Choose a random name in case the state is left a little funky. */
    2480           4 :         snprintf(fname, 256, "durable_open_alloc_size_%s.dat",
    2481             :                  generate_random_str(tctx, 8));
    2482             : 
    2483           4 :         smb2_util_unlink(tree, fname);
    2484             : 
    2485           4 :         smb2_oplock_create_share(&io, fname,
    2486             :                                  smb2_util_share_access(""),
    2487           4 :                                  smb2_util_oplock_level("b"));
    2488           4 :         io.in.durable_open = true;
    2489           4 :         io.in.alloc_size = initial_alloc_size;
    2490             : 
    2491           4 :         status = smb2_create(tree, mem_ctx, &io);
    2492           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    2493           4 :         _h = io.out.file.handle;
    2494           4 :         h = &_h;
    2495           4 :         CHECK_NOT_VAL(io.out.alloc_size, 0);
    2496           4 :         alloc_size_step = io.out.alloc_size;
    2497           4 :         CHECK_CREATED_SIZE(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE,
    2498             :                            alloc_size_step, 0);
    2499           4 :         CHECK_VAL(io.out.durable_open, true);
    2500           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    2501             : 
    2502             :         /* prepare buffer */
    2503           4 :         b = talloc_zero_size(mem_ctx, alloc_size_step);
    2504           4 :         CHECK_NOT_NULL(b);
    2505             : 
    2506           4 :         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
    2507             : 
    2508             :         /* disconnect, reconnect and then do durable reopen */
    2509           4 :         talloc_free(tree);
    2510           4 :         tree = NULL;
    2511             : 
    2512           4 :         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           4 :         ZERO_STRUCT(io);
    2521           4 :         io.in.fname = fname;
    2522           4 :         io.in.durable_handle = h;
    2523           4 :         h = NULL;
    2524             : 
    2525           4 :         status = smb2_create(tree, mem_ctx, &io);
    2526           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    2527           4 :         CHECK_CREATED_SIZE(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE,
    2528             :                            alloc_size_step, 0);
    2529           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    2530           4 :         _h = io.out.file.handle;
    2531           4 :         h = &_h;
    2532             : 
    2533           4 :         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
    2534             : 
    2535             :         /* write one byte */
    2536           4 :         status = smb2_util_write(tree, *h, b, 0, 1);
    2537           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    2538             : 
    2539             :         /* disconnect, reconnect and then do durable reopen */
    2540           4 :         talloc_free(tree);
    2541           4 :         tree = NULL;
    2542             : 
    2543           4 :         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           4 :         ZERO_STRUCT(io);
    2552           4 :         io.in.fname = fname;
    2553           4 :         io.in.durable_handle = h;
    2554           4 :         h = NULL;
    2555             : 
    2556           4 :         status = smb2_create(tree, mem_ctx, &io);
    2557           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    2558           4 :         CHECK_CREATED_SIZE(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE,
    2559             :                            alloc_size_step, 1);
    2560           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    2561           4 :         _h = io.out.file.handle;
    2562           4 :         h = &_h;
    2563             : 
    2564           4 :         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
    2565             : 
    2566             :         /* write more byte than initial allocation size */
    2567           4 :         status = smb2_util_write(tree, *h, b, 1, alloc_size_step);
    2568             : 
    2569             :         /* disconnect, reconnect and then do durable reopen */
    2570           4 :         talloc_free(tree);
    2571           4 :         tree = NULL;
    2572             : 
    2573           4 :         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           4 :         ZERO_STRUCT(io);
    2582           4 :         io.in.fname = fname;
    2583           4 :         io.in.durable_handle = h;
    2584           4 :         h = NULL;
    2585             : 
    2586           4 :         status = smb2_create(tree, mem_ctx, &io);
    2587           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    2588           4 :         CHECK_CREATED_SIZE(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE,
    2589             :                            alloc_size_step * 2, alloc_size_step + 1);
    2590           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    2591           4 :         _h = io.out.file.handle;
    2592           4 :         h = &_h;
    2593             : 
    2594           4 : done:
    2595           4 :         if (h != NULL) {
    2596           4 :                 smb2_util_close(tree, *h);
    2597             :         }
    2598             : 
    2599           4 :         smb2_util_unlink(tree, fname);
    2600             : 
    2601           4 :         talloc_free(tree);
    2602             : 
    2603           4 :         talloc_free(mem_ctx);
    2604             : 
    2605           4 :         return ret;
    2606             : }
    2607             : 
    2608             : /**
    2609             :  * test behaviour when a disconnect happens while creating a read-only file
    2610             :  */
    2611           4 : static bool test_durable_open_read_only(struct torture_context *tctx,
    2612             :                                         struct smb2_tree *tree)
    2613             : {
    2614             :         NTSTATUS status;
    2615           4 :         TALLOC_CTX *mem_ctx = talloc_new(tctx);
    2616             :         char fname[256];
    2617             :         struct smb2_handle _h;
    2618           4 :         struct smb2_handle *h = NULL;
    2619             :         struct smb2_create io;
    2620           4 :         bool ret = true;
    2621             :         uint64_t previous_session_id;
    2622           4 :         const uint8_t b = 0;
    2623           4 :         uint64_t alloc_size = 0;
    2624             :         struct smbcli_options options;
    2625             : 
    2626           4 :         options = tree->session->transport->options;
    2627             : 
    2628             :         /* Choose a random name in case the state is left a little funky. */
    2629           4 :         snprintf(fname, 256, "durable_open_initial_alloc_%s.dat",
    2630             :                  generate_random_str(tctx, 8));
    2631             : 
    2632           4 :         smb2_util_unlink(tree, fname);
    2633             : 
    2634           4 :         smb2_oplock_create_share(&io, fname,
    2635             :                                  smb2_util_share_access(""),
    2636           4 :                                  smb2_util_oplock_level("b"));
    2637           4 :         io.in.durable_open = true;
    2638           4 :         io.in.file_attributes = FILE_ATTRIBUTE_READONLY;
    2639             : 
    2640           4 :         status = smb2_create(tree, mem_ctx, &io);
    2641           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    2642           4 :         _h = io.out.file.handle;
    2643           4 :         h = &_h;
    2644           4 :         CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_ARCHIVE);
    2645           4 :         CHECK_VAL(io.out.durable_open, true);
    2646           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    2647             : 
    2648           4 :         previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
    2649             : 
    2650             :         /* write one byte */
    2651           4 :         status = smb2_util_write(tree, *h, &b, 0, 1);
    2652           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    2653             : 
    2654             :         /* disconnect, reconnect and then do durable reopen */
    2655           4 :         talloc_free(tree);
    2656           4 :         tree = NULL;
    2657             : 
    2658           4 :         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           4 :         ZERO_STRUCT(io);
    2667           4 :         io.in.fname = fname;
    2668           4 :         io.in.durable_handle = h;
    2669           4 :         h = NULL;
    2670             : 
    2671           4 :         status = smb2_create(tree, mem_ctx, &io);
    2672           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    2673           4 :         alloc_size = io.out.alloc_size;
    2674           4 :         CHECK_CREATED_SIZE(&io, EXISTED,
    2675             :                            FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_ARCHIVE,
    2676             :                            alloc_size, 1);
    2677           4 :         CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
    2678           4 :         _h = io.out.file.handle;
    2679           4 :         h = &_h;
    2680             : 
    2681             :         /* write one byte */
    2682           4 :         status = smb2_util_write(tree, *h, &b, 1, 1);
    2683           4 :         CHECK_STATUS(status, NT_STATUS_OK);
    2684             : 
    2685           8 : done:
    2686           4 :         if (h != NULL) {
    2687             :                 union smb_setfileinfo sfinfo;
    2688             : 
    2689           4 :                 ZERO_STRUCT(sfinfo);
    2690           4 :                 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
    2691           4 :                 sfinfo.basic_info.in.file.handle = *h;
    2692           4 :                 sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL;
    2693           4 :                 smb2_setinfo_file(tree, &sfinfo);
    2694             : 
    2695           4 :                 smb2_util_close(tree, *h);
    2696             :         }
    2697             : 
    2698           4 :         smb2_util_unlink(tree, fname);
    2699             : 
    2700           4 :         talloc_free(tree);
    2701             : 
    2702           4 :         talloc_free(mem_ctx);
    2703             : 
    2704           4 :         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        2353 : struct torture_suite *torture_smb2_durable_open_init(TALLOC_CTX *ctx)
    2756             : {
    2757        2353 :         struct torture_suite *suite =
    2758             :             torture_suite_create(ctx, "durable-open");
    2759             : 
    2760        2353 :         torture_suite_add_1smb2_test(suite, "open-oplock", test_durable_open_open_oplock);
    2761        2353 :         torture_suite_add_1smb2_test(suite, "open-lease", test_durable_open_open_lease);
    2762        2353 :         torture_suite_add_1smb2_test(suite, "reopen1", test_durable_open_reopen1);
    2763        2353 :         torture_suite_add_1smb2_test(suite, "reopen1a", test_durable_open_reopen1a);
    2764        2353 :         torture_suite_add_1smb2_test(suite, "reopen1a-lease", test_durable_open_reopen1a_lease);
    2765        2353 :         torture_suite_add_1smb2_test(suite, "reopen2", test_durable_open_reopen2);
    2766        2353 :         torture_suite_add_1smb2_test(suite, "reopen2-lease", test_durable_open_reopen2_lease);
    2767        2353 :         torture_suite_add_1smb2_test(suite, "reopen2-lease-v2", test_durable_open_reopen2_lease_v2);
    2768        2353 :         torture_suite_add_1smb2_test(suite, "reopen2a", test_durable_open_reopen2a);
    2769        2353 :         torture_suite_add_1smb2_test(suite, "reopen3", test_durable_open_reopen3);
    2770        2353 :         torture_suite_add_1smb2_test(suite, "reopen4", test_durable_open_reopen4);
    2771        2353 :         torture_suite_add_1smb2_test(suite, "delete_on_close1",
    2772             :                                      test_durable_open_delete_on_close1);
    2773        2353 :         torture_suite_add_1smb2_test(suite, "delete_on_close2",
    2774             :                                      test_durable_open_delete_on_close2);
    2775        2353 :         torture_suite_add_1smb2_test(suite, "file-position",
    2776             :             test_durable_open_file_position);
    2777        2353 :         torture_suite_add_2smb2_test(suite, "oplock", test_durable_open_oplock);
    2778        2353 :         torture_suite_add_2smb2_test(suite, "lease", test_durable_open_lease);
    2779        2353 :         torture_suite_add_1smb2_test(suite, "lock-oplock", test_durable_open_lock_oplock);
    2780        2353 :         torture_suite_add_1smb2_test(suite, "lock-lease", test_durable_open_lock_lease);
    2781        2353 :         torture_suite_add_2smb2_test(suite, "open2-lease",
    2782             :                                      test_durable_open_open2_lease);
    2783        2353 :         torture_suite_add_2smb2_test(suite, "open2-oplock",
    2784             :                                      test_durable_open_open2_oplock);
    2785        2353 :         torture_suite_add_1smb2_test(suite, "alloc-size",
    2786             :                                      test_durable_open_alloc_size);
    2787        2353 :         torture_suite_add_1smb2_test(suite, "read-only",
    2788             :                                      test_durable_open_read_only);
    2789             : 
    2790        2353 :         suite->description = talloc_strdup(suite, "SMB2-DURABLE-OPEN tests");
    2791             : 
    2792        2353 :         return suite;
    2793             : }
    2794             : 
    2795        2353 : struct torture_suite *torture_smb2_durable_open_disconnect_init(TALLOC_CTX *ctx)
    2796             : {
    2797        2353 :         struct torture_suite *suite =
    2798             :             torture_suite_create(ctx,
    2799             :                                  "durable-open-disconnect");
    2800             : 
    2801        2353 :         torture_suite_add_1smb2_test(suite, "open-oplock-disconnect",
    2802             :                                      test_durable_open_oplock_disconnect);
    2803             : 
    2804        2353 :         suite->description = talloc_strdup(suite,
    2805             :                                         "SMB2-DURABLE-OPEN-DISCONNECT tests");
    2806             : 
    2807        2353 :         return suite;
    2808             : }

Generated by: LCOV version 1.13