[SCM] Samba Shared Repository - branch master updated

Jeremy Allison jra at samba.org
Tue Sep 27 17:47:02 UTC 2022


The branch, master has been updated
       via  d89400b6201 samba-tool dsacl: Add additional unit test for delete subcommand
       via  50eb747c14e python security: Add unit tests for comparing ACEs and exporting as SDDL
       via  42b88992bd1 samba-tool dsacl: Add get and delete subcommand to samba-tool dsacl man section
       via  dff58819d02 samba-tool dsacl: Create common superclass for dsacl commands
       via  c9902b0574f samba-tool dsacl: Create helper functions to remove code duplication
       via  492d3316d88 samba-tool dsacl: Add unit tests for delete subcommand
       via  1bd08133067 samba-tool dsacl: Add subcommand to delete ACEs
       via  80cf4c86594 librpc ndr/py_security: Export sddl_encode_ace to python
       via  b0f494c1086 librpc ndr/py_security: Export security_ace_equal as richcmp to python
       via  84a54d2fa2b librpc ndr/py_security: Export ACE deletion functions to python
       via  6501e4f00e5 libcli security/sddl: Make sddl_encode_ace visible
       via  1a9aac53e8e libcli security_descriptor: Compare object type and inherited object type when comparing ACEs
       via  7efe673fbdc libcli security_descriptor: Add function to delete a given ace from a security descriptor
      from  b600b0c8d96 s3: smbd: Fix memory leak in smbd_server_connection_terminate_done().

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


- Log -----------------------------------------------------------------
commit d89400b6201013ffdf06dc5480f59d9a41eb2f2a
Author: Christian Merten <christian at merten.dev>
Date:   Mon Sep 19 23:28:07 2022 +0200

    samba-tool dsacl: Add additional unit test for delete subcommand
    
    Added one more unit test to the delete subcommand. This test adds
    two ACEs, deletes one of them and checks if the right one was deleted
    and the other one stayed the same.
    
    Signed-off-by: Christian Merten <christian at merten.dev>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    
    Autobuild-User(master): Jeremy Allison <jra at samba.org>
    Autobuild-Date(master): Tue Sep 27 17:46:22 UTC 2022 on sn-devel-184

commit 50eb747c14ebf5cbcb3c80bd2a5e4e82580c0d5b
Author: Christian Merten <christian at merten.dev>
Date:   Mon Sep 19 23:22:04 2022 +0200

    python security: Add unit tests for comparing ACEs and exporting as SDDL
    
    Added two unit tests for the python functions to compare ACEs and to
    export an ACE as SDDL.
    
    Signed-off-by: Christian Merten <christian at merten.dev>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 42b88992bd1a1f5ed890c1f73a187bffad963388
Author: Christian Merten <christian at merten.dev>
Date:   Thu Sep 15 10:38:22 2022 +0200

    samba-tool dsacl: Add get and delete subcommand to samba-tool dsacl man section
    
    Added get and delete subcommands to the man section of samba-tool dsacl.
    
    Signed-off-by: Christian Merten <christian at merten.dev>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit dff58819d02ef32c62292982ec6844ce634bebdd
Author: Christian Merten <christian at merten.dev>
Date:   Thu Sep 15 10:20:04 2022 +0200

    samba-tool dsacl: Create common superclass for dsacl commands
    
    Created a base class for dsacl commands providing print_acl and some fixed command line options to
    reduce code duplication.
    
    Signed-off-by: Christian Merten <christian at merten.dev>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit c9902b0574fab9b3e10f440898d4980383dfe3c7
Author: Christian Merten <christian at merten.dev>
Date:   Thu Sep 15 10:08:47 2022 +0200

    samba-tool dsacl: Create helper functions to remove code duplication
    
    Make multiple methods of dsacl command classes separate helper functions to avoid code duplication.
    
    Signed-off-by: Christian Merten <christian at merten.dev>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 492d3316d888b2ded61d949adc405d9a13fa7d10
Author: Christian Merten <christian at merten.dev>
Date:   Wed Sep 14 01:33:18 2022 +0200

    samba-tool dsacl: Add unit tests for delete subcommand
    
    Two unit tests for the new samba-tool dsacl delete command have been added.
    
    Signed-off-by: Christian Merten <christian at merten.dev>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 1bd08133067c50b6125addb2f94d293261a192fa
