[SCM] Samba Shared Repository - branch master updated

Stefan Metzmacher metze at samba.org
Wed Mar 22 15:58:02 UTC 2023


The branch, master has been updated
       via  6241380bc52 samba-tool: rewrite dsacl.py to use the new sd_utils helpers
       via  a1109a9bf12 python:sd_utils: add dacl_{prepend,append,delete}_aces() helpers
       via  8411e6d302e python:sd_utils: introduce update_aces_in_dacl() helper
       via  4627997ddae python/samba/ndr: add ndr_deepcopy() helper
       via  9ea06aaf9f5 py_security: allow idx argument to descriptor.[s|d]acl_add()
       via  2c02378029f libcli/security: add security_descriptor_[s|d]acl_insert() helpers
       via  c3cb915a67a libcli/security: prepare security_descriptor_acl_add() to place the ace at a position
       via  9d8ff0d1e0b replace: add ARRAY_INSERT_ELEMENT() helper
       via  9053862b892 lib/ldb-samba: let ldif_read_ntSecurityDescriptor() only try sddl if isupper()
      from  be1aae77b76 libcli/security: Reorder SDDL access flags table to match Windows

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


- Log -----------------------------------------------------------------
commit 6241380bc52e41744d134e31d77ab900e604e0d1
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Mar 16 18:32:49 2023 +0100

    samba-tool: rewrite dsacl.py to use the new sd_utils helpers
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    
    Autobuild-User(master): Stefan Metzmacher <metze at samba.org>
    Autobuild-Date(master): Wed Mar 22 15:57:15 UTC 2023 on atb-devel-224

commit a1109a9bf12e020636b8d66fc54984aac58bfe6b
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Mar 16 18:03:10 2023 +0100

    python:sd_utils: add dacl_{prepend,append,delete}_aces() helpers
    
    They better represent what they are doing, we keep dacl_add_ace()
    as wrapper of dacl_prepend_aces() in order to let existing callers
    work as before.
    
    In future it would be good to have a dacl_insert_aces() that
    would canonicalize the ace order before storing, but that a task
    for another day.
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 8411e6d302e25d10f1035ebbdcbde7308566e930
Author: Stefan Metzmacher <metze at samba.org>
Date:   Fri Mar 10 18:25:18 2023 +0100

    python:sd_utils: introduce update_aces_in_dacl() helper
    
    This is a more generic api that can be re-used in other places
    as well in future. It operates on a security descriptor object instead of
    SDDL.
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 4627997ddae44265ad35b3234232eb74458c6c34
Author: Stefan Metzmacher <metze at samba.org>
Date:   Fri Mar 17 14:08:34 2023 +0100

    python/samba/ndr: add ndr_deepcopy() helper
    
    This uses ndr_pack/unpack in order to create a deep copy
    of the given object.
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 9ea06aaf9f57e3c7094553d9ac40fb73057a9b74
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Mar 16 10:11:05 2023 +0100

    py_security: allow idx argument to descriptor.[s|d]acl_add()
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 2c02378029fff6636b8f19e45af78b265f2210ed
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Mar 16 10:03:44 2023 +0100

    libcli/security: add security_descriptor_[s|d]acl_insert() helpers
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit c3cb915a67aff6739b72b86d7d139609df309ada
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Mar 16 10:00:11 2023 +0100

    libcli/security: prepare security_descriptor_acl_add() to place the ace at a position
    
    Often it is important to insert an ace at a specific position in the
    ACL. As a default we still append by default by using -1, which is the
    generic version of passing the number of existing aces.
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 9d8ff0d1e0b2ba7c84af36e1931f5bc99902a44b
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Mar 16 09:57:43 2023 +0100

    replace: add ARRAY_INSERT_ELEMENT() helper
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 9053862b89258850c22735cc4123fe5bc0d2e6fa
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon May 17 17:14:34 2021 +0200

    lib/ldb-samba: let ldif_read_ntSecurityDescriptor() only try sddl if isupper()
    
    Trying ndr_pull_security_descriptor on SDDL produces just strange
    debug messages, which can cause confusion.
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

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

