241 lines
7.1 KiB
Diff
241 lines
7.1 KiB
Diff
From f9831259b9f6a49b9e1a7be75198d60374cdef2f Mon Sep 17 00:00:00 2001
|
|
From: Joseph Sutton <josephsutton@catalyst.net.nz>
|
|
Date: Tue, 7 Jun 2022 17:39:07 +1200
|
|
Subject: [PATCH 08/15] CVE-2022-32743 dsdb/modules/acl: Handle
|
|
FORCE_ALLOW_VALIDATED_DNS_HOSTNAME_SPN_WRITE control
|
|
|
|
When this control is specified, we'll assume we have Validated Write on
|
|
dNSHostName and servicePrincipalName, and Write Property on other
|
|
attributes.
|
|
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14833
|
|
|
|
Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
|
|
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
---
|
|
source4/dsdb/samdb/ldb_modules/acl.c | 148 +++++++++++++++++++++--------------
|
|
1 file changed, 91 insertions(+), 57 deletions(-)
|
|
|
|
diff --git a/source4/dsdb/samdb/ldb_modules/acl.c b/source4/dsdb/samdb/ldb_modules/acl.c
|
|
index 50802ae..a26d0ba 100644
|
|
--- a/source4/dsdb/samdb/ldb_modules/acl.c
|
|
+++ b/source4/dsdb/samdb/ldb_modules/acl.c
|
|
@@ -667,7 +667,8 @@ static int acl_check_spn(TALLOC_CTX *mem_ctx,
|
|
struct security_descriptor *sd,
|
|
struct dom_sid *sid,
|
|
const struct dsdb_attribute *attr,
|
|
- const struct dsdb_class *objectclass)
|
|
+ const struct dsdb_class *objectclass,
|
|
+ const struct ldb_control *implicit_validated_write_control)
|
|
{
|
|
int ret;
|
|
unsigned int i;
|
|
@@ -694,34 +695,44 @@ static int acl_check_spn(TALLOC_CTX *mem_ctx,
|
|
NULL
|
|
};
|
|
|
|
- /* if we have wp, we can do whatever we like */
|
|
- if (acl_check_access_on_attribute(module,
|
|
- tmp_ctx,
|
|
- sd,
|
|
- sid,
|
|
- SEC_ADS_WRITE_PROP,
|
|
- attr, objectclass) == LDB_SUCCESS) {
|
|
- talloc_free(tmp_ctx);
|
|
- return LDB_SUCCESS;
|
|
- }
|
|
+ if (implicit_validated_write_control != NULL) {
|
|
+ /*
|
|
+ * The validated write control dispenses with ACL
|
|
+ * checks. We act as if we have an implicit Self Write
|
|
+ * privilege, but, assuming we don't have Write
|
|
+ * Property, still proceed with further validation
|
|
+ * checks.
|
|
+ */
|
|
+ } else {
|
|
+ /* if we have wp, we can do whatever we like */
|
|
+ if (acl_check_access_on_attribute(module,
|
|
+ tmp_ctx,
|
|
+ sd,
|
|
+ sid,
|
|
+ SEC_ADS_WRITE_PROP,
|
|
+ attr, objectclass) == LDB_SUCCESS) {
|
|
+ talloc_free(tmp_ctx);
|
|
+ return LDB_SUCCESS;
|
|
+ }
|
|
|
|
- ret = acl_check_extended_right(tmp_ctx,
|
|
- module,
|
|
- req,
|
|
- objectclass,
|
|
- sd,
|
|
- acl_user_token(module),
|
|
- GUID_DRS_VALIDATE_SPN,
|
|
- SEC_ADS_SELF_WRITE,
|
|
- sid);
|
|
+ ret = acl_check_extended_right(tmp_ctx,
|
|
+ module,
|
|
+ req,
|
|
+ objectclass,
|
|
+ sd,
|
|
+ acl_user_token(module),
|
|
+ GUID_DRS_VALIDATE_SPN,
|
|
+ SEC_ADS_SELF_WRITE,
|
|
+ sid);
|
|
|
|
- if (ret != LDB_SUCCESS) {
|
|
- dsdb_acl_debug(sd, acl_user_token(module),
|
|
- req->op.mod.message->dn,
|
|
- true,
|
|
- 10);
|
|
- talloc_free(tmp_ctx);
|
|
- return ret;
|
|
+ if (ret != LDB_SUCCESS) {
|
|
+ dsdb_acl_debug(sd, acl_user_token(module),
|
|
+ req->op.mod.message->dn,
|
|
+ true,
|
|
+ 10);
|
|
+ talloc_free(tmp_ctx);
|
|
+ return ret;
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
@@ -809,7 +820,8 @@ static int acl_check_dns_host_name(TALLOC_CTX *mem_ctx,
|
|
struct security_descriptor *sd,
|
|
struct dom_sid *sid,
|
|
const struct dsdb_attribute *attr,
|
|
- const struct dsdb_class *objectclass)
|
|
+ const struct dsdb_class *objectclass,
|
|
+ const struct ldb_control *implicit_validated_write_control)
|
|
{
|
|
int ret;
|
|
unsigned i;
|
|
@@ -845,35 +857,45 @@ static int acl_check_dns_host_name(TALLOC_CTX *mem_ctx,
|
|
return ldb_oom(ldb);
|
|
}
|
|
|
|
- /* if we have wp, we can do whatever we like */
|
|
- ret = acl_check_access_on_attribute(module,
|
|
- tmp_ctx,
|
|
- sd,
|
|
- sid,
|
|
- SEC_ADS_WRITE_PROP,
|
|
- attr, objectclass);
|
|
- if (ret == LDB_SUCCESS) {
|
|
- talloc_free(tmp_ctx);
|
|
- return LDB_SUCCESS;
|
|
- }
|
|
+ if (implicit_validated_write_control != NULL) {
|
|
+ /*
|
|
+ * The validated write control dispenses with ACL
|
|
+ * checks. We act as if we have an implicit Self Write
|
|
+ * privilege, but, assuming we don't have Write
|
|
+ * Property, still proceed with further validation
|
|
+ * checks.
|
|
+ */
|
|
+ } else {
|
|
+ /* if we have wp, we can do whatever we like */
|
|
+ ret = acl_check_access_on_attribute(module,
|
|
+ tmp_ctx,
|
|
+ sd,
|
|
+ sid,
|
|
+ SEC_ADS_WRITE_PROP,
|
|
+ attr, objectclass);
|
|
+ if (ret == LDB_SUCCESS) {
|
|
+ talloc_free(tmp_ctx);
|
|
+ return LDB_SUCCESS;
|
|
+ }
|
|
|
|
- ret = acl_check_extended_right(tmp_ctx,
|
|
- module,
|
|
- req,
|
|
- objectclass,
|
|
- sd,
|
|
- acl_user_token(module),
|
|
- GUID_DRS_DNS_HOST_NAME,
|
|
- SEC_ADS_SELF_WRITE,
|
|
- sid);
|
|
+ ret = acl_check_extended_right(tmp_ctx,
|
|
+ module,
|
|
+ req,
|
|
+ objectclass,
|
|
+ sd,
|
|
+ acl_user_token(module),
|
|
+ GUID_DRS_DNS_HOST_NAME,
|
|
+ SEC_ADS_SELF_WRITE,
|
|
+ sid);
|
|
|
|
- if (ret != LDB_SUCCESS) {
|
|
- dsdb_acl_debug(sd, acl_user_token(module),
|
|
- req->op.mod.message->dn,
|
|
- true,
|
|
- 10);
|
|
- talloc_free(tmp_ctx);
|
|
- return ret;
|
|
+ if (ret != LDB_SUCCESS) {
|
|
+ dsdb_acl_debug(sd, acl_user_token(module),
|
|
+ req->op.mod.message->dn,
|
|
+ true,
|
|
+ 10);
|
|
+ talloc_free(tmp_ctx);
|
|
+ return ret;
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
@@ -1621,6 +1643,7 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req)
|
|
struct dom_sid *sid = NULL;
|
|
struct ldb_control *as_system;
|
|
struct ldb_control *is_undelete;
|
|
+ struct ldb_control *implicit_validated_write_control = NULL;
|
|
bool userPassword;
|
|
bool password_rights_checked = false;
|
|
TALLOC_CTX *tmp_ctx;
|
|
@@ -1647,6 +1670,12 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req)
|
|
|
|
is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
|
|
|
|
+ implicit_validated_write_control = ldb_request_get_control(
|
|
+ req, DSDB_CONTROL_FORCE_ALLOW_VALIDATED_DNS_HOSTNAME_SPN_WRITE_OID);
|
|
+ if (implicit_validated_write_control != NULL) {
|
|
+ implicit_validated_write_control->critical = 0;
|
|
+ }
|
|
+
|
|
/* Don't print this debug statement if elements[0].name is going to be NULL */
|
|
if (msg->num_elements > 0) {
|
|
DEBUG(10, ("ldb:acl_modify: %s\n", msg->elements[0].name));
|
|
@@ -1803,7 +1832,8 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req)
|
|
sd,
|
|
sid,
|
|
attr,
|
|
- objectclass);
|
|
+ objectclass,
|
|
+ implicit_validated_write_control);
|
|
if (ret != LDB_SUCCESS) {
|
|
goto fail;
|
|
}
|
|
@@ -1815,7 +1845,8 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req)
|
|
sd,
|
|
sid,
|
|
attr,
|
|
- objectclass);
|
|
+ objectclass,
|
|
+ implicit_validated_write_control);
|
|
if (ret != LDB_SUCCESS) {
|
|
goto fail;
|
|
}
|
|
@@ -1827,6 +1858,9 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req)
|
|
* tombstone_reanimate module
|
|
*/
|
|
continue;
|
|
+ } else if (implicit_validated_write_control != NULL) {
|
|
+ /* Allow the update. */
|
|
+ continue;
|
|
} else {
|
|
ret = acl_check_access_on_attribute(module,
|
|
tmp_ctx,
|
|
--
|
|
1.8.3.1
|
|
|