Author: Christian Merten <christian at merten.dev>
Date:   Wed Sep 14 01:29:34 2022 +0200

    samba-tool dsacl: Add subcommand to delete ACEs
    
    A new subcommand has been added to samba-tool dsacl to delete one or multiple ACEs from the security
    descriptor of an object.
    
    Signed-off-by: Christian Merten <christian at merten.dev>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 80cf4c86594ca1210d23712daadecb6deb829066
Author: Christian Merten <christian at merten.dev>
Date:   Mon Sep 19 23:12:59 2022 +0200

    librpc ndr/py_security: Export sddl_encode_ace to python
    
    Added sddl_encode_ace as new method as_sddl to security_ace class in python.
    
    Signed-off-by: Christian Merten <christian at merten.dev>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit b0f494c10860535c907376432a9b1678f4038d7f
Author: Christian Merten <christian at merten.dev>
Date:   Mon Sep 19 23:11:37 2022 +0200

    librpc ndr/py_security: Export security_ace_equal as richcmp to python
    
    Patched security_ace with a richcmp function given by
    security_ace_equal.
    
    Signed-off-by: Christian Merten <christian at merten.dev>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 84a54d2fa2b1590fdb4e2ea986ded9c39a82cf78
Author: Christian Merten <christian at merten.dev>
Date:   Mon Sep 19 23:01:34 2022 +0200

    librpc ndr/py_security: Export ACE deletion functions to python
    
    Exported security_descriptor_sacl_del and security_descriptor_dacl_del as new methods of the
    security descriptor class to python.
    
    Signed-off-by: Christian Merten <christian at merten.dev>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 6501e4f00e5a36debdf44add1335818a791552f0
Author: Christian Merten <christian at merten.dev>
Date:   Mon Sep 19 22:53:45 2022 +0200

    libcli security/sddl: Make sddl_encode_ace visible
    
    Removed static flag from sddl_encode_ace and added to headers.
    
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    Signed-off-by: Christian Merten <christian at merten.dev>

commit 1a9aac53e8ee081cf6d2028de759563120619554
Author: Christian Merten <christian at merten.dev>
Date:   Mon Sep 19 22:50:58 2022 +0200

    libcli security_descriptor: Compare object type and inherited object type when comparing ACEs
    
    Fixed security_ace_equal returning true, despite differing object type, by checking (inherited) object type
    of both ACEs is equal.
    
    Signed-off-by: Christian Merten <christian at merten.dev>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 7efe673fbdcd27ddd23f36281c5f5338681a68fe
Author: Christian Merten <christian at merten.dev>
Date:   Mon Sep 19 22:47:10 2022 +0200

    libcli security_descriptor: Add function to delete a given ace from a security descriptor
    
    Two functions have been added to delete a given ace from the SACL or the DACL of a security descriptor.
    
    Signed-off-by: Christian Merten <christian at merten.dev>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Jeremy Allison <jra at samba.org>

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

Summary of changes:
 docs-xml/manpages/samba-tool.8.xml     |  10 ++
 libcli/security/sddl.c                 |   4 +-
 libcli/security/sddl.h                 |   3 +-
 libcli/security/security_descriptor.c  | 101 +++++++++++++++++++
 libcli/security/security_descriptor.h  |   4 +
 python/samba/netcmd/dsacl.py           | 171 ++++++++++++++++++---------------
 python/samba/tests/samba_tool/dsacl.py |  88 +++++++++++++++++
 python/samba/tests/security.py         |  35 +++++++
 source4/librpc/ndr/py_security.c       | 131 ++++++++++++++++++++++++-
 9 files changed, 467 insertions(+), 80 deletions(-)


Changeset truncated at 500 lines:

diff --git a/docs-xml/manpages/samba-tool.8.xml b/docs-xml/manpages/samba-tool.8.xml
index 10ffa8a4d5f..60f3a5f06ed 100644
--- a/docs-xml/manpages/samba-tool.8.xml
+++ b/docs-xml/manpages/samba-tool.8.xml
@@ -764,6 +764,16 @@
 	<para>Administer DS ACLs</para>
 </refsect2>
 
+<refsect3>
+	<title>dsacl delete</title>
+	<para>Delete an access list entry on a directory object.</para>
+</refsect3>
+
+<refsect3>
+	<title>dsacl get</title>
+	<para>Print access list on a directory object.</para>
+</refsect3>
+
 <refsect3>
 	<title>dsacl set</title>
 	<para>Modify access list on a directory object.</para>
