[SCM] Samba Shared Repository - branch master updated

Stefan Metzmacher metze at samba.org
Thu Dec 17 15:02:01 UTC 2020


The branch, master has been updated
       via  6c95e467817 smbd/notify: add option "honor change notify privilege"
       via  bcfce0ecd31 selftest: add tests for smb notify, using the a special share
       via  3e9f0e97255 selftest: add option to pass args to tests to planpythontestsuite()
       via  0133c17c099 python/tests: add tests for smb notify and the dependency to the TRAVERSE privilege
       via  f4e578aa24b python/ntacls.py: add SMBHelper.set_acl() helper function
       via  b082cf321e4 python/ntacls.py: let SMBHelper.get_acl() use the default values of self.smb_conn.get_acl()
       via  18dd953d83a libsmb_samba_internal: calculate the access_mask for {g,s}et_acl() based on the secinfo flags
       via  0ccdce67d3a libsmb_samba_internal: don't send SECINFO_[UN]PROTECTED_{S,D}ACL by default
       via  752a8f870de s3:pylibsmb: remove unused SECINFO_DEFAULT_FLAGS
       via  3ffb817506c s3:pylibsmb: add notify() support
       via  fde65c2f293 s3:pylibsmb: add echo() support
       via  084c22403f0 s3:pylibsmb: PyErr_NTSTATUS_IS_ERR_RAISE => PyErr_NTSTATUS_NOT_OK_RAISE
       via  560e4b1b32f libcli/smb: add smbXcli_conn_send_queue()
       via  76121ae7cf4 s3:libsmb: set correct min and max smb protocol when smb2 is enforced on connect
       via  f40da74e145 s3:libsmb: set min smb protocol when enforcing smb1 on connect
       via  98119189cfe blackbox/test_samba-tool_ntacl.sh: script requires two arguments
       via  577d4f1a60c docs:smbdotconf: fix a typo in oldpasswordallowedperiod.xml
      from  8004cf7a4af pep8 tidy up config

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 6c95e467817b246a0eab626cac10b6120f6c88f8
Author: Björn Baumbach <bb at sernet.de>
Date:   Tue Nov 6 15:21:37 2018 +0100

    smbd/notify: add option "honor change notify privilege"
    
    This option can be used to make use of the change notify privilege.
    By default notify results are not checked against the file system
    permissions.
    
    If "honor change notify privilege" is enabled, a user will only
    receive notify results, if he has change notify privilege or sufficient
    file system permissions. If a user has the change notify privilege, he
    will receive all requested notify results, even if the user does not
    have the permissions on the file system.
    
    Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
    
    Signed-off-by: Björn Baumbach <bb at sernet.de>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    
    Autobuild-User(master): Stefan Metzmacher <metze at samba.org>
    Autobuild-Date(master): Thu Dec 17 15:01:53 UTC 2020 on sn-devel-184

commit bcfce0ecd3153d158f712ff548a1ccd005031bc8
Author: Björn Baumbach <bb at sernet.de>
Date:   Mon Jul 20 16:49:39 2020 +0200

    selftest: add tests for smb notify, using the a special share
    
    That share will get the "honor change notify privilege = yes" option
    once it's implemented. For now it's marked as knownfail.
    
    Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
    
    Signed-off-by: Björn Baumbach <bb at sernet.de>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 3e9f0e97255de1b4235c4dca6912635386328746
Author: Björn Baumbach <bb at sernet.de>
Date:   Fri Jul 24 12:18:11 2020 +0200

    selftest: add option to pass args to tests to planpythontestsuite()
    
    The logic is basically a copy from planoldpythontestsuite().
    
    Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
    
    Signed-off-by: Björn Baumbach <bb at sernet.de>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 0133c17c099f6a482e2941a2254c983ec0188592
