141 lines
3.9 KiB
Diff
141 lines
3.9 KiB
Diff
|
|
From 49ac07e786df58b914ee85e2db773c0ba8d4e171 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Joseph Sutton <josephsutton@catalyst.net.nz>
|
||
|
|
Date: Tue, 7 Jun 2022 17:36:56 +1200
|
||
|
|
Subject: [PATCH 04/15] CVE-2022-32743 s4/dsdb/util: Add
|
||
|
|
dsdb_msg_get_single_value()
|
||
|
|
|
||
|
|
This function simulates an add or modify operation for an ldb message to
|
||
|
|
determine the final value of a particular single-valued attribute. This
|
||
|
|
is useful when validating attributes that should stay in sync with other
|
||
|
|
attributes, such as servicePrincipalName and dNSHostName.
|
||
|
|
|
||
|
|
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/util.c | 107 ++++++++++++++++++++++++++++++++++
|
||
|
|
1 file changed, 107 insertions(+)
|
||
|
|
|
||
|
|
diff --git a/source4/dsdb/samdb/ldb_modules/util.c b/source4/dsdb/samdb/ldb_modules/util.c
|
||
|
|
index e7fe8f8..42aa9a2 100644
|
||
|
|
--- a/source4/dsdb/samdb/ldb_modules/util.c
|
||
|
|
+++ b/source4/dsdb/samdb/ldb_modules/util.c
|
||
|
|
@@ -1568,6 +1568,113 @@ int dsdb_get_expected_new_values(TALLOC_CTX *mem_ctx,
|
||
|
|
return LDB_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Get the value of a single-valued attribute from an ADDed message. 'val' will only live as
|
||
|
|
+ * long as 'msg' and 'original_val' do, and must not be freed.
|
||
|
|
+ */
|
||
|
|
+int dsdb_msg_add_get_single_value(const struct ldb_message *msg,
|
||
|
|
+ const char *attr_name,
|
||
|
|
+ const struct ldb_val **val)
|
||
|
|
+{
|
||
|
|
+ const struct ldb_message_element *el = NULL;
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * The ldb_msg_normalize() call in ldb_request() ensures that
|
||
|
|
+ * there is at most one message element for each
|
||
|
|
+ * attribute. Thus, we don't need a loop to deal with an
|
||
|
|
+ * LDB_ADD.
|
||
|
|
+ */
|
||
|
|
+ el = ldb_msg_find_element(msg, attr_name);
|
||
|
|
+ if (el == NULL) {
|
||
|
|
+ *val = NULL;
|
||
|
|
+ return LDB_SUCCESS;
|
||
|
|
+ }
|
||
|
|
+ if (el->num_values != 1) {
|
||
|
|
+ return LDB_ERR_CONSTRAINT_VIOLATION;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ *val = &el->values[0];
|
||
|
|
+ return LDB_SUCCESS;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Get the value of a single-valued attribute after processing a
|
||
|
|
+ * message. 'operation' is either LDB_ADD or LDB_MODIFY. 'val' will only live as
|
||
|
|
+ * long as 'msg' and 'original_val' do, and must not be freed.
|
||
|
|
+ */
|
||
|
|
+int dsdb_msg_get_single_value(const struct ldb_message *msg,
|
||
|
|
+ const char *attr_name,
|
||
|
|
+ const struct ldb_val *original_val,
|
||
|
|
+ const struct ldb_val **val,
|
||
|
|
+ enum ldb_request_type operation)
|
||
|
|
+{
|
||
|
|
+ unsigned idx;
|
||
|
|
+
|
||
|
|
+ *val = NULL;
|
||
|
|
+
|
||
|
|
+ if (operation == LDB_ADD) {
|
||
|
|
+ if (original_val != NULL) {
|
||
|
|
+ /* This is an error on the caller's part. */
|
||
|
|
+ return LDB_ERR_CONSTRAINT_VIOLATION;
|
||
|
|
+ }
|
||
|
|
+ return dsdb_msg_add_get_single_value(msg, attr_name, val);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ SMB_ASSERT(operation == LDB_MODIFY);
|
||
|
|
+
|
||
|
|
+ *val = original_val;
|
||
|
|
+
|
||
|
|
+ for (idx = 0; idx < msg->num_elements; ++idx) {
|
||
|
|
+ const struct ldb_message_element *el = &msg->elements[idx];
|
||
|
|
+
|
||
|
|
+ if (ldb_attr_cmp(el->name, attr_name) != 0) {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ switch (el->flags & LDB_FLAG_MOD_MASK) {
|
||
|
|
+ case LDB_FLAG_MOD_ADD:
|
||
|
|
+ if (el->num_values != 1) {
|
||
|
|
+ return LDB_ERR_CONSTRAINT_VIOLATION;
|
||
|
|
+ }
|
||
|
|
+ if (*val != NULL) {
|
||
|
|
+ return LDB_ERR_CONSTRAINT_VIOLATION;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ *val = &el->values[0];
|
||
|
|
+
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case LDB_FLAG_MOD_REPLACE:
|
||
|
|
+ if (el->num_values > 1) {
|
||
|
|
+ return LDB_ERR_CONSTRAINT_VIOLATION;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ *val = el->num_values ? &el->values[0] : NULL;
|
||
|
|
+
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case LDB_FLAG_MOD_DELETE:
|
||
|
|
+ if (el->num_values > 1) {
|
||
|
|
+ return LDB_ERR_CONSTRAINT_VIOLATION;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * If a value was specified for the delete, we don't
|
||
|
|
+ * bother checking it matches the value we currently
|
||
|
|
+ * have. Any mismatch will be caught later (e.g. in
|
||
|
|
+ * ldb_kv_modify_internal).
|
||
|
|
+ */
|
||
|
|
+
|
||
|
|
+ *val = NULL;
|
||
|
|
+
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return LDB_SUCCESS;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
/*
|
||
|
|
* This function determines the (last) structural or 88 object class of a passed
|
||
|
|
* "objectClass" attribute - per MS-ADTS 3.1.1.1.4 this is the last value.
|
||
|
|
--
|
||
|
|
1.8.3.1
|
||
|
|
|