diff --git a/libcli/security/sddl.c b/libcli/security/sddl.c
index 5bb65ddfd6b..e6c3c94f215 100644
--- a/libcli/security/sddl.c
+++ b/libcli/security/sddl.c
@@ -583,8 +583,8 @@ static char *sddl_encode_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
 /*
   encode an ACE in SDDL format
 */
-static char *sddl_encode_ace(TALLOC_CTX *mem_ctx, const struct security_ace *ace,
-			     const struct dom_sid *domain_sid)
+char *sddl_encode_ace(TALLOC_CTX *mem_ctx, const struct security_ace *ace,
+		      const struct dom_sid *domain_sid)
 {
 	char *sddl = NULL;
 	TALLOC_CTX *tmp_ctx;
diff --git a/libcli/security/sddl.h b/libcli/security/sddl.h
index e8bc25a619c..6720ec6453e 100644
--- a/libcli/security/sddl.h
+++ b/libcli/security/sddl.h
@@ -27,6 +27,7 @@ struct security_descriptor *sddl_decode(TALLOC_CTX *mem_ctx, const char *sddl,
 					const struct dom_sid *domain_sid);
 char *sddl_encode(TALLOC_CTX *mem_ctx, const struct security_descriptor *sd,
 		  const struct dom_sid *domain_sid);
-
+char *sddl_encode_ace(TALLOC_CTX *mem_ctx, const struct security_ace *ace,
+		      const struct dom_sid *domain_sid);
 
 #endif /* __SDDL_H__ */
diff --git a/libcli/security/security_descriptor.c b/libcli/security/security_descriptor.c
index ba142016389..23d436dbaeb 100644
--- a/libcli/security/security_descriptor.c
+++ b/libcli/security/security_descriptor.c
@@ -21,6 +21,7 @@
 
 #include "includes.h"
 #include "libcli/security/security.h"
+#include "librpc/ndr/libndr.h"
 
 /*
   return a blank security descriptor (no owners, dacl or sacl)
@@ -419,6 +420,98 @@ NTSTATUS security_descriptor_sacl_del(struct security_descriptor *sd,
 	return security_descriptor_acl_del(sd, true, trustee);
 }
 
+/*
+  delete the given ACE in the SACL or DACL of a security_descriptor
+*/
+static NTSTATUS security_descriptor_acl_del_ace(struct security_descriptor *sd,
+						bool sacl_del,
+						const struct security_ace *ace)
+{
+	uint32_t i;
+	bool found = false;
+	struct security_acl *acl = NULL;
+
+	if (sacl_del) {
+		acl = sd->sacl;
+	} else {
+		acl = sd->dacl;
+	}
+
+	if (acl == NULL) {
+		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+	}
+
+	for (i=0;i<acl->num_aces;i++) {
+		if (security_ace_equal(ace, &acl->aces[i])) {
+			ARRAY_DEL_ELEMENT(acl->aces, i, acl->num_aces);
+			acl->num_aces--;
+			if (acl->num_aces == 0) {
+				acl->aces = NULL;
+			}
+			found = true;
+			i--;
+		}
+	}
+
+	if (!found) {
+		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+	}
+
+	acl->revision = SECURITY_ACL_REVISION_NT4;
+
+	for (i=0;i<acl->num_aces;i++) {
+		switch (acl->aces[i].type) {
+		case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT:
+		case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
+		case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT:
+		case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT:
+			acl->revision = SECURITY_ACL_REVISION_ADS;
+			return NT_STATUS_OK;
+		default:
+			break; /* only for the switch statement */
+		}
+	}
+
+	return NT_STATUS_OK;
+}
+
+NTSTATUS security_descriptor_dacl_del_ace(struct security_descriptor *sd,
+					  const struct security_ace *ace)
+{
+	return security_descriptor_acl_del_ace(sd, false, ace);
+}
+
+NTSTATUS security_descriptor_sacl_del_ace(struct security_descriptor *sd,
+					  const struct security_ace *ace)
+{
+	return security_descriptor_acl_del_ace(sd, true, ace);
+}
+
+static bool security_ace_object_equal(const struct security_ace_object *object1,
+				      const struct security_ace_object *object2)
+{
+	if (object1 == object2) {
+		return true;
+	}
+	if ((object1 == NULL) || (object2 == NULL)) {
+		return false;
+	}
+	if (object1->flags != object2->flags) {
+		return false;
+	}
+	if (object1->flags & SEC_ACE_OBJECT_TYPE_PRESENT
+			&& !GUID_equal(&object1->type.type, &object2->type.type)) {
+		return false;
+	}
+	if (object1->flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT
+	    && !GUID_equal(&object1->inherited_type.inherited_type,
+			   &object2->inherited_type.inherited_type)) {
+		return false;
+	}
+
+	return true;
+}
+
 /*
   compare two security ace structures
 */
@@ -440,6 +533,14 @@ bool security_ace_equal(const struct security_ace *ace1,
 	if (ace1->access_mask != ace2->access_mask) {
 		return false;
 	}
+	if ((ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT
+	     || ace1->type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT
+	     || ace1->type == SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT
+	     || ace1->type == SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT)
+	    && !security_ace_object_equal(&ace1->object.object,
+					  &ace2->object.object)) {
+		return false;
+	}
 	if (!dom_sid_equal(&ace1->trustee, &ace2->trustee)) {
 		return false;
 	}
diff --git a/libcli/security/security_descriptor.h b/libcli/security/security_descriptor.h
index 7e6df87fefa..46545321d15 100644
--- a/libcli/security/security_descriptor.h
+++ b/libcli/security/security_descriptor.h
@@ -39,6 +39,10 @@ NTSTATUS security_descriptor_dacl_del(struct security_descriptor *sd,
 				      const struct dom_sid *trustee);
 NTSTATUS security_descriptor_sacl_del(struct security_descriptor *sd,
 				      const struct dom_sid *trustee);
+NTSTATUS security_descriptor_dacl_del_ace(struct security_descriptor *sd,
+					  const struct security_ace *ace);
+NTSTATUS security_descriptor_sacl_del_ace(struct security_descriptor *sd,
+					  const struct security_ace *ace);
 bool security_ace_equal(const struct security_ace *ace1, 
 			const struct security_ace *ace2);
 bool security_acl_equal(const struct security_acl *acl1, 
diff --git a/python/samba/netcmd/dsacl.py b/python/samba/netcmd/dsacl.py
index d3b8b5f554e..02be8fd982b 100644
--- a/python/samba/netcmd/dsacl.py
+++ b/python/samba/netcmd/dsacl.py
@@ -42,12 +42,42 @@ from samba.netcmd import (
     Option,
 )
 
+def find_trustee_sid(samdb, trusteedn):
+    res = samdb.search(base=trusteedn, expression="(objectClass=*)",
+                       scope=SCOPE_BASE)
+    assert(len(res) == 1)
+    return ndr_unpack(security.dom_sid, res[0]["objectSid"][0])
+
+
+def modify_descriptor(samdb, object_dn, desc, controls=None):
+    assert(isinstance(desc, security.descriptor))
+    m = ldb.Message()
+    m.dn = ldb.Dn(samdb, object_dn)
+    m["nTSecurityDescriptor"] = ldb.MessageElement(
+            (ndr_pack(desc)), ldb.FLAG_MOD_REPLACE,
+            "nTSecurityDescriptor")
+    samdb.modify(m)
+
+
+def read_descriptor(samdb, object_dn):
+    res = samdb.search(base=object_dn, scope=SCOPE_BASE,
+                       attrs=["nTSecurityDescriptor"])
+    # we should theoretically always have an SD
+    assert(len(res) == 1)
+    desc = res[0]["nTSecurityDescriptor"][0]
+    return ndr_unpack(security.descriptor, desc)
+
+
+def get_domain_sid(samdb):
+    res = samdb.search(base=samdb.domain_dn(),
+                       expression="(objectClass=*)", scope=SCOPE_BASE)
+    return ndr_unpack(security.dom_sid, res[0]["objectSid"][0])
 
-class cmd_dsacl_set(Command):
-    """Modify access list on a directory object."""
+
+class cmd_dsacl_base(Command):
+    """Base class for DSACL commands."""
 
     synopsis = "%prog [options]"
-    car_help = """ The access control right to allow or deny """
 
     takes_optiongroups = {
         "sambaopts": options.SambaOptions,
@@ -55,6 +85,18 @@ class cmd_dsacl_set(Command):
         "versionopts": options.VersionOptions,
     }
 
+    def print_acl(self, samdb, object_dn, prefix=''):
+        desc = read_descriptor(samdb, object_dn)
+        desc_sddl = desc.as_sddl(get_domain_sid(samdb))
+        self.outf.write("%sdescriptor for %s:\n" % (prefix, object_dn))
+        self.outf.write(desc_sddl + "\n")
+
+
+class cmd_dsacl_set(cmd_dsacl_base):
+    """Modify access list on a directory object."""
+
+    car_help = """ The access control right to allow or deny """
+
     takes_options = [
         Option("-H", "--URL", help="LDB URL for database or target server",
                type=str, metavar="URL", dest="H"),
@@ -82,41 +124,13 @@ class cmd_dsacl_set(Command):
                type="string"),
     ]
 
-    def find_trustee_sid(self, samdb, trusteedn):
-        res = samdb.search(base=trusteedn, expression="(objectClass=*)",
-                           scope=SCOPE_BASE)
-        assert(len(res) == 1)
-        return ndr_unpack(security.dom_sid, res[0]["objectSid"][0])
-
-    def modify_descriptor(self, samdb, object_dn, desc, controls=None):
-        assert(isinstance(desc, security.descriptor))
-        m = ldb.Message()
-        m.dn = ldb.Dn(samdb, object_dn)
-        m["nTSecurityDescriptor"] = ldb.MessageElement(
-                (ndr_pack(desc)), ldb.FLAG_MOD_REPLACE,
-                "nTSecurityDescriptor")
-        samdb.modify(m)
-
-    def read_descriptor(self, samdb, object_dn):
-        res = samdb.search(base=object_dn, scope=SCOPE_BASE,
-                           attrs=["nTSecurityDescriptor"])
-        # we should theoretically always have an SD
-        assert(len(res) == 1)
-        desc = res[0]["nTSecurityDescriptor"][0]
-        return ndr_unpack(security.descriptor, desc)
-
-    def get_domain_sid(self, samdb):
-        res = samdb.search(base=samdb.domain_dn(),
-                           expression="(objectClass=*)", scope=SCOPE_BASE)
-        return ndr_unpack(security.dom_sid, res[0]["objectSid"][0])
-
     def add_ace(self, samdb, object_dn, new_ace):
         """Add new ace explicitly."""
-        desc = self.read_descriptor(samdb, object_dn)
-        new_ace = security.descriptor.from_sddl("D:" + new_ace,self.get_domain_sid(samdb))
+        desc = read_descriptor(samdb, object_dn)
+        new_ace = security.descriptor.from_sddl("D:" + new_ace, get_domain_sid(samdb))
         new_ace_list = re.findall(r"\(.*?\)",new_ace.as_sddl())
         for new_ace in new_ace_list:
-            desc_sddl = desc.as_sddl(self.get_domain_sid(samdb))
+            desc_sddl = desc.as_sddl(get_domain_sid(samdb))
             # TODO add bindings for descriptor manipulation and get rid of this
             desc_aces = re.findall(r"\(.*?\)", desc_sddl)
             for ace in desc_aces:
@@ -128,17 +142,8 @@ class cmd_dsacl_set(Command):
                 desc_sddl = desc_sddl[:desc_sddl.index("(")] + new_ace + desc_sddl[desc_sddl.index("("):]
             else:
                 desc_sddl = desc_sddl + new_ace
-            desc = security.descriptor.from_sddl(desc_sddl, self.get_domain_sid(samdb))
-            self.modify_descriptor(samdb, object_dn, desc)
-
-    def print_acl(self, samdb, object_dn, new=False):
-        desc = self.read_descriptor(samdb, object_dn)
-        desc_sddl = desc.as_sddl(self.get_domain_sid(samdb))
-        if new:
-            self.outf.write("new descriptor for %s:\n" % object_dn)
-        else:
-            self.outf.write("old descriptor for %s:\n" % object_dn)
-        self.outf.write(desc_sddl + "\n")
+            desc = security.descriptor.from_sddl(desc_sddl, get_domain_sid(samdb))
+            modify_descriptor(samdb, object_dn, desc)
 
     def run(self, car, action, objectdn, trusteedn, sddl,
             H=None, credopts=None, sambaopts=None, versionopts=None):
@@ -165,7 +170,7 @@ class cmd_dsacl_set(Command):
                 'repl-sync': GUID_DRS_REPL_SYNCRONIZE,
                 'ro-repl-secret-sync': GUID_DRS_RO_REPL_SECRET_SYNC,
                 }
-        sid = self.find_trustee_sid(samdb, trusteedn)
+        sid = find_trustee_sid(samdb, trusteedn)
         if sddl:
             new_ace = sddl
         elif action == "allow":
@@ -175,22 +180,14 @@ class cmd_dsacl_set(Command):
         else:
             raise CommandError("Wrong argument '%s'!" % action)
 
-        self.print_acl(samdb, objectdn)
+        self.print_acl(samdb, objectdn, prefix='old ')
         self.add_ace(samdb, objectdn, new_ace)
-        self.print_acl(samdb, objectdn, new=True)
+        self.print_acl(samdb, objectdn, prefix='new ')
 
 
-class cmd_dsacl_get(Command):
+class cmd_dsacl_get(cmd_dsacl_base):
     """Print access list on a directory object."""
 
-    synopsis = "%prog [options]"
-
-    takes_optiongroups = {
-        "sambaopts": options.SambaOptions,
-        "credopts": options.CredentialsOptions,
-        "versionopts": options.VersionOptions,
-        }
-
     takes_options = [
         Option("-H", "--URL", help="LDB URL for database or target server",
                type=str, metavar="URL", dest="H"),
@@ -198,25 +195,6 @@ class cmd_dsacl_get(Command):
             type="string"),
         ]
 
