From 8c0be1d17a5f4e700fe38b5f58d1caa359e8c383 Mon Sep 17 00:00:00 2001
From: Christian Merten <christian@merten.dev>
Date: Mon, 19 Sep 2022 22:47:10 +0200
Subject: [PATCH 06/30] CVE-2023-4154 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.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15424

Signed-off-by: Christian Merten <christian@merten.dev>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Reviewed-by: Jeremy Allison <jra@samba.org>
(cherry picked from commit 7efe673fbdcd27ddd23f36281c5f5338681a68fe)

Conflict: NA
Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch
[PATCH 06/30] CVE-2023-4154 libcli security_descriptor: Add function
 to delete a given ace from a security descriptor
---
 libcli/security/security_descriptor.c | 66 +++++++++++++++++++++++++++
 libcli/security/security_descriptor.h |  4 ++
 2 files changed, 70 insertions(+)

diff --git a/libcli/security/security_descriptor.c b/libcli/security/security_descriptor.c
index ba142016389..64c2d027876 100644
--- a/libcli/security/security_descriptor.c
+++ b/libcli/security/security_descriptor.c
@@ -419,6 +419,72 @@ 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);
+}
 /*
   compare two security ace structures
 */
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, 
-- 
2.34.1