Summary of changes:
 lib/ldb-samba/ldif_handlers.c         |  24 ++++--
 lib/replace/replace.h                 |  15 ++++
 libcli/security/security_descriptor.c |  55 ++++++++++--
 libcli/security/security_descriptor.h |   6 ++
 python/samba/ndr.py                   |  19 +++++
 python/samba/netcmd/dsacl.py          | 109 ++++++++----------------
 python/samba/sd_utils.py              | 153 +++++++++++++++++++++++++++++++---
 source4/librpc/ndr/py_security.c      |  10 ++-
 8 files changed, 288 insertions(+), 103 deletions(-)


Changeset truncated at 500 lines:

diff --git a/lib/ldb-samba/ldif_handlers.c b/lib/ldb-samba/ldif_handlers.c
index b8f04747456..f77a268c1a8 100644
--- a/lib/ldb-samba/ldif_handlers.c
+++ b/lib/ldb-samba/ldif_handlers.c
@@ -369,6 +369,21 @@ static int ldif_read_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx
 	struct security_descriptor *sd;
 	enum ndr_err_code ndr_err;
 
+	if (in->length >= 2 && isupper(in->data[0]) && in->data[1] == ':') {
+		/*
+		 * If it starts with an upper case character followed by ':',
+		 * we know it's not NDR, but most likely SDDL...
+		 */
+		const struct dom_sid *sid = samdb_domain_sid(ldb);
+
+		sd = sddl_decode(mem_ctx, (const char *)in->data, sid);
+		if (sd == NULL) {
+			return -1;
+		}
+
+		goto decoded;
+	}
+
 	sd = talloc(mem_ctx, struct security_descriptor);
 	if (sd == NULL) {
 		return -1;
@@ -377,16 +392,11 @@ static int ldif_read_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx
 	ndr_err = ndr_pull_struct_blob(in, sd, sd,
 				       (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-		/* If this does not parse, then it is probably SDDL, and we should try it that way */
-
-		const struct dom_sid *sid = samdb_domain_sid(ldb);
 		talloc_free(sd);
-		sd = sddl_decode(mem_ctx, (const char *)in->data, sid);
-		if (sd == NULL) {
-			return -1;
-		}
+		return -1;
 	}
 
+decoded:
 	ndr_err = ndr_push_struct_blob(out, mem_ctx, sd,
 				       (ndr_push_flags_fn_t)ndr_push_security_descriptor);
 	talloc_free(sd);
diff --git a/lib/replace/replace.h b/lib/replace/replace.h
index b15f3d14c8a..25e6e145eeb 100644
--- a/lib/replace/replace.h
+++ b/lib/replace/replace.h
@@ -885,6 +885,21 @@ typedef unsigned long long ptrdiff_t ;
 #define ARRAY_DEL_ELEMENT(a,i,n) \
 if((i)<((n)-1)){memmove(&((a)[(i)]),&((a)[(i)+1]),(sizeof(*(a))*((n)-(i)-1)));}
 
+/**
+ * Insert an array element by moving the rest one up
+ *
+ */
+#define ARRAY_INSERT_ELEMENT(__array,__old_last_idx,__new_elem,__new_idx) do { \
+	if ((__new_idx) < (__old_last_idx)) { \
+		const void *__src = &((__array)[(__new_idx)]); \
+		void *__dst = &((__array)[(__new_idx)+1]); \
+		size_t __num = (__old_last_idx)-(__new_idx); \
+		size_t __len = sizeof(*(__array)) * __num; \
+		memmove(__dst, __src, __len); \
+	} \
+	(__array)[(__new_idx)] = (__new_elem); \
+} while(0)
+
 /**
  * Pointer difference macro
  */
diff --git a/libcli/security/security_descriptor.c b/libcli/security/security_descriptor.c
index ff3aa07606c..d6a7eda611b 100644
--- a/libcli/security/security_descriptor.c
+++ b/libcli/security/security_descriptor.c
@@ -268,9 +268,11 @@ NTSTATUS security_descriptor_for_client(TALLOC_CTX *mem_ctx,
 
 static NTSTATUS security_descriptor_acl_add(struct security_descriptor *sd,
 					    bool add_to_sacl,
-					    const struct security_ace *ace)
+					    const struct security_ace *ace,
+					    ssize_t _idx)
 {
 	struct security_acl *acl = NULL;
+	ssize_t idx;
 
 	if (add_to_sacl) {
 		acl = sd->sacl;
@@ -289,15 +291,28 @@ static NTSTATUS security_descriptor_acl_add(struct security_descriptor *sd,
 		acl->aces     = NULL;
 	}
 
+	if (_idx < 0) {
+		idx = (acl->num_aces + 1) + _idx;
+	} else {
+		idx = _idx;
+	}
+
+	if (idx < 0) {
+		return NT_STATUS_ARRAY_BOUNDS_EXCEEDED;
+	} else if (idx > acl->num_aces) {
+		return NT_STATUS_ARRAY_BOUNDS_EXCEEDED;
+	}
+
 	acl->aces = talloc_realloc(acl, acl->aces,
 				   struct security_ace, acl->num_aces+1);
 	if (acl->aces == NULL) {
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	acl->aces[acl->num_aces] = *ace;
+	ARRAY_INSERT_ELEMENT(acl->aces, acl->num_aces, *ace, idx);
+	acl->num_aces++;
 
-	switch (acl->aces[acl->num_aces].type) {
+	switch (acl->aces[idx].type) {
 	case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT:
 	case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
 	case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT:
@@ -308,8 +323,6 @@ static NTSTATUS security_descriptor_acl_add(struct security_descriptor *sd,
 		break;
 	}
 
-	acl->num_aces++;
-
 	if (add_to_sacl) {
 		sd->sacl = acl;
 		sd->type |= SEC_DESC_SACL_PRESENT;
@@ -328,7 +341,21 @@ static NTSTATUS security_descriptor_acl_add(struct security_descriptor *sd,
 NTSTATUS security_descriptor_sacl_add(struct security_descriptor *sd,
 				      const struct security_ace *ace)
 {
-	return security_descriptor_acl_add(sd, true, ace);
+	return security_descriptor_acl_add(sd, true, ace, -1);
+}
+
+/*
+  insert an ACE at a given index to the SACL of a security_descriptor
+
+  idx can be negative, which means it's related to the new size from the
+  end, so -1 means the ace is appended at the end.
+*/
+
+NTSTATUS security_descriptor_sacl_insert(struct security_descriptor *sd,
+					 const struct security_ace *ace,
+					 ssize_t idx)
+{
+	return security_descriptor_acl_add(sd, true, ace, idx);
 }
 
 /*
@@ -338,7 +365,21 @@ NTSTATUS security_descriptor_sacl_add(struct security_descriptor *sd,
 NTSTATUS security_descriptor_dacl_add(struct security_descriptor *sd,
 				      const struct security_ace *ace)
 {
-	return security_descriptor_acl_add(sd, false, ace);
+	return security_descriptor_acl_add(sd, false, ace, -1);
+}
+
+/*
+  insert an ACE at a given index to the DACL of a security_descriptor
+
+  idx can be negative, which means it's related to the new size from the
+  end, so -1 means the ace is appended at the end.
+*/
+
+NTSTATUS security_descriptor_dacl_insert(struct security_descriptor *sd,
+					 const struct security_ace *ace,
+					 ssize_t idx)
+{
+	return security_descriptor_acl_add(sd, false, ace, idx);
 }
 
 /*
diff --git a/libcli/security/security_descriptor.h b/libcli/security/security_descriptor.h
index 46545321d15..354bc17e925 100644
--- a/libcli/security/security_descriptor.h
+++ b/libcli/security/security_descriptor.h
@@ -33,8 +33,14 @@ NTSTATUS security_descriptor_for_client(TALLOC_CTX *mem_ctx,
 					struct security_descriptor **_csd);
 NTSTATUS security_descriptor_sacl_add(struct security_descriptor *sd,
 				      const struct security_ace *ace);
+NTSTATUS security_descriptor_sacl_insert(struct security_descriptor *sd,
+					 const struct security_ace *ace,
+					 ssize_t idx);
 NTSTATUS security_descriptor_dacl_add(struct security_descriptor *sd,
 				      const struct security_ace *ace);
+NTSTATUS security_descriptor_dacl_insert(struct security_descriptor *sd,
+					 const struct security_ace *ace,
+					 ssize_t idx);
 NTSTATUS security_descriptor_dacl_del(struct security_descriptor *sd,
 				      const struct dom_sid *trustee);
 NTSTATUS security_descriptor_sacl_del(struct security_descriptor *sd,
diff --git a/python/samba/ndr.py b/python/samba/ndr.py
index 314e57b7f8e..4207ee2a318 100644
--- a/python/samba/ndr.py
+++ b/python/samba/ndr.py
@@ -56,6 +56,25 @@ def ndr_print(object):
     return ndr_print()
 
 
+def ndr_deepcopy(object):
+    """Create a deep copy of a NDR object, using pack/unpack
+
+    :param object: Object to copy
+    :return: The object copy
+    """
+    ndr_pack = getattr(object, "__ndr_pack__", None)
+    if ndr_pack is None:
+        raise TypeError("%r is not a NDR object" % object)
+    data = ndr_pack()
+    cls = type(object)
+    copy = cls()
+    ndr_unpack = getattr(copy, "__ndr_unpack__", None)
+    if ndr_unpack is None:
+        raise TypeError("%r is not a NDR object" % copy)
+    ndr_unpack(data, allow_remaining=False)
+    return copy
+
+
 def ndr_pack_in(object, bigendian=False, ndr64=False):
     """Pack the input of an NDR function object.
 
diff --git a/python/samba/netcmd/dsacl.py b/python/samba/netcmd/dsacl.py
index 02be8fd982b..527c53482b6 100644
--- a/python/samba/netcmd/dsacl.py
+++ b/python/samba/netcmd/dsacl.py
@@ -17,6 +17,7 @@
 #
 
 import samba.getopt as options
+from samba import sd_utils
 from samba.dcerpc import security
 from samba.samdb import SamDB
 from samba.ndr import ndr_unpack, ndr_pack
@@ -42,38 +43,6 @@ 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_base(Command):
     """Base class for DSACL commands."""
 
@@ -85,9 +54,8 @@ class cmd_dsacl_base(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))
+    def print_acl(self, sd_helper, object_dn, prefix=''):
+        desc_sddl = sd_helper.get_sd_as_sddl(object_dn)
         self.outf.write("%sdescriptor for %s:\n" % (prefix, object_dn))
         self.outf.write(desc_sddl + "\n")
 
@@ -124,26 +92,21 @@ class cmd_dsacl_set(cmd_dsacl_base):
                type="string"),
     ]
 
-    def add_ace(self, samdb, object_dn, new_ace):
+    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 add_ace(self, sd_helper, object_dn, new_ace):
         """Add new ace explicitly."""
-        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(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:
-                if ("ID" in ace):
-                    desc_sddl = desc_sddl.replace(ace, "")
-            if new_ace in desc_sddl:
-                continue
-            if desc_sddl.find("(") >= 0:
-                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, get_domain_sid(samdb))
-            modify_descriptor(samdb, object_dn, desc)
+        ai,ii = sd_helper.dacl_prepend_aces(object_dn, new_ace)
+        for ace in ii:
+            sddl = ace.as_sddl(sd_helper.domain_sid)
+            self.outf.write("WARNING: ignored INHERITED_ACE (%s).\n" % sddl)
+        for ace in ai:
+            sddl = ace.as_sddl(sd_helper.domain_sid)
+            self.outf.write("WARNING: (%s) was already found in the current security descriptor.\n" % sddl)
 
     def run(self, car, action, objectdn, trusteedn, sddl,
             H=None, credopts=None, sambaopts=None, versionopts=None):
@@ -156,6 +119,7 @@ class cmd_dsacl_set(cmd_dsacl_base):
 
         samdb = SamDB(url=H, session_info=system_session(),
                       credentials=creds, lp=lp)
+        sd_helper = sd_utils.SDUtils(samdb)
         cars = {'change-rid': GUID_DRS_CHANGE_RID_MASTER,
                 'change-pdc': GUID_DRS_CHANGE_PDC,
                 'change-infrastructure': GUID_DRS_CHANGE_INFR_MASTER,
@@ -170,7 +134,7 @@ class cmd_dsacl_set(cmd_dsacl_base):
                 'repl-sync': GUID_DRS_REPL_SYNCRONIZE,
                 'ro-repl-secret-sync': GUID_DRS_RO_REPL_SECRET_SYNC,
                 }
-        sid = find_trustee_sid(samdb, trusteedn)
+        sid = self.find_trustee_sid(samdb, trusteedn)
         if sddl:
             new_ace = sddl
         elif action == "allow":
@@ -180,9 +144,9 @@ class cmd_dsacl_set(cmd_dsacl_base):
         else:
             raise CommandError("Wrong argument '%s'!" % action)
 
-        self.print_acl(samdb, objectdn, prefix='old ')
-        self.add_ace(samdb, objectdn, new_ace)
-        self.print_acl(samdb, objectdn, prefix='new ')
+        self.print_acl(sd_helper, objectdn, prefix='old ')
+        self.add_ace(sd_helper, objectdn, new_ace)
+        self.print_acl(sd_helper, objectdn, prefix='new ')
 
 
 class cmd_dsacl_get(cmd_dsacl_base):
@@ -202,7 +166,8 @@ class cmd_dsacl_get(cmd_dsacl_base):
 
         samdb = SamDB(url=H, session_info=system_session(),
             credentials=creds, lp=lp)
-        self.print_acl(samdb, objectdn)
+        sd_helper = sd_utils.SDUtils(samdb)
+        self.print_acl(sd_helper, objectdn)
 
 
 class cmd_dsacl_delete(cmd_dsacl_base):
@@ -226,23 +191,21 @@ class cmd_dsacl_delete(cmd_dsacl_base):
 
         samdb = SamDB(url=H, session_info=system_session(),
                       credentials=creds, lp=lp)
+        sd_helper = sd_utils.SDUtils(samdb)
 
-        self.print_acl(samdb, objectdn, prefix='old ')
-        self.delete_ace(samdb, objectdn, sddl)
-        self.print_acl(samdb, objectdn, prefix='new ')
+        self.print_acl(sd_helper, objectdn, prefix='old ')
+        self.delete_ace(sd_helper, objectdn, sddl)
+        self.print_acl(sd_helper, objectdn, prefix='new ')
 
-    def delete_ace(self, samdb, object_dn, delete_aces):
+    def delete_ace(self, sd_helper, 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)
+        di,ii = sd_helper.dacl_delete_aces(object_dn, delete_aces)
+        for ace in ii:
+            sddl = ace.as_sddl(sd_helper.domain_sid)
+            self.outf.write("WARNING: ignored INHERITED_ACE (%s).\n" % sddl)
+        for ace in di:
+            sddl = ace.as_sddl(sd_helper.domain_sid)
+            self.outf.write("WARNING: (%s) was not found in the current security descriptor.\n" % sddl)
 
 
 class cmd_dsacl(SuperCommand):
diff --git a/python/samba/sd_utils.py b/python/samba/sd_utils.py
index c42bc602b4d..4e5f6e2aa53 100644
--- a/python/samba/sd_utils.py
+++ b/python/samba/sd_utils.py
@@ -21,8 +21,11 @@
 import samba
 from ldb import Message, MessageElement, Dn
 from ldb import FLAG_MOD_REPLACE, SCOPE_BASE
-from samba.ndr import ndr_pack, ndr_unpack
+from samba.ndr import ndr_pack, ndr_unpack, ndr_deepcopy
 from samba.dcerpc import security
+from samba.ntstatus import (
+    NT_STATUS_OBJECT_NAME_NOT_FOUND,
+)
 
 
 class SDUtils(object):
@@ -63,19 +66,145 @@ class SDUtils(object):
         res = self.ldb.search(object_dn)
         return ndr_unpack(security.dom_sid, res[0]["objectSid"][0])
 
+    def update_aces_in_dacl(self, dn, del_aces=None, add_aces=None,
+                            sddl_attr=None, controls=None):
+        if del_aces is None:
+            del_aces=[]
+        if add_aces is None:
+            add_aces=[]
+
+        def ace_from_sddl(ace_sddl):
+            ace_sd = security.descriptor.from_sddl("D:" + ace_sddl, self.domain_sid)
+            assert(len(ace_sd.dacl.aces)==1)
+            return ace_sd.dacl.aces[0]
+
+        if sddl_attr is None:
+            if controls is None:
+                controls=["sd_flags:1:%d" % security.SECINFO_DACL]
+            sd = self.read_sd_on_dn(dn, controls=controls)
+            if not sd.type & security.SEC_DESC_DACL_PROTECTED:
+                # if the DACL is not protected remove all
+                # inherited aces, as they will be re-inherited
+                # on the server, we need a ndr_deepcopy in order
+                # to avoid reference problems while deleting
+                # the aces while looping over them
+                dacl_copy = ndr_deepcopy(sd.dacl)
+                for ace in dacl_copy.aces:
+                    if ace.flags & security.SEC_ACE_FLAG_INHERITED_ACE:
+                        try:
+                            sd.dacl_del_ace(ace)
+                        except samba.NTSTATUSError as err:
+                            if err.args[0] != NT_STATUS_OBJECT_NAME_NOT_FOUND:
+                                raise err
+                            # dacl_del_ace may remove more than
+                            # one ace, so we may not find it anymore
+                            pass
+        else:
+            if controls is None:
+                controls=[]
+            res = self.ldb.search(dn, SCOPE_BASE, None,
+                                  [sddl_attr], controls=controls)
+            old_sddl = str(res[0][sddl_attr][0])
+            sd = security.descriptor.from_sddl(old_sddl, self.domain_sid)
+
+        num_changes = 0
+        del_ignored = []
+        add_ignored = []
+        inherited_ignored = []
+
+        for ace in del_aces:
+            if isinstance(ace, str):
+                ace = ace_from_sddl(ace)
+            assert(isinstance(ace, security.ace))
+
+            if ace.flags & security.SEC_ACE_FLAG_INHERITED_ACE:
+                inherited_ignored.append(ace)
+                continue
+
+            if ace not in sd.dacl.aces:
+                del_ignored.append(ace)
+                continue
+
+            sd.dacl_del_ace(ace)
+            num_changes += 1
+
+        for ace in add_aces:
+            add_idx = -1
+            if isinstance(ace, dict):
+                if "idx" in ace:
+                    add_idx = ace["idx"]
+                ace = ace["ace"]
+            if isinstance(ace, str):
+                ace = ace_from_sddl(ace)
+            assert(isinstance(ace, security.ace))
+
+            if ace.flags & security.SEC_ACE_FLAG_INHERITED_ACE:
+                inherited_ignored.append(ace)
+                continue
+


-- 
Samba Shared Repository



More information about the samba-cvs mailing list