-    def read_descriptor(self, samdb, object_dn):
-        res = samdb.search(base=object_dn, scope=SCOPE_BASE,
-                attrs=["nTSecurityDescriptor"])
-        # we should theoretically always have an SD
-        assert(len(res) == 1)
-        desc = res[0]["nTSecurityDescriptor"][0]
-        return ndr_unpack(security.descriptor, desc)
-
-    def get_domain_sid(self, samdb):
-        res = samdb.search(base=samdb.domain_dn(),
-                expression="(objectClass=*)", scope=SCOPE_BASE)
-        return ndr_unpack( security.dom_sid,res[0]["objectSid"][0])
-
-    def print_acl(self, samdb, object_dn):
-        desc = self.read_descriptor(samdb, object_dn)
-        desc_sddl = desc.as_sddl(self.get_domain_sid(samdb))
-        self.outf.write("descriptor for %s:\n" % object_dn)
-        self.outf.write(desc_sddl + "\n")
-
     def run(self, objectdn,
             H=None, credopts=None, sambaopts=None, versionopts=None):
         lp = sambaopts.get_loadparm()
@@ -227,9 +205,50 @@ class cmd_dsacl_get(Command):
         self.print_acl(samdb, objectdn)
 
 
+class cmd_dsacl_delete(cmd_dsacl_base):
+    """Delete an access list entry on a directory object."""
+
+    takes_options = [
+        Option("-H", "--URL", help="LDB URL for database or target server",
+               type=str, metavar="URL", dest="H"),
+        Option("--objectdn", help="DN of the object whose SD to modify",
+            type="string"),
+        Option("--sddl", help="An ACE or group of ACEs to be deleted from the object",
+               type="string"),
+        ]
+
+    def run(self, objectdn, sddl, H=None, credopts=None, sambaopts=None, versionopts=None):
+        lp = sambaopts.get_loadparm()
+        creds = credopts.get_credentials(lp)
+
+        if sddl is None or objectdn is None:
+            return self.usage()
+
+        samdb = SamDB(url=H, session_info=system_session(),
+                      credentials=creds, lp=lp)
+
+        self.print_acl(samdb, objectdn, prefix='old ')
+        self.delete_ace(samdb, objectdn, sddl)
+        self.print_acl(samdb, objectdn, prefix='new ')
+
+    def delete_ace(self, samdb, object_dn, delete_aces):
+        """Delete ace explicitly."""
+        desc = read_descriptor(samdb, object_dn)
+        domsid = get_domain_sid(samdb)
+        delete_aces = security.descriptor.from_sddl("D:" + delete_aces, domsid).dacl.aces
+        for ace in delete_aces:
+            if ace in desc.dacl.aces:
+                desc.dacl_del_ace(ace)
+            else:
+                sddl = ace.as_sddl(domsid)
+                self.outf.write("WARNING: (%s) was not found in the current security descriptor.\n" % sddl)
+        modify_descriptor(samdb, object_dn, desc)
+
+
 class cmd_dsacl(SuperCommand):
     """DS ACLs manipulation."""
 
     subcommands = {}
     subcommands["set"] = cmd_dsacl_set()
     subcommands["get"] = cmd_dsacl_get()
