LCOV - code coverage report
Current view: top level - source4/torture/smb2 - notify.c (source / functions) Hit Total Coverage
Test: coverage report for master 6248eab5 Lines: 1353 1452 93.2 %
Date: 2021-08-25 13:27:56 Functions: 29 30 96.7 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    SMB2 notify test suite
       5             : 
       6             :    Copyright (C) Stefan Metzmacher 2006
       7             :    Copyright (C) Andrew Tridgell 2009
       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             : 
      28             : #include "torture/torture.h"
      29             : #include "torture/smb2/proto.h"
      30             : #include "librpc/gen_ndr/ndr_security.h"
      31             : #include "libcli/security/security.h"
      32             : #include "torture/util.h"
      33             : 
      34             : #include "system/filesys.h"
      35             : #include "auth/credentials/credentials.h"
      36             : #include "lib/cmdline/cmdline.h"
      37             : #include "librpc/gen_ndr/security.h"
      38             : 
      39             : #include "lib/events/events.h"
      40             : 
      41             : #include "libcli/raw/libcliraw.h"
      42             : #include "libcli/raw/raw_proto.h"
      43             : #include "libcli/libcli.h"
      44             : 
      45             : #define CHECK_STATUS(status, correct) do { \
      46             :         if (!NT_STATUS_EQUAL(status, correct)) { \
      47             :                 torture_result(torture, TORTURE_FAIL, \
      48             :                        "(%s) Incorrect status %s - should be %s\n", \
      49             :                        __location__, nt_errstr(status), nt_errstr(correct)); \
      50             :                 ret = false; \
      51             :                 goto done; \
      52             :         }} while (0)
      53             : 
      54             : #define CHECK_VAL(v, correct) do { \
      55             :         if ((v) != (correct)) { \
      56             :                 torture_result(torture, TORTURE_FAIL, \
      57             :                        "(%s) wrong value for %s  0x%x should be 0x%x\n", \
      58             :                        __location__, #v, (int)v, (int)correct); \
      59             :                 ret = false; \
      60             :                 goto done; \
      61             :         }} while (0)
      62             : 
      63             : #define CHECK_WIRE_STR(field, value) do { \
      64             :         if (!field.s || strcmp(field.s, value)) { \
      65             :                 torture_result(torture, TORTURE_FAIL, \
      66             :                         "(%s) %s [%s] != %s\n",  __location__, #field, \
      67             :                         field.s, value); \
      68             :                 ret = false; \
      69             :                 goto done; \
      70             :         }} while (0)
      71             : 
      72             : #define WAIT_FOR_ASYNC_RESPONSE(req) \
      73             :         while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) { \
      74             :                 if (tevent_loop_once(torture->ev) != 0) { \
      75             :                         break; \
      76             :                 } \
      77             :         }
      78             : 
      79             : #define BASEDIR "test_notify"
      80             : #define FNAME "smb2-notify01.dat"
      81             : 
      82           2 : static bool test_valid_request(struct torture_context *torture,
      83             :                                struct smb2_tree *tree)
      84             : {
      85           2 :         bool ret = true;
      86             :         NTSTATUS status;
      87             :         struct smb2_handle dh;
      88             :         struct smb2_notify n;
      89             :         struct smb2_request *req;
      90             :         uint32_t max_buffer_size;
      91             : 
      92           2 :         torture_comment(torture, "TESTING VALIDITY OF CHANGE NOTIFY REQUEST\n");
      93             : 
      94           2 :         smb2_transport_credits_ask_num(tree->session->transport, 256);
      95             : 
      96           2 :         smb2_util_unlink(tree, FNAME);
      97             : 
      98           2 :         status = smb2_util_roothandle(tree, &dh);
      99           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     100             : 
     101           2 :         max_buffer_size =
     102           2 :                 smb2cli_conn_max_trans_size(tree->session->transport->conn);
     103             : 
     104           2 :         n.in.recursive          = 0x0000;
     105           2 :         n.in.buffer_size        = max_buffer_size;
     106           2 :         n.in.file.handle        = dh;
     107           2 :         n.in.completion_filter  = FILE_NOTIFY_CHANGE_ALL;
     108           2 :         n.in.unknown            = 0x00000000;
     109           2 :         req = smb2_notify_send(tree, &n);
     110             : 
     111           2 :         while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
     112           8 :                 if (tevent_loop_once(torture->ev) != 0) {
     113           0 :                         break;
     114             :                 }
     115             :         }
     116             : 
     117           2 :         status = torture_setup_simple_file(torture, tree, FNAME);
     118           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     119             : 
     120           2 :         status = smb2_notify_recv(req, torture, &n);
     121           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     122           2 :         CHECK_VAL(n.out.num_changes, 1);
     123           2 :         CHECK_VAL(n.out.changes[0].action, NOTIFY_ACTION_ADDED);
     124           2 :         CHECK_WIRE_STR(n.out.changes[0].name, FNAME);
     125             : 
     126             :         /*
     127             :          * if the change response doesn't fit in the buffer
     128             :          * NOTIFY_ENUM_DIR is returned.
     129             :          */
     130           2 :         n.in.buffer_size        = 0x00000000;
     131           2 :         req = smb2_notify_send(tree, &n);
     132             : 
     133           2 :         while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
     134           8 :                 if (tevent_loop_once(torture->ev) != 0) {
     135           0 :                         break;
     136             :                 }
     137             :         }
     138             : 
     139           2 :         status = torture_setup_simple_file(torture, tree, FNAME);
     140           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     141             : 
     142           2 :         status = smb2_notify_recv(req, torture, &n);
     143           2 :         CHECK_STATUS(status, NT_STATUS_NOTIFY_ENUM_DIR);
     144             : 
     145             :         /*
     146             :          * if the change response fits in the buffer we get
     147             :          * NT_STATUS_OK again
     148             :          */
     149           2 :         n.in.buffer_size        = max_buffer_size;
     150           2 :         req = smb2_notify_send(tree, &n);
     151             : 
     152           2 :         while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
     153           8 :                 if (tevent_loop_once(torture->ev) != 0) {
     154           0 :                         break;
     155             :                 }
     156             :         }
     157             : 
     158           2 :         status = torture_setup_simple_file(torture, tree, FNAME);
     159           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     160             : 
     161           2 :         status = smb2_notify_recv(req, torture, &n);
     162           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     163           2 :         CHECK_VAL(n.out.num_changes, 3);
     164           0 :         CHECK_VAL(n.out.changes[0].action, NOTIFY_ACTION_REMOVED);
     165           0 :         CHECK_WIRE_STR(n.out.changes[0].name, FNAME);
     166           0 :         CHECK_VAL(n.out.changes[1].action, NOTIFY_ACTION_ADDED);
     167           0 :         CHECK_WIRE_STR(n.out.changes[1].name, FNAME);
     168           0 :         CHECK_VAL(n.out.changes[2].action, NOTIFY_ACTION_MODIFIED);
     169           0 :         CHECK_WIRE_STR(n.out.changes[2].name, FNAME);
     170             : 
     171             :         /* if the first notify returns NOTIFY_ENUM_DIR, all do */
     172           0 :         status = smb2_util_close(tree, dh);
     173           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     174           0 :         status = smb2_util_roothandle(tree, &dh);
     175           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     176             : 
     177           0 :         n.in.recursive          = 0x0000;
     178           0 :         n.in.buffer_size        = 0x00000001;
     179           0 :         n.in.file.handle        = dh;
     180           0 :         n.in.completion_filter  = FILE_NOTIFY_CHANGE_ALL;
     181           0 :         n.in.unknown            = 0x00000000;
     182           0 :         req = smb2_notify_send(tree, &n);
     183             : 
     184           0 :         while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
     185           0 :                 if (tevent_loop_once(torture->ev) != 0) {
     186           0 :                         break;
     187             :                 }
     188             :         }
     189             : 
     190           0 :         status = torture_setup_simple_file(torture, tree, FNAME);
     191           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     192             : 
     193           0 :         status = smb2_notify_recv(req, torture, &n);
     194           0 :         CHECK_STATUS(status, NT_STATUS_NOTIFY_ENUM_DIR);
     195             : 
     196           0 :         n.in.buffer_size        = max_buffer_size;
     197           0 :         req = smb2_notify_send(tree, &n);
     198           0 :         while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
     199           0 :                 if (tevent_loop_once(torture->ev) != 0) {
     200           0 :                         break;
     201             :                 }
     202             :         }
     203             : 
     204           0 :         status = torture_setup_simple_file(torture, tree, FNAME);
     205           0 :         CHECK_STATUS(status, NT_STATUS_OK);
     206             : 
     207           0 :         status = smb2_notify_recv(req, torture, &n);
     208           0 :         CHECK_STATUS(status, NT_STATUS_NOTIFY_ENUM_DIR);
     209             : 
     210             :         /* if the buffer size is too large, we get invalid parameter */
     211           0 :         n.in.recursive          = 0x0000;
     212           0 :         n.in.buffer_size        = max_buffer_size + 1;
     213           0 :         n.in.file.handle        = dh;
     214           0 :         n.in.completion_filter  = FILE_NOTIFY_CHANGE_ALL;
     215           0 :         n.in.unknown            = 0x00000000;
     216           0 :         req = smb2_notify_send(tree, &n);
     217           0 :         status = smb2_notify_recv(req, torture, &n);
     218           0 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
     219             : 
     220           2 : done:
     221           2 :         return ret;
     222             : }
     223             : 
     224             : /*
     225             :    basic testing of change notify on directories
     226             : */
     227             : 
     228             : #define BASEDIR_DIR BASEDIR "_DIR"
     229             : 
     230           2 : static bool torture_smb2_notify_dir(struct torture_context *torture,
     231             :                               struct smb2_tree *tree1,
     232             :                               struct smb2_tree *tree2)
     233             : {
     234           2 :         bool ret = true;
     235             :         NTSTATUS status;
     236             :         union smb_notify notify;
     237             :         union smb_open io;
     238             :         union smb_close cl;
     239             :         int i, count;
     240           2 :         struct smb2_handle h1 = {{0}};
     241           2 :         struct smb2_handle h2 = {{0}};
     242             :         struct smb2_request *req, *req2;
     243           2 :         const char *fname = BASEDIR_DIR "\\subdir-name";
     244             :         extern int torture_numops;
     245             : 
     246           2 :         torture_comment(torture, "TESTING CHANGE NOTIFY ON DIRECTORIES\n");
     247             : 
     248           2 :         smb2_deltree(tree1, BASEDIR_DIR);
     249           2 :         smb2_util_rmdir(tree1, BASEDIR_DIR);
     250             :         /*
     251             :           get a handle on the directory
     252             :         */
     253           2 :         ZERO_STRUCT(io.smb2);
     254           2 :         io.generic.level = RAW_OPEN_SMB2;
     255           2 :         io.smb2.in.create_flags = 0;
     256           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
     257           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
     258           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
     259           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
     260             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
     261           2 :         io.smb2.in.alloc_size = 0;
     262           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
     263           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
     264           2 :         io.smb2.in.security_flags = 0;
     265           2 :         io.smb2.in.fname = BASEDIR_DIR;
     266             : 
     267           2 :         status = smb2_create(tree1, torture, &(io.smb2));
     268           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     269           2 :         h1 = io.smb2.out.file.handle;
     270             : 
     271           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
     272           2 :         io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ;
     273           2 :         status = smb2_create(tree1, torture, &(io.smb2));
     274           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     275           2 :         h2 = io.smb2.out.file.handle;
     276             : 
     277             :         /* ask for a change notify,
     278             :            on file or directory name changes */
     279           2 :         ZERO_STRUCT(notify.smb2);
     280           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
     281           2 :         notify.smb2.in.buffer_size = 1000;
     282           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
     283           2 :         notify.smb2.in.file.handle = h1;
     284           2 :         notify.smb2.in.recursive = true;
     285             : 
     286           2 :         torture_comment(torture, "Testing notify cancel\n");
     287             : 
     288           2 :         req = smb2_notify_send(tree1, &(notify.smb2));
     289           2 :         smb2_cancel(req);
     290           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
     291           2 :         CHECK_STATUS(status, NT_STATUS_CANCELLED);
     292             : 
     293           2 :         torture_comment(torture, "Testing notify mkdir\n");
     294             : 
     295           2 :         req = smb2_notify_send(tree1, &(notify.smb2));
     296           2 :         smb2_util_mkdir(tree2, fname);
     297             : 
     298           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
     299           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     300             : 
     301           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
     302           2 :         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
     303           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
     304             : 
     305           2 :         torture_comment(torture, "Testing notify rmdir\n");
     306             : 
     307           2 :         req = smb2_notify_send(tree1, &(notify.smb2));
     308           2 :         smb2_util_rmdir(tree2, fname);
     309             : 
     310           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
     311           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     312           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
     313           2 :         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
     314           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
     315             : 
     316           2 :         torture_comment(torture,
     317             :                 "Testing notify mkdir - rmdir - mkdir - rmdir\n");
     318             : 
     319           2 :         smb2_util_mkdir(tree2, fname);
     320           2 :         smb2_util_rmdir(tree2, fname);
     321           2 :         smb2_util_mkdir(tree2, fname);
     322           2 :         smb2_util_rmdir(tree2, fname);
     323           2 :         smb_msleep(200);
     324           2 :         req = smb2_notify_send(tree1, &(notify.smb2));
     325           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
     326           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     327           2 :         CHECK_VAL(notify.smb2.out.num_changes, 4);
     328           2 :         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
     329           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
     330           2 :         CHECK_VAL(notify.smb2.out.changes[1].action, NOTIFY_ACTION_REMOVED);
     331           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[1].name, "subdir-name");
     332           2 :         CHECK_VAL(notify.smb2.out.changes[2].action, NOTIFY_ACTION_ADDED);
     333           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[2].name, "subdir-name");
     334           2 :         CHECK_VAL(notify.smb2.out.changes[3].action, NOTIFY_ACTION_REMOVED);
     335           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[3].name, "subdir-name");
     336             : 
     337           2 :         count = torture_numops;
     338           2 :         torture_comment(torture,
     339             :                 "Testing buffered notify on create of %d files\n", count);
     340          22 :         for (i=0;i<count;i++) {
     341             :                 struct smb2_handle h12;
     342          20 :                 char *fname2 = talloc_asprintf(torture,
     343             :                                                 BASEDIR_DIR "\\test%d.txt",
     344             :                                                 i);
     345             : 
     346          20 :                 ZERO_STRUCT(io.smb2);
     347          20 :                 io.generic.level = RAW_OPEN_SMB2;
     348          20 :                 io.smb2.in.create_flags = 0;
     349          20 :                 io.smb2.in.desired_access = SEC_FILE_ALL;
     350          20 :                 io.smb2.in.create_options =
     351             :                     NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
     352          20 :                 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
     353          20 :                 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
     354             :                                         NTCREATEX_SHARE_ACCESS_WRITE;
     355          20 :                 io.smb2.in.alloc_size = 0;
     356          20 :                 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
     357          20 :                 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
     358          20 :                 io.smb2.in.security_flags = 0;
     359          20 :                 io.smb2.in.fname = fname2;
     360             : 
     361          20 :                 status = smb2_create(tree1, torture, &(io.smb2));
     362          20 :                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
     363           0 :                         torture_comment(torture, "Failed to create %s \n",
     364             :                                fname);
     365           0 :                         ret = false;
     366           0 :                         goto done;
     367             :                 }
     368          20 :                 h12 = io.smb2.out.file.handle;
     369          20 :                 talloc_free(fname2);
     370          20 :                 smb2_util_close(tree1, h12);
     371             :         }
     372             : 
     373             :         /* (1st notify) setup a new notify on a different directory handle.
     374             :            This new notify won't see the events above. */
     375           2 :         notify.smb2.in.file.handle = h2;
     376           2 :         req2 = smb2_notify_send(tree1, &(notify.smb2));
     377             : 
     378             :         /* (2nd notify) whereas this notify will see the above buffered events,
     379             :            and it directly returns the buffered events */
     380           2 :         notify.smb2.in.file.handle = h1;
     381           2 :         req = smb2_notify_send(tree1, &(notify.smb2));
     382             : 
     383           2 :         status = smb2_util_unlink(tree1, BASEDIR_DIR "\\nonexistent.txt");
     384           2 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     385             : 
     386             :         /* (1st unlink) as the 2nd notify directly returns,
     387             :            this unlink is only seen by the 1st notify and
     388             :            the 3rd notify (later) */
     389           2 :         torture_comment(torture,
     390             :                 "Testing notify on unlink for the first file\n");
     391           2 :         status = smb2_util_unlink(tree2, BASEDIR_DIR "\\test0.txt");
     392           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     393             : 
     394             :         /* receive the reply from the 2nd notify */
     395           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
     396           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     397             : 
     398           2 :         CHECK_VAL(notify.smb2.out.num_changes, count);
     399          20 :         for (i=1;i<count;i++) {
     400          18 :                 CHECK_VAL(notify.smb2.out.changes[i].action,
     401             :                           NOTIFY_ACTION_ADDED);
     402             :         }
     403           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
     404             : 
     405           2 :         torture_comment(torture, "and now from the 1st notify\n");
     406           2 :         status = smb2_notify_recv(req2, torture, &(notify.smb2));
     407           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     408           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
     409           2 :         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
     410           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
     411             : 
     412           2 :         torture_comment(torture,
     413             :                 "(3rd notify) this notify will only see the 1st unlink\n");
     414           2 :         req = smb2_notify_send(tree1, &(notify.smb2));
     415             : 
     416           2 :         status = smb2_util_unlink(tree1, BASEDIR_DIR "\\nonexistent.txt");
     417           2 :         CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     418             : 
     419          20 :         for (i=1;i<count;i++) {
     420          18 :                 char *fname2 = talloc_asprintf(torture,
     421             :                               BASEDIR_DIR "\\test%d.txt", i);
     422          18 :                 status = smb2_util_unlink(tree2, fname2);
     423          18 :                 CHECK_STATUS(status, NT_STATUS_OK);
     424          18 :                 talloc_free(fname2);
     425             :         }
     426             : 
     427             :         /* receive the 3rd notify */
     428           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
     429           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     430           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
     431           2 :         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
     432           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
     433             : 
     434             :         /* and we now see the rest of the unlink calls on both
     435             :          * directory handles */
     436           2 :         notify.smb2.in.file.handle = h1;
     437           2 :         sleep(3);
     438           2 :         req = smb2_notify_send(tree1, &(notify.smb2));
     439           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
     440           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     441           2 :         CHECK_VAL(notify.smb2.out.num_changes, count-1);
     442          20 :         for (i=0;i<notify.smb2.out.num_changes;i++) {
     443          18 :                 CHECK_VAL(notify.smb2.out.changes[i].action,
     444             :                           NOTIFY_ACTION_REMOVED);
     445             :         }
     446           2 :         notify.smb2.in.file.handle = h2;
     447           2 :         req = smb2_notify_send(tree1, &(notify.smb2));
     448           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
     449           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     450           2 :         CHECK_VAL(notify.smb2.out.num_changes, count-1);
     451          20 :         for (i=0;i<notify.smb2.out.num_changes;i++) {
     452          18 :                 CHECK_VAL(notify.smb2.out.changes[i].action,
     453             :                           NOTIFY_ACTION_REMOVED);
     454             :         }
     455             : 
     456           2 :         torture_comment(torture,
     457             :         "Testing if a close() on the dir handle triggers the notify reply\n");
     458             : 
     459           2 :         notify.smb2.in.file.handle = h1;
     460           2 :         req = smb2_notify_send(tree1, &(notify.smb2));
     461             : 
     462           2 :         ZERO_STRUCT(cl.smb2);
     463           2 :         cl.smb2.level = RAW_CLOSE_SMB2;
     464           2 :         cl.smb2.in.file.handle = h1;
     465           2 :         status = smb2_close(tree1, &(cl.smb2));
     466           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     467             : 
     468           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
     469           2 :         CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
     470           2 :         CHECK_VAL(notify.smb2.out.num_changes, 9);
     471             : 
     472           4 : done:
     473           2 :         smb2_util_close(tree1, h1);
     474           2 :         smb2_util_close(tree1, h2);
     475           2 :         smb2_deltree(tree1, BASEDIR_DIR);
     476           2 :         return ret;
     477             : }
     478             : 
     479         522 : static struct smb2_handle custom_smb2_create(struct smb2_tree *tree,
     480             :                                                 struct torture_context *torture,
     481             :                                                 struct smb2_create *smb2)
     482             : {
     483             :         struct smb2_handle h1;
     484         522 :         bool ret = true;
     485             :         NTSTATUS status;
     486         522 :         smb2_deltree(tree, smb2->in.fname);
     487         522 :         status = smb2_create(tree, torture, smb2);
     488         522 :         CHECK_STATUS(status, NT_STATUS_OK);
     489         522 :         h1 = smb2->out.file.handle;
     490         522 : done:
     491         522 :         if (!ret) {
     492           0 :                 h1 = (struct smb2_handle) {
     493             :                         .data = { 0 , 0},
     494             :                 };
     495             :         }
     496         522 :         return h1;
     497             : }
     498             : 
     499             : /*
     500             :    testing of recursive change notify
     501             : */
     502             : 
     503             : #define BASEDIR_REC BASEDIR "_REC"
     504             : 
     505           2 : static bool torture_smb2_notify_recursive(struct torture_context *torture,
     506             :                                 struct smb2_tree *tree1,
     507             :                                 struct smb2_tree *tree2)
     508             : {
     509           2 :         bool ret = true;
     510             :         NTSTATUS status;
     511             :         union smb_notify notify;
     512             :         union smb_open io, io1;
     513             :         union smb_setfileinfo sinfo;
     514             :         struct smb2_handle h1;
     515             :         struct smb2_request *req1, *req2;
     516             : 
     517           2 :         smb2_deltree(tree1, BASEDIR_REC);
     518           2 :         smb2_util_rmdir(tree1, BASEDIR_REC);
     519             : 
     520           2 :         torture_comment(torture, "TESTING CHANGE NOTIFY WITH RECURSION\n");
     521             : 
     522             :         /*
     523             :           get a handle on the directory
     524             :         */
     525           2 :         ZERO_STRUCT(io.smb2);
     526           2 :         io.generic.level = RAW_OPEN_SMB2;
     527           2 :         io.smb2.in.create_flags = 0;
     528           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
     529           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
     530           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
     531           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
     532             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
     533           2 :         io.smb2.in.alloc_size = 0;
     534           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
     535           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
     536           2 :         io.smb2.in.security_flags = 0;
     537           2 :         io.smb2.in.fname = BASEDIR_REC;
     538             : 
     539           2 :         status = smb2_create(tree1, torture, &(io.smb2));
     540           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     541           2 :         h1 = io.smb2.out.file.handle;
     542             : 
     543             :         /* ask for a change notify, on file or directory name
     544             :            changes. Setup both with and without recursion */
     545           2 :         ZERO_STRUCT(notify.smb2);
     546           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
     547           2 :         notify.smb2.in.buffer_size = 1000;
     548           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
     549             :                                 FILE_NOTIFY_CHANGE_ATTRIBUTES |
     550             :                                 FILE_NOTIFY_CHANGE_CREATION;
     551           2 :         notify.smb2.in.file.handle = h1;
     552             : 
     553           2 :         notify.smb2.in.recursive = true;
     554           2 :         req1 = smb2_notify_send(tree1, &(notify.smb2));
     555           2 :         smb2_cancel(req1);
     556           2 :         status = smb2_notify_recv(req1, torture, &(notify.smb2));
     557           2 :         CHECK_STATUS(status, NT_STATUS_CANCELLED);
     558             : 
     559           2 :         notify.smb2.in.recursive = false;
     560           2 :         req2 = smb2_notify_send(tree1, &(notify.smb2));
     561           2 :         smb2_cancel(req2);
     562           2 :         status = smb2_notify_recv(req2, torture, &(notify.smb2));
     563           2 :         CHECK_STATUS(status, NT_STATUS_CANCELLED);
     564             : 
     565           2 :         ZERO_STRUCT(io1.smb2);
     566           2 :         io1.generic.level = RAW_OPEN_SMB2;
     567           2 :         io1.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
     568           2 :         io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
     569             :                                 SEC_RIGHTS_FILE_WRITE|
     570             :                                 SEC_RIGHTS_FILE_ALL;
     571           2 :         io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
     572           2 :         io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
     573           2 :         io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
     574             :                                 NTCREATEX_SHARE_ACCESS_WRITE |
     575             :                                 NTCREATEX_SHARE_ACCESS_DELETE;
     576           2 :         io1.smb2.in.alloc_size = 0;
     577           2 :         io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
     578           2 :         io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
     579           2 :         io1.smb2.in.security_flags = 0;
     580           2 :         io1.smb2.in.fname = BASEDIR_REC "\\subdir-name";
     581           2 :         status = smb2_create(tree2, torture, &(io1.smb2));
     582           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     583           2 :         smb2_util_close(tree2, io1.smb2.out.file.handle);
     584             : 
     585           2 :         io1.smb2.in.fname = BASEDIR_REC "\\subdir-name\\subname1";
     586           2 :         status = smb2_create(tree2, torture, &(io1.smb2));
     587           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     588           2 :         ZERO_STRUCT(sinfo);
     589           2 :         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
     590           2 :         sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
     591           2 :         sinfo.rename_information.in.overwrite = 0;
     592           2 :         sinfo.rename_information.in.root_fid = 0;
     593           2 :         sinfo.rename_information.in.new_name =
     594             :                                 BASEDIR_REC "\\subdir-name\\subname1-r";
     595           2 :         status = smb2_setinfo_file(tree2, &sinfo);
     596           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     597             : 
     598           2 :         io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
     599           2 :         io1.smb2.in.fname = BASEDIR_REC "\\subdir-name\\subname2";
     600           2 :         status = smb2_create(tree2, torture, &(io1.smb2));
     601           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     602           2 :         ZERO_STRUCT(sinfo);
     603           2 :         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
     604           2 :         sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
     605           2 :         sinfo.rename_information.in.overwrite = true;
     606           2 :         sinfo.rename_information.in.root_fid = 0;
     607           2 :         sinfo.rename_information.in.new_name = BASEDIR_REC "\\subname2-r";
     608           2 :         status = smb2_setinfo_file(tree2, &sinfo);
     609           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     610             : 
     611           2 :         io1.smb2.in.fname = BASEDIR_REC "\\subname2-r";
     612           2 :         io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
     613           2 :         status = smb2_create(tree2, torture, &(io1.smb2));
     614           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     615           2 :         ZERO_STRUCT(sinfo);
     616           2 :         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
     617           2 :         sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
     618           2 :         sinfo.rename_information.in.overwrite = true;
     619           2 :         sinfo.rename_information.in.root_fid = 0;
     620           2 :         sinfo.rename_information.in.new_name = BASEDIR_REC "\\subname3-r";
     621           2 :         status = smb2_setinfo_file(tree2, &sinfo);
     622           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     623             : 
     624           2 :         notify.smb2.in.completion_filter = 0;
     625           2 :         notify.smb2.in.recursive = true;
     626           2 :         smb_msleep(200);
     627           2 :         req1 = smb2_notify_send(tree1, &(notify.smb2));
     628             : 
     629           2 :         status = smb2_util_rmdir(tree2,
     630             :                 BASEDIR_REC "\\subdir-name\\subname1-r");
     631           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     632           2 :         status = smb2_util_rmdir(tree2,
     633             :                 BASEDIR_REC "\\subdir-name");
     634           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     635           2 :         status = smb2_util_unlink(tree2, BASEDIR_REC "\\subname3-r");
     636           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     637             : 
     638           2 :         notify.smb2.in.recursive = false;
     639           2 :         req2 = smb2_notify_send(tree1, &(notify.smb2));
     640             : 
     641           2 :         status = smb2_notify_recv(req1, torture, &(notify.smb2));
     642           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     643             : 
     644           2 :         CHECK_VAL(notify.smb2.out.num_changes, 9);
     645           0 :         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
     646           0 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
     647           0 :         CHECK_VAL(notify.smb2.out.changes[1].action, NOTIFY_ACTION_ADDED);
     648           0 :         CHECK_WIRE_STR(notify.smb2.out.changes[1].name, "subdir-name\\subname1");
     649           0 :         CHECK_VAL(notify.smb2.out.changes[2].action, NOTIFY_ACTION_OLD_NAME);
     650           0 :         CHECK_WIRE_STR(notify.smb2.out.changes[2].name, "subdir-name\\subname1");
     651           0 :         CHECK_VAL(notify.smb2.out.changes[3].action, NOTIFY_ACTION_NEW_NAME);
     652           0 :         CHECK_WIRE_STR(notify.smb2.out.changes[3].name, "subdir-name\\subname1-r");
     653           0 :         CHECK_VAL(notify.smb2.out.changes[4].action, NOTIFY_ACTION_ADDED);
     654           0 :         CHECK_WIRE_STR(notify.smb2.out.changes[4].name, "subdir-name\\subname2");
     655           0 :         CHECK_VAL(notify.smb2.out.changes[5].action, NOTIFY_ACTION_REMOVED);
     656           0 :         CHECK_WIRE_STR(notify.smb2.out.changes[5].name, "subdir-name\\subname2");
     657           0 :         CHECK_VAL(notify.smb2.out.changes[6].action, NOTIFY_ACTION_ADDED);
     658           0 :         CHECK_WIRE_STR(notify.smb2.out.changes[6].name, "subname2-r");
     659           0 :         CHECK_VAL(notify.smb2.out.changes[7].action, NOTIFY_ACTION_OLD_NAME);
     660           0 :         CHECK_WIRE_STR(notify.smb2.out.changes[7].name, "subname2-r");
     661           0 :         CHECK_VAL(notify.smb2.out.changes[8].action, NOTIFY_ACTION_NEW_NAME);
     662           0 :         CHECK_WIRE_STR(notify.smb2.out.changes[8].name, "subname3-r");
     663             : 
     664           2 : done:
     665           2 :         smb2_deltree(tree1, BASEDIR_REC);
     666           2 :         return ret;
     667             : }
     668             : 
     669             : /*
     670             :    testing of change notify mask change
     671             : */
     672             : 
     673             : #define BASEDIR_MC BASEDIR "_MC"
     674             : 
     675           2 : static bool torture_smb2_notify_mask_change(struct torture_context *torture,
     676             :                                             struct smb2_tree *tree1,
     677             :                                             struct smb2_tree *tree2)
     678             : {
     679           2 :         bool ret = true;
     680             :         NTSTATUS status;
     681             :         union smb_notify notify;
     682             :         union smb_open io, io1;
     683             :         struct smb2_handle h1;
     684             :         struct smb2_request *req1, *req2;
     685             :         union smb_setfileinfo sinfo;
     686             : 
     687           2 :         smb2_deltree(tree1, BASEDIR_MC);
     688           2 :         smb2_util_rmdir(tree1, BASEDIR_MC);
     689             : 
     690           2 :         torture_comment(torture, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
     691             : 
     692             :         /*
     693             :           get a handle on the directory
     694             :         */
     695           2 :         ZERO_STRUCT(io.smb2);
     696           2 :         io.generic.level = RAW_OPEN_SMB2;
     697           2 :         io.smb2.in.create_flags = 0;
     698           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
     699           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
     700           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
     701           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
     702             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
     703           2 :         io.smb2.in.alloc_size = 0;
     704           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
     705           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
     706           2 :         io.smb2.in.security_flags = 0;
     707           2 :         io.smb2.in.fname = BASEDIR_MC;
     708             : 
     709           2 :         status = smb2_create(tree1, torture, &(io.smb2));
     710           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     711           2 :         h1 = io.smb2.out.file.handle;
     712             : 
     713             :         /* ask for a change notify, on file or directory name
     714             :            changes. Setup both with and without recursion */
     715           2 :         ZERO_STRUCT(notify.smb2);
     716           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
     717           2 :         notify.smb2.in.buffer_size = 1000;
     718           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
     719           2 :         notify.smb2.in.file.handle = h1;
     720             : 
     721           2 :         notify.smb2.in.recursive = true;
     722           2 :         req1 = smb2_notify_send(tree1, &(notify.smb2));
     723             : 
     724           2 :         smb2_cancel(req1);
     725           2 :         status = smb2_notify_recv(req1, torture, &(notify.smb2));
     726           2 :         CHECK_STATUS(status, NT_STATUS_CANCELLED);
     727             : 
     728             : 
     729           2 :         notify.smb2.in.recursive = false;
     730           2 :         req2 = smb2_notify_send(tree1, &(notify.smb2));
     731             : 
     732           2 :         smb2_cancel(req2);
     733           2 :         status = smb2_notify_recv(req2, torture, &(notify.smb2));
     734           2 :         CHECK_STATUS(status, NT_STATUS_CANCELLED);
     735             : 
     736           2 :         notify.smb2.in.recursive = true;
     737           2 :         req1 = smb2_notify_send(tree1, &(notify.smb2));
     738             : 
     739             :         /* Set to hidden then back again. */
     740           2 :         ZERO_STRUCT(io1.smb2);
     741           2 :         io1.generic.level = RAW_OPEN_SMB2;
     742           2 :         io1.smb2.in.create_flags = 0;
     743           2 :         io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
     744             :                                 SEC_RIGHTS_FILE_WRITE|
     745             :                                 SEC_RIGHTS_FILE_ALL;
     746           2 :         io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
     747           2 :         io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
     748             :                                 NTCREATEX_SHARE_ACCESS_WRITE |
     749             :                                 NTCREATEX_SHARE_ACCESS_DELETE;
     750           2 :         io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
     751           2 :         io1.smb2.in.security_flags = 0;
     752           2 :         io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
     753           2 :         io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
     754           2 :         io1.smb2.in.fname = BASEDIR_MC "\\tname1";
     755             : 
     756           2 :         smb2_util_close(tree1,
     757             :                 custom_smb2_create(tree1, torture, &(io1.smb2)));
     758           2 :         status = smb2_util_setatr(tree1, BASEDIR_MC "\\tname1",
     759             :                                 FILE_ATTRIBUTE_HIDDEN);
     760           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     761           2 :         smb2_util_unlink(tree1, BASEDIR_MC "\\tname1");
     762             : 
     763           2 :         status = smb2_notify_recv(req1, torture, &(notify.smb2));
     764           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     765             : 
     766           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
     767           2 :         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
     768           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
     769             : 
     770             :         /* Now try and change the mask to include other events.
     771             :          * This should not work - once the mask is set on a directory
     772             :          * h1 it seems to be fixed until the fnum is closed. */
     773             : 
     774           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
     775             :                                         FILE_NOTIFY_CHANGE_ATTRIBUTES |
     776             :                                         FILE_NOTIFY_CHANGE_CREATION;
     777           2 :         notify.smb2.in.recursive = true;
     778           2 :         req1 = smb2_notify_send(tree1, &(notify.smb2));
     779             : 
     780           2 :         notify.smb2.in.recursive = false;
     781           2 :         req2 = smb2_notify_send(tree1, &(notify.smb2));
     782             : 
     783           2 :         io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
     784           2 :         io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
     785           2 :         io1.smb2.in.fname = BASEDIR_MC "\\subdir-name";
     786           2 :         status = smb2_create(tree2, torture, &(io1.smb2));
     787           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     788           2 :         smb2_util_close(tree2, io1.smb2.out.file.handle);
     789             : 
     790           2 :         ZERO_STRUCT(sinfo);
     791           2 :         io1.smb2.in.fname = BASEDIR_MC "\\subdir-name\\subname1";
     792           2 :         io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
     793           2 :         io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
     794           2 :         status = smb2_create(tree2, torture, &(io1.smb2));
     795           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     796           2 :         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
     797           2 :         sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
     798           2 :         sinfo.rename_information.in.overwrite = true;
     799           2 :         sinfo.rename_information.in.root_fid = 0;
     800           2 :         sinfo.rename_information.in.new_name =
     801             :                                 BASEDIR_MC "\\subdir-name\\subname1-r";
     802           2 :         status = smb2_setinfo_file(tree2, &sinfo);
     803           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     804             : 
     805           2 :         io1.smb2.in.fname = BASEDIR_MC "\\subdir-name\\subname2";
     806           2 :         io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
     807           2 :         io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
     808           2 :         status = smb2_create(tree2, torture, &(io1.smb2));
     809           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     810           2 :         sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
     811           2 :         sinfo.rename_information.in.new_name = BASEDIR_MC "\\subname2-r";
     812           2 :         status = smb2_setinfo_file(tree2, &sinfo);
     813           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     814           2 :         smb2_util_close(tree2, io1.smb2.out.file.handle);
     815             : 
     816           2 :         io1.smb2.in.fname = BASEDIR_MC "\\subname2-r";
     817           2 :         io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
     818           2 :         status = smb2_create(tree2, torture, &(io1.smb2));
     819           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     820           2 :         sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
     821           2 :         sinfo.rename_information.in.new_name = BASEDIR_MC "\\subname3-r";
     822           2 :         status = smb2_setinfo_file(tree2, &sinfo);
     823           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     824           2 :         smb2_util_close(tree2, io1.smb2.out.file.handle);
     825             : 
     826           2 :         status = smb2_util_rmdir(tree2, BASEDIR_MC "\\subdir-name\\subname1-r");
     827           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     828           2 :         status = smb2_util_rmdir(tree2, BASEDIR_MC "\\subdir-name");
     829           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     830           2 :         status = smb2_util_unlink(tree2, BASEDIR_MC "\\subname3-r");
     831           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     832             : 
     833           2 :         status = smb2_notify_recv(req1, torture, &(notify.smb2));
     834           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     835             : 
     836           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
     837           2 :         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
     838           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname2-r");
     839             : 
     840           2 :         status = smb2_notify_recv(req2, torture, &(notify.smb2));
     841           2 :         CHECK_STATUS(status, NT_STATUS_OK);
     842             : 
     843           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
     844           2 :         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
     845           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname3-r");
     846             : 
     847           2 :         if (!ret) {
     848           0 :                 goto done;
     849             :         }
     850             : 
     851           4 : done:
     852           2 :         smb2_deltree(tree1, BASEDIR_MC);
     853           2 :         return ret;
     854             : }
     855             : 
     856             : /*
     857             :    testing of mask bits for change notify
     858             : */
     859             : 
     860             : #define BASEDIR_MSK BASEDIR "_MSK"
     861             : 
     862           2 : static bool torture_smb2_notify_mask(struct torture_context *torture,
     863             :                                      struct smb2_tree *tree1,
     864             :                                      struct smb2_tree *tree2)
     865             : {
     866           2 :         bool ret = true;
     867             :         NTSTATUS status;
     868             :         union smb_notify notify;
     869             :         union smb_open io, io1;
     870             :         struct smb2_handle h1, h2;
     871             :         uint32_t mask;
     872             :         int i;
     873           2 :         char c = 1;
     874             :         union smb_setfileinfo sinfo;
     875             : 
     876           2 :         smb2_deltree(tree1, BASEDIR_MSK);
     877           2 :         smb2_util_rmdir(tree1, BASEDIR_MSK);
     878             : 
     879           2 :         torture_comment(torture, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
     880             : 
     881             : 
     882           2 :         ZERO_STRUCT(h1);
     883           2 :         ZERO_STRUCT(h2);
     884             :         /*
     885             :           get a handle on the directory
     886             :         */
     887           2 :         ZERO_STRUCT(io.smb2);
     888           2 :         io.generic.level = RAW_OPEN_SMB2;
     889           2 :         io.smb2.in.create_flags = 0;
     890           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
     891           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
     892           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
     893           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
     894             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
     895           2 :         io.smb2.in.alloc_size = 0;
     896           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
     897           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
     898           2 :         io.smb2.in.security_flags = 0;
     899           2 :         io.smb2.in.fname = BASEDIR_MSK;
     900             : 
     901           2 :         ZERO_STRUCT(notify.smb2);
     902           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
     903           2 :         notify.smb2.in.buffer_size = 1000;
     904           2 :         notify.smb2.in.recursive = true;
     905             : 
     906             : #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, \
     907             :                          expected, nchanges) \
     908             :         do { \
     909             :         do { for (mask=i=0;i<32;i++) { \
     910             :                 struct smb2_request *req; \
     911             :                 status = smb2_create(tree1, torture, &(io.smb2)); \
     912             :                 CHECK_STATUS(status, NT_STATUS_OK); \
     913             :                 h1 = io.smb2.out.file.handle; \
     914             :                 setup \
     915             :                 notify.smb2.in.file.handle = h1;        \
     916             :                 notify.smb2.in.completion_filter = ((uint32_t)1<<i); \
     917             :                 /* cancel initial requests so the buffer is setup */    \
     918             :                 req = smb2_notify_send(tree1, &(notify.smb2)); \
     919             :                 smb2_cancel(req); \
     920             :                 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
     921             :                 CHECK_STATUS(status, NT_STATUS_CANCELLED); \
     922             :                 /* send the change notify request */ \
     923             :                 req = smb2_notify_send(tree1, &(notify.smb2)); \
     924             :                 op \
     925             :                 smb_msleep(200); smb2_cancel(req); \
     926             :                 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
     927             :                 cleanup \
     928             :                 smb2_util_close(tree1, h1); \
     929             :                 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
     930             :                 CHECK_STATUS(status, NT_STATUS_OK); \
     931             :                 /* special case to cope with file rename behaviour */ \
     932             :                 if (nchanges == 2 && notify.smb2.out.num_changes == 1 && \
     933             :                     notify.smb2.out.changes[0].action == \
     934             :                         NOTIFY_ACTION_MODIFIED && \
     935             :                     ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
     936             :                     Action == NOTIFY_ACTION_OLD_NAME) { \
     937             :                         torture_comment(torture, \
     938             :                                 "(rename file special handling OK)\n"); \
     939             :                 } else if (nchanges != notify.smb2.out.num_changes) { \
     940             :                         torture_result(torture, TORTURE_FAIL, \
     941             :                                "ERROR: nchanges=%d expected=%d "\
     942             :                                "action=%d filter=0x%08x\n", \
     943             :                                notify.smb2.out.num_changes, \
     944             :                                nchanges, \
     945             :                                notify.smb2.out.changes[0].action, \
     946             :                                notify.smb2.in.completion_filter); \
     947             :                         ret = false; \
     948             :                 } else if (notify.smb2.out.changes[0].action != Action) { \
     949             :                         torture_result(torture, TORTURE_FAIL, \
     950             :                                "ERROR: nchanges=%d action=%d " \
     951             :                                "expectedAction=%d filter=0x%08x\n", \
     952             :                                notify.smb2.out.num_changes, \
     953             :                                notify.smb2.out.changes[0].action, \
     954             :                                Action, \
     955             :                                notify.smb2.in.completion_filter); \
     956             :                         ret = false; \
     957             :                 } else if (strcmp(notify.smb2.out.changes[0].name.s, \
     958             :                            "tname1") != 0) { \
     959             :                         torture_result(torture, TORTURE_FAIL, \
     960             :                                "ERROR: nchanges=%d action=%d " \
     961             :                                "filter=0x%08x name=%s\n", \
     962             :                                notify.smb2.out.num_changes, \
     963             :                                notify.smb2.out.changes[0].action, \
     964             :                                notify.smb2.in.completion_filter, \
     965             :                                notify.smb2.out.changes[0].name.s);      \
     966             :                         ret = false; \
     967             :                 } \
     968             :                 mask |= ((uint32_t)1<<i); \
     969             :         } \
     970             :         } while (0); \
     971             :         } while (0);
     972             : 
     973           2 :         torture_comment(torture, "Testing mkdir\n");
     974           2 :         NOTIFY_MASK_TEST("Testing mkdir",;,
     975             :                          smb2_util_mkdir(tree2, BASEDIR_MSK "\\tname1");,
     976             :                          smb2_util_rmdir(tree2, BASEDIR_MSK "\\tname1");,
     977             :                          NOTIFY_ACTION_ADDED,
     978             :                          FILE_NOTIFY_CHANGE_DIR_NAME, 1);
     979             : 
     980           2 :         torture_comment(torture, "Testing create file\n");
     981           2 :         ZERO_STRUCT(io1.smb2);
     982           2 :         io1.generic.level = RAW_OPEN_SMB2;
     983           2 :         io1.smb2.in.create_flags = 0;
     984           2 :         io1.smb2.in.desired_access = SEC_FILE_ALL;
     985           2 :         io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
     986           2 :         io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
     987             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
     988           2 :         io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
     989           2 :         io1.smb2.in.security_flags = 0;
     990           2 :         io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
     991           2 :         io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
     992           2 :         io1.smb2.in.fname = BASEDIR_MSK "\\tname1";
     993             : 
     994           2 :         NOTIFY_MASK_TEST("Testing create file",;,
     995             :                          smb2_util_close(tree2, custom_smb2_create(tree2,
     996             :                                                 torture, &(io1.smb2)));,
     997             :                          smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1");,
     998             :                          NOTIFY_ACTION_ADDED,
     999             :                          FILE_NOTIFY_CHANGE_FILE_NAME, 1);
    1000             : 
    1001           2 :         torture_comment(torture, "Testing unlink\n");
    1002           2 :         NOTIFY_MASK_TEST("Testing unlink",
    1003             :                          smb2_util_close(tree2, custom_smb2_create(tree2,
    1004             :                                                 torture, &(io1.smb2)));,
    1005             :                          smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1");,
    1006             :                          ;,
    1007             :                          NOTIFY_ACTION_REMOVED,
    1008             :                          FILE_NOTIFY_CHANGE_FILE_NAME, 1);
    1009             : 
    1010           2 :         torture_comment(torture, "Testing rmdir\n");
    1011           2 :         NOTIFY_MASK_TEST("Testing rmdir",
    1012             :                          smb2_util_mkdir(tree2, BASEDIR_MSK "\\tname1");,
    1013             :                          smb2_util_rmdir(tree2, BASEDIR_MSK "\\tname1");,
    1014             :                          ;,
    1015             :                          NOTIFY_ACTION_REMOVED,
    1016             :                          FILE_NOTIFY_CHANGE_DIR_NAME, 1);
    1017             : 
    1018           2 :         torture_comment(torture, "Testing rename file\n");
    1019           2 :         ZERO_STRUCT(sinfo);
    1020           2 :         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
    1021           2 :         sinfo.rename_information.in.file.handle = h1;
    1022           2 :         sinfo.rename_information.in.overwrite = true;
    1023           2 :         sinfo.rename_information.in.root_fid = 0;
    1024           2 :         sinfo.rename_information.in.new_name = BASEDIR_MSK "\\tname2";
    1025           2 :         NOTIFY_MASK_TEST("Testing rename file",
    1026             :                          smb2_util_close(tree2, custom_smb2_create(tree2,
    1027             :                                                 torture, &(io1.smb2)));,
    1028             :                          smb2_setinfo_file(tree2, &sinfo);,
    1029             :                          smb2_util_unlink(tree2, BASEDIR_MSK "\\tname2");,
    1030             :                          NOTIFY_ACTION_OLD_NAME,
    1031             :                          FILE_NOTIFY_CHANGE_FILE_NAME, 2);
    1032             : 
    1033           2 :         torture_comment(torture, "Testing rename dir\n");
    1034           2 :         ZERO_STRUCT(sinfo);
    1035           2 :         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
    1036           2 :         sinfo.rename_information.in.file.handle = h1;
    1037           2 :         sinfo.rename_information.in.overwrite = true;
    1038           2 :         sinfo.rename_information.in.root_fid = 0;
    1039           2 :         sinfo.rename_information.in.new_name = BASEDIR_MSK "\\tname2";
    1040           2 :         NOTIFY_MASK_TEST("Testing rename dir",
    1041             :                 smb2_util_mkdir(tree2, BASEDIR_MSK "\\tname1");,
    1042             :                 smb2_setinfo_file(tree2, &sinfo);,
    1043             :                 smb2_util_rmdir(tree2, BASEDIR_MSK "\\tname2");,
    1044             :                 NOTIFY_ACTION_OLD_NAME,
    1045             :                 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
    1046             : 
    1047           2 :         torture_comment(torture, "Testing set path attribute\n");
    1048           2 :         NOTIFY_MASK_TEST("Testing set path attribute",
    1049             :                 smb2_util_close(tree2, custom_smb2_create(tree2,
    1050             :                                        torture, &(io.smb2)));,
    1051             :                 smb2_util_setatr(tree2, BASEDIR_MSK "\\tname1",
    1052             :                                  FILE_ATTRIBUTE_HIDDEN);,
    1053             :                 smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1");,
    1054             :                 NOTIFY_ACTION_MODIFIED,
    1055             :                 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
    1056             : 
    1057           2 :         torture_comment(torture, "Testing set path write time\n");
    1058           2 :         ZERO_STRUCT(sinfo);
    1059           2 :         sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
    1060           2 :         sinfo.generic.in.file.handle = h1;
    1061           2 :         sinfo.basic_info.in.write_time = 1000;
    1062           2 :         NOTIFY_MASK_TEST("Testing set path write time",
    1063             :                 smb2_util_close(tree2, custom_smb2_create(tree2,
    1064             :                                        torture, &(io1.smb2)));,
    1065             :                 smb2_setinfo_file(tree2, &sinfo);,
    1066             :                 smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1");,
    1067             :                 NOTIFY_ACTION_MODIFIED,
    1068             :                 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
    1069             : 
    1070           2 :         if (torture_setting_bool(torture, "samba3", false)) {
    1071           2 :                 torture_comment(torture,
    1072             :                        "Samba3 does not yet support create times "
    1073             :                        "everywhere\n");
    1074             :         }
    1075             :         else {
    1076           0 :                 ZERO_STRUCT(sinfo);
    1077           0 :                 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
    1078           0 :                 sinfo.generic.in.file.handle = h1;
    1079           0 :                 sinfo.basic_info.in.create_time = 0;
    1080           0 :                 torture_comment(torture, "Testing set file create time\n");
    1081           0 :                 NOTIFY_MASK_TEST("Testing set file create time",
    1082             :                         smb2_create_complex_file(torture, tree2,
    1083             :                         BASEDIR_MSK "\\tname1", &h2);,
    1084             :                         smb2_setinfo_file(tree2, &sinfo);,
    1085             :                         (smb2_util_close(tree2, h2),
    1086             :                          smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1"));,
    1087             :                         NOTIFY_ACTION_MODIFIED,
    1088             :                         FILE_NOTIFY_CHANGE_CREATION, 1);
    1089             :         }
    1090             : 
    1091           2 :         ZERO_STRUCT(sinfo);
    1092           2 :         sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
    1093           2 :         sinfo.generic.in.file.handle = h1;
    1094           2 :         sinfo.basic_info.in.access_time = 0;
    1095           2 :         torture_comment(torture, "Testing set file access time\n");
    1096           2 :         NOTIFY_MASK_TEST("Testing set file access time",
    1097             :                 smb2_create_complex_file(torture,
    1098             :                         tree2,
    1099             :                         BASEDIR_MSK "\\tname1",
    1100             :                         &h2);,
    1101             :                 smb2_setinfo_file(tree2, &sinfo);,
    1102             :                 (smb2_util_close(tree2, h2),
    1103             :                 smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1"));,
    1104             :                 NOTIFY_ACTION_MODIFIED,
    1105             :                 FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
    1106             : 
    1107           2 :         ZERO_STRUCT(sinfo);
    1108           2 :         sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
    1109           2 :         sinfo.generic.in.file.handle = h1;
    1110           2 :         sinfo.basic_info.in.change_time = 0;
    1111           2 :         torture_comment(torture, "Testing set file change time\n");
    1112           2 :         NOTIFY_MASK_TEST("Testing set file change time",
    1113             :                 smb2_create_complex_file(torture,
    1114             :                         tree2,
    1115             :                         BASEDIR_MSK "\\tname1",
    1116             :                         &h2);,
    1117             :                 smb2_setinfo_file(tree2, &sinfo);,
    1118             :                 (smb2_util_close(tree2, h2),
    1119             :                 smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1"));,
    1120             :                 NOTIFY_ACTION_MODIFIED,
    1121             :                 0, 1);
    1122             : 
    1123             : 
    1124           2 :         torture_comment(torture, "Testing write\n");
    1125           2 :         NOTIFY_MASK_TEST("Testing write",
    1126             :                 smb2_create_complex_file(torture,
    1127             :                         tree2,
    1128             :                         BASEDIR_MSK "\\tname1",
    1129             :                         &h2);,
    1130             :                 smb2_util_write(tree2, h2, &c, 10000, 1);,
    1131             :                 (smb2_util_close(tree2, h2),
    1132             :                 smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1"));,
    1133             :                 NOTIFY_ACTION_MODIFIED,
    1134             :                 0, 1);
    1135             : 
    1136           2 : done:
    1137           2 :         smb2_deltree(tree1, BASEDIR_MSK);
    1138           2 :         return ret;
    1139             : }
    1140             : 
    1141             : #define BASEDIR_FL BASEDIR "_FL"
    1142             : /*
    1143             :   basic testing of change notify on files
    1144             : */
    1145           2 : static bool torture_smb2_notify_file(struct torture_context *torture,
    1146             :                                 struct smb2_tree *tree)
    1147             : {
    1148             :         NTSTATUS status;
    1149           2 :         bool ret = true;
    1150             :         union smb_open io;
    1151             :         union smb_close cl;
    1152             :         union smb_notify notify;
    1153             :         struct smb2_request *req;
    1154             :         struct smb2_handle h1;
    1155           2 :         const char *fname = BASEDIR_FL "\\file.txt";
    1156             : 
    1157           2 :         smb2_deltree(tree, BASEDIR_FL);
    1158           2 :         smb2_util_rmdir(tree, BASEDIR_FL);
    1159             : 
    1160           2 :         torture_comment(torture, "TESTING CHANGE NOTIFY ON FILES\n");
    1161           2 :         status = torture_smb2_testdir(tree, BASEDIR_FL, &h1);
    1162           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1163             : 
    1164           2 :         ZERO_STRUCT(io.smb2);
    1165           2 :         io.generic.level = RAW_OPEN_SMB2;
    1166           2 :         io.smb2.in.create_flags = 0;
    1167           2 :         io.smb2.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
    1168           2 :         io.smb2.in.create_options = 0;
    1169           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1170           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1171             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    1172           2 :         io.smb2.in.alloc_size = 0;
    1173           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    1174           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1175           2 :         io.smb2.in.security_flags = 0;
    1176           2 :         io.smb2.in.fname = fname;
    1177           2 :         status = smb2_create(tree, torture, &(io.smb2));
    1178           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1179           2 :         h1 = io.smb2.out.file.handle;
    1180             : 
    1181             :         /* ask for a change notify,
    1182             :            on file or directory name changes */
    1183           2 :         ZERO_STRUCT(notify.smb2);
    1184           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    1185           2 :         notify.smb2.in.file.handle = h1;
    1186           2 :         notify.smb2.in.buffer_size = 1000;
    1187           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
    1188           2 :         notify.smb2.in.recursive = false;
    1189             : 
    1190           2 :         torture_comment(torture,
    1191             :         "Testing if notifies on file handles are invalid (should be)\n");
    1192             : 
    1193           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    1194           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    1195           2 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
    1196             : 
    1197           2 :         ZERO_STRUCT(cl.smb2);
    1198           2 :         cl.close.level = RAW_CLOSE_SMB2;
    1199           2 :         cl.close.in.file.handle = h1;
    1200           2 :         status = smb2_close(tree, &(cl.smb2));
    1201           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1202             : 
    1203           2 :         status = smb2_util_unlink(tree, fname);
    1204           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1205             : 
    1206           4 : done:
    1207           2 :         smb2_deltree(tree, BASEDIR_FL);
    1208           2 :         return ret;
    1209             : }
    1210             : /*
    1211             :   basic testing of change notifies followed by a tdis
    1212             : */
    1213             : 
    1214             : #define BASEDIR_TD BASEDIR "_TD"
    1215             : 
    1216           2 : static bool torture_smb2_notify_tree_disconnect(
    1217             :                 struct torture_context *torture,
    1218             :                 struct smb2_tree *tree)
    1219             : {
    1220           2 :         bool ret = true;
    1221             :         NTSTATUS status;
    1222             :         union smb_notify notify;
    1223             :         union smb_open io;
    1224             :         struct smb2_handle h1;
    1225             :         struct smb2_request *req;
    1226             : 
    1227           2 :         smb2_deltree(tree, BASEDIR_TD);
    1228           2 :         smb2_util_rmdir(tree, BASEDIR_TD);
    1229             : 
    1230           2 :         torture_comment(torture, "TESTING CHANGE NOTIFY+CANCEL FOLLOWED BY "
    1231             :                         "TREE-DISCONNECT\n");
    1232             : 
    1233             :         /*
    1234             :           get a handle on the directory
    1235             :         */
    1236           2 :         ZERO_STRUCT(io.smb2);
    1237           2 :         io.generic.level = RAW_OPEN_SMB2;
    1238           2 :         io.smb2.in.create_flags = 0;
    1239           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
    1240           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1241           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1242           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1243             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    1244           2 :         io.smb2.in.alloc_size = 0;
    1245           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    1246           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1247           2 :         io.smb2.in.security_flags = 0;
    1248           2 :         io.smb2.in.fname = BASEDIR_TD;
    1249             : 
    1250           2 :         status = smb2_create(tree, torture, &(io.smb2));
    1251           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1252           2 :         h1 = io.smb2.out.file.handle;
    1253             : 
    1254             :         /* ask for a change notify,
    1255             :            on file or directory name changes */
    1256           2 :         ZERO_STRUCT(notify.smb2);
    1257           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    1258           2 :         notify.smb2.in.buffer_size = 1000;
    1259           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1260           2 :         notify.smb2.in.file.handle = h1;
    1261           2 :         notify.smb2.in.recursive = true;
    1262             : 
    1263           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    1264           2 :         smb2_cancel(req);
    1265           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    1266             : 
    1267           2 :         status = smb2_tdis(tree);
    1268           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1269             : 
    1270           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    1271             : 
    1272           2 :         smb2_notify_recv(req, torture, &(notify.smb2));
    1273           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1274           2 :         CHECK_VAL(notify.smb2.out.num_changes, 0);
    1275             : 
    1276           4 : done:
    1277           2 :         smb2_deltree(tree, BASEDIR_TD);
    1278           2 :         return ret;
    1279             : }
    1280             : 
    1281             : /*
    1282             :   testing of change notifies followed by a tdis - no cancel
    1283             : */
    1284             : 
    1285             : #define BASEDIR_NTDIS BASEDIR "_NTDIS"
    1286             : 
    1287           2 : static bool torture_smb2_notify_tree_disconnect_1(
    1288             :                 struct torture_context *torture,
    1289             :                 struct smb2_tree *tree)
    1290             : {
    1291           2 :         bool ret = true;
    1292             :         NTSTATUS status;
    1293             :         union smb_notify notify;
    1294             :         union smb_open io;
    1295             :         struct smb2_handle h1;
    1296             :         struct smb2_request *req;
    1297             : 
    1298           2 :         smb2_deltree(tree, BASEDIR_NTDIS);
    1299           2 :         smb2_util_rmdir(tree, BASEDIR_NTDIS);
    1300             : 
    1301           2 :         torture_comment(torture, "TESTING CHANGE NOTIFY ASYNC FOLLOWED BY "
    1302             :                         "TREE-DISCONNECT\n");
    1303             : 
    1304             :         /*
    1305             :           get a handle on the directory
    1306             :         */
    1307           2 :         ZERO_STRUCT(io.smb2);
    1308           2 :         io.generic.level = RAW_OPEN_SMB2;
    1309           2 :         io.smb2.in.create_flags = 0;
    1310           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
    1311           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1312           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1313           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1314             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    1315           2 :         io.smb2.in.alloc_size = 0;
    1316           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    1317           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1318           2 :         io.smb2.in.security_flags = 0;
    1319           2 :         io.smb2.in.fname = BASEDIR_NTDIS;
    1320             : 
    1321           2 :         status = smb2_create(tree, torture, &(io.smb2));
    1322           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1323           2 :         h1 = io.smb2.out.file.handle;
    1324             : 
    1325             :         /* ask for a change notify,
    1326             :            on file or directory name changes */
    1327           2 :         ZERO_STRUCT(notify.smb2);
    1328           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    1329           2 :         notify.smb2.in.buffer_size = 1000;
    1330           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1331           2 :         notify.smb2.in.file.handle = h1;
    1332           2 :         notify.smb2.in.recursive = true;
    1333             : 
    1334           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    1335           8 :         WAIT_FOR_ASYNC_RESPONSE(req);
    1336             : 
    1337           2 :         status = smb2_tdis(tree);
    1338           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1339             : 
    1340           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    1341           2 :         CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
    1342           2 :         CHECK_VAL(notify.smb2.out.num_changes, 0);
    1343             : 
    1344           4 : done:
    1345           2 :         smb2_deltree(tree, BASEDIR_NTDIS);
    1346           2 :         return ret;
    1347             : }
    1348             : 
    1349             : /*
    1350             :   basic testing of change notifies followed by a close
    1351             : */
    1352             : 
    1353             : #define BASEDIR_CNC BASEDIR "_CNC"
    1354             : 
    1355           2 : static bool torture_smb2_notify_close(struct torture_context *torture,
    1356             :                                 struct smb2_tree *tree1)
    1357             : {
    1358           2 :         bool ret = true;
    1359             :         NTSTATUS status;
    1360             :         union smb_notify notify;
    1361             :         union smb_open io;
    1362             :         struct smb2_handle h1;
    1363             :         struct smb2_request *req;
    1364             : 
    1365           2 :         smb2_deltree(tree1, BASEDIR_CNC);
    1366           2 :         smb2_util_rmdir(tree1, BASEDIR_CNC);
    1367             : 
    1368           2 :         torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
    1369             : 
    1370             :         /*
    1371             :           get a handle on the directory
    1372             :         */
    1373           2 :         ZERO_STRUCT(io.smb2);
    1374           2 :         io.generic.level = RAW_OPEN_SMB2;
    1375           2 :         io.smb2.in.create_flags = 0;
    1376           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
    1377           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1378           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1379           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1380             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    1381           2 :         io.smb2.in.alloc_size = 0;
    1382           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    1383           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1384           2 :         io.smb2.in.security_flags = 0;
    1385           2 :         io.smb2.in.fname = BASEDIR_CNC;
    1386             : 
    1387           2 :         status = smb2_create(tree1, torture, &(io.smb2));
    1388           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1389             : 
    1390           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
    1391           2 :         status = smb2_create(tree1, torture, &(io.smb2));
    1392           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1393           2 :         h1 = io.smb2.out.file.handle;
    1394             : 
    1395             :         /* ask for a change notify,
    1396             :            on file or directory name changes */
    1397           2 :         ZERO_STRUCT(notify.smb2);
    1398           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    1399           2 :         notify.smb2.in.buffer_size = 1000;
    1400           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1401           2 :         notify.smb2.in.file.handle = h1;
    1402           2 :         notify.smb2.in.recursive = true;
    1403             : 
    1404           2 :         req = smb2_notify_send(tree1, &(notify.smb2));
    1405             : 
    1406           8 :         WAIT_FOR_ASYNC_RESPONSE(req);
    1407             : 
    1408           2 :         status = smb2_util_close(tree1, h1);
    1409           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1410             : 
    1411           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    1412           2 :         CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
    1413           2 :         CHECK_VAL(notify.smb2.out.num_changes, 0);
    1414             : 
    1415           4 : done:
    1416           2 :         smb2_deltree(tree1, BASEDIR_CNC);
    1417           2 :         return ret;
    1418             : }
    1419             : 
    1420             : /*
    1421             :   basic testing of change notifies followed by a ulogoff
    1422             : */
    1423             : 
    1424             : #define BASEDIR_NUL BASEDIR "_NUL"
    1425           2 : static bool torture_smb2_notify_ulogoff(struct torture_context *torture,
    1426             :                                 struct smb2_tree *tree1)
    1427             : {
    1428           2 :         bool ret = true;
    1429             :         NTSTATUS status;
    1430             :         union smb_notify notify;
    1431             :         union smb_open io;
    1432             :         struct smb2_handle h1;
    1433             :         struct smb2_request *req;
    1434             : 
    1435           2 :         smb2_deltree(tree1, BASEDIR_NUL);
    1436           2 :         smb2_util_rmdir(tree1, BASEDIR_NUL);
    1437             : 
    1438           2 :         torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
    1439             : 
    1440             :         /*
    1441             :           get a handle on the directory
    1442             :         */
    1443           2 :         ZERO_STRUCT(io.smb2);
    1444           2 :         io.generic.level = RAW_OPEN_SMB2;
    1445           2 :         io.smb2.in.create_flags = 0;
    1446           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
    1447           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1448           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1449           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1450             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    1451           2 :         io.smb2.in.alloc_size = 0;
    1452           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    1453           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1454           2 :         io.smb2.in.security_flags = 0;
    1455           2 :         io.smb2.in.fname = BASEDIR_NUL;
    1456             : 
    1457           2 :         status = smb2_create(tree1, torture, &(io.smb2));
    1458           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1459             : 
    1460           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
    1461           2 :         status = smb2_create(tree1, torture, &(io.smb2));
    1462           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1463           2 :         h1 = io.smb2.out.file.handle;
    1464             : 
    1465             :         /* ask for a change notify,
    1466             :            on file or directory name changes */
    1467           2 :         ZERO_STRUCT(notify.smb2);
    1468           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    1469           2 :         notify.smb2.in.buffer_size = 1000;
    1470           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1471           2 :         notify.smb2.in.file.handle = h1;
    1472           2 :         notify.smb2.in.recursive = true;
    1473             : 
    1474           2 :         req = smb2_notify_send(tree1, &(notify.smb2));
    1475             : 
    1476           8 :         WAIT_FOR_ASYNC_RESPONSE(req);
    1477             : 
    1478           2 :         status = smb2_logoff(tree1->session);
    1479           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1480             : 
    1481           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    1482           2 :         CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
    1483           2 :         CHECK_VAL(notify.smb2.out.num_changes, 0);
    1484             : 
    1485           4 : done:
    1486           2 :         smb2_deltree(tree1, BASEDIR_NUL);
    1487           2 :         return ret;
    1488             : }
    1489             : 
    1490             : /*
    1491             :   basic testing of change notifies followed by a session reconnect
    1492             : */
    1493             : 
    1494             : #define BASEDIR_NSR BASEDIR "_NSR"
    1495             : 
    1496           2 : static bool torture_smb2_notify_session_reconnect(struct torture_context *torture,
    1497             :                                 struct smb2_tree *tree1)
    1498             : {
    1499           2 :         bool ret = true;
    1500             :         NTSTATUS status;
    1501             :         union smb_notify notify;
    1502             :         union smb_open io;
    1503             :         struct smb2_handle h1;
    1504             :         struct smb2_request *req;
    1505           2 :         uint64_t previous_session_id = 0;
    1506           2 :         struct smb2_session *session2 = NULL;
    1507             : 
    1508           2 :         smb2_deltree(tree1, BASEDIR_NSR);
    1509           2 :         smb2_util_rmdir(tree1, BASEDIR_NSR);
    1510             : 
    1511           2 :         torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY SESSION RECONNECT\n");
    1512             : 
    1513             :         /*
    1514             :           get a handle on the directory
    1515             :         */
    1516           2 :         ZERO_STRUCT(io.smb2);
    1517           2 :         io.generic.level = RAW_OPEN_SMB2;
    1518           2 :         io.smb2.in.create_flags = 0;
    1519           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
    1520           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1521           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1522           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1523             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    1524           2 :         io.smb2.in.alloc_size = 0;
    1525           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    1526           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1527           2 :         io.smb2.in.security_flags = 0;
    1528           2 :         io.smb2.in.fname = BASEDIR_NSR;
    1529             : 
    1530           2 :         status = smb2_create(tree1, torture, &(io.smb2));
    1531           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1532             : 
    1533           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
    1534           2 :         status = smb2_create(tree1, torture, &(io.smb2));
    1535           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1536           2 :         h1 = io.smb2.out.file.handle;
    1537             : 
    1538             :         /* ask for a change notify,
    1539             :            on file or directory name changes */
    1540           2 :         ZERO_STRUCT(notify.smb2);
    1541           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    1542           2 :         notify.smb2.in.buffer_size = 1000;
    1543           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1544           2 :         notify.smb2.in.file.handle = h1;
    1545           2 :         notify.smb2.in.recursive = true;
    1546             : 
    1547           2 :         req = smb2_notify_send(tree1, &(notify.smb2));
    1548             : 
    1549           8 :         WAIT_FOR_ASYNC_RESPONSE(req);
    1550             : 
    1551           2 :         previous_session_id = smb2cli_session_current_id(tree1->session->smbXcli);
    1552           2 :         torture_assert(torture, torture_smb2_session_setup(torture,
    1553             :                        tree1->session->transport,
    1554             :                        previous_session_id,
    1555             :                        torture, &session2),
    1556             :                        "session setup with previous_session_id failed");
    1557             : 
    1558           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    1559           2 :         CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
    1560           2 :         CHECK_VAL(notify.smb2.out.num_changes, 0);
    1561             : 
    1562           2 :         status = smb2_logoff(tree1->session);
    1563           2 :         CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
    1564             : 
    1565           2 :         status = smb2_logoff(session2);
    1566           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1567           4 : done:
    1568           2 :         smb2_deltree(tree1, BASEDIR_NSR);
    1569           2 :         return ret;
    1570             : }
    1571             : 
    1572             : /*
    1573             :   basic testing of change notifies followed by an invalid reauth
    1574             : */
    1575             : 
    1576             : #define BASEDIR_IR BASEDIR "_IR"
    1577             : 
    1578           2 : static bool torture_smb2_notify_invalid_reauth(struct torture_context *torture,
    1579             :                                                struct smb2_tree *tree1,
    1580             :                                                struct smb2_tree *tree2)
    1581             : {
    1582           2 :         bool ret = true;
    1583             :         NTSTATUS status;
    1584             :         union smb_notify notify;
    1585             :         union smb_open io;
    1586             :         struct smb2_handle h1;
    1587             :         struct smb2_request *req;
    1588             :         struct cli_credentials *invalid_creds;
    1589             : 
    1590           2 :         smb2_deltree(tree2, BASEDIR_IR);
    1591           2 :         smb2_util_rmdir(tree2, BASEDIR_IR);
    1592             : 
    1593           2 :         torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY invalid REAUTH\n");
    1594             : 
    1595             :         /*
    1596             :           get a handle on the directory
    1597             :         */
    1598           2 :         ZERO_STRUCT(io.smb2);
    1599           2 :         io.generic.level = RAW_OPEN_SMB2;
    1600           2 :         io.smb2.in.create_flags = 0;
    1601           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
    1602           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1603           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1604           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1605             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    1606           2 :         io.smb2.in.alloc_size = 0;
    1607           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    1608           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1609           2 :         io.smb2.in.security_flags = 0;
    1610           2 :         io.smb2.in.fname = BASEDIR_IR;
    1611             : 
    1612           2 :         status = smb2_create(tree1, torture, &(io.smb2));
    1613           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1614             : 
    1615           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
    1616           2 :         status = smb2_create(tree1, torture, &(io.smb2));
    1617           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1618           2 :         h1 = io.smb2.out.file.handle;
    1619             : 
    1620             :         /* ask for a change notify,
    1621             :            on file or directory name changes */
    1622           2 :         ZERO_STRUCT(notify.smb2);
    1623           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    1624           2 :         notify.smb2.in.buffer_size = 1000;
    1625           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1626           2 :         notify.smb2.in.file.handle = h1;
    1627           2 :         notify.smb2.in.recursive = true;
    1628             : 
    1629           2 :         req = smb2_notify_send(tree1, &(notify.smb2));
    1630             : 
    1631           8 :         WAIT_FOR_ASYNC_RESPONSE(req);
    1632             : 
    1633           2 :         invalid_creds = cli_credentials_init(torture);
    1634           2 :         torture_assert(torture, (invalid_creds != NULL), "talloc error");
    1635           2 :         cli_credentials_set_username(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
    1636           2 :         cli_credentials_set_domain(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
    1637           2 :         cli_credentials_set_password(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
    1638           2 :         cli_credentials_set_realm(invalid_creds, NULL, CRED_SPECIFIED);
    1639           2 :         cli_credentials_set_workstation(invalid_creds, "", CRED_UNINITIALISED);
    1640             : 
    1641           2 :         status = smb2_session_setup_spnego(tree1->session,
    1642             :                                            invalid_creds,
    1643             :                                            0 /* previous_session_id */);
    1644           2 :         CHECK_STATUS(status, NT_STATUS_LOGON_FAILURE);
    1645             : 
    1646           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    1647           2 :         CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
    1648           2 :         CHECK_VAL(notify.smb2.out.num_changes, 0);
    1649             : 
    1650             :         /*
    1651             :          * Demonstrate that the session is no longer valid.
    1652             :          */
    1653           2 :         status = smb2_create(tree1, torture, &(io.smb2));
    1654           2 :         CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
    1655           4 : done:
    1656           2 :         smb2_deltree(tree2, BASEDIR_IR);
    1657           2 :         return ret;
    1658             : }
    1659             : 
    1660           2 : static void tcp_dis_handler(struct smb2_transport *t, void *p)
    1661             : {
    1662           2 :         struct smb2_tree *tree = (struct smb2_tree *)p;
    1663           2 :         smb2_transport_dead(tree->session->transport,
    1664           2 :                         NT_STATUS_LOCAL_DISCONNECT);
    1665           2 :         t = NULL;
    1666           2 :         tree = NULL;
    1667           2 : }
    1668             : 
    1669             : /*
    1670             :   basic testing of change notifies followed by tcp disconnect
    1671             : */
    1672             : 
    1673             : #define BASEDIR_NTCPD BASEDIR "_NTCPD"
    1674             : 
    1675           2 : static bool torture_smb2_notify_tcp_disconnect(
    1676             :                 struct torture_context *torture,
    1677             :                 struct smb2_tree *tree)
    1678             : {
    1679           2 :         bool ret = true;
    1680             :         NTSTATUS status;
    1681             :         union smb_notify notify;
    1682             :         union smb_open io;
    1683             :         struct smb2_handle h1;
    1684             :         struct smb2_request *req;
    1685             : 
    1686           2 :         smb2_deltree(tree, BASEDIR_NTCPD);
    1687           2 :         smb2_util_rmdir(tree, BASEDIR_NTCPD);
    1688             : 
    1689           2 :         torture_comment(torture,
    1690             :                 "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
    1691             : 
    1692             :         /*
    1693             :           get a handle on the directory
    1694             :         */
    1695           2 :         ZERO_STRUCT(io.smb2);
    1696           2 :         io.generic.level = RAW_OPEN_SMB2;
    1697           2 :         io.smb2.in.create_flags = 0;
    1698           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
    1699           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1700           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1701           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1702             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    1703           2 :         io.smb2.in.alloc_size = 0;
    1704           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
    1705           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1706           2 :         io.smb2.in.security_flags = 0;
    1707           2 :         io.smb2.in.fname = BASEDIR_NTCPD;
    1708             : 
    1709           2 :         status = smb2_create(tree, torture, &(io.smb2));
    1710           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1711           2 :         h1 = io.smb2.out.file.handle;
    1712             : 
    1713             :         /* ask for a change notify,
    1714             :            on file or directory name changes */
    1715           2 :         ZERO_STRUCT(notify.smb2);
    1716           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    1717           2 :         notify.smb2.in.buffer_size = 1000;
    1718           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1719           2 :         notify.smb2.in.file.handle = h1;
    1720           2 :         notify.smb2.in.recursive = true;
    1721             : 
    1722           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    1723           2 :         smb2_cancel(req);
    1724           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    1725           2 :         CHECK_STATUS(status, NT_STATUS_CANCELLED);
    1726             : 
    1727           2 :         notify.smb2.in.recursive = true;
    1728           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    1729           2 :         smb2_transport_idle_handler(tree->session->transport,
    1730             :                                 tcp_dis_handler, 250000, tree);
    1731           2 :         tree = NULL;
    1732           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    1733           2 :         CHECK_STATUS(status, NT_STATUS_LOCAL_DISCONNECT);
    1734             : 
    1735           4 : done:
    1736           2 :         return ret;
    1737             : }
    1738             : 
    1739             : /*
    1740             :    test setting up two change notify requests on one handle
    1741             : */
    1742             : 
    1743             : #define BASEDIR_NDOH BASEDIR "_NDOH"
    1744             : 
    1745           2 : static bool torture_smb2_notify_double(struct torture_context *torture,
    1746             :                         struct smb2_tree *tree1,
    1747             :                         struct smb2_tree *tree2)
    1748             : {
    1749           2 :         bool ret = true;
    1750             :         NTSTATUS status;
    1751             :         union smb_notify notify;
    1752             :         union smb_open io;
    1753             :         struct smb2_handle h1;
    1754             :         struct smb2_request *req1, *req2;
    1755             : 
    1756           2 :         smb2_deltree(tree1, BASEDIR_NDOH);
    1757           2 :         smb2_util_rmdir(tree1, BASEDIR_NDOH);
    1758             : 
    1759           2 :         torture_comment(torture,
    1760             :                 "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
    1761             : 
    1762             :         /*
    1763             :           get a handle on the directory
    1764             :         */
    1765           2 :         ZERO_STRUCT(io.smb2);
    1766           2 :         io.generic.level = RAW_OPEN_SMB2;
    1767           2 :         io.smb2.in.create_flags = 0;
    1768           2 :         io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ|
    1769             :                                 SEC_RIGHTS_FILE_WRITE|
    1770             :                                 SEC_RIGHTS_FILE_ALL;
    1771           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1772           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1773           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1774             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    1775           2 :         io.smb2.in.alloc_size = 0;
    1776           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    1777           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1778           2 :         io.smb2.in.security_flags = 0;
    1779           2 :         io.smb2.in.fname = BASEDIR_NDOH;
    1780             : 
    1781           2 :         status = smb2_create(tree1, torture, &(io.smb2));
    1782           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1783           2 :         h1 = io.smb2.out.file.handle;
    1784             : 
    1785             :         /* ask for a change notify,
    1786             :            on file or directory name changes */
    1787           2 :         ZERO_STRUCT(notify.smb2);
    1788           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    1789           2 :         notify.smb2.in.buffer_size = 1000;
    1790           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1791           2 :         notify.smb2.in.file.handle = h1;
    1792           2 :         notify.smb2.in.recursive = true;
    1793             : 
    1794           2 :         req1 = smb2_notify_send(tree1, &(notify.smb2));
    1795           2 :         smb2_cancel(req1);
    1796           2 :         status = smb2_notify_recv(req1, torture, &(notify.smb2));
    1797           2 :         CHECK_STATUS(status, NT_STATUS_CANCELLED);
    1798             : 
    1799           2 :         req2 = smb2_notify_send(tree1, &(notify.smb2));
    1800           2 :         smb2_cancel(req2);
    1801           2 :         status = smb2_notify_recv(req2, torture, &(notify.smb2));
    1802           2 :         CHECK_STATUS(status, NT_STATUS_CANCELLED);
    1803             : 
    1804           2 :         smb2_util_mkdir(tree2, BASEDIR_NDOH "\\subdir-name");
    1805           2 :         req1 = smb2_notify_send(tree1, &(notify.smb2));
    1806           2 :         req2 = smb2_notify_send(tree1, &(notify.smb2));
    1807             : 
    1808           2 :         status = smb2_notify_recv(req1, torture, &(notify.smb2));
    1809           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1810           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
    1811           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
    1812             : 
    1813           2 :         smb2_util_mkdir(tree2, BASEDIR_NDOH "\\subdir-name2");
    1814             : 
    1815           2 :         status = smb2_notify_recv(req2, torture, &(notify.smb2));
    1816           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1817           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
    1818           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name2");
    1819             : 
    1820           4 : done:
    1821           2 :         smb2_deltree(tree1, BASEDIR_NDOH);
    1822           2 :         return ret;
    1823             : }
    1824             : 
    1825             : 
    1826             : /*
    1827             :    test multiple change notifies at different depths and with/without recursion
    1828             : */
    1829             : 
    1830             : #define BASEDIR_TREE BASEDIR "_TREE"
    1831             : 
    1832           2 : static bool torture_smb2_notify_tree(struct torture_context *torture,
    1833             :                              struct smb2_tree *tree)
    1834             : {
    1835           2 :         bool ret = true;
    1836             :         union smb_notify notify;
    1837             :         union smb_open io;
    1838             :         struct smb2_request *req;
    1839             :         struct timeval tv;
    1840             :         struct {
    1841             :                 const char *path;
    1842             :                 bool recursive;
    1843             :                 uint32_t filter;
    1844             :                 int expected;
    1845             :                 struct smb2_handle h1;
    1846             :                 int counted;
    1847           2 :         } dirs[] = {
    1848             :                 {
    1849             :                         .path      = BASEDIR_TREE "\\abc",
    1850             :                         .recursive = true,
    1851             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1852             :                         .expected  = 30,
    1853             :                 },
    1854             :                 {
    1855             :                         .path      = BASEDIR_TREE "\\zqy",
    1856             :                         .recursive = true,
    1857             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1858             :                         .expected  = 8,
    1859             :                 },
    1860             :                 {
    1861             :                         .path      = BASEDIR_TREE "\\atsy",
    1862             :                         .recursive = true,
    1863             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1864             :                         .expected  = 4,
    1865             :                 },
    1866             :                 {
    1867             :                         .path      = BASEDIR_TREE "\\abc\\foo",
    1868             :                         .recursive = true,
    1869             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1870             :                         .expected  = 2,
    1871             :                 },
    1872             :                 {
    1873             :                         .path      = BASEDIR_TREE "\\abc\\blah",
    1874             :                         .recursive = true,
    1875             :                         .filter    =  FILE_NOTIFY_CHANGE_NAME,
    1876             :                         .expected  = 13,
    1877             :                 },
    1878             :                 {
    1879             :                         .path      = BASEDIR_TREE "\\abc\\blah",
    1880             :                         .recursive = false,
    1881             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1882             :                         .expected  = 7,
    1883             :                 },
    1884             :                 {
    1885             :                         .path      = BASEDIR_TREE "\\abc\\blah\\a",
    1886             :                         .recursive = true,
    1887             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1888             :                         .expected  = 2,
    1889             :                 },
    1890             :                 {
    1891             :                         .path      = BASEDIR_TREE "\\abc\\blah\\b",
    1892             :                         .recursive = true,
    1893             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1894             :                         .expected  = 2,
    1895             :                 },
    1896             :                 {
    1897             :                         .path      = BASEDIR_TREE "\\abc\\blah\\c",
    1898             :                         .recursive = true,
    1899             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1900             :                         .expected  = 2,
    1901             :                 },
    1902             :                 {
    1903             :                         .path      = BASEDIR_TREE "\\abc\\fooblah",
    1904             :                         .recursive = true,
    1905             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1906             :                         .expected  = 2,
    1907             :                 },
    1908             :                 {
    1909             :                         .path      = BASEDIR_TREE "\\zqy\\xx",
    1910             :                         .recursive = true,
    1911             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1912             :                         .expected  = 2,
    1913             :                 },
    1914             :                 {
    1915             :                         .path      = BASEDIR_TREE "\\zqy\\yyy",
    1916             :                         .recursive = true,
    1917             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1918             :                         .expected  = 2,
    1919             :                 },
    1920             :                 {
    1921             :                         .path      = BASEDIR_TREE "\\zqy\\..",
    1922             :                         .recursive = true,
    1923             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1924             :                         .expected  = 40,
    1925             :                 },
    1926             :                 {
    1927             :                         .path      = BASEDIR_TREE,
    1928             :                         .recursive = true,
    1929             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1930             :                         .expected  = 40,
    1931             :                 },
    1932             :                 {
    1933             :                         .path      = BASEDIR_TREE,
    1934             :                         .recursive = false,
    1935             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1936             :                         .expected  = 6,
    1937             :                 },
    1938             :                 {
    1939             :                         .path      = BASEDIR_TREE "\\atsy",
    1940             :                         .recursive = false,
    1941             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1942             :                         .expected  = 4,
    1943             :                 },
    1944             :                 {
    1945             :                         .path      = BASEDIR_TREE "\\abc",
    1946             :                         .recursive = true,
    1947             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1948             :                         .expected  = 24,
    1949             :                 },
    1950             :                 {
    1951             :                         .path      = BASEDIR_TREE "\\abc",
    1952             :                         .recursive = false,
    1953             :                         .filter    = FILE_NOTIFY_CHANGE_FILE_NAME,
    1954             :                         .expected  = 0,
    1955             :                 },
    1956             :                 {
    1957             :                         .path      = BASEDIR_TREE "\\abc",
    1958             :                         .recursive = true,
    1959             :                         .filter    = FILE_NOTIFY_CHANGE_FILE_NAME,
    1960             :                         .expected  = 0,
    1961             :                 },
    1962             :                 {
    1963             :                         .path      = BASEDIR_TREE "\\abc",
    1964             :                         .recursive = true,
    1965             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1966             :                         .expected  = 24,
    1967             :                 },
    1968             :         };
    1969             :         int i;
    1970             :         NTSTATUS status;
    1971           2 :         bool all_done = false;
    1972             : 
    1973           2 :         smb2_deltree(tree, BASEDIR_TREE);
    1974           2 :         smb2_util_rmdir(tree, BASEDIR_TREE);
    1975             : 
    1976           2 :         torture_comment(torture, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
    1977             : 
    1978           2 :         ZERO_STRUCT(io.smb2);
    1979           2 :         io.generic.level = RAW_OPEN_SMB2;
    1980           2 :         io.smb2.in.create_flags = 0;
    1981           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
    1982           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1983           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1984           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1985             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    1986           2 :         io.smb2.in.alloc_size = 0;
    1987           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
    1988           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1989           2 :         io.smb2.in.security_flags = 0;
    1990           2 :         io.smb2.in.fname = BASEDIR_TREE;
    1991           2 :         status = smb2_create(tree, torture, &(io.smb2));
    1992           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1993             : 
    1994           2 :         ZERO_STRUCT(notify.smb2);
    1995           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    1996           2 :         notify.smb2.in.buffer_size = 20000;
    1997             : 
    1998             :         /*
    1999             :           setup the directory tree, and the notify buffer on each directory
    2000             :         */
    2001          42 :         for (i=0;i<ARRAY_SIZE(dirs);i++) {
    2002          40 :                 io.smb2.in.fname = dirs[i].path;
    2003          40 :                 status = smb2_create(tree, torture, &(io.smb2));
    2004          40 :                 CHECK_STATUS(status, NT_STATUS_OK);
    2005          40 :                 dirs[i].h1 = io.smb2.out.file.handle;
    2006             : 
    2007          40 :                 notify.smb2.in.completion_filter = dirs[i].filter;
    2008          40 :                 notify.smb2.in.file.handle = dirs[i].h1;
    2009          40 :                 notify.smb2.in.recursive = dirs[i].recursive;
    2010          40 :                 req = smb2_notify_send(tree, &(notify.smb2));
    2011          40 :                 smb2_cancel(req);
    2012          40 :                 status = smb2_notify_recv(req, torture, &(notify.smb2));
    2013          40 :                 CHECK_STATUS(status, NT_STATUS_CANCELLED);
    2014             :         }
    2015             : 
    2016             :         /* trigger 2 events in each dir */
    2017          42 :         for (i=0;i<ARRAY_SIZE(dirs);i++) {
    2018          40 :                 char *path = talloc_asprintf(torture, "%s\\test.dir",
    2019             :                                              dirs[i].path);
    2020          40 :                 smb2_util_mkdir(tree, path);
    2021          40 :                 smb2_util_rmdir(tree, path);
    2022          40 :                 talloc_free(path);
    2023             :         }
    2024             : 
    2025             :         /* give a bit of time for the events to propagate */
    2026           2 :         tv = timeval_current();
    2027             : 
    2028             :         do {
    2029             :                 /* count events that have happened in each dir */
    2030          42 :                 for (i=0;i<ARRAY_SIZE(dirs);i++) {
    2031          40 :                         notify.smb2.in.completion_filter = dirs[i].filter;
    2032          40 :                         notify.smb2.in.file.handle = dirs[i].h1;
    2033          40 :                         notify.smb2.in.recursive = dirs[i].recursive;
    2034          40 :                         req = smb2_notify_send(tree, &(notify.smb2));
    2035          40 :                         smb2_cancel(req);
    2036          40 :                         notify.smb2.out.num_changes = 0;
    2037          40 :                         status = smb2_notify_recv(req, torture,
    2038             :                                  &(notify.smb2));
    2039          40 :                         dirs[i].counted += notify.smb2.out.num_changes;
    2040             :                 }
    2041             : 
    2042           2 :                 all_done = true;
    2043             : 
    2044          42 :                 for (i=0;i<ARRAY_SIZE(dirs);i++) {
    2045          40 :                         if (dirs[i].counted != dirs[i].expected) {
    2046           0 :                                 all_done = false;
    2047             :                         }
    2048             :                 }
    2049           2 :         } while (!all_done && timeval_elapsed(&tv) < 20);
    2050             : 
    2051           2 :         torture_comment(torture, "took %.4f seconds to propagate all events\n",
    2052             :                         timeval_elapsed(&tv));
    2053             : 
    2054          42 :         for (i=0;i<ARRAY_SIZE(dirs);i++) {
    2055          40 :                 if (dirs[i].counted != dirs[i].expected) {
    2056           0 :                         torture_comment(torture,
    2057             :                                 "ERROR: i=%d expected %d got %d for '%s'\n",
    2058             :                                 i, dirs[i].expected, dirs[i].counted,
    2059             :                                 dirs[i].path);
    2060           0 :                         ret = false;
    2061             :                 }
    2062             :         }
    2063             : 
    2064             :         /*
    2065             :           run from the back, closing and deleting
    2066             :         */
    2067          42 :         for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
    2068          40 :                 smb2_util_close(tree, dirs[i].h1);
    2069          40 :                 smb2_util_rmdir(tree, dirs[i].path);
    2070             :         }
    2071             : 
    2072           2 : done:
    2073           2 :         smb2_deltree(tree, BASEDIR_TREE);
    2074           2 :         smb2_util_rmdir(tree, BASEDIR_TREE);
    2075           2 :         return ret;
    2076             : }
    2077             : 
    2078             : /*
    2079             :    Test response when cached server events exceed single NT NOTFIY response
    2080             :    packet size.
    2081             : */
    2082             : 
    2083             : #define BASEDIR_OVF BASEDIR "_OVF"
    2084             : 
    2085           2 : static bool torture_smb2_notify_overflow(struct torture_context *torture,
    2086             :                                 struct smb2_tree *tree)
    2087             : {
    2088           2 :         bool ret = true;
    2089             :         NTSTATUS status;
    2090             :         union smb_notify notify;
    2091             :         union smb_open io;
    2092             :         struct smb2_handle h1, h2;
    2093           2 :         int count = 100;
    2094             :         struct smb2_request *req1;
    2095             :         int i;
    2096             : 
    2097           2 :         smb2_deltree(tree, BASEDIR_OVF);
    2098           2 :         smb2_util_rmdir(tree, BASEDIR_OVF);
    2099             : 
    2100           2 :         torture_comment(torture, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
    2101             : 
    2102             :         /* get a handle on the directory */
    2103           2 :         ZERO_STRUCT(io.smb2);
    2104           2 :         io.generic.level = RAW_OPEN_SMB2;
    2105           2 :         io.smb2.in.create_flags = 0;
    2106           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
    2107           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    2108           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    2109           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    2110             :                             NTCREATEX_SHARE_ACCESS_WRITE;
    2111           2 :         io.smb2.in.alloc_size = 0;
    2112           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    2113           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    2114           2 :         io.smb2.in.security_flags = 0;
    2115           2 :         io.smb2.in.fname = BASEDIR_OVF;
    2116             : 
    2117           2 :         status = smb2_create(tree, torture, &(io.smb2));
    2118           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2119           2 :         h1 = io.smb2.out.file.handle;
    2120             : 
    2121             :         /* ask for a change notify, on name changes. */
    2122           2 :         ZERO_STRUCT(notify.smb2);
    2123           2 :         notify.smb2.level = RAW_NOTIFY_NTTRANS;
    2124           2 :         notify.smb2.in.buffer_size = 1000;
    2125           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    2126           2 :         notify.smb2.in.file.handle = h1;
    2127             : 
    2128           2 :         notify.smb2.in.recursive = true;
    2129           2 :         req1 = smb2_notify_send(tree, &(notify.smb2));
    2130             : 
    2131             :         /* cancel initial requests so the buffer is setup */
    2132           2 :         smb2_cancel(req1);
    2133           2 :         status = smb2_notify_recv(req1, torture, &(notify.smb2));
    2134           2 :         CHECK_STATUS(status, NT_STATUS_CANCELLED);
    2135             : 
    2136             :         /* open a lot of files, filling up the server side notify buffer */
    2137           2 :         torture_comment(torture,
    2138             :                 "Testing overflowed buffer notify on create of %d files\n",
    2139             :                 count);
    2140             : 
    2141         202 :         for (i=0;i<count;i++) {
    2142         200 :                 char *fname = talloc_asprintf(torture,
    2143             :                               BASEDIR_OVF "\\test%d.txt", i);
    2144             :                 union smb_open io1;
    2145         200 :                 ZERO_STRUCT(io1.smb2);
    2146         200 :                 io1.generic.level = RAW_OPEN_SMB2;
    2147         200 :                 io1.smb2.in.create_flags = 0;
    2148         200 :                 io1.smb2.in.desired_access = SEC_FILE_ALL;
    2149         200 :                 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    2150         200 :                 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    2151         200 :                 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    2152             :                                     NTCREATEX_SHARE_ACCESS_WRITE;
    2153         200 :                 io1.smb2.in.alloc_size = 0;
    2154         200 :                 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    2155         200 :                 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    2156         200 :                 io1.smb2.in.security_flags = 0;
    2157         200 :                 io1.smb2.in.fname = fname;
    2158             : 
    2159         200 :                 h2 = custom_smb2_create(tree, torture, &(io1.smb2));
    2160         200 :                 talloc_free(fname);
    2161         200 :                 smb2_util_close(tree, h2);
    2162             :         }
    2163             : 
    2164           2 :         req1 = smb2_notify_send(tree, &(notify.smb2));
    2165           2 :         status = smb2_notify_recv(req1, torture, &(notify.smb2));
    2166           2 :         CHECK_STATUS(status, NT_STATUS_NOTIFY_ENUM_DIR);
    2167           2 :         CHECK_VAL(notify.smb2.out.num_changes, 0);
    2168             : 
    2169           4 : done:
    2170           2 :         smb2_deltree(tree, BASEDIR_OVF);
    2171           2 :         return ret;
    2172             : }
    2173             : 
    2174             : /*
    2175             :    Test if notifications are returned for changes to the base directory.
    2176             :    They shouldn't be.
    2177             : */
    2178             : 
    2179             : #define BASEDIR_BAS BASEDIR "_BAS"
    2180             : 
    2181           2 : static bool torture_smb2_notify_basedir(struct torture_context *torture,
    2182             :                                 struct smb2_tree *tree1,
    2183             :                                 struct smb2_tree *tree2)
    2184             : {
    2185           2 :         bool ret = true;
    2186             :         NTSTATUS status;
    2187             :         union smb_notify notify;
    2188             :         union smb_open io;
    2189             :         struct smb2_handle h1;
    2190             :         struct smb2_request *req1;
    2191             : 
    2192           2 :         smb2_deltree(tree1, BASEDIR_BAS);
    2193           2 :         smb2_util_rmdir(tree1, BASEDIR_BAS);
    2194             : 
    2195           2 :         torture_comment(torture, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
    2196             : 
    2197             :         /* get a handle on the directory */
    2198           2 :         ZERO_STRUCT(io.smb2);
    2199           2 :         io.generic.level = RAW_OPEN_SMB2;
    2200           2 :         io.smb2.in.create_flags = 0;
    2201           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
    2202           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    2203           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    2204           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    2205             :             NTCREATEX_SHARE_ACCESS_WRITE;
    2206           2 :         io.smb2.in.alloc_size = 0;
    2207           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
    2208           2 :         io.smb2.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
    2209           2 :         io.smb2.in.security_flags = 0;
    2210           2 :         io.smb2.in.fname = BASEDIR_BAS;
    2211             : 
    2212           2 :         status = smb2_create(tree1, torture, &(io.smb2));
    2213           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2214           2 :         h1 = io.smb2.out.file.handle;
    2215             : 
    2216             :         /* create a test file that will also be modified */
    2217           2 :         io.smb2.in.fname = BASEDIR_BAS "\\tname1";
    2218           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
    2219           2 :         status =  smb2_create(tree2, torture, &(io.smb2));
    2220           2 :         CHECK_STATUS(status,NT_STATUS_OK);
    2221           2 :         smb2_util_close(tree2, io.smb2.out.file.handle);
    2222             : 
    2223             :         /* ask for a change notify, on attribute changes. */
    2224           2 :         ZERO_STRUCT(notify.smb2);
    2225           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    2226           2 :         notify.smb2.in.buffer_size = 1000;
    2227           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
    2228           2 :         notify.smb2.in.file.handle = h1;
    2229           2 :         notify.smb2.in.recursive = true;
    2230             : 
    2231           2 :         req1 = smb2_notify_send(tree1, &(notify.smb2));
    2232             : 
    2233             :         /* set attribute on the base dir */
    2234           2 :         smb2_util_setatr(tree2, BASEDIR_BAS, FILE_ATTRIBUTE_HIDDEN);
    2235             : 
    2236             :         /* set attribute on a file to assure we receive a notification */
    2237           2 :         smb2_util_setatr(tree2, BASEDIR_BAS "\\tname1", FILE_ATTRIBUTE_HIDDEN);
    2238           2 :         smb_msleep(200);
    2239             : 
    2240             :         /* check how many responses were given, expect only 1 for the file */
    2241           2 :         status = smb2_notify_recv(req1, torture, &(notify.smb2));
    2242           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2243           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
    2244           2 :         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
    2245           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
    2246             : 
    2247           4 : done:
    2248           2 :         smb2_deltree(tree1, BASEDIR_BAS);
    2249           2 :         return ret;
    2250             : }
    2251             : 
    2252             : /*
    2253             :    very simple change notify test
    2254             : */
    2255             : 
    2256             : #define BASEDIR_TCON BASEDIR "_TCON"
    2257             : 
    2258           2 : static bool torture_smb2_notify_tcon(struct torture_context *torture,
    2259             :                                   struct smb2_tree *tree)
    2260             : {
    2261           2 :         bool ret = true;
    2262             :         NTSTATUS status;
    2263             :         union smb_notify notify;
    2264             :         union smb_open io;
    2265           2 :         struct smb2_handle h1 = {{0}};
    2266           2 :         struct smb2_request *req = NULL;
    2267           2 :         struct smb2_tree *tree1 = NULL;
    2268           2 :         const char *fname = BASEDIR_TCON "\\subdir-name";
    2269             : 
    2270           2 :         smb2_deltree(tree, BASEDIR_TCON);
    2271           2 :         smb2_util_rmdir(tree, BASEDIR_TCON);
    2272             : 
    2273           2 :         torture_comment(torture, "TESTING SIMPLE CHANGE NOTIFY\n");
    2274             : 
    2275             :         /*
    2276             :           get a handle on the directory
    2277             :         */
    2278             : 
    2279           2 :         ZERO_STRUCT(io.smb2);
    2280           2 :         io.generic.level = RAW_OPEN_SMB2;
    2281           2 :         io.smb2.in.create_flags = 0;
    2282           2 :         io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
    2283           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    2284           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL |
    2285             :                                 FILE_ATTRIBUTE_DIRECTORY;
    2286           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    2287             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    2288           2 :         io.smb2.in.alloc_size = 0;
    2289           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
    2290           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    2291           2 :         io.smb2.in.security_flags = 0;
    2292           2 :         io.smb2.in.fname = BASEDIR_TCON;
    2293             : 
    2294           2 :         status = smb2_create(tree, torture, &(io.smb2));
    2295           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2296           2 :         h1 = io.smb2.out.file.handle;
    2297             : 
    2298             :         /* ask for a change notify,
    2299             :            on file or directory name changes */
    2300           2 :         ZERO_STRUCT(notify.smb2);
    2301           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    2302           2 :         notify.smb2.in.buffer_size = 1000;
    2303           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    2304           2 :         notify.smb2.in.file.handle = h1;
    2305           2 :         notify.smb2.in.recursive = true;
    2306             : 
    2307           2 :         torture_comment(torture, "Testing notify mkdir\n");
    2308           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    2309           2 :         smb2_cancel(req);
    2310           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    2311           2 :         CHECK_STATUS(status, NT_STATUS_CANCELLED);
    2312             : 
    2313           2 :         notify.smb2.in.recursive = true;
    2314           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    2315           2 :         status = smb2_util_mkdir(tree, fname);
    2316           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2317             : 
    2318           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    2319           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2320             : 
    2321           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
    2322           2 :         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
    2323           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
    2324             : 
    2325           2 :         torture_comment(torture, "Testing notify rmdir\n");
    2326           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    2327           2 :         status = smb2_util_rmdir(tree, fname);
    2328           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2329             : 
    2330           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    2331           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2332           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
    2333           2 :         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
    2334           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
    2335             : 
    2336           2 :         torture_comment(torture, "SIMPLE CHANGE NOTIFY OK\n");
    2337             : 
    2338           2 :         torture_comment(torture, "TESTING WITH SECONDARY TCON\n");
    2339           2 :         if (!torture_smb2_tree_connect(torture, tree->session, tree, &tree1)) {
    2340           0 :                 torture_warning(torture, "couldn't reconnect to share, bailing\n");
    2341           0 :                 ret = false;
    2342           0 :                 goto done;
    2343             :         }
    2344             : 
    2345           2 :         torture_comment(torture, "tid1=%d tid2=%d\n",
    2346             :                         smb2cli_tcon_current_id(tree->smbXcli),
    2347           2 :                         smb2cli_tcon_current_id(tree1->smbXcli));
    2348             : 
    2349           2 :         torture_comment(torture, "Testing notify mkdir\n");
    2350           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    2351           2 :         smb2_util_mkdir(tree1, fname);
    2352             : 
    2353           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    2354           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2355             : 
    2356           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
    2357           2 :         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
    2358           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
    2359             : 
    2360           2 :         torture_comment(torture, "Testing notify rmdir\n");
    2361           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    2362           2 :         smb2_util_rmdir(tree, fname);
    2363             : 
    2364           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    2365           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2366           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
    2367           2 :         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
    2368           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
    2369             : 
    2370           2 :         torture_comment(torture, "CHANGE NOTIFY WITH TCON OK\n");
    2371             : 
    2372           2 :         torture_comment(torture, "Disconnecting secondary tree\n");
    2373           2 :         status = smb2_tdis(tree1);
    2374           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2375           2 :         talloc_free(tree1);
    2376             : 
    2377           2 :         torture_comment(torture, "Testing notify mkdir\n");
    2378           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    2379           2 :         smb2_util_mkdir(tree, fname);
    2380             : 
    2381           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    2382           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2383             : 
    2384           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
    2385           2 :         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
    2386           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
    2387             : 
    2388           2 :         torture_comment(torture, "Testing notify rmdir\n");
    2389           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    2390           2 :         smb2_util_rmdir(tree, fname);
    2391             : 
    2392           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    2393           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2394           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
    2395           2 :         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
    2396           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
    2397             : 
    2398           2 :         torture_comment(torture, "CHANGE NOTIFY WITH TDIS OK\n");
    2399           2 : done:
    2400           2 :         smb2_util_close(tree, h1);
    2401           2 :         smb2_deltree(tree, BASEDIR_TCON);
    2402             : 
    2403           2 :         return ret;
    2404             : }
    2405             : 
    2406             : #define BASEDIR_RMD BASEDIR "_RMD"
    2407             : 
    2408           8 : static bool torture_smb2_notify_rmdir(struct torture_context *torture,
    2409             :                                       struct smb2_tree *tree1,
    2410             :                                       struct smb2_tree *tree2,
    2411             :                                       bool initial_delete_on_close)
    2412             : {
    2413           8 :         bool ret = true;
    2414             :         NTSTATUS status;
    2415           8 :         union smb_notify notify = {};
    2416           8 :         union smb_setfileinfo sfinfo = {};
    2417           8 :         union smb_open io = {};
    2418           8 :         struct smb2_handle h = {};
    2419             :         struct smb2_request *req;
    2420             : 
    2421           8 :         torture_comment(torture, "TESTING NOTIFY CANCEL FOR DELETED DIR\n");
    2422             : 
    2423           8 :         smb2_deltree(tree1, BASEDIR_RMD);
    2424           8 :         smb2_util_rmdir(tree1, BASEDIR_RMD);
    2425             : 
    2426           8 :         ZERO_STRUCT(io.smb2);
    2427           8 :         io.generic.level = RAW_OPEN_SMB2;
    2428           8 :         io.smb2.in.create_flags = 0;
    2429           8 :         io.smb2.in.desired_access = SEC_FILE_ALL;
    2430           8 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    2431           8 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    2432           8 :         io.smb2.in.share_access =
    2433             :                 NTCREATEX_SHARE_ACCESS_READ |
    2434             :                 NTCREATEX_SHARE_ACCESS_WRITE |
    2435             :                 NTCREATEX_SHARE_ACCESS_DELETE ;
    2436           8 :         io.smb2.in.alloc_size = 0;
    2437           8 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    2438           8 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    2439           8 :         io.smb2.in.security_flags = 0;
    2440           8 :         io.smb2.in.fname = BASEDIR_RMD;
    2441             : 
    2442           8 :         status = smb2_create(tree1, torture, &(io.smb2));
    2443           8 :         CHECK_STATUS(status, NT_STATUS_OK);
    2444           8 :         h = io.smb2.out.file.handle;
    2445             : 
    2446           8 :         ZERO_STRUCT(notify.smb2);
    2447           8 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    2448           8 :         notify.smb2.in.buffer_size = 1000;
    2449           8 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    2450           8 :         notify.smb2.in.file.handle = h;
    2451           8 :         notify.smb2.in.recursive = false;
    2452             : 
    2453           8 :         io.smb2.in.desired_access |= SEC_STD_DELETE;
    2454           8 :         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
    2455           8 :         req = smb2_notify_send(tree1, &(notify.smb2));
    2456             : 
    2457           8 :         if (initial_delete_on_close) {
    2458           4 :                 status = smb2_util_rmdir(tree2, BASEDIR_RMD);
    2459           4 :                 CHECK_STATUS(status, NT_STATUS_OK);
    2460             :         } else {
    2461           4 :                 status = smb2_create(tree2, torture, &(io.smb2));
    2462           4 :                 CHECK_STATUS(status, NT_STATUS_OK);
    2463             : 
    2464           4 :                 sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
    2465           4 :                 sfinfo.generic.in.file.handle = io.smb2.out.file.handle;
    2466           4 :                 sfinfo.disposition_info.in.delete_on_close = 1;
    2467           4 :                 status = smb2_setinfo_file(tree2, &sfinfo);
    2468           4 :                 CHECK_STATUS(status, NT_STATUS_OK);
    2469             : 
    2470           4 :                 smb2_util_close(tree2, io.smb2.out.file.handle);
    2471             :         }
    2472             : 
    2473           8 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    2474           8 :         CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
    2475             : 
    2476          16 : done:
    2477             : 
    2478           8 :         smb2_util_close(tree1, h);
    2479           8 :         smb2_deltree(tree1, BASEDIR_RMD);
    2480             : 
    2481           8 :         return ret;
    2482             : }
    2483             : 
    2484           2 : static bool torture_smb2_notify_rmdir1(struct torture_context *torture,
    2485             :                                        struct smb2_tree *tree)
    2486             : {
    2487           2 :         return torture_smb2_notify_rmdir(torture, tree, tree, false);
    2488             : }
    2489             : 
    2490           2 : static bool torture_smb2_notify_rmdir2(struct torture_context *torture,
    2491             :                                        struct smb2_tree *tree)
    2492             : {
    2493           2 :         return torture_smb2_notify_rmdir(torture, tree, tree, true);
    2494             : }
    2495             : 
    2496           2 : static bool torture_smb2_notify_rmdir3(struct torture_context *torture,
    2497             :                                        struct smb2_tree *tree1,
    2498             :                                        struct smb2_tree *tree2)
    2499             : {
    2500           2 :         return torture_smb2_notify_rmdir(torture, tree1, tree2, false);
    2501             : }
    2502             : 
    2503           2 : static bool torture_smb2_notify_rmdir4(struct torture_context *torture,
    2504             :                                        struct smb2_tree *tree1,
    2505             :                                        struct smb2_tree *tree2)
    2506             : {
    2507           2 :         return torture_smb2_notify_rmdir(torture, tree1, tree2, true);
    2508             : }
    2509             : 
    2510           0 : static void notify_timeout(struct tevent_context *ev,
    2511             :                            struct tevent_timer *te,
    2512             :                            struct timeval current_time,
    2513             :                            void *private_data)
    2514             : {
    2515           0 :         struct smb2_request *req = talloc_get_type_abort(
    2516             :                 private_data, struct smb2_request);
    2517             : 
    2518           0 :         smb2_cancel(req);
    2519           0 : }
    2520             : 
    2521             : #define BASEDIR_INR BASEDIR "_INR"
    2522             : 
    2523           2 : static bool torture_smb2_inotify_rename(struct torture_context *torture,
    2524             :                                         struct smb2_tree *tree1,
    2525             :                                         struct smb2_tree *tree2)
    2526             : {
    2527             :         NTSTATUS status;
    2528             :         struct smb2_notify notify;
    2529           2 :         struct notify_changes change1 = {0};
    2530           2 :         struct notify_changes change2 = {0};
    2531             :         struct smb2_create create;
    2532             :         union smb_setfileinfo sinfo;
    2533           2 :         struct smb2_handle h1 = {{0}};
    2534           2 :         struct smb2_handle h2 = {{0}};
    2535             :         struct smb2_request *req;
    2536           2 :         struct tevent_timer *te = NULL;
    2537           2 :         bool ok = false;
    2538             : 
    2539           2 :         smb2_deltree(tree1, BASEDIR_INR);
    2540             : 
    2541           2 :         torture_comment(torture, "Testing change notify of a rename with inotify\n");
    2542             : 
    2543           2 :         status = torture_smb2_testdir(tree1, BASEDIR_INR, &h1);
    2544           2 :         torture_assert_ntstatus_ok_goto(torture, status, ok, done, "torture_smb2_testdir failed");
    2545             : 
    2546           2 :         ZERO_STRUCT(create);
    2547           2 :         create.in.desired_access = SEC_RIGHTS_FILE_READ |
    2548             :                 SEC_RIGHTS_FILE_WRITE|
    2549             :                 SEC_RIGHTS_FILE_ALL;
    2550           2 :         create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    2551           2 :         create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    2552           2 :         create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    2553             :                 NTCREATEX_SHARE_ACCESS_WRITE |
    2554             :                 NTCREATEX_SHARE_ACCESS_DELETE;
    2555           2 :         create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
    2556           2 :         create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    2557           2 :         create.in.fname = BASEDIR_INR "\\subdir-name";
    2558             : 
    2559           2 :         status = smb2_create(tree2, torture, &create);
    2560           2 :         torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_create failed\n");
    2561           2 :         h2 = create.out.file.handle;
    2562             : 
    2563           2 :         ZERO_STRUCT(notify);
    2564           2 :         notify.level = RAW_NOTIFY_SMB2;
    2565           2 :         notify.in.buffer_size = 4096;
    2566           2 :         notify.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    2567           2 :         notify.in.file.handle = h1;
    2568           2 :         notify.in.recursive = true;
    2569           2 :         req = smb2_notify_send(tree1, &notify);
    2570           2 :         torture_assert_not_null_goto(torture, req, ok, done, "smb2_notify_send failed\n");
    2571             : 
    2572          12 :         while (!NT_STATUS_EQUAL(req->status, NT_STATUS_PENDING)) {
    2573           8 :                 if (tevent_loop_once(torture->ev) != 0) {
    2574           0 :                         goto done;
    2575             :                 }
    2576             :         }
    2577             : 
    2578           2 :         ZERO_STRUCT(sinfo);
    2579           2 :         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
    2580           2 :         sinfo.rename_information.in.file.handle = h2;
    2581           2 :         sinfo.rename_information.in.new_name = BASEDIR_INR "\\subdir-name-r";
    2582             : 
    2583           2 :         status = smb2_setinfo_file(tree2, &sinfo);
    2584           2 :         torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_setinfo_file failed\n");
    2585             : 
    2586           2 :         smb2_util_close(tree2, h2);
    2587             : 
    2588           2 :         te = tevent_add_timer(torture->ev,
    2589             :                               tree1,
    2590             :                               tevent_timeval_current_ofs(1, 0),
    2591             :                               notify_timeout,
    2592             :                               req);
    2593           2 :         torture_assert_not_null_goto(torture, te, ok, done, "tevent_add_timer failed\n");
    2594             : 
    2595           2 :         status = smb2_notify_recv(req, torture, &notify);
    2596           2 :         torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_notify_recv failed\n");
    2597             : 
    2598           2 :         torture_assert_goto(torture, notify.out.num_changes == 1 || notify.out.num_changes == 2,
    2599             :                             ok, done, "bad notify\n");
    2600             : 
    2601           2 :         change1 = notify.out.changes[0];
    2602           2 :         if (notify.out.num_changes == 2) {
    2603           2 :                 change2 = notify.out.changes[1];
    2604             :         } else {
    2605             :                 /*
    2606             :                  * We may only get one event at a time, so check for the
    2607             :                  * matching second event for the oldname/newname or
    2608             :                  * removed/added pair.
    2609             :                  */
    2610           0 :                 ZERO_STRUCT(notify);
    2611           0 :                 notify.level = RAW_NOTIFY_SMB2;
    2612           0 :                 notify.in.buffer_size = 4096;
    2613           0 :                 notify.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    2614           0 :                 notify.in.file.handle = h1;
    2615           0 :                 notify.in.recursive = true;
    2616           0 :                 req = smb2_notify_send(tree1, &notify);
    2617           0 :                 torture_assert_not_null_goto(torture, req, ok, done, "smb2_notify_send failed\n");
    2618             : 
    2619           0 :                 status = smb2_notify_recv(req, torture, &notify);
    2620           0 :                 torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_notify_recv failed\n");
    2621             : 
    2622           0 :                 torture_assert_goto(torture, notify.out.num_changes == 1, ok, done,
    2623             :                                     "bad notify\n");
    2624             : 
    2625           0 :                 change2 = notify.out.changes[0];
    2626             :         }
    2627             : 
    2628           2 :         if ((change1.action != NOTIFY_ACTION_OLD_NAME) &&
    2629           0 :             (change1.action != NOTIFY_ACTION_REMOVED))
    2630             :         {
    2631           0 :                 torture_fail_goto(torture, done, "bad change notification\n");
    2632             :         }
    2633           2 :         torture_assert_str_equal_goto(torture, change1.name.s, "subdir-name",
    2634             :                             ok, done, "bad change notification\n");
    2635             : 
    2636           2 :         if ((change2.action != NOTIFY_ACTION_NEW_NAME) &&
    2637           0 :             (change2.action != NOTIFY_ACTION_ADDED))
    2638             :         {
    2639           0 :                 torture_fail_goto(torture, done, "bad change notification\n");
    2640             :         }
    2641           2 :         torture_assert_str_equal_goto(torture, change2.name.s, "subdir-name-r",
    2642             :                             ok, done, "bad change notification\n");
    2643             : 
    2644           2 :         ok = true;
    2645           2 : done:
    2646           2 :         if (!smb2_util_handle_empty(h1)) {
    2647           2 :                 smb2_util_close(tree1, h1);
    2648             :         }
    2649           2 :         if (!smb2_util_handle_empty(h2)) {
    2650           2 :                 smb2_util_close(tree2, h2);
    2651             :         }
    2652             : 
    2653           2 :         smb2_deltree(tree1, BASEDIR_INR);
    2654           2 :         return ok;
    2655             : }
    2656             : 
    2657             : /*
    2658             :   Test asking for a change notify on a handle without permissions.
    2659             : */
    2660             : 
    2661             : #define BASEDIR_HPERM BASEDIR "_HPERM"
    2662             : 
    2663           2 : static bool torture_smb2_notify_handle_permissions(
    2664             :                 struct torture_context *torture,
    2665             :                 struct smb2_tree *tree)
    2666             : {
    2667           2 :         bool ret = true;
    2668             :         NTSTATUS status;
    2669             :         union smb_notify notify;
    2670             :         union smb_open io;
    2671           2 :         struct smb2_handle h1 = {{0}};
    2672             :         struct smb2_request *req;
    2673             : 
    2674           2 :         smb2_deltree(tree, BASEDIR_HPERM);
    2675           2 :         smb2_util_rmdir(tree, BASEDIR_HPERM);
    2676             : 
    2677           2 :         torture_comment(torture,
    2678             :                 "TESTING CHANGE NOTIFY "
    2679             :                 "ON A HANDLE WITHOUT PERMISSIONS\n");
    2680             : 
    2681             :         /*
    2682             :           get a handle on the directory
    2683             :         */
    2684           2 :         ZERO_STRUCT(io.smb2);
    2685           2 :         io.generic.level = RAW_OPEN_SMB2;
    2686           2 :         io.smb2.in.create_flags = 0;
    2687           2 :         io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE;
    2688           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    2689           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    2690           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    2691             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    2692           2 :         io.smb2.in.alloc_size = 0;
    2693           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    2694           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    2695           2 :         io.smb2.in.security_flags = 0;
    2696           2 :         io.smb2.in.fname = BASEDIR_HPERM;
    2697             : 
    2698           2 :         status = smb2_create(tree, torture, &io.smb2);
    2699           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2700           2 :         h1 = io.smb2.out.file.handle;
    2701             : 
    2702             :         /* ask for a change notify,
    2703             :            on file or directory name changes */
    2704           2 :         ZERO_STRUCT(notify.smb2);
    2705           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    2706           2 :         notify.smb2.in.buffer_size = 1000;
    2707           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    2708           2 :         notify.smb2.in.file.handle = h1;
    2709           2 :         notify.smb2.in.recursive = true;
    2710             : 
    2711           2 :         req = smb2_notify_send(tree, &notify.smb2);
    2712           2 :         torture_assert_goto(torture,
    2713             :                         req != NULL,
    2714             :                         ret,
    2715             :                         done,
    2716             :                         "smb2_notify_send failed\n");
    2717             : 
    2718             :         /*
    2719             :          * Cancel it, we don't really want to wait.
    2720             :          */
    2721           2 :         smb2_cancel(req);
    2722           2 :         status = smb2_notify_recv(req, torture, &notify.smb2);
    2723             :         /* Handle h1 doesn't have permissions for ChangeNotify. */
    2724           2 :         CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
    2725             : 
    2726           4 : done:
    2727           2 :         if (!smb2_util_handle_empty(h1)) {
    2728           2 :                 smb2_util_close(tree, h1);
    2729             :         }
    2730           2 :         smb2_deltree(tree, BASEDIR_HPERM);
    2731           2 :         return ret;
    2732             : }
    2733             : 
    2734             : /*
    2735             :    basic testing of SMB2 change notify
    2736             : */
    2737        2353 : struct torture_suite *torture_smb2_notify_init(TALLOC_CTX *ctx)
    2738             : {
    2739        2353 :         struct torture_suite *suite = torture_suite_create(ctx, "notify");
    2740             : 
    2741        2353 :         torture_suite_add_1smb2_test(suite, "valid-req", test_valid_request);
    2742        2353 :         torture_suite_add_1smb2_test(suite, "tcon", torture_smb2_notify_tcon);
    2743        2353 :         torture_suite_add_2smb2_test(suite, "dir", torture_smb2_notify_dir);
    2744        2353 :         torture_suite_add_2smb2_test(suite, "mask", torture_smb2_notify_mask);
    2745        2353 :         torture_suite_add_1smb2_test(suite, "tdis", torture_smb2_notify_tree_disconnect);
    2746        2353 :         torture_suite_add_1smb2_test(suite, "tdis1", torture_smb2_notify_tree_disconnect_1);
    2747        2353 :         torture_suite_add_2smb2_test(suite, "mask-change", torture_smb2_notify_mask_change);
    2748        2353 :         torture_suite_add_1smb2_test(suite, "close", torture_smb2_notify_close);
    2749        2353 :         torture_suite_add_1smb2_test(suite, "logoff", torture_smb2_notify_ulogoff);
    2750        2353 :         torture_suite_add_1smb2_test(suite, "session-reconnect", torture_smb2_notify_session_reconnect);
    2751        2353 :         torture_suite_add_2smb2_test(suite, "invalid-reauth", torture_smb2_notify_invalid_reauth);
    2752        2353 :         torture_suite_add_1smb2_test(suite, "tree", torture_smb2_notify_tree);
    2753        2353 :         torture_suite_add_2smb2_test(suite, "basedir", torture_smb2_notify_basedir);
    2754        2353 :         torture_suite_add_2smb2_test(suite, "double", torture_smb2_notify_double);
    2755        2353 :         torture_suite_add_1smb2_test(suite, "file", torture_smb2_notify_file);
    2756        2353 :         torture_suite_add_1smb2_test(suite, "tcp", torture_smb2_notify_tcp_disconnect);
    2757        2353 :         torture_suite_add_2smb2_test(suite, "rec", torture_smb2_notify_recursive);
    2758        2353 :         torture_suite_add_1smb2_test(suite, "overflow", torture_smb2_notify_overflow);
    2759        2353 :         torture_suite_add_1smb2_test(suite, "rmdir1",
    2760             :                                      torture_smb2_notify_rmdir1);
    2761        2353 :         torture_suite_add_1smb2_test(suite, "rmdir2",
    2762             :                                      torture_smb2_notify_rmdir2);
    2763        2353 :         torture_suite_add_2smb2_test(suite, "rmdir3",
    2764             :                                      torture_smb2_notify_rmdir3);
    2765        2353 :         torture_suite_add_2smb2_test(suite, "rmdir4",
    2766             :                                      torture_smb2_notify_rmdir4);
    2767        2353 :         torture_suite_add_1smb2_test(suite,
    2768             :                                     "handle-permissions",
    2769             :                                     torture_smb2_notify_handle_permissions);
    2770             : 
    2771        2353 :         suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests");
    2772             : 
    2773        2353 :         return suite;
    2774             : }
    2775             : 
    2776             : /*
    2777             :    basic testing of SMB2 change notify
    2778             : */
    2779        2353 : struct torture_suite *torture_smb2_notify_inotify_init(TALLOC_CTX *ctx)
    2780             : {
    2781        2353 :         struct torture_suite *suite = torture_suite_create(ctx, "notify-inotify");
    2782             : 
    2783        2353 :         suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests that use inotify");
    2784             : 
    2785        2353 :         torture_suite_add_2smb2_test(suite, "inotify-rename", torture_smb2_inotify_rename);
    2786             : 
    2787        2353 :         return suite;
    2788             : }

Generated by: LCOV version 1.13