218 lines
7.5 KiB
Diff
218 lines
7.5 KiB
Diff
|
|
From 3ebfe8666c02ab2de823457c68a922d0b0437cec Mon Sep 17 00:00:00 2001
|
||
|
|
From: Joseph Sutton <josephsutton@catalyst.net.nz>
|
||
|
|
Date: Mon, 27 Feb 2023 13:55:36 +1300
|
||
|
|
Subject: [PATCH 23/34] CVE-2023-0614 s4-acl: Split out function to set up
|
||
|
|
access checking variables
|
||
|
|
|
||
|
|
These variables are often used together, and it is useful to have the
|
||
|
|
setup code in one place.
|
||
|
|
|
||
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270
|
||
|
|
|
||
|
|
Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
|
||
|
|
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
|
||
|
|
|
||
|
|
[abartlet@samba.org adapted to the use of
|
||
|
|
acl_check_access_on_attribute as
|
||
|
|
acl_check_access_on_attribute_implicit_owner is
|
||
|
|
only in Samba 4.18 and newer]
|
||
|
|
|
||
|
|
Conflict: NA
|
||
|
|
Reference: https://attachments.samba.org/attachment.cgi?id=17821
|
||
|
|
---
|
||
|
|
source4/dsdb/samdb/ldb_modules/acl_read.c | 113 +++++++++++++++-------
|
||
|
|
1 file changed, 80 insertions(+), 33 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/source4/dsdb/samdb/ldb_modules/acl_read.c b/source4/dsdb/samdb/ldb_modules/acl_read.c
|
||
|
|
index 3980c44345e..6659c71c965 100644
|
||
|
|
--- a/source4/dsdb/samdb/ldb_modules/acl_read.c
|
||
|
|
+++ b/source4/dsdb/samdb/ldb_modules/acl_read.c
|
||
|
|
@@ -70,6 +70,13 @@ struct aclread_private {
|
||
|
|
struct ldb_val sd_cached_blob;
|
||
|
|
};
|
||
|
|
|
||
|
|
+struct access_check_context {
|
||
|
|
+ struct security_descriptor *sd;
|
||
|
|
+ struct dom_sid sid_buf;
|
||
|
|
+ const struct dom_sid *sid;
|
||
|
|
+ const struct dsdb_class *objectclass;
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
/*
|
||
|
|
* the object has a parent, so we have to check for visibility
|
||
|
|
*
|
||
|
|
@@ -254,7 +261,7 @@ static int aclread_check_object_visible(struct aclread_context *ac,
|
||
|
|
*/
|
||
|
|
|
||
|
|
static int aclread_get_sd_from_ldb_message(struct aclread_context *ac,
|
||
|
|
- struct ldb_message *acl_res,
|
||
|
|
+ const struct ldb_message *acl_res,
|
||
|
|
struct security_descriptor **sd)
|
||
|
|
{
|
||
|
|
struct ldb_message_element *sd_element;
|
||
|
|
@@ -358,7 +365,7 @@ static uint32_t get_attr_access_mask(const struct dsdb_attribute *attr,
|
||
|
|
struct parse_tree_aclread_ctx {
|
||
|
|
struct aclread_context *ac;
|
||
|
|
TALLOC_CTX *mem_ctx;
|
||
|
|
- struct dom_sid *sid;
|
||
|
|
+ const struct dom_sid *sid;
|
||
|
|
struct ldb_dn *dn;
|
||
|
|
struct security_descriptor *sd;
|
||
|
|
const struct dsdb_class *objectclass;
|
||
|
|
@@ -372,7 +379,7 @@ static int check_attr_access_rights(TALLOC_CTX *mem_ctx, const char *attr_name,
|
||
|
|
struct aclread_context *ac,
|
||
|
|
struct security_descriptor *sd,
|
||
|
|
const struct dsdb_class *objectclass,
|
||
|
|
- struct dom_sid *sid, struct ldb_dn *dn)
|
||
|
|
+ const struct dom_sid *sid, struct ldb_dn *dn)
|
||
|
|
{
|
||
|
|
int ret;
|
||
|
|
const struct dsdb_attribute *attr = NULL;
|
||
|
|
@@ -448,6 +455,69 @@ static const char * parse_tree_get_attr(struct ldb_parse_tree *tree)
|
||
|
|
return attr;
|
||
|
|
}
|
||
|
|
|
||
|
|
+static int setup_access_check_context(struct aclread_context *ac,
|
||
|
|
+ const struct ldb_message *msg,
|
||
|
|
+ struct access_check_context *ctx)
|
||
|
|
+{
|
||
|
|
+ int ret;
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * Fetch the schema so we can check which attributes are
|
||
|
|
+ * considered confidential.
|
||
|
|
+ */
|
||
|
|
+ if (ac->schema == NULL) {
|
||
|
|
+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
|
||
|
|
+
|
||
|
|
+ /* Cache the schema for later use. */
|
||
|
|
+ ac->schema = dsdb_get_schema(ldb, ac);
|
||
|
|
+
|
||
|
|
+ if (ac->schema == NULL) {
|
||
|
|
+ return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
|
||
|
|
+ "aclread_callback: Error obtaining schema.");
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /* Fetch the object's security descriptor. */
|
||
|
|
+ ret = aclread_get_sd_from_ldb_message(ac, msg, &ctx->sd);
|
||
|
|
+ if (ret != LDB_SUCCESS) {
|
||
|
|
+ ldb_debug_set(ldb_module_get_ctx(ac->module), LDB_DEBUG_FATAL,
|
||
|
|
+ "acl_read: cannot get descriptor of %s: %s\n",
|
||
|
|
+ ldb_dn_get_linearized(msg->dn), ldb_strerror(ret));
|
||
|
|
+ return LDB_ERR_OPERATIONS_ERROR;
|
||
|
|
+ } else if (ctx->sd == NULL) {
|
||
|
|
+ ldb_debug_set(ldb_module_get_ctx(ac->module), LDB_DEBUG_FATAL,
|
||
|
|
+ "acl_read: cannot get descriptor of %s (attribute not found)\n",
|
||
|
|
+ ldb_dn_get_linearized(msg->dn));
|
||
|
|
+ return LDB_ERR_OPERATIONS_ERROR;
|
||
|
|
+ }
|
||
|
|
+ /*
|
||
|
|
+ * Get the most specific structural object class for the ACL check
|
||
|
|
+ */
|
||
|
|
+ ctx->objectclass = dsdb_get_structural_oc_from_msg(ac->schema, msg);
|
||
|
|
+ if (ctx->objectclass == NULL) {
|
||
|
|
+ ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
|
||
|
|
+ "acl_read: Failed to find a structural class for %s",
|
||
|
|
+ ldb_dn_get_linearized(msg->dn));
|
||
|
|
+ return LDB_ERR_OPERATIONS_ERROR;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /* Fetch the object's SID. */
|
||
|
|
+ ret = samdb_result_dom_sid_buf(msg, "objectSid", &ctx->sid_buf);
|
||
|
|
+ if (ret == LDB_SUCCESS) {
|
||
|
|
+ ctx->sid = &ctx->sid_buf;
|
||
|
|
+ } else if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
|
||
|
|
+ /* This is expected. */
|
||
|
|
+ ctx->sid = NULL;
|
||
|
|
+ } else {
|
||
|
|
+ ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
|
||
|
|
+ "acl_read: Failed to parse objectSid as dom_sid for %s",
|
||
|
|
+ ldb_dn_get_linearized(msg->dn));
|
||
|
|
+ return ret;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return LDB_SUCCESS;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
/*
|
||
|
|
* Checks a single attribute in the search parse-tree to make sure the user has
|
||
|
|
* sufficient rights to view it.
|
||
|
|
@@ -522,7 +592,7 @@ static int check_search_ops_access(struct aclread_context *ac,
|
||
|
|
TALLOC_CTX *mem_ctx,
|
||
|
|
struct security_descriptor *sd,
|
||
|
|
const struct dsdb_class *objectclass,
|
||
|
|
- struct dom_sid *sid, struct ldb_dn *dn,
|
||
|
|
+ const struct dom_sid *sid, struct ldb_dn *dn,
|
||
|
|
bool *suppress_result)
|
||
|
|
{
|
||
|
|
int ret;
|
||
|
|
@@ -585,10 +655,8 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares)
|
||
|
|
struct ldb_message *msg;
|
||
|
|
int ret;
|
||
|
|
unsigned int i;
|
||
|
|
- struct security_descriptor *sd = NULL;
|
||
|
|
- struct dom_sid *sid = NULL;
|
||
|
|
+ struct access_check_context acl_ctx;
|
||
|
|
TALLOC_CTX *tmp_ctx;
|
||
|
|
- const struct dsdb_class *objectclass;
|
||
|
|
bool suppress_result = false;
|
||
|
|
|
||
|
|
ac = talloc_get_type_abort(req->context, struct aclread_context);
|
||
|
|
@@ -604,32 +672,11 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares)
|
||
|
|
switch (ares->type) {
|
||
|
|
case LDB_REPLY_ENTRY:
|
||
|
|
msg = ares->message;
|
||
|
|
- ret = aclread_get_sd_from_ldb_message(ac, msg, &sd);
|
||
|
|
+ ret = setup_access_check_context(ac, msg, &acl_ctx);
|
||
|
|
if (ret != LDB_SUCCESS) {
|
||
|
|
- ldb_debug_set(ldb, LDB_DEBUG_FATAL,
|
||
|
|
- "acl_read: cannot get descriptor of %s: %s\n",
|
||
|
|
- ldb_dn_get_linearized(msg->dn), ldb_strerror(ret));
|
||
|
|
- ret = LDB_ERR_OPERATIONS_ERROR;
|
||
|
|
- goto fail;
|
||
|
|
- } else if (sd == NULL) {
|
||
|
|
- ldb_debug_set(ldb, LDB_DEBUG_FATAL,
|
||
|
|
- "acl_read: cannot get descriptor of %s (attribute not found)\n",
|
||
|
|
- ldb_dn_get_linearized(msg->dn));
|
||
|
|
- ret = LDB_ERR_OPERATIONS_ERROR;
|
||
|
|
- goto fail;
|
||
|
|
- }
|
||
|
|
- /*
|
||
|
|
- * Get the most specific structural object class for the ACL check
|
||
|
|
- */
|
||
|
|
- objectclass = dsdb_get_structural_oc_from_msg(ac->schema, msg);
|
||
|
|
- if (objectclass == NULL) {
|
||
|
|
- ldb_asprintf_errstring(ldb, "acl_read: Failed to find a structural class for %s",
|
||
|
|
- ldb_dn_get_linearized(msg->dn));
|
||
|
|
- ret = LDB_ERR_OPERATIONS_ERROR;
|
||
|
|
- goto fail;
|
||
|
|
+ return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
- sid = samdb_result_dom_sid(tmp_ctx, msg, "objectSid");
|
||
|
|
if (!ldb_dn_is_null(msg->dn)) {
|
||
|
|
/*
|
||
|
|
* this is a real object, so we have
|
||
|
|
@@ -678,8 +725,8 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares)
|
||
|
|
|
||
|
|
ret = acl_check_access_on_attribute(ac->module,
|
||
|
|
tmp_ctx,
|
||
|
|
- sd,
|
||
|
|
- sid,
|
||
|
|
+ acl_ctx.sd,
|
||
|
|
+ acl_ctx.sid,
|
||
|
|
access_mask,
|
||
|
|
attr,
|
||
|
|
objectclass);
|
||
|
|
@@ -733,7 +780,7 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares)
|
||
|
|
* check access rights for the search attributes, as well as the
|
||
|
|
* attribute values actually being returned
|
||
|
|
*/
|
||
|
|
- ret = check_search_ops_access(ac, tmp_ctx, sd, objectclass, sid,
|
||
|
|
+ ret = check_search_ops_access(ac, tmp_ctx, acl_ctx.sd, acl_ctx.objectclass, acl_ctx.sid,
|
||
|
|
msg->dn, &suppress_result);
|
||
|
|
if (ret != LDB_SUCCESS) {
|
||
|
|
ldb_debug_set(ldb, LDB_DEBUG_FATAL,
|
||
|
|
--
|
||
|
|
2.25.1
|