Author: Björn Baumbach <bb at sernet.de>
Date:   Mon Jul 20 16:49:39 2020 +0200

    python/tests: add tests for smb notify and the dependency to the TRAVERSE privilege
    
    The easiest way to run this against Windows was to use a domain
    controller and configure an enforce group policy and grant the
    "Bypass Traverse Checking" only to the "BUILTIN\Administrators" group.
    (Note that "LOCAL SERVICE" and "NETWORK SERVICE" are always added in
    the local security policy.
    
    The test runs like this:
    
      SMB_CONF_PATH=/dev/null \
      SERVER=172.31.9.188 \
      TARGET_HOSTNAME=w2012r2-188.w2012r2-l6.base \
      USERNAME=administrator \
      PASSWORD=A1b2C3d4 \
      NOTIFY_SHARE=torture \
      USERNAME_UNPRIV=ldaptestuser \
      PASSWORD_UNPRIV=a1B2c3D4 \
      python/samba/tests/smb-notify.py -v -f SMBNotifyTests
    
    Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
    
    Signed-off-by: Björn Baumbach <bb at sernet.de>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit f4e578aa24bc020d87716915ea5037d7677b75e9
Author: Björn Baumbach <bb at sernet.de>
Date:   Tue Jul 21 12:34:19 2020 +0200

    python/ntacls.py: add SMBHelper.set_acl() helper function
    
    Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
    
    Signed-off-by: Björn Baumbach <bb at sernet.de>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit b082cf321e4267cc214f2a74550847585275e25a
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Dec 3 13:59:58 2020 +0100

    python/ntacls.py: let SMBHelper.get_acl() use the default values of self.smb_conn.get_acl()
    
    Now that self.smb_conn.get_acl() has sane default values for secinfo and
    access_mask we can remove any additional logic in SMBHelper.
    
    The resulting values are the same.
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 18dd953d83a5d43b243047d9dd622620034ee6c7
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Dec 3 14:51:52 2020 +0100

    libsmb_samba_internal: calculate the access_mask for {g,s}et_acl() based on the secinfo flags
    
    SEC_FLAG_MAXIMUM_ALLOWED will never result in SEC_FLAG_SYSTEM_SECURITY
    being granted. As SECINFO_SACL is part of the default secinfo value
    (SECINFO_DEFAULT_FLAGS), {g,s}et_acl() will always return
    NT_STATUS_ACCESS_DENIED by default.
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 0ccdce67d3adfc06b6d8235b53d677da1526ba4b
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Dec 3 13:58:53 2020 +0100

    libsmb_samba_internal: don't send SECINFO_[UN]PROTECTED_{S,D}ACL by default
    
    We want to get the default behavior.
    
    It's also pointless to set PROTECTED and UNPROTECTED at the same time.
    These are defined in MS-DTYP 2.4.7 SECURITY_INFORMATION with a brief
    description, but they aren't referenced in anywhere in MS-DTYP itself,
    nor in MS-FSA are any other document.
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 752a8f870de2bb087802a1287d7fb6c7624ac631
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Dec 3 13:19:58 2020 +0100

    s3:pylibsmb: remove unused SECINFO_DEFAULT_FLAGS
    
    commit 42be033b0b0c02413a74f984c8622b5baed2689a removed the last
    reference.
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 3ffb817506c032cdc05064abfbffb9f364e09a22
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Aug 27 13:49:04 2019 +0000

    s3:pylibsmb: add notify() support
    
    The operation is a bit different from others,
    as results are returned in an async fashion.
    It returns a request handle.
    
      notify_req = conn.notify(fnum=fnum,
                               buffer_size=0xffff,
                               completion_filter=libsmb.FILE_NOTIFY_CHANGE_ALL,
                               recursive=True)
    
      # ... do other operations on conn.*() ...
    
      changes = notify_req.get_changes(wait=False)
      # changes is likely to be None if no result arrived yet
    
      # ... do other operations on conn.*() ...
    
      changes = notify_req.get_changes(wait=True)
      # changes is a list of change dictionaries
      # each containing "name" (a string) and
      # "action" (an integer, e.g. libsmb.NOTIFY_ACTION_REMOVED)
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit fde65c2f293ae3038c0052ea9d0dcdf3261d3fbc
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Dec 7 17:52:49 2020 +0100

    s3:pylibsmb: add echo() support
    
    In tests it's sometimes to have a no-op in order to check the
    transport is still alive.
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 084c22403f0042f9cb6c5af6651cc9ef8b5f3bd0
Author: Stefan Metzmacher <metze at samba.org>
Date:   Wed Dec 9 10:13:54 2020 +0100

    s3:pylibsmb: PyErr_NTSTATUS_IS_ERR_RAISE => PyErr_NTSTATUS_NOT_OK_RAISE
    
    We want to raise an exception for everything that's not NT_STATUS_OK.
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 560e4b1b32f56ed4cfffc60efd9199ed435409ba
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Aug 29 10:28:14 2019 +0000

    libcli/smb: add smbXcli_conn_send_queue()
    
    This is useful in order to test async requests
    tevent_queue_wait_send/recv() can be used to block
    the queue between requests or wait for the queue to be flushed.
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 76121ae7cf4967329b9745137999fde00309c987
Author: Björn Baumbach <bb at sernet.de>
Date:   Thu Aug 29 12:13:50 2019 +0200

    s3:libsmb: set correct min and max smb protocol when smb2 is enforced on connect
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14105
    
    Pair-programmed-with: Stefan Metzmacher <metze at samba.org>
    
    Signed-off-by: Björn Baumbach <bb at sernet.de>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit f40da74e1452e73799f8643d93b8b9e572df1088
Author: Björn Baumbach <bb at sernet.de>
Date:   Wed Aug 28 14:11:02 2019 +0200

    s3:libsmb: set min smb protocol when enforcing smb1 on connect
    
    Otherwise the connect fails if the configured client min protocol is
    higher than NT1.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14105
    
    Signed-off-by: Björn Baumbach <bb at sernet.de>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 98119189cfe7b76322253d30170528eb0bf33eb7
Author: Björn Baumbach <bb at sernet.de>
Date:   Tue Aug 27 11:19:42 2019 +0200

    blackbox/test_samba-tool_ntacl.sh: script requires two arguments
    
    Signed-off-by: Björn Baumbach <bb at sernet.de>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 577d4f1a60c41df82da8711dabde9361780a9144
Author: Björn Baumbach <bb at sernet.de>
Date:   Wed Mar 18 10:31:04 2020 +0100

    docs:smbdotconf: fix a typo in oldpasswordallowedperiod.xml
    
    Signed-off-by: Björn Baumbach <bb at sernet.de>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

-----------------------------------------------------------------------

Summary of changes:
 .../smbdotconf/misc/honorchangenotifyprivilege.xml |  20 +
 .../security/oldpasswordallowedperiod.xml          |   2 +-
 libcli/smb/smbXcli_base.c                          |   5 +
 libcli/smb/smbXcli_base.h                          |   1 +
 python/samba/ntacls.py                             |  28 +-
 python/samba/samba3/libsmb_samba_internal.py       |  83 +++-
 python/samba/tests/smb-notify.py                   | 430 +++++++++++++++++++++
 python/samba/tests/usage.py                        |   1 +
 selftest/selftesthelpers.py                        |  16 +-
 selftest/target/Samba3.pm                          |   4 +
 source3/libsmb/cliconnect.c                        |  11 +-
 source3/libsmb/pylibsmb.c                          | 309 ++++++++++++++-
 source3/param/loadparm.c                           |   1 +
 source3/smbd/notify.c                              | 129 +++++++
 source4/selftest/tests.py                          |   8 +
 testprogs/blackbox/test_samba-tool_ntacl.sh        |   8 +-
 16 files changed, 1008 insertions(+), 48 deletions(-)
 create mode 100644 docs-xml/smbdotconf/misc/honorchangenotifyprivilege.xml
 create mode 100755 python/samba/tests/smb-notify.py


Changeset truncated at 500 lines:

diff --git a/docs-xml/smbdotconf/misc/honorchangenotifyprivilege.xml b/docs-xml/smbdotconf/misc/honorchangenotifyprivilege.xml
new file mode 100644
index 00000000000..a9c880ce467
--- /dev/null
+++ b/docs-xml/smbdotconf/misc/honorchangenotifyprivilege.xml
@@ -0,0 +1,20 @@
+<samba:parameter name="honor change notify privilege"
+                 context="S"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+	<para>
+	  This option can be used to make use of the change notify privilege.
+	  By default notify results are not checked against the file system
+	  permissions.
+	</para>
+	<para>
+	  If "honor change notify privilege" is enabled, a user will only
+	  receive notify results, if he has change notify privilege or
+	  sufficient file system permissions. If a user has the change notify
+	  privilege, he will receive all requested notify results, even if the
+	  user does not have the permissions on the file system.
+	</para>
+</description>
+<value type="default">no</value>
+</samba:parameter>
diff --git a/docs-xml/smbdotconf/security/oldpasswordallowedperiod.xml b/docs-xml/smbdotconf/security/oldpasswordallowedperiod.xml
index 9cb607b11b3..78d6ff1d609 100644
--- a/docs-xml/smbdotconf/security/oldpasswordallowedperiod.xml
+++ b/docs-xml/smbdotconf/security/oldpasswordallowedperiod.xml
@@ -5,7 +5,7 @@
 <description>
     <para>Number of minutes to permit an NTLM login after a password change or reset using the old password.  This allows the user to re-cache the new password on multiple clients without disrupting a network reconnection in the meantime. </para>
 
-    <para>This parameter only applies when <smbconfoption name="server role"/> is set to Active Directory Domain Controller</para>
+    <para>This parameter only applies when <smbconfoption name="server role"/> is set to Active Directory Domain Controller.</para>
 </description>
 
 <value type="default">60</value>
diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
index df80be6bf16..0fc4aa4451a 100644
--- a/libcli/smb/smbXcli_base.c
+++ b/libcli/smb/smbXcli_base.c
@@ -2743,6 +2743,11 @@ NTSTATUS smb1cli_req_chain_submit(struct tevent_req **reqs, int num_reqs)
 	return NT_STATUS_OK;
 }
 
