From: Stefan Metzmacher Date: Mon, 29 Jun 2026 17:09:28 +0000 (+0200) Subject: CVE-2026-58221: s4:dsdb: provide dsdb_audit_{log_attributes,operation_human_readable... X-Git-Tag: talloc-2.5.0~7 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ac1c8d6ad5747e69987dbec2307943efbbfdec5c;p=thirdparty%2Fsamba.git CVE-2026-58221: s4:dsdb: provide dsdb_audit_{log_attributes,operation_human_readable}() functions They are useful outside of audit_log.c soon. BUG: https://bugzilla.samba.org/show_bug.cgi?id=16147 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke Reviewed-by: Douglas Bagnall --- diff --git a/source4/dsdb/samdb/ldb_modules/audit_log.c b/source4/dsdb/samdb/ldb_modules/audit_log.c index c944a84b360..3aad76a914a 100644 --- a/source4/dsdb/samdb/ldb_modules/audit_log.c +++ b/source4/dsdb/samdb/ldb_modules/audit_log.c @@ -867,185 +867,6 @@ static char *password_change_human_readable( TALLOC_FREE(ctx); return log_entry; } -/* - * @brief Generate a human readable string, detailing attributes in a message - * - * For modify operations each attribute is prefixed with the action. - * Normal values are enclosed in [] - * Base64 values are enclosed in {} - * Truncated values are indicated by three trailing dots "..." - * - * @param[in] ldb the ldb_context - * @param[out] buffer the attributes will be appended to the buffer. - * assumed to have been allocated via talloc. - * @param[in] operation the operation type - * @param[in] message the message to process - * - * @return a pointer to buffer - * - */ -static char *log_attributes( - struct ldb_context *ldb, - char *buffer, - enum ldb_request_type operation, - const struct ldb_message *message) -{ - size_t i, j; - for (i=0;inum_elements;i++) { - if (i > 0) { - buffer = talloc_asprintf_append_buffer(buffer, " "); - } - - if (message->elements[i].name == NULL) { - ldb_debug( - ldb, - LDB_DEBUG_ERROR, - "Error: Invalid element name (NULL) at " - "position %zu", i); - return NULL; - } - - if (operation == LDB_MODIFY) { - const char *action =NULL; - action = dsdb_audit_get_modification_action( - message->elements[i].flags); - buffer = talloc_asprintf_append_buffer( - buffer, - "%s: %s ", - action, - message->elements[i].name); - } else { - buffer = talloc_asprintf_append_buffer( - buffer, - "%s ", - message->elements[i].name); - } - - if (dsdb_audit_redact_attribute(message->elements[i].name)) { - /* - * Do not log the value of any secret or password - * attributes - */ - buffer = talloc_asprintf_append_buffer( - buffer, - "[REDACTED SECRET ATTRIBUTE]"); - continue; - } - - for (j=0;jelements[i].num_values;j++) { - struct ldb_val v; - bool use_b64_encode = false; - size_t length; - if (j > 0) { - buffer = talloc_asprintf_append_buffer( - buffer, - " "); - } - - v = message->elements[i].values[j]; - length = MIN(MAX_LENGTH, v.length); - use_b64_encode = ldb_should_b64_encode(ldb, &v); - if (use_b64_encode) { - const char *encoded = ldb_base64_encode( - buffer, - (char *)v.data, - length); - buffer = talloc_asprintf_append_buffer( - buffer, - "{%s%s}", - encoded, - (v.length > MAX_LENGTH ? "..." : "")); - } else { - buffer = talloc_asprintf_append_buffer( - buffer, - "[%*.*s%s]", - (int)length, - (int)length, - (char *)v.data, - (v.length > MAX_LENGTH ? "..." : "")); - } - } - } - return buffer; -} - -/* - * @brief generate a human readable log entry detailing an ldb operation. - * - * Generate a human readable log entry detailing an ldb operation. - * - * @param[in] mem_ctx the talloc context owning the returned string. - * @param[in] module the ldb module - * @param[in] request the request - * @param[in] reply the result of the operation - * - * @return the log entry. - * - */ -static char *operation_human_readable( - TALLOC_CTX *mem_ctx, - struct ldb_module *module, - const struct ldb_request *request, - const struct ldb_reply *reply) -{ - struct ldb_context *ldb = NULL; - const char *remote_host = NULL; - const struct tsocket_address *remote = NULL; - const struct dom_sid *sid = NULL; - struct dom_sid_buf user_sid; - const char *timestamp = NULL; - const char *op_name = NULL; - char *log_entry = NULL; - const char *dn = NULL; - const char *new_dn = NULL; - const struct ldb_message *message = NULL; - - TALLOC_CTX *ctx = talloc_new(NULL); - - ldb = ldb_module_get_ctx(module); - - remote_host = dsdb_audit_get_remote_host(ldb, ctx); - remote = dsdb_audit_get_remote_address(ldb); - if (remote != NULL && dsdb_audit_is_system_session(module)) { - sid = dsdb_audit_get_actual_sid(ldb); - } else { - sid = dsdb_audit_get_user_sid(module); - } - timestamp = audit_get_timestamp(ctx); - op_name = dsdb_audit_get_operation_name(request); - dn = dsdb_audit_get_primary_dn(request); - new_dn = dsdb_audit_get_secondary_dn(request); - - message = dsdb_audit_get_message(request); - - log_entry = talloc_asprintf( - mem_ctx, - "[%s] at [%s] status [%s] " - "remote host [%s] SID [%s] DN [%s]", - op_name, - timestamp, - ldb_strerror(reply->error), - remote_host, - dom_sid_str_buf(sid, &user_sid), - dn); - if (new_dn != NULL) { - log_entry = talloc_asprintf_append_buffer( - log_entry, - " New DN [%s]", - new_dn); - } - if (message != NULL) { - log_entry = talloc_asprintf_append_buffer(log_entry, - " attributes ["); - log_entry = log_attributes(ldb, - log_entry, - request->operation, - message); - log_entry = talloc_asprintf_append_buffer(log_entry, "]"); - } - TALLOC_FREE(ctx); - return log_entry; -} /* * @brief generate a human readable log entry detailing a replicated update @@ -1213,7 +1034,7 @@ static void log_standard_operation( if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT, OPERATION_LOG_LVL)) { char *entry = NULL; - entry = operation_human_readable( + entry = dsdb_audit_operation_human_readable( ctx, module, request, diff --git a/source4/dsdb/samdb/ldb_modules/audit_util.c b/source4/dsdb/samdb/ldb_modules/audit_util.c index 11e1b755616..33910d7c9a8 100644 --- a/source4/dsdb/samdb/ldb_modules/audit_util.c +++ b/source4/dsdb/samdb/ldb_modules/audit_util.c @@ -716,3 +716,183 @@ failure: DBG_ERR("Unable to create ldb attributes JSON audit message\n"); return attributes; } + +/* + * @brief Generate a human readable string, detailing attributes in a message + * + * For modify operations each attribute is prefixed with the action. + * Normal values are enclosed in [] + * Base64 values are enclosed in {} + * Truncated values are indicated by three trailing dots "..." + * + * @param[in] ldb the ldb_context + * @param[out] buffer the attributes will be appended to the buffer. + * assumed to have been allocated via talloc. + * @param[in] operation the operation type + * @param[in] message the message to process + * + * @return a pointer to buffer + * + */ +char *dsdb_audit_log_attributes( + struct ldb_context *ldb, + char *buffer, + enum ldb_request_type operation, + const struct ldb_message *message) +{ + size_t i, j; + for (i=0;inum_elements;i++) { + if (i > 0) { + buffer = talloc_asprintf_append_buffer(buffer, " "); + } + + if (message->elements[i].name == NULL) { + ldb_debug( + ldb, + LDB_DEBUG_ERROR, + "Error: Invalid element name (NULL) at " + "position %zu", i); + return NULL; + } + + if (operation == LDB_MODIFY) { + const char *action =NULL; + action = dsdb_audit_get_modification_action( + message->elements[i].flags); + buffer = talloc_asprintf_append_buffer( + buffer, + "%s: %s ", + action, + message->elements[i].name); + } else { + buffer = talloc_asprintf_append_buffer( + buffer, + "%s ", + message->elements[i].name); + } + + if (dsdb_audit_redact_attribute(message->elements[i].name)) { + /* + * Do not log the value of any secret or password + * attributes + */ + buffer = talloc_asprintf_append_buffer( + buffer, + "[REDACTED SECRET ATTRIBUTE]"); + continue; + } + + for (j=0;jelements[i].num_values;j++) { + struct ldb_val v; + bool use_b64_encode = false; + size_t length; + if (j > 0) { + buffer = talloc_asprintf_append_buffer( + buffer, + " "); + } + + v = message->elements[i].values[j]; + length = MIN(MAX_LENGTH, v.length); + use_b64_encode = ldb_should_b64_encode(ldb, &v); + if (use_b64_encode) { + const char *encoded = ldb_base64_encode( + buffer, + (char *)v.data, + length); + buffer = talloc_asprintf_append_buffer( + buffer, + "{%s%s}", + encoded, + (v.length > MAX_LENGTH ? "..." : "")); + } else { + buffer = talloc_asprintf_append_buffer( + buffer, + "[%*.*s%s]", + (int)length, + (int)length, + (char *)v.data, + (v.length > MAX_LENGTH ? "..." : "")); + } + } + } + return buffer; +} + +/* + * @brief generate a human readable log entry detailing an ldb operation. + * + * Generate a human readable log entry detailing an ldb operation. + * + * @param[in] mem_ctx the talloc context owning the returned string. + * @param[in] module the ldb module + * @param[in] request the request + * @param[in] reply the result of the operation + * + * @return the log entry. + * + */ +char *dsdb_audit_operation_human_readable( + TALLOC_CTX *mem_ctx, + struct ldb_module *module, + const struct ldb_request *request, + const struct ldb_reply *reply) +{ + struct ldb_context *ldb = NULL; + const char *remote_host = NULL; + const struct tsocket_address *remote = NULL; + const struct dom_sid *sid = NULL; + struct dom_sid_buf user_sid; + const char *timestamp = NULL; + const char *op_name = NULL; + char *log_entry = NULL; + const char *dn = NULL; + const char *new_dn = NULL; + const struct ldb_message *message = NULL; + + TALLOC_CTX *ctx = talloc_new(NULL); + + ldb = ldb_module_get_ctx(module); + + remote_host = dsdb_audit_get_remote_host(ldb, ctx); + remote = dsdb_audit_get_remote_address(ldb); + if (remote != NULL && dsdb_audit_is_system_session(module)) { + sid = dsdb_audit_get_actual_sid(ldb); + } else { + sid = dsdb_audit_get_user_sid(module); + } + timestamp = audit_get_timestamp(ctx); + op_name = dsdb_audit_get_operation_name(request); + dn = dsdb_audit_get_primary_dn(request); + new_dn = dsdb_audit_get_secondary_dn(request); + + message = dsdb_audit_get_message(request); + + log_entry = talloc_asprintf( + mem_ctx, + "[%s] at [%s] status [%s] " + "remote host [%s] SID [%s] DN [%s]", + op_name, + timestamp, + ldb_strerror(reply->error), + remote_host, + dom_sid_str_buf(sid, &user_sid), + dn); + if (new_dn != NULL) { + log_entry = talloc_asprintf_append_buffer( + log_entry, + " New DN [%s]", + new_dn); + } + if (message != NULL) { + log_entry = talloc_asprintf_append_buffer(log_entry, + " attributes ["); + log_entry = dsdb_audit_log_attributes(ldb, + log_entry, + request->operation, + message); + log_entry = talloc_asprintf_append_buffer(log_entry, "]"); + } + TALLOC_FREE(ctx); + return log_entry; +} diff --git a/source4/dsdb/samdb/ldb_modules/tests/test_audit_log.c b/source4/dsdb/samdb/ldb_modules/tests/test_audit_log.c index 2862fa25f3f..6e7ceaf0cdc 100644 --- a/source4/dsdb/samdb/ldb_modules/tests/test_audit_log.c +++ b/source4/dsdb/samdb/ldb_modules/tests/test_audit_log.c @@ -1615,7 +1615,7 @@ static void test_replicated_update_json(void **state) } /* - * minimal unit test of operation_human_readable, that ensures that all the + * minimal unit test of dsdb_audit_operation_human_readable, that ensures that all the * expected attributes and objects are in the json object. */ static void test_operation_hr_empty(void **state) @@ -1645,7 +1645,7 @@ static void test_operation_hr_empty(void **state) reply = talloc_zero(ctx, struct ldb_reply); reply->error = LDB_SUCCESS; - line = operation_human_readable(ctx, module, req, reply); + line = dsdb_audit_operation_human_readable(ctx, module, req, reply); assert_non_null(line); /* @@ -1740,7 +1740,7 @@ static void test_operation_hr(void **state) reply = talloc_zero(ctx, struct ldb_reply); reply->error = LDB_SUCCESS; - line = operation_human_readable(ctx, module, req, reply); + line = dsdb_audit_operation_human_readable(ctx, module, req, reply); assert_non_null(line); /* @@ -1851,7 +1851,7 @@ static void test_as_system_operation_hr(void **state) reply = talloc_zero(ctx, struct ldb_reply); reply->error = LDB_SUCCESS; - line = operation_human_readable(ctx, module, req, reply); + line = dsdb_audit_operation_human_readable(ctx, module, req, reply); assert_non_null(line); /* @@ -2162,7 +2162,7 @@ static void test_log_attributes(void **state) buf = talloc_zero(ctx, char); msg = talloc_zero(ctx, struct ldb_message); - str = log_attributes(ctx, buf, LDB_ADD, msg); + str = dsdb_audit_log_attributes(ctx, buf, LDB_ADD, msg); assert_string_equal("", str); TALLOC_FREE(str); @@ -2175,7 +2175,7 @@ static void test_log_attributes(void **state) msg = talloc_zero(ctx, struct ldb_message); ldb_msg_add_string(msg, "clearTextPassword", "secret"); - str = log_attributes(ctx, buf, LDB_ADD, msg); + str = dsdb_audit_log_attributes(ctx, buf, LDB_ADD, msg); assert_string_equal( "clearTextPassword [REDACTED SECRET ATTRIBUTE]", str); @@ -2185,7 +2185,7 @@ static void test_log_attributes(void **state) * action will be unknown as there are no ACL's set */ buf = talloc_zero(ctx, char); - str = log_attributes(ctx, buf, LDB_MODIFY, msg); + str = dsdb_audit_log_attributes(ctx, buf, LDB_MODIFY, msg); assert_string_equal( "unknown: clearTextPassword [REDACTED SECRET ATTRIBUTE]", str); @@ -2200,7 +2200,7 @@ static void test_log_attributes(void **state) msg = talloc_zero(ctx, struct ldb_message); ldb_msg_add_string(msg, "attribute", "value"); - str = log_attributes(ctx, buf, LDB_ADD, msg); + str = dsdb_audit_log_attributes(ctx, buf, LDB_ADD, msg); assert_string_equal( "attribute [value]", str); @@ -2216,7 +2216,7 @@ static void test_log_attributes(void **state) msg = talloc_zero(ctx, struct ldb_message); ldb_msg_add_string(msg, "attribute", "value"); - str = log_attributes(ctx, buf, LDB_MODIFY, msg); + str = dsdb_audit_log_attributes(ctx, buf, LDB_MODIFY, msg); assert_string_equal( "unknown: attribute [value]", str); @@ -2234,7 +2234,7 @@ static void test_log_attributes(void **state) ldb_msg_add_string(msg, "attribute02", "value02"); ldb_msg_add_string(msg, "attribute02", "value03"); - str = log_attributes(ctx, buf, LDB_MODIFY, msg); + str = dsdb_audit_log_attributes(ctx, buf, LDB_MODIFY, msg); assert_string_equal( "unknown: attribute01 [value01] " "unknown: attribute02 [value02] [value03]", @@ -2251,7 +2251,7 @@ static void test_log_attributes(void **state) msg = talloc_zero(ctx, struct ldb_message); ldb_msg_add_string(msg, "attribute", "value\n"); - str = log_attributes(ctx, buf, LDB_ADD, msg); + str = dsdb_audit_log_attributes(ctx, buf, LDB_ADD, msg); assert_string_equal("attribute {dmFsdWUK}", str); TALLOC_FREE(str); @@ -2268,7 +2268,7 @@ static void test_log_attributes(void **state) memset(lv, 'x', MAX_LENGTH+1); ldb_msg_add_string(msg, "attribute", lv); - str = log_attributes(ctx, buf, LDB_ADD, msg); + str = dsdb_audit_log_attributes(ctx, buf, LDB_ADD, msg); snprintf(ex, sizeof(ex), "attribute [%.*s...]", MAX_LENGTH, lv); assert_string_equal(ex, str);