4 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 * Provide an audit log of changes made to the database and at a
22 * higher level details of any password changes and resets.
27 #include "ldb_module.h"
28 #include "lib/audit_logging/audit_logging.h"
30 #include "dsdb/samdb/samdb.h"
31 #include "dsdb/samdb/ldb_modules/util.h"
32 #include "dsdb/samdb/ldb_modules/audit_util_proto.h"
33 #include "libcli/security/dom_sid.h"
34 #include "auth/common_auth.h"
35 #include "param/param.h"
36 #include "librpc/gen_ndr/windows_event_ids.h"
38 #define OPERATION_JSON_TYPE "dsdbChange"
39 #define OPERATION_HR_TAG "DSDB Change"
40 #define OPERATION_MAJOR 1
41 #define OPERATION_MINOR 0
42 #define OPERATION_LOG_LVL 5
44 #define PASSWORD_JSON_TYPE "passwordChange"
45 #define PASSWORD_HR_TAG "Password Change"
46 #define PASSWORD_MAJOR 1
47 #define PASSWORD_MINOR 1
48 #define PASSWORD_LOG_LVL 5
50 #define TRANSACTION_JSON_TYPE "dsdbTransaction"
51 #define TRANSACTION_HR_TAG "DSDB Transaction"
52 #define TRANSACTION_MAJOR 1
53 #define TRANSACTION_MINOR 0
54 #define TRANSACTION_LOG_FAILURE_LVL 5
55 #define TRANSACTION_LOG_COMPLETION_LVL 10
57 #define REPLICATION_JSON_TYPE "replicatedUpdate"
58 #define REPLICATION_HR_TAG "Replicated Update"
59 #define REPLICATION_MAJOR 1
60 #define REPLICATION_MINOR 0
61 #define REPLICATION_LOG_LVL 5
63 * Attribute values are truncated in the logs if they are longer than
66 #define MAX_LENGTH 1024
68 #define min(a, b) (((a)>(b))?(b):(a))
71 * Private data for the module, stored in the ldb_module private data
73 struct audit_private {
75 * Should details of database operations be sent over the
78 bool send_samdb_events;
80 * Should details of password changes and resets be sent over
83 bool send_password_events;
85 * The messaging context to send the messages over. Will only
86 * be set if send_samdb_events or send_password_events are
89 struct imessaging_context *msg_ctx;
91 * Unique transaction id for the current transaction
93 struct GUID transaction_guid;
95 * Transaction start time, used to calculate the transaction
98 struct timeval transaction_start;
102 * @brief Has the password changed.
104 * Does the message contain a change to one of the password attributes? The
105 * password attributes are defined in DSDB_PASSWORD_ATTRIBUTES
107 * @return true if the message contains a password attribute
110 static bool has_password_changed(const struct ldb_message *message)
113 if (message == NULL) {
116 for (i=0;i<message->num_elements;i++) {
117 if (dsdb_audit_is_password_attribute(
118 message->elements[i].name)) {
126 * @brief get the password change windows event id
128 * Get the Windows Event Id for the action being performed on the user password.
130 * This routine assumes that the request contains password attributes and that the
131 * password ACL checks have been performed by acl.c
133 * @param request the ldb_request to inspect
134 * @param reply the ldb_reply, will contain the password controls
136 * @return The windows event code.
138 static enum event_id_type get_password_windows_event_id(
139 const struct ldb_request *request,
140 const struct ldb_reply *reply)
142 if(request->operation == LDB_ADD) {
143 return EVT_ID_PASSWORD_RESET;
145 struct ldb_control *pav_ctrl = NULL;
146 struct dsdb_control_password_acl_validation *pav = NULL;
148 pav_ctrl = ldb_reply_get_control(
149 discard_const(reply),
150 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
151 if (pav_ctrl == NULL) {
152 return EVT_ID_PASSWORD_RESET;
155 pav = talloc_get_type_abort(
157 struct dsdb_control_password_acl_validation);
159 if (pav->pwd_reset) {
160 return EVT_ID_PASSWORD_RESET;
162 return EVT_ID_PASSWORD_CHANGE;
167 * @brief Is the request a password "Change" or a "Reset"
169 * Get a description of the action being performed on the user password. This
170 * routine assumes that the request contains password attributes and that the
171 * password ACL checks have been performed by acl.c
173 * @param request the ldb_request to inspect
174 * @param reply the ldb_reply, will contain the password controls
176 * @return "Change" if the password is being changed.
177 * "Reset" if the password is being reset.
179 static const char *get_password_action(
180 const struct ldb_request *request,
181 const struct ldb_reply *reply)
183 if(request->operation == LDB_ADD) {
186 struct ldb_control *pav_ctrl = NULL;
187 struct dsdb_control_password_acl_validation *pav = NULL;
189 pav_ctrl = ldb_reply_get_control(
190 discard_const(reply),
191 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
192 if (pav_ctrl == NULL) {
196 pav = talloc_get_type_abort(
198 struct dsdb_control_password_acl_validation);
200 if (pav->pwd_reset) {
209 * @brief generate a JSON object detailing an ldb operation.
211 * Generate a JSON object detailing an ldb operation.
213 * @param module the ldb module
214 * @param request the request
215 * @param reply the result of the operation.
217 * @return the generated JSON object, should be freed with json_free.
221 static struct json_object operation_json(
222 struct ldb_module *module,
223 const struct ldb_request *request,
224 const struct ldb_reply *reply)
226 struct ldb_context *ldb = NULL;
227 const struct dom_sid *sid = NULL;
228 bool as_system = false;
229 struct json_object wrapper = json_empty_object;
230 struct json_object audit = json_empty_object;
231 const struct tsocket_address *remote = NULL;
232 const char *dn = NULL;
233 const char* operation = NULL;
234 const struct GUID *unique_session_token = NULL;
235 const struct ldb_message *message = NULL;
236 struct audit_private *audit_private
237 = talloc_get_type_abort(ldb_module_get_private(module),
238 struct audit_private);
241 ldb = ldb_module_get_ctx(module);
243 remote = dsdb_audit_get_remote_address(ldb);
244 if (remote != NULL && dsdb_audit_is_system_session(module)) {
246 sid = dsdb_audit_get_actual_sid(ldb);
247 unique_session_token =
248 dsdb_audit_get_actual_unique_session_token(ldb);
250 sid = dsdb_audit_get_user_sid(module);
251 unique_session_token =
252 dsdb_audit_get_unique_session_token(module);
254 dn = dsdb_audit_get_primary_dn(request);
255 operation = dsdb_audit_get_operation_name(request);
257 audit = json_new_object();
258 if (json_is_invalid(&audit)) {
261 rc = json_add_version(&audit, OPERATION_MAJOR, OPERATION_MINOR);
265 rc = json_add_int(&audit, "statusCode", reply->error);
269 rc = json_add_string(&audit, "status", ldb_strerror(reply->error));
273 rc = json_add_string(&audit, "operation", operation);
277 rc = json_add_address(&audit, "remoteAddress", remote);
281 rc = json_add_bool(&audit, "performedAsSystem", as_system);
285 rc = json_add_sid(&audit, "userSid", sid);
289 rc = json_add_string(&audit, "dn", dn);
294 &audit, "transactionId", &audit_private->transaction_guid);
298 rc = json_add_guid(&audit, "sessionId", unique_session_token);
303 message = dsdb_audit_get_message(request);
304 if (message != NULL) {
305 struct json_object attributes =
306 dsdb_audit_attributes_json(
309 if (json_is_invalid(&attributes)) {
312 rc = json_add_object(&audit, "attributes", &attributes);
318 wrapper = json_new_object();
319 if (json_is_invalid(&wrapper)) {
322 rc = json_add_timestamp(&wrapper);
326 rc = json_add_string(&wrapper, "type", OPERATION_JSON_TYPE);
330 rc = json_add_object(&wrapper, OPERATION_JSON_TYPE, &audit);
338 * On a failure audit will not have been added to wrapper so it
339 * needs to free it to avoid a leak.
341 * wrapper is freed to invalidate it as it will have only been
342 * partially constructed and may be inconsistent.
344 * All the json manipulation routines handle a freed object correctly
348 DBG_ERR("Unable to create ldb operation JSON audit message\n");
353 * @brief generate a JSON object detailing a replicated update.
355 * Generate a JSON object detailing a replicated update
357 * @param module the ldb module
358 * @param request the request
359 * @paran reply the result of the operation
361 * @return the generated JSON object, should be freed with json_free.
362 * NULL if there was an error generating the message.
365 static struct json_object replicated_update_json(
366 struct ldb_module *module,
367 const struct ldb_request *request,
368 const struct ldb_reply *reply)
370 struct json_object wrapper = json_empty_object;
371 struct json_object audit = json_empty_object;
372 struct audit_private *audit_private
373 = talloc_get_type_abort(ldb_module_get_private(module),
374 struct audit_private);
375 struct dsdb_extended_replicated_objects *ro = talloc_get_type(
376 request->op.extended.data,
377 struct dsdb_extended_replicated_objects);
378 const char *partition_dn = NULL;
379 const char *error = NULL;
382 partition_dn = ldb_dn_get_linearized(ro->partition_dn);
383 error = get_friendly_werror_msg(ro->error);
385 audit = json_new_object();
386 if (json_is_invalid(&audit)) {
389 rc = json_add_version(&audit, REPLICATION_MAJOR, REPLICATION_MINOR);
393 rc = json_add_int(&audit, "statusCode", reply->error);
397 rc = json_add_string(&audit, "status", ldb_strerror(reply->error));
402 &audit, "transactionId", &audit_private->transaction_guid);
406 rc = json_add_int(&audit, "objectCount", ro->num_objects);
410 rc = json_add_int(&audit, "linkCount", ro->linked_attributes_count);
414 rc = json_add_string(&audit, "partitionDN", partition_dn);
418 rc = json_add_string(&audit, "error", error);
422 rc = json_add_int(&audit, "errorCode", W_ERROR_V(ro->error));
427 &audit, "sourceDsa", &ro->source_dsa->source_dsa_obj_guid);
432 &audit, "invocationId", &ro->source_dsa->source_dsa_invocation_id);
437 wrapper = json_new_object();
438 if (json_is_invalid(&wrapper)) {
441 rc = json_add_timestamp(&wrapper);
445 rc = json_add_string(&wrapper, "type", REPLICATION_JSON_TYPE);
449 rc = json_add_object(&wrapper, REPLICATION_JSON_TYPE, &audit);
456 * On a failure audit will not have been added to wrapper so it
457 * needs to be freed it to avoid a leak.
459 * wrapper is freed to invalidate it as it will have only been
460 * partially constructed and may be inconsistent.
462 * All the json manipulation routines handle a freed object correctly
466 DBG_ERR("Unable to create replicated update JSON audit message\n");
471 * @brief generate a JSON object detailing a password change.
473 * Generate a JSON object detailing a password change.
475 * @param module the ldb module
476 * @param request the request
477 * @param reply the result/response
478 * @param status the status code returned for the underlying ldb operation.
480 * @return the generated JSON object.
483 static struct json_object password_change_json(
484 struct ldb_module *module,
485 const struct ldb_request *request,
486 const struct ldb_reply *reply)
488 struct ldb_context *ldb = NULL;
489 const struct dom_sid *sid = NULL;
490 const char *dn = NULL;
491 struct json_object wrapper = json_empty_object;
492 struct json_object audit = json_empty_object;
493 const struct tsocket_address *remote = NULL;
494 const char* action = NULL;
495 const struct GUID *unique_session_token = NULL;
496 struct audit_private *audit_private
497 = talloc_get_type_abort(ldb_module_get_private(module),
498 struct audit_private);
500 enum event_id_type event_id;
502 ldb = ldb_module_get_ctx(module);
504 remote = dsdb_audit_get_remote_address(ldb);
505 sid = dsdb_audit_get_user_sid(module);
506 dn = dsdb_audit_get_primary_dn(request);
507 action = get_password_action(request, reply);
508 unique_session_token = dsdb_audit_get_unique_session_token(module);
509 event_id = get_password_windows_event_id(request, reply);
511 audit = json_new_object();
512 if (json_is_invalid(&audit)) {
515 rc = json_add_version(&audit, PASSWORD_MAJOR, PASSWORD_MINOR);
519 rc = json_add_int(&audit, "eventId", event_id);
523 rc = json_add_int(&audit, "statusCode", reply->error);
527 rc = json_add_string(&audit, "status", ldb_strerror(reply->error));
531 rc = json_add_address(&audit, "remoteAddress", remote);
535 rc = json_add_sid(&audit, "userSid", sid);
539 rc = json_add_string(&audit, "dn", dn);
543 rc = json_add_string(&audit, "action", action);
548 &audit, "transactionId", &audit_private->transaction_guid);
552 rc = json_add_guid(&audit, "sessionId", unique_session_token);
557 wrapper = json_new_object();
558 if (json_is_invalid(&wrapper)) {
561 rc = json_add_timestamp(&wrapper);
565 rc = json_add_string(&wrapper, "type", PASSWORD_JSON_TYPE);
569 rc = json_add_object(&wrapper, PASSWORD_JSON_TYPE, &audit);
577 * On a failure audit will not have been added to wrapper so it
578 * needs to free it to avoid a leak.
580 * wrapper is freed to invalidate it as it will have only been
581 * partially constructed and may be inconsistent.
583 * All the json manipulation routines handle a freed object correctly
587 DBG_ERR("Unable to create password change JSON audit message\n");
593 * @brief create a JSON object containing details of a transaction event.
595 * Create a JSON object detailing a transaction transaction life cycle events,
596 * i.e. begin, commit, roll back
598 * @param action a one word description of the event/action
599 * @param transaction_id the GUID identifying the current transaction.
600 * @param status the status code returned by the operation
601 * @param duration the duration of the operation.
603 * @return a JSON object detailing the event
605 static struct json_object transaction_json(
607 struct GUID *transaction_id,
608 const int64_t duration)
610 struct json_object wrapper = json_empty_object;
611 struct json_object audit = json_empty_object;
614 audit = json_new_object();
615 if (json_is_invalid(&audit)) {
619 rc = json_add_version(&audit, TRANSACTION_MAJOR, TRANSACTION_MINOR);
623 rc = json_add_string(&audit, "action", action);
627 rc = json_add_guid(&audit, "transactionId", transaction_id);
631 rc = json_add_int(&audit, "duration", duration);
636 wrapper = json_new_object();
637 if (json_is_invalid(&wrapper)) {
640 rc = json_add_timestamp(&wrapper);
644 rc = json_add_string(&wrapper, "type", TRANSACTION_JSON_TYPE);
648 rc = json_add_object(&wrapper, TRANSACTION_JSON_TYPE, &audit);
656 * On a failure audit will not have been added to wrapper so it
657 * needs to free it to avoid a leak.
659 * wrapper is freed to invalidate it as it will have only been
660 * partially constructed and may be inconsistent.
662 * All the json manipulation routines handle a freed object correctly
666 DBG_ERR("Unable to create transaction JSON audit message\n");
672 * @brief generate a JSON object detailing a commit failure.
674 * Generate a JSON object containing details of a commit failure.
676 * @param action the commit action, "commit" or "prepare"
677 * @param status the status code returned by commit
678 * @param reason any extra failure information/reason available
679 * @param transaction_id the GUID identifying the current transaction.
681 static struct json_object commit_failure_json(
683 const int64_t duration,
686 struct GUID *transaction_id)
688 struct json_object wrapper = json_empty_object;
689 struct json_object audit = json_empty_object;
692 audit = json_new_object();
693 if (json_is_invalid(&audit)) {
696 rc = json_add_version(&audit, TRANSACTION_MAJOR, TRANSACTION_MINOR);
700 rc = json_add_string(&audit, "action", action);
704 rc = json_add_guid(&audit, "transactionId", transaction_id);
708 rc = json_add_int(&audit, "duration", duration);
712 rc = json_add_int(&audit, "statusCode", status);
716 rc = json_add_string(&audit, "status", ldb_strerror(status));
720 rc = json_add_string(&audit, "reason", reason);
725 wrapper = json_new_object();
726 if (json_is_invalid(&wrapper)) {
729 rc = json_add_timestamp(&wrapper);
733 rc = json_add_string(&wrapper, "type", TRANSACTION_JSON_TYPE);
737 rc = json_add_object(&wrapper, TRANSACTION_JSON_TYPE, &audit);
745 * On a failure audit will not have been added to wrapper so it
746 * needs to free it to avoid a leak.
748 * wrapper is freed to invalidate it as it will have only been
749 * partially constructed and may be inconsistent.
751 * All the json manipulation routines handle a freed object correctly
755 DBG_ERR("Unable to create commit failure JSON audit message\n");
760 * @brief Print a human readable log line for a password change event.
762 * Generate a human readable log line detailing a password change.
764 * @param mem_ctx The talloc context that will own the generated log line.
765 * @param module the ldb module
766 * @param request the request
767 * @param reply the result/response
768 * @param status the status code returned for the underlying ldb operation.
770 * @return the generated log line.
772 static char *password_change_human_readable(
774 struct ldb_module *module,
775 const struct ldb_request *request,
776 const struct ldb_reply *reply)
778 struct ldb_context *ldb = NULL;
779 const char *remote_host = NULL;
780 const struct dom_sid *sid = NULL;
781 struct dom_sid_buf user_sid;
782 const char *timestamp = NULL;
783 char *log_entry = NULL;
784 const char *action = NULL;
785 const char *dn = NULL;
787 TALLOC_CTX *ctx = talloc_new(NULL);
789 ldb = ldb_module_get_ctx(module);
791 remote_host = dsdb_audit_get_remote_host(ldb, ctx);
792 sid = dsdb_audit_get_user_sid(module);
793 timestamp = audit_get_timestamp(ctx);
794 action = get_password_action(request, reply);
795 dn = dsdb_audit_get_primary_dn(request);
797 log_entry = talloc_asprintf(
799 "[%s] at [%s] status [%s] "
800 "remote host [%s] SID [%s] DN [%s]",
803 ldb_strerror(reply->error),
805 dom_sid_str_buf(sid, &user_sid),
811 * @brief Generate a human readable string, detailing attributes in a message
813 * For modify operations each attribute is prefixed with the action.
814 * Normal values are enclosed in []
815 * Base64 values are enclosed in {}
816 * Truncated values are indicated by three trailing dots "..."
818 * @param ldb The ldb_context
819 * @param buffer The attributes will be appended to the buffer.
820 * assumed to have been allocated via talloc.
821 * @param operation The operation type
822 * @param message the message to process
825 static char *log_attributes(
826 struct ldb_context *ldb,
828 enum ldb_request_type operation,
829 const struct ldb_message *message)
832 for (i=0;i<message->num_elements;i++) {
834 buffer = talloc_asprintf_append_buffer(buffer, " ");
837 if (message->elements[i].name == NULL) {
841 "Error: Invalid element name (NULL) at "
846 if (operation == LDB_MODIFY) {
847 const char *action =NULL;
848 action = dsdb_audit_get_modification_action(
849 message->elements[i].flags);
850 buffer = talloc_asprintf_append_buffer(
854 message->elements[i].name);
856 buffer = talloc_asprintf_append_buffer(
859 message->elements[i].name);
862 if (dsdb_audit_redact_attribute(message->elements[i].name)) {
864 * Do not log the value of any secret or password
867 buffer = talloc_asprintf_append_buffer(
869 "[REDACTED SECRET ATTRIBUTE]");
873 for (j=0;j<message->elements[i].num_values;j++) {
875 bool use_b64_encode = false;
878 buffer = talloc_asprintf_append_buffer(
883 v = message->elements[i].values[j];
884 length = min(MAX_LENGTH, v.length);
885 use_b64_encode = ldb_should_b64_encode(ldb, &v);
886 if (use_b64_encode) {
887 const char *encoded = ldb_base64_encode(
891 buffer = talloc_asprintf_append_buffer(
895 (v.length > MAX_LENGTH ? "..." : ""));
897 buffer = talloc_asprintf_append_buffer(
903 (v.length > MAX_LENGTH ? "..." : ""));
911 * @brief generate a human readable log entry detailing an ldb operation.
913 * Generate a human readable log entry detailing an ldb operation.
915 * @param mem_ctx The talloc context owning the returned string.
916 * @param module the ldb module
917 * @param request the request
918 * @param reply the result of the operation
920 * @return the log entry.
923 static char *operation_human_readable(
925 struct ldb_module *module,
926 const struct ldb_request *request,
927 const struct ldb_reply *reply)
929 struct ldb_context *ldb = NULL;
930 const char *remote_host = NULL;
931 const struct dom_sid *sid = NULL;
932 struct dom_sid_buf user_sid;
933 const char *timestamp = NULL;
934 const char *op_name = NULL;
935 char *log_entry = NULL;
936 const char *dn = NULL;
937 const char *new_dn = NULL;
938 const struct ldb_message *message = NULL;
940 TALLOC_CTX *ctx = talloc_new(NULL);
942 ldb = ldb_module_get_ctx(module);
944 remote_host = dsdb_audit_get_remote_host(ldb, ctx);
945 if (remote_host != NULL && dsdb_audit_is_system_session(module)) {
946 sid = dsdb_audit_get_actual_sid(ldb);
948 sid = dsdb_audit_get_user_sid(module);
950 timestamp = audit_get_timestamp(ctx);
951 op_name = dsdb_audit_get_operation_name(request);
952 dn = dsdb_audit_get_primary_dn(request);
953 new_dn = dsdb_audit_get_secondary_dn(request);
955 message = dsdb_audit_get_message(request);
957 log_entry = talloc_asprintf(
959 "[%s] at [%s] status [%s] "
960 "remote host [%s] SID [%s] DN [%s]",
963 ldb_strerror(reply->error),
965 dom_sid_str_buf(sid, &user_sid),
967 if (new_dn != NULL) {
968 log_entry = talloc_asprintf_append_buffer(
973 if (message != NULL) {
974 log_entry = talloc_asprintf_append_buffer(log_entry,
976 log_entry = log_attributes(ldb,
980 log_entry = talloc_asprintf_append_buffer(log_entry, "]");
987 * @brief generate a human readable log entry detailing a replicated update
990 * Generate a human readable log entry detailing a replicated update operation
992 * @param mem_ctx The talloc context owning the returned string.
993 * @param module the ldb module
994 * @param request the request
995 * @param reply the result of the operation.
997 * @return the log entry.
1000 static char *replicated_update_human_readable(
1001 TALLOC_CTX *mem_ctx,
1002 struct ldb_module *module,
1003 const struct ldb_request *request,
1004 const struct ldb_reply *reply)
1006 struct dsdb_extended_replicated_objects *ro = talloc_get_type(
1007 request->op.extended.data,
1008 struct dsdb_extended_replicated_objects);
1009 const char *partition_dn = NULL;
1010 const char *error = NULL;
1011 char *log_entry = NULL;
1012 char *timestamp = NULL;
1013 struct GUID_txt_buf object_buf;
1014 const char *object = NULL;
1015 struct GUID_txt_buf invocation_buf;
1016 const char *invocation = NULL;
1019 TALLOC_CTX *ctx = talloc_new(NULL);
1021 timestamp = audit_get_timestamp(ctx);
1022 error = get_friendly_werror_msg(ro->error);
1023 partition_dn = ldb_dn_get_linearized(ro->partition_dn);
1024 object = GUID_buf_string(
1025 &ro->source_dsa->source_dsa_obj_guid,
1027 invocation = GUID_buf_string(
1028 &ro->source_dsa->source_dsa_invocation_id,
1032 log_entry = talloc_asprintf(
1034 "at [%s] status [%s] error [%s] partition [%s] objects [%d] "
1035 "links [%d] object [%s] invocation [%s]",
1037 ldb_strerror(reply->error),
1041 ro->linked_attributes_count,
1049 * @brief create a human readable log entry detailing a transaction event.
1051 * Create a human readable log entry detailing a transaction event.
1052 * i.e. begin, commit, roll back
1054 * @param mem_ctx The talloc context owning the returned string.
1055 * @param action a one word description of the event/action
1056 * @param duration the duration of the transaction.
1058 * @return the log entry
1060 static char *transaction_human_readable(
1061 TALLOC_CTX *mem_ctx,
1063 const int64_t duration)
1065 const char *timestamp = NULL;
1066 char *log_entry = NULL;
1068 TALLOC_CTX *ctx = talloc_new(NULL);
1070 timestamp = audit_get_timestamp(ctx);
1072 log_entry = talloc_asprintf(
1074 "[%s] at [%s] duration [%"PRIi64"]",
1084 * @brief generate a human readable log entry detailing a commit failure.
1086 * Generate generate a human readable log entry detailing a commit failure.
1088 * @param mem_ctx The talloc context owning the returned string.
1089 * @param action the commit action, "prepare" or "commit"
1090 * @param status the status code returned by commit
1091 * @param reason any extra failure information/reason available
1093 * @return the log entry
1095 static char *commit_failure_human_readable(
1096 TALLOC_CTX *mem_ctx,
1098 const int64_t duration,
1102 const char *timestamp = NULL;
1103 char *log_entry = NULL;
1105 TALLOC_CTX *ctx = talloc_new(NULL);
1107 timestamp = audit_get_timestamp(ctx);
1109 log_entry = talloc_asprintf(
1111 "[%s] at [%s] duration [%"PRIi64"] status [%d] reason [%s]",
1123 * @brief log details of a standard ldb operation.
1125 * Log the details of an ldb operation in JSON and or human readable format
1126 * and send over the message bus.
1128 * @param module the ldb_module
1129 * @param request the operation request.
1130 * @param reply the operation result.
1131 * @param the status code returned for the operation.
1134 static void log_standard_operation(
1135 struct ldb_module *module,
1136 const struct ldb_request *request,
1137 const struct ldb_reply *reply)
1140 const struct ldb_message *message = dsdb_audit_get_message(request);
1141 bool password_changed = has_password_changed(message);
1142 struct audit_private *audit_private =
1143 talloc_get_type_abort(ldb_module_get_private(module),
1144 struct audit_private);
1146 TALLOC_CTX *ctx = talloc_new(NULL);
1148 if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT, OPERATION_LOG_LVL)) {
1150 entry = operation_human_readable(
1155 audit_log_human_text(
1162 if (CHECK_DEBUGLVLC(DBGC_DSDB_PWD_AUDIT, PASSWORD_LOG_LVL)) {
1163 if (password_changed) {
1165 entry = password_change_human_readable(
1170 audit_log_human_text(
1173 DBGC_DSDB_PWD_AUDIT,
1178 if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT_JSON, OPERATION_LOG_LVL) ||
1179 (audit_private->msg_ctx
1180 && audit_private->send_samdb_events)) {
1181 struct json_object json;
1182 json = operation_json(module, request, reply);
1185 DBGC_DSDB_AUDIT_JSON,
1187 if (audit_private->msg_ctx
1188 && audit_private->send_samdb_events) {
1190 audit_private->msg_ctx,
1197 if (CHECK_DEBUGLVLC(DBGC_DSDB_PWD_AUDIT_JSON, PASSWORD_LOG_LVL) ||
1198 (audit_private->msg_ctx
1199 && audit_private->send_password_events)) {
1200 if (password_changed) {
1201 struct json_object json;
1202 json = password_change_json(module, request, reply);
1205 DBGC_DSDB_PWD_AUDIT_JSON,
1207 if (audit_private->send_password_events) {
1209 audit_private->msg_ctx,
1210 DSDB_PWD_EVENT_NAME,
1221 * @brief log details of a replicated update.
1223 * Log the details of a replicated update in JSON and or human readable
1224 * format and send over the message bus.
1226 * @param module the ldb_module
1227 * @param request the operation request
1228 * @param reply the result of the operation.
1231 static void log_replicated_operation(
1232 struct ldb_module *module,
1233 const struct ldb_request *request,
1234 const struct ldb_reply *reply)
1237 struct audit_private *audit_private =
1238 talloc_get_type_abort(ldb_module_get_private(module),
1239 struct audit_private);
1241 TALLOC_CTX *ctx = talloc_new(NULL);
1243 if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT, REPLICATION_LOG_LVL)) {
1245 entry = replicated_update_human_readable(
1250 audit_log_human_text(
1254 REPLICATION_LOG_LVL);
1257 if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT_JSON, REPLICATION_LOG_LVL) ||
1258 (audit_private->msg_ctx && audit_private->send_samdb_events)) {
1259 struct json_object json;
1260 json = replicated_update_json(module, request, reply);
1263 DBGC_DSDB_AUDIT_JSON,
1264 REPLICATION_LOG_LVL);
1265 if (audit_private->send_samdb_events) {
1267 audit_private->msg_ctx,
1278 * @brief log details of an ldb operation.
1280 * Log the details of an ldb operation in JSON and or human readable format
1281 * and send over the message bus.
1283 * @param module the ldb_module
1284 * @param request the operation request
1285 * @part reply the result of the operation
1288 static void log_operation(
1289 struct ldb_module *module,
1290 const struct ldb_request *request,
1291 const struct ldb_reply *reply)
1294 if (request->operation == LDB_EXTENDED) {
1296 request->op.extended.oid,
1297 DSDB_EXTENDED_REPLICATED_OBJECTS_OID) != 0) {
1299 log_replicated_operation(module, request, reply);
1302 log_standard_operation(module, request, reply);
1307 * @brief log details of a transaction event.
1309 * Log the details of a transaction event in JSON and or human readable format
1310 * and send over the message bus.
1312 * @param module the ldb_module
1313 * @param action the transaction event i.e. begin, commit, roll back.
1314 * @param log_level the logging level
1317 static void log_transaction(
1318 struct ldb_module *module,
1323 struct audit_private *audit_private =
1324 talloc_get_type_abort(ldb_module_get_private(module),
1325 struct audit_private);
1326 const struct timeval now = timeval_current();
1327 const int64_t duration = usec_time_diff(&now, &audit_private->transaction_start);
1329 TALLOC_CTX *ctx = talloc_new(NULL);
1331 if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT, log_level)) {
1333 entry = transaction_human_readable(ctx, action, duration);
1334 audit_log_human_text(
1337 DBGC_DSDB_TXN_AUDIT,
1341 if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT_JSON, log_level) ||
1342 (audit_private->msg_ctx && audit_private->send_samdb_events)) {
1343 struct json_object json;
1344 json = transaction_json(
1346 &audit_private->transaction_guid,
1350 DBGC_DSDB_TXN_AUDIT_JSON,
1352 if (audit_private->send_samdb_events) {
1354 audit_private->msg_ctx,
1365 * @brief log details of a commit failure.
1367 * Log the details of a commit failure in JSON and or human readable
1368 * format and send over the message bus.
1370 * @param module the ldb_module
1371 * @param action the commit action "prepare" or "commit"
1372 * @param status the ldb status code returned by prepare commit.
1375 static void log_commit_failure(
1376 struct ldb_module *module,
1381 struct audit_private *audit_private =
1382 talloc_get_type_abort(ldb_module_get_private(module),
1383 struct audit_private);
1384 const char* reason = dsdb_audit_get_ldb_error_string(module, status);
1385 const int log_level = TRANSACTION_LOG_FAILURE_LVL;
1386 const struct timeval now = timeval_current();
1387 const int64_t duration = usec_time_diff(&now,
1388 &audit_private->transaction_start);
1390 TALLOC_CTX *ctx = talloc_new(NULL);
1392 if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT, log_level)) {
1395 entry = commit_failure_human_readable(
1401 audit_log_human_text(
1404 DBGC_DSDB_TXN_AUDIT,
1405 TRANSACTION_LOG_FAILURE_LVL);
1408 if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT_JSON, log_level) ||
1409 (audit_private->msg_ctx
1410 && audit_private->send_samdb_events)) {
1411 struct json_object json;
1412 json = commit_failure_json(
1417 &audit_private->transaction_guid);
1420 DBGC_DSDB_TXN_AUDIT_JSON,
1422 if (audit_private->send_samdb_events) {
1423 audit_message_send(audit_private->msg_ctx,
1434 * Context needed by audit_callback
1436 struct audit_callback_context {
1437 struct ldb_request *request;
1438 struct ldb_module *module;
1442 * @brief call back function for the ldb_operations.
1444 * As the LDB operations are async, and we wish to examine the results of
1445 * the operations, a callback needs to be registered to process the results
1446 * of the LDB operations.
1448 * @param req the ldb request
1449 * @param res the result of the operation
1451 * @return the LDB_STATUS
1453 static int audit_callback(struct ldb_request *req, struct ldb_reply *ares)
1455 struct audit_callback_context *ac = NULL;
1457 ac = talloc_get_type(
1459 struct audit_callback_context);
1462 return ldb_module_done(
1466 LDB_ERR_OPERATIONS_ERROR);
1469 /* pass on to the callback */
1470 switch (ares->type) {
1471 case LDB_REPLY_ENTRY:
1472 return ldb_module_send_entry(
1477 case LDB_REPLY_REFERRAL:
1478 return ldb_module_send_referral(
1482 case LDB_REPLY_DONE:
1484 * Log the operation once DONE
1486 log_operation(ac->module, ac->request, ares);
1487 return ldb_module_done(
1495 return LDB_ERR_OPERATIONS_ERROR;
1500 * @brief Add the current transaction identifier to the request.
1502 * Add the current transaction identifier in the module private data,
1503 * to the request as a control.
1506 * @param req the request.
1508 * @return an LDB_STATUS code, LDB_SUCCESS if successful.
1510 static int add_transaction_id(
1511 struct ldb_module *module,
1512 struct ldb_request *req)
1514 struct audit_private *audit_private =
1515 talloc_get_type_abort(ldb_module_get_private(module),
1516 struct audit_private);
1517 struct dsdb_control_transaction_identifier *transaction_id;
1520 transaction_id = talloc_zero(
1522 struct dsdb_control_transaction_identifier);
1523 if (transaction_id == NULL) {
1524 struct ldb_context *ldb = ldb_module_get_ctx(module);
1525 return ldb_oom(ldb);
1527 transaction_id->transaction_guid = audit_private->transaction_guid;
1528 ret = ldb_request_add_control(req,
1529 DSDB_CONTROL_TRANSACTION_IDENTIFIER_OID,
1537 * @brief log details of an add operation.
1539 * Log the details of an add operation.
1541 * @param module the ldb_module
1542 * @param req the ldb_request
1544 * @return ldb status code
1547 struct ldb_module *module,
1548 struct ldb_request *req)
1550 struct audit_callback_context *context = NULL;
1551 struct ldb_request *new_req = NULL;
1552 struct ldb_context *ldb = NULL;
1555 ldb = ldb_module_get_ctx(module);
1556 context = talloc_zero(req, struct audit_callback_context);
1558 if (context == NULL) {
1559 return ldb_oom(ldb);
1561 context->request = req;
1562 context->module = module;
1564 * We want to log the return code status, so we need to register
1565 * a callback function to get the actual result.
1566 * We need to take a new copy so that we don't alter the callers copy
1568 ret = ldb_build_add_req(
1572 req->op.add.message,
1577 if (ret != LDB_SUCCESS) {
1580 ret = add_transaction_id(module, new_req);
1581 if (ret != LDB_SUCCESS) {
1584 return ldb_next_request(module, new_req);
1588 * @brief log details of an delete operation.
1590 * Log the details of an delete operation.
1592 * @param module the ldb_module
1593 * @param req the ldb_request
1595 * @return ldb status code
1597 static int log_delete(
1598 struct ldb_module *module,
1599 struct ldb_request *req)
1601 struct audit_callback_context *context = NULL;
1602 struct ldb_request *new_req = NULL;
1603 struct ldb_context *ldb = NULL;
1606 ldb = ldb_module_get_ctx(module);
1607 context = talloc_zero(req, struct audit_callback_context);
1609 if (context == NULL) {
1610 return ldb_oom(ldb);
1612 context->request = req;
1613 context->module = module;
1615 * We want to log the return code status, so we need to register
1616 * a callback function to get the actual result.
1617 * We need to take a new copy so that we don't alter the callers copy
1619 ret = ldb_build_del_req(&new_req,
1627 if (ret != LDB_SUCCESS) {
1630 ret = add_transaction_id(module, new_req);
1631 if (ret != LDB_SUCCESS) {
1634 return ldb_next_request(module, new_req);
1638 * @brief log details of a modify operation.
1640 * Log the details of a modify operation.
1642 * @param module the ldb_module
1643 * @param req the ldb_request
1645 * @return ldb status code
1647 static int log_modify(
1648 struct ldb_module *module,
1649 struct ldb_request *req)
1651 struct audit_callback_context *context = NULL;
1652 struct ldb_request *new_req = NULL;
1653 struct ldb_context *ldb = NULL;
1656 ldb = ldb_module_get_ctx(module);
1657 context = talloc_zero(req, struct audit_callback_context);
1659 if (context == NULL) {
1660 return ldb_oom(ldb);
1662 context->request = req;
1663 context->module = module;
1665 * We want to log the return code status, so we need to register
1666 * a callback function to get the actual result.
1667 * We need to take a new copy so that we don't alter the callers copy
1669 ret = ldb_build_mod_req(
1673 req->op.mod.message,
1678 if (ret != LDB_SUCCESS) {
1681 ret = add_transaction_id(module, new_req);
1682 if (ret != LDB_SUCCESS) {
1685 return ldb_next_request(module, new_req);
1689 * @brief process a transaction start.
1691 * process a transaction start, as we don't currently log transaction starts
1692 * just generate the new transaction_id.
1694 * @param module the ldb_module
1695 * @param req the ldb_request
1697 * @return ldb status code
1699 static int log_start_transaction(struct ldb_module *module)
1701 struct audit_private *audit_private =
1702 talloc_get_type_abort(ldb_module_get_private(module),
1703 struct audit_private);
1706 * We do not log transaction begins
1707 * however we do generate a new transaction_id and record the start
1708 * time so that we can log the transaction duration.
1711 audit_private->transaction_guid = GUID_random();
1712 audit_private->transaction_start = timeval_current();
1713 return ldb_next_start_trans(module);
1717 * @brief log details of a prepare commit.
1719 * Log the details of a prepare commit, currently only details of
1720 * failures are logged.
1722 * @param module the ldb_module
1723 * @param req the ldb_request
1725 * @return ldb status code
1727 static int log_prepare_commit(struct ldb_module *module)
1730 int ret = ldb_next_prepare_commit(module);
1731 if (ret != LDB_SUCCESS) {
1733 * We currently only log prepare commit failures
1735 log_commit_failure(module, "prepare", ret);
1741 * @brief process a transaction end aka commit.
1743 * process a transaction end, as we don't currently log transaction ends
1744 * just clear transaction_id.
1746 * @param module the ldb_module
1747 * @param req the ldb_request
1749 * @return ldb status code
1751 static int log_end_transaction(struct ldb_module *module)
1753 struct audit_private *audit_private =
1754 talloc_get_type_abort(ldb_module_get_private(module),
1755 struct audit_private);
1759 ret = ldb_next_end_trans(module);
1760 if (ret == LDB_SUCCESS) {
1764 TRANSACTION_LOG_COMPLETION_LVL);
1766 log_commit_failure(module, "commit", ret);
1769 * Clear the transaction id inserted by log_start_transaction
1771 audit_private->transaction_guid = GUID_zero();
1776 * @brief log details of a transaction delete aka roll back.
1778 * Log details of a transaction roll back.
1780 * @param module the ldb_module
1781 * @param req the ldb_request
1783 * @return ldb status code
1785 static int log_del_transaction(struct ldb_module *module)
1787 struct audit_private *audit_private =
1788 talloc_get_type_abort(ldb_module_get_private(module),
1789 struct audit_private);
1791 log_transaction(module, "rollback", TRANSACTION_LOG_FAILURE_LVL);
1792 audit_private->transaction_guid = GUID_zero();
1793 return ldb_next_del_trans(module);
1797 * @brief log details of an extended operation.
1799 * Log the details of an extended operation.
1801 * @param module the ldb_module
1802 * @param req the ldb_request
1804 * @return ldb status code
1806 static int log_extended(
1807 struct ldb_module *module,
1808 struct ldb_request *req)
1810 struct audit_callback_context *context = NULL;
1811 struct ldb_request *new_req = NULL;
1812 struct ldb_context *ldb = NULL;
1816 * Currently we only log replication extended operations
1819 req->op.extended.oid,
1820 DSDB_EXTENDED_REPLICATED_OBJECTS_OID) != 0) {
1822 return ldb_next_request(module, req);
1824 ldb = ldb_module_get_ctx(module);
1825 context = talloc_zero(req, struct audit_callback_context);
1827 if (context == NULL) {
1828 return ldb_oom(ldb);
1830 context->request = req;
1831 context->module = module;
1833 * We want to log the return code status, so we need to register
1834 * a callback function to get the actual result.
1835 * We need to take a new copy so that we don't alter the callers copy
1837 ret = ldb_build_extended_req(
1841 req->op.extended.oid,
1842 req->op.extended.data,
1847 if (ret != LDB_SUCCESS) {
1850 ret = add_transaction_id(module, new_req);
1851 if (ret != LDB_SUCCESS) {
1854 return ldb_next_request(module, new_req);
1858 * @brief module initialisation
1860 static int log_init(struct ldb_module *module)
1863 struct ldb_context *ldb = ldb_module_get_ctx(module);
1864 struct audit_private *audit_private = NULL;
1865 struct loadparm_context *lp_ctx
1866 = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
1867 struct loadparm_context);
1868 struct tevent_context *ev = ldb_get_event_context(ldb);
1869 bool sdb_events = false;
1870 bool pwd_events = false;
1872 audit_private = talloc_zero(module, struct audit_private);
1873 if (audit_private == NULL) {
1874 return ldb_module_oom(module);
1877 if (lp_ctx != NULL) {
1878 sdb_events = lpcfg_dsdb_event_notification(lp_ctx);
1879 pwd_events = lpcfg_dsdb_password_event_notification(lp_ctx);
1881 if (sdb_events || pwd_events) {
1882 audit_private->send_samdb_events = sdb_events;
1883 audit_private->send_password_events = pwd_events;
1884 audit_private->msg_ctx
1885 = imessaging_client_init(audit_private,
1890 ldb_module_set_private(module, audit_private);
1891 return ldb_next_init(module);
1894 static const struct ldb_module_ops ldb_audit_log_module_ops = {
1895 .name = "audit_log",
1896 .init_context = log_init,
1898 .modify = log_modify,
1900 .start_transaction = log_start_transaction,
1901 .prepare_commit = log_prepare_commit,
1902 .end_transaction = log_end_transaction,
1903 .del_transaction = log_del_transaction,
1904 .extended = log_extended,
1907 int ldb_audit_log_module_init(const char *version)
1909 LDB_MODULE_CHECK_VERSION(version);
1910 return ldb_register_module(&ldb_audit_log_module_ops);