+struct tevent_queue *smbXcli_conn_send_queue(struct smbXcli_conn *conn)
+{
+	return conn->outgoing;
+}
+
 bool smbXcli_conn_has_async_calls(struct smbXcli_conn *conn)
 {
 	return ((tevent_queue_length(conn->outgoing) != 0)
diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h
index db5f5d58799..d9c3175bdf5 100644
--- a/libcli/smb/smbXcli_base.h
+++ b/libcli/smb/smbXcli_base.h
@@ -43,6 +43,7 @@ struct smbXcli_conn *smbXcli_conn_create(TALLOC_CTX *mem_ctx,
 bool smbXcli_conn_is_connected(struct smbXcli_conn *conn);
 void smbXcli_conn_disconnect(struct smbXcli_conn *conn, NTSTATUS status);
 
+struct tevent_queue *smbXcli_conn_send_queue(struct smbXcli_conn *conn);
 bool smbXcli_conn_has_async_calls(struct smbXcli_conn *conn);
 
 bool smbXcli_conn_dfs_supported(struct smbXcli_conn *conn);
diff --git a/python/samba/ntacls.py b/python/samba/ntacls.py
index 0dcf958f727..4f189965d05 100644
--- a/python/samba/ntacls.py
+++ b/python/samba/ntacls.py
@@ -49,12 +49,6 @@ SECURITY_SECINFO_FLAGS = security.SECINFO_OWNER | \
                          security.SECINFO_DACL  | \
                          security.SECINFO_SACL
 
-
-# SEC_FLAG_SYSTEM_SECURITY is required otherwise get Access Denied
-SECURITY_SEC_FLAGS = security.SEC_FLAG_SYSTEM_SECURITY | \
-                     security.SEC_STD_READ_CONTROL
-
-
 class XattrBackendError(Exception):
     """A generic xattr backend error."""
 
@@ -335,14 +329,30 @@ class SMBHelper:
         self.smb_conn = smb_conn
         self.dom_sid = dom_sid
 
-    def get_acl(self, smb_path, as_sddl=False):
+    def get_acl(self, smb_path, as_sddl=False,
+                sinfo=None, access_mask=None):
         assert '/' not in smb_path
 
-        ntacl_sd = self.smb_conn.get_acl(
-            smb_path, SECURITY_SECINFO_FLAGS, SECURITY_SEC_FLAGS)
+        ntacl_sd = self.smb_conn.get_acl(smb_path,
+                                         sinfo=sinfo,
+                                         access_mask=access_mask)
 
         return ntacl_sd.as_sddl(self.dom_sid) if as_sddl else ntacl_sd
 
+    def set_acl(self, smb_path, ntacl_sd,
+                sinfo=None, access_mask=None):
+        assert '/' not in smb_path
+
+        assert(isinstance(ntacl_sd, str) or isinstance(ntacl_sd, security.descriptor))
+        if isinstance(ntacl_sd, str):
+            tmp_desc = security.descriptor.from_sddl(ntacl_sd, self.domain_sid)
+        elif isinstance(ntacl_sd, security.descriptor):
+            tmp_desc = ntacl_sd
+
+        self.smb_conn.set_acl(smb_path, tmp_desc,
+                              sinfo=sinfo,
+                              access_mask=access_mask)
+
     def list(self, smb_path=''):
         """
         List file and dir base names in smb_path without recursive.
diff --git a/python/samba/samba3/libsmb_samba_internal.py b/python/samba/samba3/libsmb_samba_internal.py
index 84729b2041d..ef0b30d774b 100644
--- a/python/samba/samba3/libsmb_samba_internal.py
+++ b/python/samba/samba3/libsmb_samba_internal.py
@@ -29,17 +29,77 @@ class Conn(LibsmbCConn):
         security.SECINFO_OWNER | \
         security.SECINFO_GROUP | \
         security.SECINFO_DACL | \
-        security.SECINFO_PROTECTED_DACL | \
-        security.SECINFO_UNPROTECTED_DACL | \
-        security.SECINFO_SACL | \
-        security.SECINFO_PROTECTED_SACL | \
-        security.SECINFO_UNPROTECTED_SACL
+        security.SECINFO_SACL
+
+    def required_access_for_get_secinfo(self, secinfo):
+        access = 0
+
+        #
+        # This is based on MS-FSA
+        # 2.1.5.13 Server Requests a Query of Security Information
+        #
+        # Note that MS-SMB2 3.3.5.20.3 Handling SMB2_0_INFO_SECURITY
+        # doesn't specify any extra checks
+        #
+
+        if secinfo & security.SECINFO_OWNER:
+            access |= security.SEC_STD_READ_CONTROL
+        if secinfo & security.SECINFO_GROUP:
+            access |= security.SEC_STD_READ_CONTROL
+        if secinfo & security.SECINFO_DACL:
+            access |= security.SEC_STD_READ_CONTROL
+        if secinfo & security.SECINFO_SACL:
+            access |= security.SEC_FLAG_SYSTEM_SECURITY
+
+        if secinfo & security.SECINFO_LABEL:
+            access |= security.SEC_STD_READ_CONTROL
+
+        return access
+
+    def required_access_for_set_secinfo(self, secinfo):
+        access = 0
+
+        #
+        # This is based on MS-FSA
+        # 2.1.5.16 Server Requests Setting of Security Information
+        # and additional constraints from
+        # MS-SMB2 3.3.5.21.3 Handling SMB2_0_INFO_SECURITY
+        #
+
+        if secinfo & security.SECINFO_OWNER:
+            access |= security.SEC_STD_WRITE_OWNER
+        if secinfo & security.SECINFO_GROUP:
+            access |= security.SEC_STD_WRITE_OWNER
+        if secinfo & security.SECINFO_DACL:
+            access |= security.SEC_STD_WRITE_DAC
+        if secinfo & security.SECINFO_SACL:
+            access |= security.SEC_FLAG_SYSTEM_SECURITY
+
+        if secinfo & security.SECINFO_LABEL:
+            access |= security.SEC_STD_WRITE_OWNER
+
+        if secinfo & security.SECINFO_ATTRIBUTE:
+            access |= security.SEC_STD_WRITE_DAC
+
+        if secinfo & security.SECINFO_SCOPE:
+            access |= security.SEC_FLAG_SYSTEM_SECURITY
+
+        if secinfo & security.SECINFO_BACKUP:
+            access |= security.SEC_STD_WRITE_OWNER
+            access |= security.SEC_STD_WRITE_DAC
+            access |= security.SEC_FLAG_SYSTEM_SECURITY
+
+        return access
 
     def get_acl(self,
                 filename,
-                sinfo = SECINFO_DEFAULT_FLAGS,
-                access_mask = security.SEC_FLAG_MAXIMUM_ALLOWED):
+                sinfo=None,
+                access_mask=None):
         """Get security descriptor for file."""
+        if sinfo is None:
+            sinfo = self.SECINFO_DEFAULT_FLAGS
+        if access_mask is None:
+            access_mask = self.required_access_for_get_secinfo(sinfo)
         fnum = self.create(
             Name=filename,
             DesiredAccess=access_mask,
@@ -53,11 +113,16 @@ class Conn(LibsmbCConn):
     def set_acl(self,
                 filename,
                 sd,
-                sinfo = SECINFO_DEFAULT_FLAGS):
+                sinfo=None,
+                access_mask=None):
         """Set security descriptor for file."""
+        if sinfo is None:
+            sinfo = self.SECINFO_DEFAULT_FLAGS
+        if access_mask is None:
+            access_mask = self.required_access_for_set_secinfo(sinfo)
         fnum = self.create(
             Name=filename,
-            DesiredAccess=security.SEC_FLAG_MAXIMUM_ALLOWED,
+            DesiredAccess=access_mask,
             ShareAccess=(FILE_SHARE_READ|FILE_SHARE_WRITE))
         try:
             self.set_sd(fnum, sd, sinfo)
diff --git a/python/samba/tests/smb-notify.py b/python/samba/tests/smb-notify.py
new file mode 100755
index 00000000000..2f42263be25
--- /dev/null
+++ b/python/samba/tests/smb-notify.py
@@ -0,0 +1,430 @@
+#!/usr/bin/env python3
+# Unix SMB/CIFS implementation. Tests for smb notify
+# Copyright (C) Björn Baumbach <bb at samba.org> 2020
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import sys
+import os
+
+sys.path.insert(0, "bin/python")
+os.environ["PYTHONUNBUFFERED"] = "1"
+
+import samba
+import random
+from samba.tests import TestCase
+from samba import NTSTATUSError
+from samba import credentials
+from samba.ntstatus import NT_STATUS_NOTIFY_CLEANUP
+from samba.samba3 import libsmb_samba_internal as libsmb
+from samba.samba3 import param as s3param
+from samba.dcerpc import security
+
+from samba import ntacls
+
+test_dir = os.path.join('notify_test_%d' % random.randint(0, 0xFFFF))
+
+class SMBNotifyTests(TestCase):
+    def setUp(self):
+        super(SMBNotifyTests, self).setUp()
+        self.server = samba.tests.env_get_var_value("SERVER")
+
+        # create an SMB connection to the server
+        self.lp = s3param.get_context()
+        self.lp.load(samba.tests.env_get_var_value("SMB_CONF_PATH"))
+
+        self.share = samba.tests.env_get_var_value("NOTIFY_SHARE")
+
+        creds = credentials.Credentials()
+        creds.guess(self.lp)
+        creds.set_username(samba.tests.env_get_var_value("USERNAME"))
+        creds.set_password(samba.tests.env_get_var_value("PASSWORD"))
+
+        strict_checking = samba.tests.env_get_var_value('STRICT_CHECKING', allow_missing=True)
+        if strict_checking is None:
+            strict_checking = '1'
+        self.strict_checking = bool(int(strict_checking))
+
+        self.smb_conn = libsmb.Conn(self.server, self.share, self.lp, creds)
+        self.smb_conn_unpriv = None
+
+        try:
+            self.smb_conn.deltree(test_dir)
+        except:
+            pass
+        self.smb_conn.mkdir(test_dir)
+
+    def connect_unpriv(self):
+        creds_unpriv = credentials.Credentials()
+        creds_unpriv.guess(self.lp)
+        creds_unpriv.set_username(samba.tests.env_get_var_value("USERNAME_UNPRIV"))
+        creds_unpriv.set_password(samba.tests.env_get_var_value("PASSWORD_UNPRIV"))
+
+        self.smb_conn_unpriv = libsmb.Conn(self.server, self.share, self.lp, creds_unpriv)
+
+    def tearDown(self):
+        super(SMBNotifyTests, self).tearDown()
+        try:
+            self.smb_conn.deltree(test_dir)
+        except:
+            pass
+
+    def make_path(self, dirpath, filename):
+        return os.path.join(dirpath, filename).replace('/', '\\')
+
+    def test_notify(self):
+        # setup notification request on the share root
+        root_fnum = self.smb_conn.create(Name="", ShareAccess=1)
+        root_notify = self.smb_conn.notify(fnum=root_fnum,
+                                           buffer_size=0xffff,
+                                           completion_filter=libsmb.FILE_NOTIFY_CHANGE_ALL,
+                                           recursive=True)
+        # setup notification request on the test_dir
+        test_dir_fnum = self.smb_conn.create(Name=test_dir, ShareAccess=1)
+        test_dir_notify = self.smb_conn.notify(fnum=test_dir_fnum,
+                                               buffer_size=0xffff,
+                                               completion_filter=libsmb.FILE_NOTIFY_CHANGE_ALL,
+                                               recursive=True)
+
+        # make sure we didn't receive any changes yet.
+        self.smb_conn.echo()
+        changes = root_notify.get_changes(wait=False)
+        self.assertIsNone(changes)
+        changes = test_dir_notify.get_changes(wait=False)
+        self.assertIsNone(changes)
+
+        # create a test directory
+        dir_name = "dir"
+        dir_path = self.make_path(test_dir, dir_name)
+        self.smb_conn.mkdir(dir_path)
+
+        # check for 'added' notifications
+        changes = root_notify.get_changes(wait=True)
+        self.assertIsNotNone(changes)
+        self.assertEqual(changes[0]['name'], dir_path)
+        self.assertEqual(changes[0]['action'], libsmb.NOTIFY_ACTION_ADDED)
+        self.assertEqual(len(changes), 1)
+        changes = test_dir_notify.get_changes(wait=True)
+        self.assertIsNotNone(changes)
+        self.assertEqual(changes[0]['name'], dir_name)
+        self.assertEqual(changes[0]['action'], libsmb.NOTIFY_ACTION_ADDED)
+        self.assertEqual(len(changes), 1)
+
+        # readd notification requests
+        root_notify = self.smb_conn.notify(fnum=root_fnum,
+                                           buffer_size=0xffff,
+                                           completion_filter=libsmb.FILE_NOTIFY_CHANGE_ALL,
+                                           recursive=True)
+        test_dir_notify = self.smb_conn.notify(fnum=test_dir_fnum,
+                                               buffer_size=0xffff,
+                                               completion_filter=libsmb.FILE_NOTIFY_CHANGE_ALL,
+                                               recursive=True)
+
+        # make sure we didn't receive any changes yet.
+        self.smb_conn.echo()
+        changes = root_notify.get_changes(wait=False)
+        self.assertIsNone(changes)
+        changes = test_dir_notify.get_changes(wait=False)
+        self.assertIsNone(changes)
+
+        # create subdir and trigger notifications
+        sub_name = "subdir"
+        sub_path_rel = self.make_path(dir_name, sub_name)
+        sub_path_full = self.make_path(dir_path, sub_name)
+        self.smb_conn.mkdir(sub_path_full)
+
+        # check for 'added' notifications
+        changes = root_notify.get_changes(wait=True)
+        self.assertIsNotNone(changes)
+        self.assertEqual(changes[0]['name'], sub_path_full)
+        self.assertEqual(changes[0]['action'], libsmb.NOTIFY_ACTION_ADDED)
+        self.assertEqual(len(changes), 1)
+        changes = test_dir_notify.get_changes(wait=True)
+        self.assertIsNotNone(changes)
+        self.assertEqual(changes[0]['name'], sub_path_rel)
+        self.assertEqual(changes[0]['action'], libsmb.NOTIFY_ACTION_ADDED)
+        self.assertEqual(len(changes), 1)
+
+        # readd notification requests
+        root_notify = self.smb_conn.notify(fnum=root_fnum,
+                                           buffer_size=0xffff,
+                                           completion_filter=libsmb.FILE_NOTIFY_CHANGE_ALL,
+                                           recursive=True)
+        test_dir_notify = self.smb_conn.notify(fnum=test_dir_fnum,
+                                               buffer_size=0xffff,
+                                               completion_filter=libsmb.FILE_NOTIFY_CHANGE_ALL,
+                                               recursive=True)
+
+        # make sure we didn't receive any changes yet.
+        self.smb_conn.echo()
+        changes = root_notify.get_changes(wait=False)
+        self.assertIsNone(changes)
+        changes = test_dir_notify.get_changes(wait=False)
+        self.assertIsNone(changes)
+
+        # remove test dir and trigger notifications
+        self.smb_conn.rmdir(sub_path_full)
+
+        # check for 'removed' notifications
+        changes = root_notify.get_changes(wait=True)
+        self.assertIsNotNone(changes)
+        self.assertEqual(changes[0]['name'], sub_path_full)
+        self.assertEqual(changes[0]['action'], libsmb.NOTIFY_ACTION_REMOVED)
+        self.assertEqual(len(changes), 1)
+        changes = test_dir_notify.get_changes(wait=True)
+        self.assertIsNotNone(changes)
+        self.assertEqual(changes[0]['name'], sub_path_rel)
+        self.assertEqual(changes[0]['action'], libsmb.NOTIFY_ACTION_REMOVED)
+        self.assertEqual(len(changes), 1)
+
+        # readd notification requests
+        root_notify = self.smb_conn.notify(fnum=root_fnum,
+                                           buffer_size=0xffff,
+                                           completion_filter=libsmb.FILE_NOTIFY_CHANGE_ALL,
+                                           recursive=True)
+        test_dir_notify = self.smb_conn.notify(fnum=test_dir_fnum,
+                                               buffer_size=0xffff,
+                                               completion_filter=libsmb.FILE_NOTIFY_CHANGE_ALL,
+                                               recursive=True)
+
+        # make sure we didn't receive any changes yet.
+        self.smb_conn.echo()
+        changes = root_notify.get_changes(wait=False)
+        self.assertIsNone(changes)
+        changes = test_dir_notify.get_changes(wait=False)
+        self.assertIsNone(changes)
+
+        # closing the handle on test_dir will trigger
+        # a NOTIFY_CLEANUP on test_dir_notify and
+        # it also seems to update something on test_dir it self
+        # and post a MODIFIED on root_notify
+        #
+        # TODO: find out why windows generates ACTION_MODIFIED
+        #       and why Samba doesn't
+        self.smb_conn.close(test_dir_fnum)
+        try:
+            changes = test_dir_notify.get_changes(wait=True)
+            self.fail()
+        except samba.NTSTATUSError as err:
+            self.assertEqual(err.args[0], NT_STATUS_NOTIFY_CLEANUP)
+        self.smb_conn.echo()
+        changes = root_notify.get_changes(wait=False)
+        if self.strict_checking:
+            self.assertIsNotNone(changes)
+        if changes is not None:
+            self.assertEqual(changes[0]['name'], test_dir)
+            self.assertEqual(changes[0]['action'], libsmb.NOTIFY_ACTION_MODIFIED)
+            self.assertEqual(len(changes), 1)
+
+            # readd notification request
+            root_notify = self.smb_conn.notify(fnum=root_fnum,
+                                               buffer_size=0xffff,
+                                               completion_filter=libsmb.FILE_NOTIFY_CHANGE_ALL,
+                                               recursive=True)
+
+        # make sure we didn't receive any changes yet.
+        self.smb_conn.echo()
+        changes = root_notify.get_changes(wait=False)
+        self.assertIsNone(changes)
+
+        # remove test_dir
+        self.smb_conn.rmdir(dir_path)
+
+        # check for 'removed' notifications
+        changes = root_notify.get_changes(wait=True)
+        self.assertIsNotNone(changes)
+        self.assertEqual(changes[0]['name'], dir_path)
+        self.assertEqual(changes[0]['action'], libsmb.NOTIFY_ACTION_REMOVED)
+        self.assertEqual(len(changes), 1)
+
+        # readd notification request
+        root_notify = self.smb_conn.notify(fnum=root_fnum,
+                                           buffer_size=0xffff,
+                                           completion_filter=libsmb.FILE_NOTIFY_CHANGE_ALL,
+                                           recursive=True)
+        # closing the handle on test_dir will trigger
+        # a NOTIFY_CLEANUP on root_notify
+        self.smb_conn.close(root_fnum)
+        try:
+            changes = root_notify.get_changes(wait=True)
+            self.fail()
+        except samba.NTSTATUSError as err:
+            self.assertEqual(err.args[0], NT_STATUS_NOTIFY_CLEANUP)
+
+
+    def _test_notify_privileged_path(self,
+                                     monitor_path=None,
+                                     rel_prefix=None):


-- 
Samba Shared Repository



More information about the samba-cvs mailing list