LCOV - code coverage report
Current view: top level - source4/torture/smb2 - notify.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 1351 1578 85.6 %
Date: 2024-04-21 15:09:00 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           0 :         NTSTATUS status;
      87           0 :         struct smb2_handle dh;
      88           0 :         struct smb2_notify n;
      89           0 :         struct smb2_request *req;
      90           0 :         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           0 :         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          10 :         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          10 :         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          10 :         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           0 :         NTSTATUS status;
     236           0 :         union smb_notify notify;
     237           0 :         union smb_open io;
     238           0 :         union smb_close cl;
     239           0 :         int i, count;
     240           2 :         struct smb2_handle h1 = {{0}};
     241           2 :         struct smb2_handle h2 = {{0}};
     242           0 :         struct smb2_request *req, *req2;
     243           2 :         const char *fname = BASEDIR_DIR "\\subdir-name";
     244           0 :         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           0 :                 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           2 : 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           0 :         struct smb2_handle h1;
     484         522 :         bool ret = true;
     485           0 :         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           0 :         NTSTATUS status;
     511           0 :         union smb_notify notify;
     512           0 :         union smb_open io, io1;
     513           0 :         union smb_setfileinfo sinfo;
     514           0 :         struct smb2_handle h1;
     515           0 :         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           0 : 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           0 :         NTSTATUS status;
     681           0 :         union smb_notify notify;
     682           0 :         union smb_open io, io1;
     683           0 :         struct smb2_handle h1;
     684           0 :         struct smb2_request *req1, *req2;
     685           0 :         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           2 : 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           0 :         NTSTATUS status;
     868           0 :         union smb_notify notify;
     869           0 :         union smb_open io, io1;
     870           0 :         struct smb2_handle h1, h2;
     871           0 :         int i;
     872           2 :         char c = 1;
     873           0 :         union smb_setfileinfo sinfo;
     874             : 
     875           2 :         smb2_deltree(tree1, BASEDIR_MSK);
     876           2 :         smb2_util_rmdir(tree1, BASEDIR_MSK);
     877             : 
     878           2 :         torture_comment(torture, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
     879             : 
     880             : 
     881           2 :         ZERO_STRUCT(h1);
     882           2 :         ZERO_STRUCT(h2);
     883             :         /*
     884             :           get a handle on the directory
     885             :         */
     886           2 :         ZERO_STRUCT(io.smb2);
     887           2 :         io.generic.level = RAW_OPEN_SMB2;
     888           2 :         io.smb2.in.create_flags = 0;
     889           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
     890           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
     891           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
     892           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
     893             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
     894           2 :         io.smb2.in.alloc_size = 0;
     895           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
     896           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
     897           2 :         io.smb2.in.security_flags = 0;
     898           2 :         io.smb2.in.fname = BASEDIR_MSK;
     899             : 
     900           2 :         ZERO_STRUCT(notify.smb2);
     901           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
     902           2 :         notify.smb2.in.buffer_size = 1000;
     903           2 :         notify.smb2.in.recursive = true;
     904             : 
     905             : #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, \
     906             :                          expected, nchanges) \
     907             :         do { \
     908             :         do { for (i=0;i<32;i++) { \
     909             :                 struct smb2_request *req; \
     910             :                 status = smb2_create(tree1, torture, &(io.smb2)); \
     911             :                 CHECK_STATUS(status, NT_STATUS_OK); \
     912             :                 h1 = io.smb2.out.file.handle; \
     913             :                 setup \
     914             :                 notify.smb2.in.file.handle = h1;        \
     915             :                 notify.smb2.in.completion_filter = ((uint32_t)1<<i); \
     916             :                 /* cancel initial requests so the buffer is setup */    \
     917             :                 req = smb2_notify_send(tree1, &(notify.smb2)); \
     918             :                 smb2_cancel(req); \
     919             :                 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
     920             :                 CHECK_STATUS(status, NT_STATUS_CANCELLED); \
     921             :                 /* send the change notify request */ \
     922             :                 req = smb2_notify_send(tree1, &(notify.smb2)); \
     923             :                 op \
     924             :                 smb_msleep(200); smb2_cancel(req); \
     925             :                 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
     926             :                 cleanup \
     927             :                 smb2_util_close(tree1, h1); \
     928             :                 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
     929             :                 CHECK_STATUS(status, NT_STATUS_OK); \
     930             :                 /* special case to cope with file rename behaviour */ \
     931             :                 if (nchanges == 2 && notify.smb2.out.num_changes == 1 && \
     932             :                     notify.smb2.out.changes[0].action == \
     933             :                         NOTIFY_ACTION_MODIFIED && \
     934             :                     ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
     935             :                     Action == NOTIFY_ACTION_OLD_NAME) { \
     936             :                         torture_comment(torture, \
     937             :                                 "(rename file special handling OK)\n"); \
     938             :                 } else if (nchanges != notify.smb2.out.num_changes) { \
     939             :                         torture_result(torture, TORTURE_FAIL, \
     940             :                                "ERROR: nchanges=%d expected=%d "\
     941             :                                "action=%d filter=0x%08x\n", \
     942             :                                notify.smb2.out.num_changes, \
     943             :                                nchanges, \
     944             :                                notify.smb2.out.changes[0].action, \
     945             :                                notify.smb2.in.completion_filter); \
     946             :                         ret = false; \
     947             :                 } else if (notify.smb2.out.changes[0].action != Action) { \
     948             :                         torture_result(torture, TORTURE_FAIL, \
     949             :                                "ERROR: nchanges=%d action=%d " \
     950             :                                "expectedAction=%d filter=0x%08x\n", \
     951             :                                notify.smb2.out.num_changes, \
     952             :                                notify.smb2.out.changes[0].action, \
     953             :                                Action, \
     954             :                                notify.smb2.in.completion_filter); \
     955             :                         ret = false; \
     956             :                 } else if (strcmp(notify.smb2.out.changes[0].name.s, \
     957             :                            "tname1") != 0) { \
     958             :                         torture_result(torture, TORTURE_FAIL, \
     959             :                                "ERROR: nchanges=%d action=%d " \
     960             :                                "filter=0x%08x name=%s\n", \
     961             :                                notify.smb2.out.num_changes, \
     962             :                                notify.smb2.out.changes[0].action, \
     963             :                                notify.smb2.in.completion_filter, \
     964             :                                notify.smb2.out.changes[0].name.s);      \
     965             :                         ret = false; \
     966             :                 } \
     967             :         } \
     968             :         } while (0); \
     969             :         } while (0);
     970             : 
     971           2 :         torture_comment(torture, "Testing mkdir\n");
     972          66 :         NOTIFY_MASK_TEST("Testing mkdir",;,
     973             :                          smb2_util_mkdir(tree2, BASEDIR_MSK "\\tname1");,
     974             :                          smb2_util_rmdir(tree2, BASEDIR_MSK "\\tname1");,
     975             :                          NOTIFY_ACTION_ADDED,
     976           0 :                          FILE_NOTIFY_CHANGE_DIR_NAME, 1);
     977             : 
     978           2 :         torture_comment(torture, "Testing create file\n");
     979           2 :         ZERO_STRUCT(io1.smb2);
     980           2 :         io1.generic.level = RAW_OPEN_SMB2;
     981           2 :         io1.smb2.in.create_flags = 0;
     982           2 :         io1.smb2.in.desired_access = SEC_FILE_ALL;
     983           2 :         io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
     984           2 :         io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
     985             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
     986           2 :         io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
     987           2 :         io1.smb2.in.security_flags = 0;
     988           2 :         io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
     989           2 :         io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
     990           2 :         io1.smb2.in.fname = BASEDIR_MSK "\\tname1";
     991             : 
     992          66 :         NOTIFY_MASK_TEST("Testing create file",;,
     993             :                          smb2_util_close(tree2, custom_smb2_create(tree2,
     994             :                                                 torture, &(io1.smb2)));,
     995             :                          smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1");,
     996             :                          NOTIFY_ACTION_ADDED,
     997           0 :                          FILE_NOTIFY_CHANGE_FILE_NAME, 1);
     998             : 
     999           2 :         torture_comment(torture, "Testing unlink\n");
    1000          66 :         NOTIFY_MASK_TEST("Testing unlink",
    1001             :                          smb2_util_close(tree2, custom_smb2_create(tree2,
    1002             :                                                 torture, &(io1.smb2)));,
    1003             :                          smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1");,
    1004             :                          ;,
    1005             :                          NOTIFY_ACTION_REMOVED,
    1006           0 :                          FILE_NOTIFY_CHANGE_FILE_NAME, 1);
    1007             : 
    1008           2 :         torture_comment(torture, "Testing rmdir\n");
    1009          66 :         NOTIFY_MASK_TEST("Testing rmdir",
    1010             :                          smb2_util_mkdir(tree2, BASEDIR_MSK "\\tname1");,
    1011             :                          smb2_util_rmdir(tree2, BASEDIR_MSK "\\tname1");,
    1012             :                          ;,
    1013             :                          NOTIFY_ACTION_REMOVED,
    1014           0 :                          FILE_NOTIFY_CHANGE_DIR_NAME, 1);
    1015             : 
    1016           2 :         torture_comment(torture, "Testing rename file\n");
    1017           2 :         ZERO_STRUCT(sinfo);
    1018           2 :         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
    1019           2 :         sinfo.rename_information.in.file.handle = h1;
    1020           2 :         sinfo.rename_information.in.overwrite = true;
    1021           2 :         sinfo.rename_information.in.root_fid = 0;
    1022           2 :         sinfo.rename_information.in.new_name = BASEDIR_MSK "\\tname2";
    1023          66 :         NOTIFY_MASK_TEST("Testing rename file",
    1024             :                          smb2_util_close(tree2, custom_smb2_create(tree2,
    1025             :                                                 torture, &(io1.smb2)));,
    1026             :                          smb2_setinfo_file(tree2, &sinfo);,
    1027             :                          smb2_util_unlink(tree2, BASEDIR_MSK "\\tname2");,
    1028             :                          NOTIFY_ACTION_OLD_NAME,
    1029           0 :                          FILE_NOTIFY_CHANGE_FILE_NAME, 2);
    1030             : 
    1031           2 :         torture_comment(torture, "Testing rename dir\n");
    1032           2 :         ZERO_STRUCT(sinfo);
    1033           2 :         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
    1034           2 :         sinfo.rename_information.in.file.handle = h1;
    1035           2 :         sinfo.rename_information.in.overwrite = true;
    1036           2 :         sinfo.rename_information.in.root_fid = 0;
    1037           2 :         sinfo.rename_information.in.new_name = BASEDIR_MSK "\\tname2";
    1038          66 :         NOTIFY_MASK_TEST("Testing rename dir",
    1039             :                 smb2_util_mkdir(tree2, BASEDIR_MSK "\\tname1");,
    1040             :                 smb2_setinfo_file(tree2, &sinfo);,
    1041             :                 smb2_util_rmdir(tree2, BASEDIR_MSK "\\tname2");,
    1042             :                 NOTIFY_ACTION_OLD_NAME,
    1043           0 :                 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
    1044             : 
    1045           2 :         torture_comment(torture, "Testing set path attribute\n");
    1046          66 :         NOTIFY_MASK_TEST("Testing set path attribute",
    1047             :                 smb2_util_close(tree2, custom_smb2_create(tree2,
    1048             :                                        torture, &(io.smb2)));,
    1049             :                 smb2_util_setatr(tree2, BASEDIR_MSK "\\tname1",
    1050             :                                  FILE_ATTRIBUTE_HIDDEN);,
    1051             :                 smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1");,
    1052             :                 NOTIFY_ACTION_MODIFIED,
    1053           0 :                 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
    1054             : 
    1055           2 :         torture_comment(torture, "Testing set path write time\n");
    1056           2 :         ZERO_STRUCT(sinfo);
    1057           2 :         sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
    1058           2 :         sinfo.generic.in.file.handle = h1;
    1059           2 :         sinfo.basic_info.in.write_time = 1000;
    1060          66 :         NOTIFY_MASK_TEST("Testing set path write time",
    1061             :                 smb2_util_close(tree2, custom_smb2_create(tree2,
    1062             :                                        torture, &(io1.smb2)));,
    1063             :                 smb2_setinfo_file(tree2, &sinfo);,
    1064             :                 smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1");,
    1065             :                 NOTIFY_ACTION_MODIFIED,
    1066           0 :                 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
    1067             : 
    1068           2 :         if (torture_setting_bool(torture, "samba3", false)) {
    1069           2 :                 torture_comment(torture,
    1070             :                        "Samba3 does not yet support create times "
    1071             :                        "everywhere\n");
    1072             :         }
    1073             :         else {
    1074           0 :                 ZERO_STRUCT(sinfo);
    1075           0 :                 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
    1076           0 :                 sinfo.generic.in.file.handle = h1;
    1077           0 :                 sinfo.basic_info.in.create_time = 0;
    1078           0 :                 torture_comment(torture, "Testing set file create time\n");
    1079           0 :                 NOTIFY_MASK_TEST("Testing set file create time",
    1080             :                         smb2_create_complex_file(torture, tree2,
    1081             :                         BASEDIR_MSK "\\tname1", &h2);,
    1082             :                         smb2_setinfo_file(tree2, &sinfo);,
    1083             :                         (smb2_util_close(tree2, h2),
    1084             :                          smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1"));,
    1085             :                         NOTIFY_ACTION_MODIFIED,
    1086           0 :                         FILE_NOTIFY_CHANGE_CREATION, 1);
    1087             :         }
    1088             : 
    1089           2 :         ZERO_STRUCT(sinfo);
    1090           2 :         sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
    1091           2 :         sinfo.generic.in.file.handle = h1;
    1092           2 :         sinfo.basic_info.in.access_time = 0;
    1093           2 :         torture_comment(torture, "Testing set file access time\n");
    1094          66 :         NOTIFY_MASK_TEST("Testing set file access time",
    1095             :                 smb2_create_complex_file(torture,
    1096             :                         tree2,
    1097             :                         BASEDIR_MSK "\\tname1",
    1098             :                         &h2);,
    1099             :                 smb2_setinfo_file(tree2, &sinfo);,
    1100             :                 (smb2_util_close(tree2, h2),
    1101             :                 smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1"));,
    1102             :                 NOTIFY_ACTION_MODIFIED,
    1103           0 :                 FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
    1104             : 
    1105           2 :         ZERO_STRUCT(sinfo);
    1106           2 :         sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
    1107           2 :         sinfo.generic.in.file.handle = h1;
    1108           2 :         sinfo.basic_info.in.change_time = 0;
    1109           2 :         torture_comment(torture, "Testing set file change time\n");
    1110          66 :         NOTIFY_MASK_TEST("Testing set file change time",
    1111             :                 smb2_create_complex_file(torture,
    1112             :                         tree2,
    1113             :                         BASEDIR_MSK "\\tname1",
    1114             :                         &h2);,
    1115             :                 smb2_setinfo_file(tree2, &sinfo);,
    1116             :                 (smb2_util_close(tree2, h2),
    1117             :                 smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1"));,
    1118             :                 NOTIFY_ACTION_MODIFIED,
    1119           0 :                 0, 1);
    1120             : 
    1121             : 
    1122           2 :         torture_comment(torture, "Testing write\n");
    1123          66 :         NOTIFY_MASK_TEST("Testing write",
    1124             :                 smb2_create_complex_file(torture,
    1125             :                         tree2,
    1126             :                         BASEDIR_MSK "\\tname1",
    1127             :                         &h2);,
    1128             :                 smb2_util_write(tree2, h2, &c, 10000, 1);,
    1129             :                 (smb2_util_close(tree2, h2),
    1130             :                 smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1"));,
    1131             :                 NOTIFY_ACTION_MODIFIED,
    1132           0 :                 0, 1);
    1133             : 
    1134           2 : done:
    1135           2 :         smb2_deltree(tree1, BASEDIR_MSK);
    1136           2 :         return ret;
    1137             : }
    1138             : 
    1139             : #define BASEDIR_FL BASEDIR "_FL"
    1140             : /*
    1141             :   basic testing of change notify on files
    1142             : */
    1143           2 : static bool torture_smb2_notify_file(struct torture_context *torture,
    1144             :                                 struct smb2_tree *tree)
    1145             : {
    1146           0 :         NTSTATUS status;
    1147           2 :         bool ret = true;
    1148           0 :         union smb_open io;
    1149           0 :         union smb_close cl;
    1150           0 :         union smb_notify notify;
    1151           0 :         struct smb2_request *req;
    1152           0 :         struct smb2_handle h1;
    1153           2 :         const char *fname = BASEDIR_FL "\\file.txt";
    1154             : 
    1155           2 :         smb2_deltree(tree, BASEDIR_FL);
    1156           2 :         smb2_util_rmdir(tree, BASEDIR_FL);
    1157             : 
    1158           2 :         torture_comment(torture, "TESTING CHANGE NOTIFY ON FILES\n");
    1159           2 :         status = torture_smb2_testdir(tree, BASEDIR_FL, &h1);
    1160           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1161             : 
    1162           2 :         ZERO_STRUCT(io.smb2);
    1163           2 :         io.generic.level = RAW_OPEN_SMB2;
    1164           2 :         io.smb2.in.create_flags = 0;
    1165           2 :         io.smb2.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
    1166           2 :         io.smb2.in.create_options = 0;
    1167           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1168           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1169             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    1170           2 :         io.smb2.in.alloc_size = 0;
    1171           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    1172           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1173           2 :         io.smb2.in.security_flags = 0;
    1174           2 :         io.smb2.in.fname = fname;
    1175           2 :         status = smb2_create(tree, torture, &(io.smb2));
    1176           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1177           2 :         h1 = io.smb2.out.file.handle;
    1178             : 
    1179             :         /* ask for a change notify,
    1180             :            on file or directory name changes */
    1181           2 :         ZERO_STRUCT(notify.smb2);
    1182           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    1183           2 :         notify.smb2.in.file.handle = h1;
    1184           2 :         notify.smb2.in.buffer_size = 1000;
    1185           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
    1186           2 :         notify.smb2.in.recursive = false;
    1187             : 
    1188           2 :         torture_comment(torture,
    1189             :         "Testing if notifies on file handles are invalid (should be)\n");
    1190             : 
    1191           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    1192           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    1193           2 :         CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
    1194             : 
    1195           2 :         ZERO_STRUCT(cl.smb2);
    1196           2 :         cl.close.level = RAW_CLOSE_SMB2;
    1197           2 :         cl.close.in.file.handle = h1;
    1198           2 :         status = smb2_close(tree, &(cl.smb2));
    1199           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1200             : 
    1201           2 :         status = smb2_util_unlink(tree, fname);
    1202           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1203             : 
    1204           2 : done:
    1205           2 :         smb2_deltree(tree, BASEDIR_FL);
    1206           2 :         return ret;
    1207             : }
    1208             : /*
    1209             :   basic testing of change notifies followed by a tdis
    1210             : */
    1211             : 
    1212             : #define BASEDIR_TD BASEDIR "_TD"
    1213             : 
    1214           2 : static bool torture_smb2_notify_tree_disconnect(
    1215             :                 struct torture_context *torture,
    1216             :                 struct smb2_tree *tree)
    1217             : {
    1218           2 :         bool ret = true;
    1219           0 :         NTSTATUS status;
    1220           0 :         union smb_notify notify;
    1221           0 :         union smb_open io;
    1222           0 :         struct smb2_handle h1;
    1223           0 :         struct smb2_request *req;
    1224             : 
    1225           2 :         smb2_deltree(tree, BASEDIR_TD);
    1226           2 :         smb2_util_rmdir(tree, BASEDIR_TD);
    1227             : 
    1228           2 :         torture_comment(torture, "TESTING CHANGE NOTIFY+CANCEL FOLLOWED BY "
    1229             :                         "TREE-DISCONNECT\n");
    1230             : 
    1231             :         /*
    1232             :           get a handle on the directory
    1233             :         */
    1234           2 :         ZERO_STRUCT(io.smb2);
    1235           2 :         io.generic.level = RAW_OPEN_SMB2;
    1236           2 :         io.smb2.in.create_flags = 0;
    1237           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
    1238           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1239           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1240           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1241             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    1242           2 :         io.smb2.in.alloc_size = 0;
    1243           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    1244           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1245           2 :         io.smb2.in.security_flags = 0;
    1246           2 :         io.smb2.in.fname = BASEDIR_TD;
    1247             : 
    1248           2 :         status = smb2_create(tree, torture, &(io.smb2));
    1249           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1250           2 :         h1 = io.smb2.out.file.handle;
    1251             : 
    1252             :         /* ask for a change notify,
    1253             :            on file or directory name changes */
    1254           2 :         ZERO_STRUCT(notify.smb2);
    1255           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    1256           2 :         notify.smb2.in.buffer_size = 1000;
    1257           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1258           2 :         notify.smb2.in.file.handle = h1;
    1259           2 :         notify.smb2.in.recursive = true;
    1260             : 
    1261           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    1262           2 :         smb2_cancel(req);
    1263           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    1264             : 
    1265           2 :         status = smb2_tdis(tree);
    1266           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1267             : 
    1268           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    1269             : 
    1270           2 :         smb2_notify_recv(req, torture, &(notify.smb2));
    1271           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1272           2 :         CHECK_VAL(notify.smb2.out.num_changes, 0);
    1273             : 
    1274           2 : done:
    1275           2 :         smb2_deltree(tree, BASEDIR_TD);
    1276           2 :         return ret;
    1277             : }
    1278             : 
    1279             : /*
    1280             :   testing of change notifies followed by a tdis - no cancel
    1281             : */
    1282             : 
    1283             : #define BASEDIR_NTDIS BASEDIR "_NTDIS"
    1284             : 
    1285           2 : static bool torture_smb2_notify_tree_disconnect_1(
    1286             :                 struct torture_context *torture,
    1287             :                 struct smb2_tree *tree)
    1288             : {
    1289           2 :         bool ret = true;
    1290           0 :         NTSTATUS status;
    1291           0 :         union smb_notify notify;
    1292           0 :         union smb_open io;
    1293           0 :         struct smb2_handle h1;
    1294           0 :         struct smb2_request *req;
    1295             : 
    1296           2 :         smb2_deltree(tree, BASEDIR_NTDIS);
    1297           2 :         smb2_util_rmdir(tree, BASEDIR_NTDIS);
    1298             : 
    1299           2 :         torture_comment(torture, "TESTING CHANGE NOTIFY ASYNC FOLLOWED BY "
    1300             :                         "TREE-DISCONNECT\n");
    1301             : 
    1302             :         /*
    1303             :           get a handle on the directory
    1304             :         */
    1305           2 :         ZERO_STRUCT(io.smb2);
    1306           2 :         io.generic.level = RAW_OPEN_SMB2;
    1307           2 :         io.smb2.in.create_flags = 0;
    1308           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
    1309           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1310           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1311           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1312             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    1313           2 :         io.smb2.in.alloc_size = 0;
    1314           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    1315           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1316           2 :         io.smb2.in.security_flags = 0;
    1317           2 :         io.smb2.in.fname = BASEDIR_NTDIS;
    1318             : 
    1319           2 :         status = smb2_create(tree, torture, &(io.smb2));
    1320           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1321           2 :         h1 = io.smb2.out.file.handle;
    1322             : 
    1323             :         /* ask for a change notify,
    1324             :            on file or directory name changes */
    1325           2 :         ZERO_STRUCT(notify.smb2);
    1326           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    1327           2 :         notify.smb2.in.buffer_size = 1000;
    1328           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1329           2 :         notify.smb2.in.file.handle = h1;
    1330           2 :         notify.smb2.in.recursive = true;
    1331             : 
    1332           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    1333          10 :         WAIT_FOR_ASYNC_RESPONSE(req);
    1334             : 
    1335           2 :         status = smb2_tdis(tree);
    1336           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1337             : 
    1338           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    1339           2 :         CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
    1340           2 :         CHECK_VAL(notify.smb2.out.num_changes, 0);
    1341             : 
    1342           2 : done:
    1343           2 :         smb2_deltree(tree, BASEDIR_NTDIS);
    1344           2 :         return ret;
    1345             : }
    1346             : 
    1347             : /*
    1348             :   basic testing of change notifies followed by a close
    1349             : */
    1350             : 
    1351             : #define BASEDIR_CNC BASEDIR "_CNC"
    1352             : 
    1353           2 : static bool torture_smb2_notify_close(struct torture_context *torture,
    1354             :                                 struct smb2_tree *tree1)
    1355             : {
    1356           2 :         bool ret = true;
    1357           0 :         NTSTATUS status;
    1358           0 :         union smb_notify notify;
    1359           0 :         union smb_open io;
    1360           0 :         struct smb2_handle h1;
    1361           0 :         struct smb2_request *req;
    1362             : 
    1363           2 :         smb2_deltree(tree1, BASEDIR_CNC);
    1364           2 :         smb2_util_rmdir(tree1, BASEDIR_CNC);
    1365             : 
    1366           2 :         torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
    1367             : 
    1368             :         /*
    1369             :           get a handle on the directory
    1370             :         */
    1371           2 :         ZERO_STRUCT(io.smb2);
    1372           2 :         io.generic.level = RAW_OPEN_SMB2;
    1373           2 :         io.smb2.in.create_flags = 0;
    1374           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
    1375           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1376           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1377           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1378             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    1379           2 :         io.smb2.in.alloc_size = 0;
    1380           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    1381           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1382           2 :         io.smb2.in.security_flags = 0;
    1383           2 :         io.smb2.in.fname = BASEDIR_CNC;
    1384             : 
    1385           2 :         status = smb2_create(tree1, torture, &(io.smb2));
    1386           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1387             : 
    1388           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
    1389           2 :         status = smb2_create(tree1, torture, &(io.smb2));
    1390           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1391           2 :         h1 = io.smb2.out.file.handle;
    1392             : 
    1393             :         /* ask for a change notify,
    1394             :            on file or directory name changes */
    1395           2 :         ZERO_STRUCT(notify.smb2);
    1396           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    1397           2 :         notify.smb2.in.buffer_size = 1000;
    1398           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1399           2 :         notify.smb2.in.file.handle = h1;
    1400           2 :         notify.smb2.in.recursive = true;
    1401             : 
    1402           2 :         req = smb2_notify_send(tree1, &(notify.smb2));
    1403             : 
    1404          10 :         WAIT_FOR_ASYNC_RESPONSE(req);
    1405             : 
    1406           2 :         status = smb2_util_close(tree1, h1);
    1407           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1408             : 
    1409           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    1410           2 :         CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
    1411           2 :         CHECK_VAL(notify.smb2.out.num_changes, 0);
    1412             : 
    1413           2 : done:
    1414           2 :         smb2_deltree(tree1, BASEDIR_CNC);
    1415           2 :         return ret;
    1416             : }
    1417             : 
    1418             : /*
    1419             :   basic testing of change notifies followed by a ulogoff
    1420             : */
    1421             : 
    1422             : #define BASEDIR_NUL BASEDIR "_NUL"
    1423           2 : static bool torture_smb2_notify_ulogoff(struct torture_context *torture,
    1424             :                                 struct smb2_tree *tree1)
    1425             : {
    1426           2 :         bool ret = true;
    1427           0 :         NTSTATUS status;
    1428           0 :         union smb_notify notify;
    1429           0 :         union smb_open io;
    1430           0 :         struct smb2_handle h1;
    1431           0 :         struct smb2_request *req;
    1432             : 
    1433           2 :         smb2_deltree(tree1, BASEDIR_NUL);
    1434           2 :         smb2_util_rmdir(tree1, BASEDIR_NUL);
    1435             : 
    1436           2 :         torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
    1437             : 
    1438             :         /*
    1439             :           get a handle on the directory
    1440             :         */
    1441           2 :         ZERO_STRUCT(io.smb2);
    1442           2 :         io.generic.level = RAW_OPEN_SMB2;
    1443           2 :         io.smb2.in.create_flags = 0;
    1444           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
    1445           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1446           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1447           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1448             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    1449           2 :         io.smb2.in.alloc_size = 0;
    1450           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    1451           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1452           2 :         io.smb2.in.security_flags = 0;
    1453           2 :         io.smb2.in.fname = BASEDIR_NUL;
    1454             : 
    1455           2 :         status = smb2_create(tree1, torture, &(io.smb2));
    1456           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1457             : 
    1458           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
    1459           2 :         status = smb2_create(tree1, torture, &(io.smb2));
    1460           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1461           2 :         h1 = io.smb2.out.file.handle;
    1462             : 
    1463             :         /* ask for a change notify,
    1464             :            on file or directory name changes */
    1465           2 :         ZERO_STRUCT(notify.smb2);
    1466           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    1467           2 :         notify.smb2.in.buffer_size = 1000;
    1468           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1469           2 :         notify.smb2.in.file.handle = h1;
    1470           2 :         notify.smb2.in.recursive = true;
    1471             : 
    1472           2 :         req = smb2_notify_send(tree1, &(notify.smb2));
    1473             : 
    1474          10 :         WAIT_FOR_ASYNC_RESPONSE(req);
    1475             : 
    1476           2 :         status = smb2_logoff(tree1->session);
    1477           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1478             : 
    1479           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    1480           2 :         CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
    1481           2 :         CHECK_VAL(notify.smb2.out.num_changes, 0);
    1482             : 
    1483           2 : done:
    1484           2 :         smb2_deltree(tree1, BASEDIR_NUL);
    1485           2 :         return ret;
    1486             : }
    1487             : 
    1488             : /*
    1489             :   basic testing of change notifies followed by a session reconnect
    1490             : */
    1491             : 
    1492             : #define BASEDIR_NSR BASEDIR "_NSR"
    1493             : 
    1494           2 : static bool torture_smb2_notify_session_reconnect(struct torture_context *torture,
    1495             :                                 struct smb2_tree *tree1)
    1496             : {
    1497           2 :         bool ret = true;
    1498           0 :         NTSTATUS status;
    1499           0 :         union smb_notify notify;
    1500           0 :         union smb_open io;
    1501           0 :         struct smb2_handle h1;
    1502           0 :         struct smb2_request *req;
    1503           2 :         uint64_t previous_session_id = 0;
    1504           2 :         struct smb2_session *session2 = NULL;
    1505             : 
    1506           2 :         smb2_deltree(tree1, BASEDIR_NSR);
    1507           2 :         smb2_util_rmdir(tree1, BASEDIR_NSR);
    1508             : 
    1509           2 :         torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY SESSION RECONNECT\n");
    1510             : 
    1511             :         /*
    1512             :           get a handle on the directory
    1513             :         */
    1514           2 :         ZERO_STRUCT(io.smb2);
    1515           2 :         io.generic.level = RAW_OPEN_SMB2;
    1516           2 :         io.smb2.in.create_flags = 0;
    1517           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
    1518           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1519           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1520           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1521             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    1522           2 :         io.smb2.in.alloc_size = 0;
    1523           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    1524           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1525           2 :         io.smb2.in.security_flags = 0;
    1526           2 :         io.smb2.in.fname = BASEDIR_NSR;
    1527             : 
    1528           2 :         status = smb2_create(tree1, torture, &(io.smb2));
    1529           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1530             : 
    1531           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
    1532           2 :         status = smb2_create(tree1, torture, &(io.smb2));
    1533           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1534           2 :         h1 = io.smb2.out.file.handle;
    1535             : 
    1536             :         /* ask for a change notify,
    1537             :            on file or directory name changes */
    1538           2 :         ZERO_STRUCT(notify.smb2);
    1539           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    1540           2 :         notify.smb2.in.buffer_size = 1000;
    1541           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1542           2 :         notify.smb2.in.file.handle = h1;
    1543           2 :         notify.smb2.in.recursive = true;
    1544             : 
    1545           2 :         req = smb2_notify_send(tree1, &(notify.smb2));
    1546             : 
    1547          10 :         WAIT_FOR_ASYNC_RESPONSE(req);
    1548             : 
    1549           2 :         previous_session_id = smb2cli_session_current_id(tree1->session->smbXcli);
    1550           2 :         torture_assert(torture, torture_smb2_session_setup(torture,
    1551             :                        tree1->session->transport,
    1552             :                        previous_session_id,
    1553             :                        torture, &session2),
    1554             :                        "session setup with previous_session_id failed");
    1555             : 
    1556           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    1557           2 :         CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
    1558           2 :         CHECK_VAL(notify.smb2.out.num_changes, 0);
    1559             : 
    1560           2 :         status = smb2_logoff(tree1->session);
    1561           2 :         CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
    1562             : 
    1563           2 :         status = smb2_logoff(session2);
    1564           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1565           2 : done:
    1566           2 :         smb2_deltree(tree1, BASEDIR_NSR);
    1567           2 :         return ret;
    1568             : }
    1569             : 
    1570             : /*
    1571             :   basic testing of change notifies followed by an invalid reauth
    1572             : */
    1573             : 
    1574             : #define BASEDIR_IR BASEDIR "_IR"
    1575             : 
    1576           2 : static bool torture_smb2_notify_invalid_reauth(struct torture_context *torture,
    1577             :                                                struct smb2_tree *tree1,
    1578             :                                                struct smb2_tree *tree2)
    1579             : {
    1580           2 :         bool ret = true;
    1581           0 :         NTSTATUS status;
    1582           0 :         union smb_notify notify;
    1583           0 :         union smb_open io;
    1584           0 :         struct smb2_handle h1;
    1585           0 :         struct smb2_request *req;
    1586           0 :         struct cli_credentials *invalid_creds;
    1587             : 
    1588           2 :         smb2_deltree(tree2, BASEDIR_IR);
    1589           2 :         smb2_util_rmdir(tree2, BASEDIR_IR);
    1590             : 
    1591           2 :         torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY invalid REAUTH\n");
    1592             : 
    1593             :         /*
    1594             :           get a handle on the directory
    1595             :         */
    1596           2 :         ZERO_STRUCT(io.smb2);
    1597           2 :         io.generic.level = RAW_OPEN_SMB2;
    1598           2 :         io.smb2.in.create_flags = 0;
    1599           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
    1600           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1601           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1602           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1603             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    1604           2 :         io.smb2.in.alloc_size = 0;
    1605           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    1606           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1607           2 :         io.smb2.in.security_flags = 0;
    1608           2 :         io.smb2.in.fname = BASEDIR_IR;
    1609             : 
    1610           2 :         status = smb2_create(tree1, torture, &(io.smb2));
    1611           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1612             : 
    1613           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
    1614           2 :         status = smb2_create(tree1, torture, &(io.smb2));
    1615           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1616           2 :         h1 = io.smb2.out.file.handle;
    1617             : 
    1618             :         /* ask for a change notify,
    1619             :            on file or directory name changes */
    1620           2 :         ZERO_STRUCT(notify.smb2);
    1621           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    1622           2 :         notify.smb2.in.buffer_size = 1000;
    1623           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1624           2 :         notify.smb2.in.file.handle = h1;
    1625           2 :         notify.smb2.in.recursive = true;
    1626             : 
    1627           2 :         req = smb2_notify_send(tree1, &(notify.smb2));
    1628             : 
    1629          10 :         WAIT_FOR_ASYNC_RESPONSE(req);
    1630             : 
    1631           2 :         invalid_creds = cli_credentials_init(torture);
    1632           2 :         torture_assert(torture, (invalid_creds != NULL), "talloc error");
    1633           2 :         cli_credentials_set_username(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
    1634           2 :         cli_credentials_set_domain(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
    1635           2 :         cli_credentials_set_password(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
    1636           2 :         cli_credentials_set_realm(invalid_creds, NULL, CRED_SPECIFIED);
    1637           2 :         cli_credentials_set_workstation(invalid_creds, "", CRED_UNINITIALISED);
    1638             : 
    1639           2 :         status = smb2_session_setup_spnego(tree1->session,
    1640             :                                            invalid_creds,
    1641             :                                            0 /* previous_session_id */);
    1642           2 :         CHECK_STATUS(status, NT_STATUS_LOGON_FAILURE);
    1643             : 
    1644           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    1645           2 :         CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
    1646           2 :         CHECK_VAL(notify.smb2.out.num_changes, 0);
    1647             : 
    1648             :         /*
    1649             :          * Demonstrate that the session is no longer valid.
    1650             :          */
    1651           2 :         status = smb2_create(tree1, torture, &(io.smb2));
    1652           2 :         CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
    1653           2 : done:
    1654           2 :         smb2_deltree(tree2, BASEDIR_IR);
    1655           2 :         return ret;
    1656             : }
    1657             : 
    1658           2 : static void tcp_dis_handler(struct smb2_transport *t, void *p)
    1659             : {
    1660           2 :         struct smb2_tree *tree = (struct smb2_tree *)p;
    1661           2 :         smb2_transport_dead(tree->session->transport,
    1662           2 :                         NT_STATUS_LOCAL_DISCONNECT);
    1663           2 :         t = NULL;
    1664           2 :         tree = NULL;
    1665           2 : }
    1666             : 
    1667             : /*
    1668             :   basic testing of change notifies followed by tcp disconnect
    1669             : */
    1670             : 
    1671             : #define BASEDIR_NTCPD BASEDIR "_NTCPD"
    1672             : 
    1673           2 : static bool torture_smb2_notify_tcp_disconnect(
    1674             :                 struct torture_context *torture,
    1675             :                 struct smb2_tree *tree)
    1676             : {
    1677           2 :         bool ret = true;
    1678           0 :         NTSTATUS status;
    1679           0 :         union smb_notify notify;
    1680           0 :         union smb_open io;
    1681           0 :         struct smb2_handle h1;
    1682           0 :         struct smb2_request *req;
    1683             : 
    1684           2 :         smb2_deltree(tree, BASEDIR_NTCPD);
    1685           2 :         smb2_util_rmdir(tree, BASEDIR_NTCPD);
    1686             : 
    1687           2 :         torture_comment(torture,
    1688             :                 "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
    1689             : 
    1690             :         /*
    1691             :           get a handle on the directory
    1692             :         */
    1693           2 :         ZERO_STRUCT(io.smb2);
    1694           2 :         io.generic.level = RAW_OPEN_SMB2;
    1695           2 :         io.smb2.in.create_flags = 0;
    1696           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
    1697           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1698           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1699           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1700             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    1701           2 :         io.smb2.in.alloc_size = 0;
    1702           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
    1703           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1704           2 :         io.smb2.in.security_flags = 0;
    1705           2 :         io.smb2.in.fname = BASEDIR_NTCPD;
    1706             : 
    1707           2 :         status = smb2_create(tree, torture, &(io.smb2));
    1708           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1709           2 :         h1 = io.smb2.out.file.handle;
    1710             : 
    1711             :         /* ask for a change notify,
    1712             :            on file or directory name changes */
    1713           2 :         ZERO_STRUCT(notify.smb2);
    1714           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    1715           2 :         notify.smb2.in.buffer_size = 1000;
    1716           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1717           2 :         notify.smb2.in.file.handle = h1;
    1718           2 :         notify.smb2.in.recursive = true;
    1719             : 
    1720           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    1721           2 :         smb2_cancel(req);
    1722           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    1723           2 :         CHECK_STATUS(status, NT_STATUS_CANCELLED);
    1724             : 
    1725           2 :         notify.smb2.in.recursive = true;
    1726           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    1727           2 :         smb2_transport_idle_handler(tree->session->transport,
    1728             :                                 tcp_dis_handler, 250000, tree);
    1729           2 :         tree = NULL;
    1730           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    1731           2 :         CHECK_STATUS(status, NT_STATUS_LOCAL_DISCONNECT);
    1732             : 
    1733           2 : done:
    1734           2 :         return ret;
    1735             : }
    1736             : 
    1737             : /*
    1738             :    test setting up two change notify requests on one handle
    1739             : */
    1740             : 
    1741             : #define BASEDIR_NDOH BASEDIR "_NDOH"
    1742             : 
    1743           2 : static bool torture_smb2_notify_double(struct torture_context *torture,
    1744             :                         struct smb2_tree *tree1,
    1745             :                         struct smb2_tree *tree2)
    1746             : {
    1747           2 :         bool ret = true;
    1748           0 :         NTSTATUS status;
    1749           0 :         union smb_notify notify;
    1750           0 :         union smb_open io;
    1751           0 :         struct smb2_handle h1;
    1752           0 :         struct smb2_request *req1, *req2;
    1753             : 
    1754           2 :         smb2_deltree(tree1, BASEDIR_NDOH);
    1755           2 :         smb2_util_rmdir(tree1, BASEDIR_NDOH);
    1756             : 
    1757           2 :         torture_comment(torture,
    1758             :                 "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
    1759             : 
    1760             :         /*
    1761             :           get a handle on the directory
    1762             :         */
    1763           2 :         ZERO_STRUCT(io.smb2);
    1764           2 :         io.generic.level = RAW_OPEN_SMB2;
    1765           2 :         io.smb2.in.create_flags = 0;
    1766           2 :         io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ|
    1767             :                                 SEC_RIGHTS_FILE_WRITE|
    1768             :                                 SEC_RIGHTS_FILE_ALL;
    1769           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1770           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1771           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1772             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    1773           2 :         io.smb2.in.alloc_size = 0;
    1774           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    1775           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1776           2 :         io.smb2.in.security_flags = 0;
    1777           2 :         io.smb2.in.fname = BASEDIR_NDOH;
    1778             : 
    1779           2 :         status = smb2_create(tree1, torture, &(io.smb2));
    1780           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1781           2 :         h1 = io.smb2.out.file.handle;
    1782             : 
    1783             :         /* ask for a change notify,
    1784             :            on file or directory name changes */
    1785           2 :         ZERO_STRUCT(notify.smb2);
    1786           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    1787           2 :         notify.smb2.in.buffer_size = 1000;
    1788           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    1789           2 :         notify.smb2.in.file.handle = h1;
    1790           2 :         notify.smb2.in.recursive = true;
    1791             : 
    1792           2 :         req1 = smb2_notify_send(tree1, &(notify.smb2));
    1793           2 :         smb2_cancel(req1);
    1794           2 :         status = smb2_notify_recv(req1, torture, &(notify.smb2));
    1795           2 :         CHECK_STATUS(status, NT_STATUS_CANCELLED);
    1796             : 
    1797           2 :         req2 = smb2_notify_send(tree1, &(notify.smb2));
    1798           2 :         smb2_cancel(req2);
    1799           2 :         status = smb2_notify_recv(req2, torture, &(notify.smb2));
    1800           2 :         CHECK_STATUS(status, NT_STATUS_CANCELLED);
    1801             : 
    1802           2 :         smb2_util_mkdir(tree2, BASEDIR_NDOH "\\subdir-name");
    1803           2 :         req1 = smb2_notify_send(tree1, &(notify.smb2));
    1804           2 :         req2 = smb2_notify_send(tree1, &(notify.smb2));
    1805             : 
    1806           2 :         status = smb2_notify_recv(req1, torture, &(notify.smb2));
    1807           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1808           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
    1809           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
    1810             : 
    1811           2 :         smb2_util_mkdir(tree2, BASEDIR_NDOH "\\subdir-name2");
    1812             : 
    1813           2 :         status = smb2_notify_recv(req2, torture, &(notify.smb2));
    1814           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1815           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
    1816           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name2");
    1817             : 
    1818           2 : done:
    1819           2 :         smb2_deltree(tree1, BASEDIR_NDOH);
    1820           2 :         return ret;
    1821             : }
    1822             : 
    1823             : 
    1824             : /*
    1825             :    test multiple change notifies at different depths and with/without recursion
    1826             : */
    1827             : 
    1828             : #define BASEDIR_TREE BASEDIR "_TREE"
    1829             : 
    1830           2 : static bool torture_smb2_notify_tree(struct torture_context *torture,
    1831             :                              struct smb2_tree *tree)
    1832             : {
    1833           2 :         bool ret = true;
    1834           0 :         union smb_notify notify;
    1835           0 :         union smb_open io;
    1836           0 :         struct smb2_request *req;
    1837           0 :         struct timeval tv;
    1838           0 :         struct {
    1839             :                 const char *path;
    1840             :                 bool recursive;
    1841             :                 uint32_t filter;
    1842             :                 int expected;
    1843             :                 struct smb2_handle h1;
    1844             :                 int counted;
    1845           2 :         } dirs[] = {
    1846             :                 {
    1847             :                         .path      = BASEDIR_TREE "\\abc",
    1848             :                         .recursive = true,
    1849             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1850             :                         .expected  = 30,
    1851             :                 },
    1852             :                 {
    1853             :                         .path      = BASEDIR_TREE "\\zqy",
    1854             :                         .recursive = true,
    1855             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1856             :                         .expected  = 8,
    1857             :                 },
    1858             :                 {
    1859             :                         .path      = BASEDIR_TREE "\\atsy",
    1860             :                         .recursive = true,
    1861             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1862             :                         .expected  = 4,
    1863             :                 },
    1864             :                 {
    1865             :                         .path      = BASEDIR_TREE "\\abc\\foo",
    1866             :                         .recursive = true,
    1867             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1868             :                         .expected  = 2,
    1869             :                 },
    1870             :                 {
    1871             :                         .path      = BASEDIR_TREE "\\abc\\blah",
    1872             :                         .recursive = true,
    1873             :                         .filter    =  FILE_NOTIFY_CHANGE_NAME,
    1874             :                         .expected  = 13,
    1875             :                 },
    1876             :                 {
    1877             :                         .path      = BASEDIR_TREE "\\abc\\blah",
    1878             :                         .recursive = false,
    1879             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1880             :                         .expected  = 7,
    1881             :                 },
    1882             :                 {
    1883             :                         .path      = BASEDIR_TREE "\\abc\\blah\\a",
    1884             :                         .recursive = true,
    1885             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1886             :                         .expected  = 2,
    1887             :                 },
    1888             :                 {
    1889             :                         .path      = BASEDIR_TREE "\\abc\\blah\\b",
    1890             :                         .recursive = true,
    1891             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1892             :                         .expected  = 2,
    1893             :                 },
    1894             :                 {
    1895             :                         .path      = BASEDIR_TREE "\\abc\\blah\\c",
    1896             :                         .recursive = true,
    1897             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1898             :                         .expected  = 2,
    1899             :                 },
    1900             :                 {
    1901             :                         .path      = BASEDIR_TREE "\\abc\\fooblah",
    1902             :                         .recursive = true,
    1903             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1904             :                         .expected  = 2,
    1905             :                 },
    1906             :                 {
    1907             :                         .path      = BASEDIR_TREE "\\zqy\\xx",
    1908             :                         .recursive = true,
    1909             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1910             :                         .expected  = 2,
    1911             :                 },
    1912             :                 {
    1913             :                         .path      = BASEDIR_TREE "\\zqy\\yyy",
    1914             :                         .recursive = true,
    1915             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1916             :                         .expected  = 2,
    1917             :                 },
    1918             :                 {
    1919             :                         .path      = BASEDIR_TREE "\\zqy\\..",
    1920             :                         .recursive = true,
    1921             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1922             :                         .expected  = 40,
    1923             :                 },
    1924             :                 {
    1925             :                         .path      = BASEDIR_TREE,
    1926             :                         .recursive = true,
    1927             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1928             :                         .expected  = 40,
    1929             :                 },
    1930             :                 {
    1931             :                         .path      = BASEDIR_TREE,
    1932             :                         .recursive = false,
    1933             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1934             :                         .expected  = 6,
    1935             :                 },
    1936             :                 {
    1937             :                         .path      = BASEDIR_TREE "\\atsy",
    1938             :                         .recursive = false,
    1939             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1940             :                         .expected  = 4,
    1941             :                 },
    1942             :                 {
    1943             :                         .path      = BASEDIR_TREE "\\abc",
    1944             :                         .recursive = true,
    1945             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1946             :                         .expected  = 24,
    1947             :                 },
    1948             :                 {
    1949             :                         .path      = BASEDIR_TREE "\\abc",
    1950             :                         .recursive = false,
    1951             :                         .filter    = FILE_NOTIFY_CHANGE_FILE_NAME,
    1952             :                         .expected  = 0,
    1953             :                 },
    1954             :                 {
    1955             :                         .path      = BASEDIR_TREE "\\abc",
    1956             :                         .recursive = true,
    1957             :                         .filter    = FILE_NOTIFY_CHANGE_FILE_NAME,
    1958             :                         .expected  = 0,
    1959             :                 },
    1960             :                 {
    1961             :                         .path      = BASEDIR_TREE "\\abc",
    1962             :                         .recursive = true,
    1963             :                         .filter    = FILE_NOTIFY_CHANGE_NAME,
    1964             :                         .expected  = 24,
    1965             :                 },
    1966             :         };
    1967           0 :         int i;
    1968           0 :         NTSTATUS status;
    1969           2 :         bool all_done = false;
    1970             : 
    1971           2 :         smb2_deltree(tree, BASEDIR_TREE);
    1972           2 :         smb2_util_rmdir(tree, BASEDIR_TREE);
    1973             : 
    1974           2 :         torture_comment(torture, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
    1975             : 
    1976           2 :         ZERO_STRUCT(io.smb2);
    1977           2 :         io.generic.level = RAW_OPEN_SMB2;
    1978           2 :         io.smb2.in.create_flags = 0;
    1979           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
    1980           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    1981           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1982           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    1983             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    1984           2 :         io.smb2.in.alloc_size = 0;
    1985           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
    1986           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1987           2 :         io.smb2.in.security_flags = 0;
    1988           2 :         io.smb2.in.fname = BASEDIR_TREE;
    1989           2 :         status = smb2_create(tree, torture, &(io.smb2));
    1990           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    1991             : 
    1992           2 :         ZERO_STRUCT(notify.smb2);
    1993           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    1994           2 :         notify.smb2.in.buffer_size = 20000;
    1995             : 
    1996             :         /*
    1997             :           setup the directory tree, and the notify buffer on each directory
    1998             :         */
    1999          42 :         for (i=0;i<ARRAY_SIZE(dirs);i++) {
    2000          40 :                 io.smb2.in.fname = dirs[i].path;
    2001          40 :                 status = smb2_create(tree, torture, &(io.smb2));
    2002          40 :                 CHECK_STATUS(status, NT_STATUS_OK);
    2003          40 :                 dirs[i].h1 = io.smb2.out.file.handle;
    2004             : 
    2005          40 :                 notify.smb2.in.completion_filter = dirs[i].filter;
    2006          40 :                 notify.smb2.in.file.handle = dirs[i].h1;
    2007          40 :                 notify.smb2.in.recursive = dirs[i].recursive;
    2008          40 :                 req = smb2_notify_send(tree, &(notify.smb2));
    2009          40 :                 smb2_cancel(req);
    2010          40 :                 status = smb2_notify_recv(req, torture, &(notify.smb2));
    2011          40 :                 CHECK_STATUS(status, NT_STATUS_CANCELLED);
    2012             :         }
    2013             : 
    2014             :         /* trigger 2 events in each dir */
    2015          42 :         for (i=0;i<ARRAY_SIZE(dirs);i++) {
    2016          40 :                 char *path = talloc_asprintf(torture, "%s\\test.dir",
    2017             :                                              dirs[i].path);
    2018          40 :                 smb2_util_mkdir(tree, path);
    2019          40 :                 smb2_util_rmdir(tree, path);
    2020          40 :                 talloc_free(path);
    2021             :         }
    2022             : 
    2023             :         /* give a bit of time for the events to propagate */
    2024           2 :         tv = timeval_current();
    2025             : 
    2026           0 :         do {
    2027             :                 /* count events that have happened in each dir */
    2028          42 :                 for (i=0;i<ARRAY_SIZE(dirs);i++) {
    2029          40 :                         notify.smb2.in.completion_filter = dirs[i].filter;
    2030          40 :                         notify.smb2.in.file.handle = dirs[i].h1;
    2031          40 :                         notify.smb2.in.recursive = dirs[i].recursive;
    2032          40 :                         req = smb2_notify_send(tree, &(notify.smb2));
    2033          40 :                         smb2_cancel(req);
    2034          40 :                         notify.smb2.out.num_changes = 0;
    2035          40 :                         status = smb2_notify_recv(req, torture,
    2036             :                                  &(notify.smb2));
    2037          40 :                         dirs[i].counted += notify.smb2.out.num_changes;
    2038             :                 }
    2039             : 
    2040           2 :                 all_done = true;
    2041             : 
    2042          42 :                 for (i=0;i<ARRAY_SIZE(dirs);i++) {
    2043          40 :                         if (dirs[i].counted != dirs[i].expected) {
    2044           0 :                                 all_done = false;
    2045             :                         }
    2046             :                 }
    2047           2 :         } while (!all_done && timeval_elapsed(&tv) < 20);
    2048             : 
    2049           2 :         torture_comment(torture, "took %.4f seconds to propagate all events\n",
    2050             :                         timeval_elapsed(&tv));
    2051             : 
    2052          42 :         for (i=0;i<ARRAY_SIZE(dirs);i++) {
    2053          40 :                 if (dirs[i].counted != dirs[i].expected) {
    2054           0 :                         torture_comment(torture,
    2055             :                                 "ERROR: i=%d expected %d got %d for '%s'\n",
    2056             :                                 i, dirs[i].expected, dirs[i].counted,
    2057             :                                 dirs[i].path);
    2058           0 :                         ret = false;
    2059             :                 }
    2060             :         }
    2061             : 
    2062             :         /*
    2063             :           run from the back, closing and deleting
    2064             :         */
    2065          42 :         for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
    2066          40 :                 smb2_util_close(tree, dirs[i].h1);
    2067          40 :                 smb2_util_rmdir(tree, dirs[i].path);
    2068             :         }
    2069             : 
    2070           2 : done:
    2071           2 :         smb2_deltree(tree, BASEDIR_TREE);
    2072           2 :         smb2_util_rmdir(tree, BASEDIR_TREE);
    2073           2 :         return ret;
    2074             : }
    2075             : 
    2076             : /*
    2077             :    Test response when cached server events exceed single NT NOTFIY response
    2078             :    packet size.
    2079             : */
    2080             : 
    2081             : #define BASEDIR_OVF BASEDIR "_OVF"
    2082             : 
    2083           2 : static bool torture_smb2_notify_overflow(struct torture_context *torture,
    2084             :                                 struct smb2_tree *tree)
    2085             : {
    2086           2 :         bool ret = true;
    2087           0 :         NTSTATUS status;
    2088           0 :         union smb_notify notify;
    2089           0 :         union smb_open io;
    2090           0 :         struct smb2_handle h1, h2;
    2091           2 :         int count = 100;
    2092           0 :         struct smb2_request *req1;
    2093           0 :         int i;
    2094             : 
    2095           2 :         smb2_deltree(tree, BASEDIR_OVF);
    2096           2 :         smb2_util_rmdir(tree, BASEDIR_OVF);
    2097             : 
    2098           2 :         torture_comment(torture, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
    2099             : 
    2100             :         /* get a handle on the directory */
    2101           2 :         ZERO_STRUCT(io.smb2);
    2102           2 :         io.generic.level = RAW_OPEN_SMB2;
    2103           2 :         io.smb2.in.create_flags = 0;
    2104           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
    2105           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    2106           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    2107           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    2108             :                             NTCREATEX_SHARE_ACCESS_WRITE;
    2109           2 :         io.smb2.in.alloc_size = 0;
    2110           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    2111           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    2112           2 :         io.smb2.in.security_flags = 0;
    2113           2 :         io.smb2.in.fname = BASEDIR_OVF;
    2114             : 
    2115           2 :         status = smb2_create(tree, torture, &(io.smb2));
    2116           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2117           2 :         h1 = io.smb2.out.file.handle;
    2118             : 
    2119             :         /* ask for a change notify, on name changes. */
    2120           2 :         ZERO_STRUCT(notify.smb2);
    2121           2 :         notify.smb2.level = RAW_NOTIFY_NTTRANS;
    2122           2 :         notify.smb2.in.buffer_size = 1000;
    2123           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    2124           2 :         notify.smb2.in.file.handle = h1;
    2125             : 
    2126           2 :         notify.smb2.in.recursive = true;
    2127           2 :         req1 = smb2_notify_send(tree, &(notify.smb2));
    2128             : 
    2129             :         /* cancel initial requests so the buffer is setup */
    2130           2 :         smb2_cancel(req1);
    2131           2 :         status = smb2_notify_recv(req1, torture, &(notify.smb2));
    2132           2 :         CHECK_STATUS(status, NT_STATUS_CANCELLED);
    2133             : 
    2134             :         /* open a lot of files, filling up the server side notify buffer */
    2135           2 :         torture_comment(torture,
    2136             :                 "Testing overflowed buffer notify on create of %d files\n",
    2137             :                 count);
    2138             : 
    2139         202 :         for (i=0;i<count;i++) {
    2140         200 :                 char *fname = talloc_asprintf(torture,
    2141             :                               BASEDIR_OVF "\\test%d.txt", i);
    2142           0 :                 union smb_open io1;
    2143         200 :                 ZERO_STRUCT(io1.smb2);
    2144         200 :                 io1.generic.level = RAW_OPEN_SMB2;
    2145         200 :                 io1.smb2.in.create_flags = 0;
    2146         200 :                 io1.smb2.in.desired_access = SEC_FILE_ALL;
    2147         200 :                 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    2148         200 :                 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    2149         200 :                 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    2150             :                                     NTCREATEX_SHARE_ACCESS_WRITE;
    2151         200 :                 io1.smb2.in.alloc_size = 0;
    2152         200 :                 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    2153         200 :                 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    2154         200 :                 io1.smb2.in.security_flags = 0;
    2155         200 :                 io1.smb2.in.fname = fname;
    2156             : 
    2157         200 :                 h2 = custom_smb2_create(tree, torture, &(io1.smb2));
    2158         200 :                 talloc_free(fname);
    2159         200 :                 smb2_util_close(tree, h2);
    2160             :         }
    2161             : 
    2162           2 :         req1 = smb2_notify_send(tree, &(notify.smb2));
    2163           2 :         status = smb2_notify_recv(req1, torture, &(notify.smb2));
    2164           2 :         CHECK_STATUS(status, NT_STATUS_NOTIFY_ENUM_DIR);
    2165           2 :         CHECK_VAL(notify.smb2.out.num_changes, 0);
    2166             : 
    2167           2 : done:
    2168           2 :         smb2_deltree(tree, BASEDIR_OVF);
    2169           2 :         return ret;
    2170             : }
    2171             : 
    2172             : /*
    2173             :    Test if notifications are returned for changes to the base directory.
    2174             :    They shouldn't be.
    2175             : */
    2176             : 
    2177             : #define BASEDIR_BAS BASEDIR "_BAS"
    2178             : 
    2179           2 : static bool torture_smb2_notify_basedir(struct torture_context *torture,
    2180             :                                 struct smb2_tree *tree1,
    2181             :                                 struct smb2_tree *tree2)
    2182             : {
    2183           2 :         bool ret = true;
    2184           0 :         NTSTATUS status;
    2185           0 :         union smb_notify notify;
    2186           0 :         union smb_open io;
    2187           0 :         struct smb2_handle h1;
    2188           0 :         struct smb2_request *req1;
    2189             : 
    2190           2 :         smb2_deltree(tree1, BASEDIR_BAS);
    2191           2 :         smb2_util_rmdir(tree1, BASEDIR_BAS);
    2192             : 
    2193           2 :         torture_comment(torture, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
    2194             : 
    2195             :         /* get a handle on the directory */
    2196           2 :         ZERO_STRUCT(io.smb2);
    2197           2 :         io.generic.level = RAW_OPEN_SMB2;
    2198           2 :         io.smb2.in.create_flags = 0;
    2199           2 :         io.smb2.in.desired_access = SEC_FILE_ALL;
    2200           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    2201           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    2202           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    2203             :             NTCREATEX_SHARE_ACCESS_WRITE;
    2204           2 :         io.smb2.in.alloc_size = 0;
    2205           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
    2206           2 :         io.smb2.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
    2207           2 :         io.smb2.in.security_flags = 0;
    2208           2 :         io.smb2.in.fname = BASEDIR_BAS;
    2209             : 
    2210           2 :         status = smb2_create(tree1, torture, &(io.smb2));
    2211           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2212           2 :         h1 = io.smb2.out.file.handle;
    2213             : 
    2214             :         /* create a test file that will also be modified */
    2215           2 :         io.smb2.in.fname = BASEDIR_BAS "\\tname1";
    2216           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
    2217           2 :         status =  smb2_create(tree2, torture, &(io.smb2));
    2218           2 :         CHECK_STATUS(status,NT_STATUS_OK);
    2219           2 :         smb2_util_close(tree2, io.smb2.out.file.handle);
    2220             : 
    2221             :         /* ask for a change notify, on attribute changes. */
    2222           2 :         ZERO_STRUCT(notify.smb2);
    2223           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    2224           2 :         notify.smb2.in.buffer_size = 1000;
    2225           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
    2226           2 :         notify.smb2.in.file.handle = h1;
    2227           2 :         notify.smb2.in.recursive = true;
    2228             : 
    2229           2 :         req1 = smb2_notify_send(tree1, &(notify.smb2));
    2230             : 
    2231             :         /* set attribute on the base dir */
    2232           2 :         smb2_util_setatr(tree2, BASEDIR_BAS, FILE_ATTRIBUTE_HIDDEN);
    2233             : 
    2234             :         /* set attribute on a file to assure we receive a notification */
    2235           2 :         smb2_util_setatr(tree2, BASEDIR_BAS "\\tname1", FILE_ATTRIBUTE_HIDDEN);
    2236           2 :         smb_msleep(200);
    2237             : 
    2238             :         /* check how many responses were given, expect only 1 for the file */
    2239           2 :         status = smb2_notify_recv(req1, torture, &(notify.smb2));
    2240           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2241           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
    2242           2 :         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
    2243           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
    2244             : 
    2245           2 : done:
    2246           2 :         smb2_deltree(tree1, BASEDIR_BAS);
    2247           2 :         return ret;
    2248             : }
    2249             : 
    2250             : /*
    2251             :    very simple change notify test
    2252             : */
    2253             : 
    2254             : #define BASEDIR_TCON BASEDIR "_TCON"
    2255             : 
    2256           2 : static bool torture_smb2_notify_tcon(struct torture_context *torture,
    2257             :                                   struct smb2_tree *tree)
    2258             : {
    2259           2 :         bool ret = true;
    2260           0 :         NTSTATUS status;
    2261           0 :         union smb_notify notify;
    2262           0 :         union smb_open io;
    2263           2 :         struct smb2_handle h1 = {{0}};
    2264           2 :         struct smb2_request *req = NULL;
    2265           2 :         struct smb2_tree *tree1 = NULL;
    2266           2 :         const char *fname = BASEDIR_TCON "\\subdir-name";
    2267             : 
    2268           2 :         smb2_deltree(tree, BASEDIR_TCON);
    2269           2 :         smb2_util_rmdir(tree, BASEDIR_TCON);
    2270             : 
    2271           2 :         torture_comment(torture, "TESTING SIMPLE CHANGE NOTIFY\n");
    2272             : 
    2273             :         /*
    2274             :           get a handle on the directory
    2275             :         */
    2276             : 
    2277           2 :         ZERO_STRUCT(io.smb2);
    2278           2 :         io.generic.level = RAW_OPEN_SMB2;
    2279           2 :         io.smb2.in.create_flags = 0;
    2280           2 :         io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
    2281           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    2282           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL |
    2283             :                                 FILE_ATTRIBUTE_DIRECTORY;
    2284           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    2285             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    2286           2 :         io.smb2.in.alloc_size = 0;
    2287           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
    2288           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    2289           2 :         io.smb2.in.security_flags = 0;
    2290           2 :         io.smb2.in.fname = BASEDIR_TCON;
    2291             : 
    2292           2 :         status = smb2_create(tree, torture, &(io.smb2));
    2293           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2294           2 :         h1 = io.smb2.out.file.handle;
    2295             : 
    2296             :         /* ask for a change notify,
    2297             :            on file or directory name changes */
    2298           2 :         ZERO_STRUCT(notify.smb2);
    2299           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    2300           2 :         notify.smb2.in.buffer_size = 1000;
    2301           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    2302           2 :         notify.smb2.in.file.handle = h1;
    2303           2 :         notify.smb2.in.recursive = true;
    2304             : 
    2305           2 :         torture_comment(torture, "Testing notify mkdir\n");
    2306           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    2307           2 :         smb2_cancel(req);
    2308           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    2309           2 :         CHECK_STATUS(status, NT_STATUS_CANCELLED);
    2310             : 
    2311           2 :         notify.smb2.in.recursive = true;
    2312           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    2313           2 :         status = smb2_util_mkdir(tree, fname);
    2314           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2315             : 
    2316           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    2317           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2318             : 
    2319           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
    2320           2 :         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
    2321           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
    2322             : 
    2323           2 :         torture_comment(torture, "Testing notify rmdir\n");
    2324           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    2325           2 :         status = smb2_util_rmdir(tree, fname);
    2326           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2327             : 
    2328           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    2329           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2330           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
    2331           2 :         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
    2332           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
    2333             : 
    2334           2 :         torture_comment(torture, "SIMPLE CHANGE NOTIFY OK\n");
    2335             : 
    2336           2 :         torture_comment(torture, "TESTING WITH SECONDARY TCON\n");
    2337           2 :         if (!torture_smb2_tree_connect(torture, tree->session, tree, &tree1)) {
    2338           0 :                 torture_warning(torture, "couldn't reconnect to share, bailing\n");
    2339           0 :                 ret = false;
    2340           0 :                 goto done;
    2341             :         }
    2342             : 
    2343           2 :         torture_comment(torture, "tid1=%d tid2=%d\n",
    2344             :                         smb2cli_tcon_current_id(tree->smbXcli),
    2345           2 :                         smb2cli_tcon_current_id(tree1->smbXcli));
    2346             : 
    2347           2 :         torture_comment(torture, "Testing notify mkdir\n");
    2348           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    2349           2 :         smb2_util_mkdir(tree1, fname);
    2350             : 
    2351           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    2352           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2353             : 
    2354           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
    2355           2 :         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
    2356           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
    2357             : 
    2358           2 :         torture_comment(torture, "Testing notify rmdir\n");
    2359           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    2360           2 :         smb2_util_rmdir(tree, fname);
    2361             : 
    2362           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    2363           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2364           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
    2365           2 :         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
    2366           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
    2367             : 
    2368           2 :         torture_comment(torture, "CHANGE NOTIFY WITH TCON OK\n");
    2369             : 
    2370           2 :         torture_comment(torture, "Disconnecting secondary tree\n");
    2371           2 :         status = smb2_tdis(tree1);
    2372           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2373           2 :         talloc_free(tree1);
    2374             : 
    2375           2 :         torture_comment(torture, "Testing notify mkdir\n");
    2376           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    2377           2 :         smb2_util_mkdir(tree, fname);
    2378             : 
    2379           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    2380           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2381             : 
    2382           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
    2383           2 :         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
    2384           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
    2385             : 
    2386           2 :         torture_comment(torture, "Testing notify rmdir\n");
    2387           2 :         req = smb2_notify_send(tree, &(notify.smb2));
    2388           2 :         smb2_util_rmdir(tree, fname);
    2389             : 
    2390           2 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    2391           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2392           2 :         CHECK_VAL(notify.smb2.out.num_changes, 1);
    2393           2 :         CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
    2394           2 :         CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
    2395             : 
    2396           2 :         torture_comment(torture, "CHANGE NOTIFY WITH TDIS OK\n");
    2397           2 : done:
    2398           2 :         smb2_util_close(tree, h1);
    2399           2 :         smb2_deltree(tree, BASEDIR_TCON);
    2400             : 
    2401           2 :         return ret;
    2402             : }
    2403             : 
    2404             : #define BASEDIR_RMD BASEDIR "_RMD"
    2405             : 
    2406           8 : static bool torture_smb2_notify_rmdir(struct torture_context *torture,
    2407             :                                       struct smb2_tree *tree1,
    2408             :                                       struct smb2_tree *tree2,
    2409             :                                       bool initial_delete_on_close)
    2410             : {
    2411           8 :         bool ret = true;
    2412           0 :         NTSTATUS status;
    2413           8 :         union smb_notify notify = {};
    2414           8 :         union smb_setfileinfo sfinfo = {};
    2415           8 :         union smb_open io = {};
    2416           8 :         struct smb2_handle h = {};
    2417           0 :         struct smb2_request *req;
    2418             : 
    2419           8 :         torture_comment(torture, "TESTING NOTIFY CANCEL FOR DELETED DIR\n");
    2420             : 
    2421           8 :         smb2_deltree(tree1, BASEDIR_RMD);
    2422           8 :         smb2_util_rmdir(tree1, BASEDIR_RMD);
    2423             : 
    2424           8 :         ZERO_STRUCT(io.smb2);
    2425           8 :         io.generic.level = RAW_OPEN_SMB2;
    2426           8 :         io.smb2.in.create_flags = 0;
    2427           8 :         io.smb2.in.desired_access = SEC_FILE_ALL;
    2428           8 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    2429           8 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    2430           8 :         io.smb2.in.share_access =
    2431             :                 NTCREATEX_SHARE_ACCESS_READ |
    2432             :                 NTCREATEX_SHARE_ACCESS_WRITE |
    2433             :                 NTCREATEX_SHARE_ACCESS_DELETE ;
    2434           8 :         io.smb2.in.alloc_size = 0;
    2435           8 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    2436           8 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    2437           8 :         io.smb2.in.security_flags = 0;
    2438           8 :         io.smb2.in.fname = BASEDIR_RMD;
    2439             : 
    2440           8 :         status = smb2_create(tree1, torture, &(io.smb2));
    2441           8 :         CHECK_STATUS(status, NT_STATUS_OK);
    2442           8 :         h = io.smb2.out.file.handle;
    2443             : 
    2444           8 :         ZERO_STRUCT(notify.smb2);
    2445           8 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    2446           8 :         notify.smb2.in.buffer_size = 1000;
    2447           8 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    2448           8 :         notify.smb2.in.file.handle = h;
    2449           8 :         notify.smb2.in.recursive = false;
    2450             : 
    2451           8 :         io.smb2.in.desired_access |= SEC_STD_DELETE;
    2452           8 :         io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
    2453           8 :         req = smb2_notify_send(tree1, &(notify.smb2));
    2454             : 
    2455           8 :         if (initial_delete_on_close) {
    2456           4 :                 status = smb2_util_rmdir(tree2, BASEDIR_RMD);
    2457           4 :                 CHECK_STATUS(status, NT_STATUS_OK);
    2458             :         } else {
    2459           4 :                 status = smb2_create(tree2, torture, &(io.smb2));
    2460           4 :                 CHECK_STATUS(status, NT_STATUS_OK);
    2461             : 
    2462           4 :                 sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
    2463           4 :                 sfinfo.generic.in.file.handle = io.smb2.out.file.handle;
    2464           4 :                 sfinfo.disposition_info.in.delete_on_close = 1;
    2465           4 :                 status = smb2_setinfo_file(tree2, &sfinfo);
    2466           4 :                 CHECK_STATUS(status, NT_STATUS_OK);
    2467             : 
    2468           4 :                 smb2_util_close(tree2, io.smb2.out.file.handle);
    2469             :         }
    2470             : 
    2471           8 :         status = smb2_notify_recv(req, torture, &(notify.smb2));
    2472           8 :         CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
    2473             : 
    2474           8 : done:
    2475             : 
    2476           8 :         smb2_util_close(tree1, h);
    2477           8 :         smb2_deltree(tree1, BASEDIR_RMD);
    2478             : 
    2479           8 :         return ret;
    2480             : }
    2481             : 
    2482           2 : static bool torture_smb2_notify_rmdir1(struct torture_context *torture,
    2483             :                                        struct smb2_tree *tree)
    2484             : {
    2485           2 :         return torture_smb2_notify_rmdir(torture, tree, tree, false);
    2486             : }
    2487             : 
    2488           2 : static bool torture_smb2_notify_rmdir2(struct torture_context *torture,
    2489             :                                        struct smb2_tree *tree)
    2490             : {
    2491           2 :         return torture_smb2_notify_rmdir(torture, tree, tree, true);
    2492             : }
    2493             : 
    2494           2 : static bool torture_smb2_notify_rmdir3(struct torture_context *torture,
    2495             :                                        struct smb2_tree *tree1,
    2496             :                                        struct smb2_tree *tree2)
    2497             : {
    2498           2 :         return torture_smb2_notify_rmdir(torture, tree1, tree2, false);
    2499             : }
    2500             : 
    2501           2 : static bool torture_smb2_notify_rmdir4(struct torture_context *torture,
    2502             :                                        struct smb2_tree *tree1,
    2503             :                                        struct smb2_tree *tree2)
    2504             : {
    2505           2 :         return torture_smb2_notify_rmdir(torture, tree1, tree2, true);
    2506             : }
    2507             : 
    2508           0 : static void notify_timeout(struct tevent_context *ev,
    2509             :                            struct tevent_timer *te,
    2510             :                            struct timeval current_time,
    2511             :                            void *private_data)
    2512             : {
    2513           0 :         struct smb2_request *req = talloc_get_type_abort(
    2514             :                 private_data, struct smb2_request);
    2515             : 
    2516           0 :         smb2_cancel(req);
    2517           0 : }
    2518             : 
    2519             : #define BASEDIR_INR BASEDIR "_INR"
    2520             : 
    2521           2 : static bool torture_smb2_inotify_rename(struct torture_context *torture,
    2522             :                                         struct smb2_tree *tree1,
    2523             :                                         struct smb2_tree *tree2)
    2524             : {
    2525           0 :         NTSTATUS status;
    2526           0 :         struct smb2_notify notify;
    2527           2 :         struct notify_changes change1 = {0};
    2528           2 :         struct notify_changes change2 = {0};
    2529           0 :         struct smb2_create create;
    2530           0 :         union smb_setfileinfo sinfo;
    2531           2 :         struct smb2_handle h1 = {{0}};
    2532           2 :         struct smb2_handle h2 = {{0}};
    2533           0 :         struct smb2_request *req;
    2534           2 :         struct tevent_timer *te = NULL;
    2535           2 :         bool ok = false;
    2536             : 
    2537           2 :         smb2_deltree(tree1, BASEDIR_INR);
    2538             : 
    2539           2 :         torture_comment(torture, "Testing change notify of a rename with inotify\n");
    2540             : 
    2541           2 :         status = torture_smb2_testdir(tree1, BASEDIR_INR, &h1);
    2542           2 :         torture_assert_ntstatus_ok_goto(torture, status, ok, done, "torture_smb2_testdir failed");
    2543             : 
    2544           2 :         ZERO_STRUCT(create);
    2545           2 :         create.in.desired_access = SEC_RIGHTS_FILE_READ |
    2546             :                 SEC_RIGHTS_FILE_WRITE|
    2547             :                 SEC_RIGHTS_FILE_ALL;
    2548           2 :         create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    2549           2 :         create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    2550           2 :         create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    2551             :                 NTCREATEX_SHARE_ACCESS_WRITE |
    2552             :                 NTCREATEX_SHARE_ACCESS_DELETE;
    2553           2 :         create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
    2554           2 :         create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    2555           2 :         create.in.fname = BASEDIR_INR "\\subdir-name";
    2556             : 
    2557           2 :         status = smb2_create(tree2, torture, &create);
    2558           2 :         torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_create failed\n");
    2559           2 :         h2 = create.out.file.handle;
    2560             : 
    2561           2 :         ZERO_STRUCT(notify);
    2562           2 :         notify.level = RAW_NOTIFY_SMB2;
    2563           2 :         notify.in.buffer_size = 4096;
    2564           2 :         notify.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    2565           2 :         notify.in.file.handle = h1;
    2566           2 :         notify.in.recursive = true;
    2567           2 :         req = smb2_notify_send(tree1, &notify);
    2568           2 :         torture_assert_not_null_goto(torture, req, ok, done, "smb2_notify_send failed\n");
    2569             : 
    2570          10 :         while (!NT_STATUS_EQUAL(req->status, NT_STATUS_PENDING)) {
    2571           8 :                 if (tevent_loop_once(torture->ev) != 0) {
    2572           0 :                         goto done;
    2573             :                 }
    2574             :         }
    2575             : 
    2576           2 :         ZERO_STRUCT(sinfo);
    2577           2 :         sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
    2578           2 :         sinfo.rename_information.in.file.handle = h2;
    2579           2 :         sinfo.rename_information.in.new_name = BASEDIR_INR "\\subdir-name-r";
    2580             : 
    2581           2 :         status = smb2_setinfo_file(tree2, &sinfo);
    2582           2 :         torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_setinfo_file failed\n");
    2583             : 
    2584           2 :         smb2_util_close(tree2, h2);
    2585             : 
    2586           2 :         te = tevent_add_timer(torture->ev,
    2587             :                               tree1,
    2588             :                               tevent_timeval_current_ofs(1, 0),
    2589             :                               notify_timeout,
    2590             :                               req);
    2591           2 :         torture_assert_not_null_goto(torture, te, ok, done, "tevent_add_timer failed\n");
    2592             : 
    2593           2 :         status = smb2_notify_recv(req, torture, &notify);
    2594           2 :         torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_notify_recv failed\n");
    2595             : 
    2596           2 :         torture_assert_goto(torture, notify.out.num_changes == 1 || notify.out.num_changes == 2,
    2597             :                             ok, done, "bad notify\n");
    2598             : 
    2599           2 :         change1 = notify.out.changes[0];
    2600           2 :         if (notify.out.num_changes == 2) {
    2601           2 :                 change2 = notify.out.changes[1];
    2602             :         } else {
    2603             :                 /*
    2604             :                  * We may only get one event at a time, so check for the
    2605             :                  * matching second event for the oldname/newname or
    2606             :                  * removed/added pair.
    2607             :                  */
    2608           0 :                 ZERO_STRUCT(notify);
    2609           0 :                 notify.level = RAW_NOTIFY_SMB2;
    2610           0 :                 notify.in.buffer_size = 4096;
    2611           0 :                 notify.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    2612           0 :                 notify.in.file.handle = h1;
    2613           0 :                 notify.in.recursive = true;
    2614           0 :                 req = smb2_notify_send(tree1, &notify);
    2615           0 :                 torture_assert_not_null_goto(torture, req, ok, done, "smb2_notify_send failed\n");
    2616             : 
    2617           0 :                 status = smb2_notify_recv(req, torture, &notify);
    2618           0 :                 torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_notify_recv failed\n");
    2619             : 
    2620           0 :                 torture_assert_goto(torture, notify.out.num_changes == 1, ok, done,
    2621             :                                     "bad notify\n");
    2622             : 
    2623           0 :                 change2 = notify.out.changes[0];
    2624             :         }
    2625             : 
    2626           2 :         if ((change1.action != NOTIFY_ACTION_OLD_NAME) &&
    2627           0 :             (change1.action != NOTIFY_ACTION_REMOVED))
    2628             :         {
    2629           0 :                 torture_fail_goto(torture, done, "bad change notification\n");
    2630             :         }
    2631           2 :         torture_assert_str_equal_goto(torture, change1.name.s, "subdir-name",
    2632             :                             ok, done, "bad change notification\n");
    2633             : 
    2634           2 :         if ((change2.action != NOTIFY_ACTION_NEW_NAME) &&
    2635           0 :             (change2.action != NOTIFY_ACTION_ADDED))
    2636             :         {
    2637           0 :                 torture_fail_goto(torture, done, "bad change notification\n");
    2638             :         }
    2639           2 :         torture_assert_str_equal_goto(torture, change2.name.s, "subdir-name-r",
    2640             :                             ok, done, "bad change notification\n");
    2641             : 
    2642           2 :         ok = true;
    2643           2 : done:
    2644           2 :         if (!smb2_util_handle_empty(h1)) {
    2645           2 :                 smb2_util_close(tree1, h1);
    2646             :         }
    2647           2 :         if (!smb2_util_handle_empty(h2)) {
    2648           2 :                 smb2_util_close(tree2, h2);
    2649             :         }
    2650             : 
    2651           2 :         smb2_deltree(tree1, BASEDIR_INR);
    2652           2 :         return ok;
    2653             : }
    2654             : 
    2655             : /*
    2656             :   Test asking for a change notify on a handle without permissions.
    2657             : */
    2658             : 
    2659             : #define BASEDIR_HPERM BASEDIR "_HPERM"
    2660             : 
    2661           2 : static bool torture_smb2_notify_handle_permissions(
    2662             :                 struct torture_context *torture,
    2663             :                 struct smb2_tree *tree)
    2664             : {
    2665           2 :         bool ret = true;
    2666           0 :         NTSTATUS status;
    2667           0 :         union smb_notify notify;
    2668           0 :         union smb_open io;
    2669           2 :         struct smb2_handle h1 = {{0}};
    2670           0 :         struct smb2_request *req;
    2671             : 
    2672           2 :         smb2_deltree(tree, BASEDIR_HPERM);
    2673           2 :         smb2_util_rmdir(tree, BASEDIR_HPERM);
    2674             : 
    2675           2 :         torture_comment(torture,
    2676             :                 "TESTING CHANGE NOTIFY "
    2677             :                 "ON A HANDLE WITHOUT PERMISSIONS\n");
    2678             : 
    2679             :         /*
    2680             :           get a handle on the directory
    2681             :         */
    2682           2 :         ZERO_STRUCT(io.smb2);
    2683           2 :         io.generic.level = RAW_OPEN_SMB2;
    2684           2 :         io.smb2.in.create_flags = 0;
    2685           2 :         io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE;
    2686           2 :         io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    2687           2 :         io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    2688           2 :         io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
    2689             :                                 NTCREATEX_SHARE_ACCESS_WRITE;
    2690           2 :         io.smb2.in.alloc_size = 0;
    2691           2 :         io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
    2692           2 :         io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    2693           2 :         io.smb2.in.security_flags = 0;
    2694           2 :         io.smb2.in.fname = BASEDIR_HPERM;
    2695             : 
    2696           2 :         status = smb2_create(tree, torture, &io.smb2);
    2697           2 :         CHECK_STATUS(status, NT_STATUS_OK);
    2698           2 :         h1 = io.smb2.out.file.handle;
    2699             : 
    2700             :         /* ask for a change notify,
    2701             :            on file or directory name changes */
    2702           2 :         ZERO_STRUCT(notify.smb2);
    2703           2 :         notify.smb2.level = RAW_NOTIFY_SMB2;
    2704           2 :         notify.smb2.in.buffer_size = 1000;
    2705           2 :         notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
    2706           2 :         notify.smb2.in.file.handle = h1;
    2707           2 :         notify.smb2.in.recursive = true;
    2708             : 
    2709           2 :         req = smb2_notify_send(tree, &notify.smb2);
    2710           2 :         torture_assert_goto(torture,
    2711             :                         req != NULL,
    2712             :                         ret,
    2713             :                         done,
    2714             :                         "smb2_notify_send failed\n");
    2715             : 
    2716             :         /*
    2717             :          * Cancel it, we don't really want to wait.
    2718             :          */
    2719           2 :         smb2_cancel(req);
    2720           2 :         status = smb2_notify_recv(req, torture, &notify.smb2);
    2721             :         /* Handle h1 doesn't have permissions for ChangeNotify. */
    2722           2 :         CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
    2723             : 
    2724           2 : done:
    2725           2 :         if (!smb2_util_handle_empty(h1)) {
    2726           2 :                 smb2_util_close(tree, h1);
    2727             :         }
    2728           2 :         smb2_deltree(tree, BASEDIR_HPERM);
    2729           2 :         return ret;
    2730             : }
    2731             : 
    2732             : /*
    2733             :    basic testing of SMB2 change notify
    2734             : */
    2735        2354 : struct torture_suite *torture_smb2_notify_init(TALLOC_CTX *ctx)
    2736             : {
    2737        2354 :         struct torture_suite *suite = torture_suite_create(ctx, "notify");
    2738             : 
    2739        2354 :         torture_suite_add_1smb2_test(suite, "valid-req", test_valid_request);
    2740        2354 :         torture_suite_add_1smb2_test(suite, "tcon", torture_smb2_notify_tcon);
    2741        2354 :         torture_suite_add_2smb2_test(suite, "dir", torture_smb2_notify_dir);
    2742        2354 :         torture_suite_add_2smb2_test(suite, "mask", torture_smb2_notify_mask);
    2743        2354 :         torture_suite_add_1smb2_test(suite, "tdis", torture_smb2_notify_tree_disconnect);
    2744        2354 :         torture_suite_add_1smb2_test(suite, "tdis1", torture_smb2_notify_tree_disconnect_1);
    2745        2354 :         torture_suite_add_2smb2_test(suite, "mask-change", torture_smb2_notify_mask_change);
    2746        2354 :         torture_suite_add_1smb2_test(suite, "close", torture_smb2_notify_close);
    2747        2354 :         torture_suite_add_1smb2_test(suite, "logoff", torture_smb2_notify_ulogoff);
    2748        2354 :         torture_suite_add_1smb2_test(suite, "session-reconnect", torture_smb2_notify_session_reconnect);
    2749        2354 :         torture_suite_add_2smb2_test(suite, "invalid-reauth", torture_smb2_notify_invalid_reauth);
    2750        2354 :         torture_suite_add_1smb2_test(suite, "tree", torture_smb2_notify_tree);
    2751        2354 :         torture_suite_add_2smb2_test(suite, "basedir", torture_smb2_notify_basedir);
    2752        2354 :         torture_suite_add_2smb2_test(suite, "double", torture_smb2_notify_double);
    2753        2354 :         torture_suite_add_1smb2_test(suite, "file", torture_smb2_notify_file);
    2754        2354 :         torture_suite_add_1smb2_test(suite, "tcp", torture_smb2_notify_tcp_disconnect);
    2755        2354 :         torture_suite_add_2smb2_test(suite, "rec", torture_smb2_notify_recursive);
    2756        2354 :         torture_suite_add_1smb2_test(suite, "overflow", torture_smb2_notify_overflow);
    2757        2354 :         torture_suite_add_1smb2_test(suite, "rmdir1",
    2758             :                                      torture_smb2_notify_rmdir1);
    2759        2354 :         torture_suite_add_1smb2_test(suite, "rmdir2",
    2760             :                                      torture_smb2_notify_rmdir2);
    2761        2354 :         torture_suite_add_2smb2_test(suite, "rmdir3",
    2762             :                                      torture_smb2_notify_rmdir3);
    2763        2354 :         torture_suite_add_2smb2_test(suite, "rmdir4",
    2764             :                                      torture_smb2_notify_rmdir4);
    2765        2354 :         torture_suite_add_1smb2_test(suite,
    2766             :                                     "handle-permissions",
    2767             :                                     torture_smb2_notify_handle_permissions);
    2768             : 
    2769        2354 :         suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests");
    2770             : 
    2771        2354 :         return suite;
    2772             : }
    2773             : 
    2774             : /*
    2775             :    basic testing of SMB2 change notify
    2776             : */
    2777        2354 : struct torture_suite *torture_smb2_notify_inotify_init(TALLOC_CTX *ctx)
    2778             : {
    2779        2354 :         struct torture_suite *suite = torture_suite_create(ctx, "notify-inotify");
    2780             : 
    2781        2354 :         suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests that use inotify");
    2782             : 
    2783        2354 :         torture_suite_add_2smb2_test(suite, "inotify-rename", torture_smb2_inotify_rename);
    2784             : 
    2785        2354 :         return suite;
    2786             : }

Generated by: LCOV version 1.14