+    subcommands["delete"] = cmd_dsacl_delete()
diff --git a/python/samba/tests/samba_tool/dsacl.py b/python/samba/tests/samba_tool/dsacl.py
index 66c662f7a3b..54aef5bd39a 100644
--- a/python/samba/tests/samba_tool/dsacl.py
+++ b/python/samba/tests/samba_tool/dsacl.py
@@ -122,3 +122,91 @@ class DSaclSetSddlTestCase(SambaToolCmdTest):
         self.assertEqual(err, "", "Shouldn't be any error messages")
         acl_list = re.findall('.*descriptor for.*:\n(.*?)\n',out)
         return acl_list
+
+    def test_add_delete_sddl(self):
+        """Tests if a sddl string can be added 'the normal way', deleted and
+        final state is the same as initial.
+        """
+        (result, out, err) = self.runsubcmd("dsacl", "get",
+                                            "--objectdn=%s" % self.dn)
+        self.assertCmdSuccess(result, out, err)
+        self.assertEqual(err, "", "Shouldn't be any error messages")
+        # extract only the two sddl strings from samba-tool output
+        acl_list_orig = re.findall('^descriptor for.*:\n(.*?)\n', out)[0]
+
+        (result, out, err) = self.runsubcmd("dsacl", "set",
+                                            "--objectdn=%s" % self.dn,
+                                            "--sddl=%s" % self.sddl)
+        self.assertCmdSuccess(result, out, err)
+        self.assertEqual(err, "", "Shouldn't be any error messages")
+        acl_list_added = re.findall('new descriptor for.*:\n(.*?)\n', out)[0]
+        self.assertNotEqual(acl_list_added, acl_list_orig, "After adding the SD should be different.")
+        self.assertMatch(acl_list_added, self.sddl, "The added ACE should be part of the new SD.")
+
+        (result, out, err) = self.runsubcmd("dsacl", "delete",
+                                            "--objectdn=%s" % self.dn,
+                                            "--sddl=%s" % self.sddl)
+        self.assertCmdSuccess(result, out, err)
+        self.assertEqual(err, "", "Shouldn't be any error messages")
+        acl_list_final = re.findall('new descriptor for.*:\n(.*?)\n', out)[0]
+        self.assertEqual(acl_list_orig, acl_list_final,
+                         "output of dsacl delete should be the same as before adding")
+
+        (result, out, err) = self.runsubcmd("dsacl", "get",
+                                            "--objectdn=%s" % self.dn)
+        self.assertCmdSuccess(result, out, err)
+        self.assertEqual(err, "", "Shouldn't be any error messages")
+        # extract only the two sddl strings from samba-tool output
+        acl_list_final_get = re.findall('^descriptor for.*:\n(.*?)\n', out)[0]
+        self.assertEqual(acl_list_orig, acl_list_final_get,
+                         "output of dsacl get should be the same as after adding and deleting again")
+
+    def test_delete(self):
+        # add sddl_multi first
+        (result, out, err) = self.runsubcmd("dsacl", "set",
+                                            "--objectdn=%s" % self.dn,
+                                            "--sddl=%s" % self.sddl_multi)
+
+        self.assertCmdSuccess(result, out, err)
+        self.assertEqual(err, "", "Shouldn't be any error messages")
+        # delete sddl
+        (result, out, err) = self.runsubcmd("dsacl", "delete",
+                                            "--objectdn=%s" % self.dn,
+                                            "--sddl=%s" % self.sddl)
+        self.assertCmdSuccess(result, out, err)
+        self.assertEqual(err, "", "Shouldn't be any error messages")
+        acl_list_deleted = re.findall('new descriptor for.*:\n(.*?)\n', out)[0]
+
+        self.assertNotRegex(acl_list_deleted, re.escape(self.sddl))


-- 
Samba Shared Repository



More information about the samba-cvs mailing list