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 const char *user_sid = NULL;
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 user_sid = dom_sid_string(ctx, sid);
794 timestamp = audit_get_timestamp(ctx);
795 action = get_password_action(request, reply);
796 dn = dsdb_audit_get_primary_dn(request);
798 log_entry = talloc_asprintf(
800 "[%s] at [%s] status [%s] "
801 "remote host [%s] SID [%s] DN [%s]",
804 ldb_strerror(reply->error),
812 * @brief Generate a human readable string, detailing attributes in a message
814 * For modify operations each attribute is prefixed with the action.
815 * Normal values are enclosed in []
816 * Base64 values are enclosed in {}
817 * Truncated values are indicated by three trailing dots "..."
819 * @param ldb The ldb_context
820 * @param buffer The attributes will be appended to the buffer.
821 * assumed to have been allocated via talloc.
822 * @param operation The operation type
823 * @param message the message to process
826 static char *log_attributes(
827 struct ldb_context *ldb,
829 enum ldb_request_type operation,
830 const struct ldb_message *message)
833 for (i=0;i<message->num_elements;i++) {
835 buffer = talloc_asprintf_append_buffer(buffer, " ");
838 if (message->elements[i].name == NULL) {
842 "Error: Invalid element name (NULL) at "
847 if (operation == LDB_MODIFY) {
848 const char *action =NULL;
849 action = dsdb_audit_get_modification_action(
850 message->elements[i].flags);
851 buffer = talloc_asprintf_append_buffer(
855 message->elements[i].name);
857 buffer = talloc_asprintf_append_buffer(
860 message->elements[i].name);
863 if (dsdb_audit_redact_attribute(message->elements[i].name)) {
865 * Do not log the value of any secret or password
868 buffer = talloc_asprintf_append_buffer(
870 "[REDACTED SECRET ATTRIBUTE]");
874 for (j=0;j<message->elements[i].num_values;j++) {
876 bool use_b64_encode = false;
879 buffer = talloc_asprintf_append_buffer(
884 v = message->elements[i].values[j];
885 length = min(MAX_LENGTH, v.length);
886 use_b64_encode = ldb_should_b64_encode(ldb, &v);
887 if (use_b64_encode) {
888 const char *encoded = ldb_base64_encode(
892 buffer = talloc_asprintf_append_buffer(
896 (v.length > MAX_LENGTH ? "..." : ""));
898 buffer = talloc_asprintf_append_buffer(
904 (v.length > MAX_LENGTH ? "..." : ""));
912 * @brief generate a human readable log entry detailing an ldb operation.
914 * Generate a human readable log entry detailing an ldb operation.
916 * @param mem_ctx The talloc context owning the returned string.
917 * @param module the ldb module
918 * @param request the request
919 * @param reply the result of the operation
921 * @return the log entry.
924 static char *operation_human_readable(
926 struct ldb_module *module,
927 const struct ldb_request *request,
928 const struct ldb_reply *reply)
930 struct ldb_context *ldb = NULL;
931 const char *remote_host = NULL;
932 const struct dom_sid *sid = NULL;
933 const char *user_sid = NULL;
934 const char *timestamp = NULL;
935 const char *op_name = NULL;
936 char *log_entry = NULL;
937 const char *dn = NULL;
938 const char *new_dn = NULL;
939 const struct ldb_message *message = NULL;
941 TALLOC_CTX *ctx = talloc_new(NULL);
943 ldb = ldb_module_get_ctx(module);
945 remote_host = dsdb_audit_get_remote_host(ldb, ctx);
946 if (remote_host != NULL && dsdb_audit_is_system_session(module)) {
947 sid = dsdb_audit_get_actual_sid(ldb);
949 sid = dsdb_audit_get_user_sid(module);
951 user_sid = dom_sid_string(ctx, sid);
952 timestamp = audit_get_timestamp(ctx);
953 op_name = dsdb_audit_get_operation_name(request);
954 dn = dsdb_audit_get_primary_dn(request);
955 new_dn = dsdb_audit_get_secondary_dn(request);
957 message = dsdb_audit_get_message(request);
959 log_entry = talloc_asprintf(
961 "[%s] at [%s] status [%s] "
962 "remote host [%s] SID [%s] DN [%s]",
965 ldb_strerror(reply->error),
969 if (new_dn != NULL) {
970 log_entry = talloc_asprintf_append_buffer(
975 if (message != NULL) {
976 log_entry = talloc_asprintf_append_buffer(log_entry,
978 log_entry = log_attributes(ldb,
982 log_entry = talloc_asprintf_append_buffer(log_entry, "]");
989 * @brief generate a human readable log entry detailing a replicated update
992 * Generate a human readable log entry detailing a replicated update operation
994 * @param mem_ctx The talloc context owning the returned string.
995 * @param module the ldb module
996 * @param request the request
997 * @param reply the result of the operation.
999 * @return the log entry.
1002 static char *replicated_update_human_readable(
1003 TALLOC_CTX *mem_ctx,
1004 struct ldb_module *module,
1005 const struct ldb_request *request,
1006 const struct ldb_reply *reply)
1008 struct dsdb_extended_replicated_objects *ro = talloc_get_type(
1009 request->op.extended.data,
1010 struct dsdb_extended_replicated_objects);
1011 const char *partition_dn = NULL;
1012 const char *error = NULL;
1013 char *log_entry = NULL;
1014 char *timestamp = NULL;
1015 struct GUID_txt_buf object_buf;
1016 const char *object = NULL;
1017 struct GUID_txt_buf invocation_buf;
1018 const char *invocation = NULL;
1021 TALLOC_CTX *ctx = talloc_new(NULL);
1023 timestamp = audit_get_timestamp(ctx);
1024 error = get_friendly_werror_msg(ro->error);
1025 partition_dn = ldb_dn_get_linearized(ro->partition_dn);
1026 object = GUID_buf_string(
1027 &ro->source_dsa->source_dsa_obj_guid,
1029 invocation = GUID_buf_string(
1030 &ro->source_dsa->source_dsa_invocation_id,
1034 log_entry = talloc_asprintf(
1036 "at [%s] status [%s] error [%s] partition [%s] objects [%d] "
1037 "links [%d] object [%s] invocation [%s]",
1039 ldb_strerror(reply->error),
1043 ro->linked_attributes_count,
1051 * @brief create a human readable log entry detailing a transaction event.
1053 * Create a human readable log entry detailing a transaction event.
1054 * i.e. begin, commit, roll back
1056 * @param mem_ctx The talloc context owning the returned string.
1057 * @param action a one word description of the event/action
1058 * @param duration the duration of the transaction.
1060 * @return the log entry
1062 static char *transaction_human_readable(
1063 TALLOC_CTX *mem_ctx,
1065 const int64_t duration)
1067 const char *timestamp = NULL;
1068 char *log_entry = NULL;
1070 TALLOC_CTX *ctx = talloc_new(NULL);
1072 timestamp = audit_get_timestamp(ctx);
1074 log_entry = talloc_asprintf(
1076 "[%s] at [%s] duration [%"PRIi64"]",
1086 * @brief generate a human readable log entry detailing a commit failure.
1088 * Generate generate a human readable log entry detailing a commit failure.
1090 * @param mem_ctx The talloc context owning the returned string.
1091 * @param action the commit action, "prepare" or "commit"
1092 * @param status the status code returned by commit
1093 * @param reason any extra failure information/reason available
1095 * @return the log entry
1097 static char *commit_failure_human_readable(
1098 TALLOC_CTX *mem_ctx,
1100 const int64_t duration,
1104 const char *timestamp = NULL;
1105 char *log_entry = NULL;
1107 TALLOC_CTX *ctx = talloc_new(NULL);
1109 timestamp = audit_get_timestamp(ctx);
1111 log_entry = talloc_asprintf(
1113 "[%s] at [%s] duration [%"PRIi64"] status [%d] reason [%s]",
1125 * @brief log details of a standard ldb operation.
1127 * Log the details of an ldb operation in JSON and or human readable format
1128 * and send over the message bus.
1130 * @param module the ldb_module
1131 * @param request the operation request.
1132 * @param reply the operation result.
1133 * @param the status code returned for the operation.
1136 static void log_standard_operation(
1137 struct ldb_module *module,
1138 const struct ldb_request *request,
1139 const struct ldb_reply *reply)
1142 const struct ldb_message *message = dsdb_audit_get_message(request);
1143 bool password_changed = has_password_changed(message);
1144 struct audit_private *audit_private =
1145 talloc_get_type_abort(ldb_module_get_private(module),
1146 struct audit_private);
1148 TALLOC_CTX *ctx = talloc_new(NULL);
1150 if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT, OPERATION_LOG_LVL)) {
1152 entry = operation_human_readable(
1157 audit_log_human_text(
1164 if (CHECK_DEBUGLVLC(DBGC_DSDB_PWD_AUDIT, PASSWORD_LOG_LVL)) {
1165 if (password_changed) {
1167 entry = password_change_human_readable(
1172 audit_log_human_text(
1175 DBGC_DSDB_PWD_AUDIT,
1180 if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT_JSON, OPERATION_LOG_LVL) ||
1181 (audit_private->msg_ctx
1182 && audit_private->send_samdb_events)) {
1183 struct json_object json;
1184 json = operation_json(module, request, reply);
1187 DBGC_DSDB_AUDIT_JSON,
1189 if (audit_private->msg_ctx
1190 && audit_private->send_samdb_events) {
1192 audit_private->msg_ctx,
1199 if (CHECK_DEBUGLVLC(DBGC_DSDB_PWD_AUDIT_JSON, PASSWORD_LOG_LVL) ||
1200 (audit_private->msg_ctx
1201 && audit_private->send_password_events)) {
1202 if (password_changed) {
1203 struct json_object json;
1204 json = password_change_json(module, request, reply);
1207 DBGC_DSDB_PWD_AUDIT_JSON,
1209 if (audit_private->send_password_events) {
1211 audit_private->msg_ctx,
1212 DSDB_PWD_EVENT_NAME,
1223 * @brief log details of a replicated update.
1225 * Log the details of a replicated update in JSON and or human readable
1226 * format and send over the message bus.
1228 * @param module the ldb_module
1229 * @param request the operation request
1230 * @param reply the result of the operation.
1233 static void log_replicated_operation(
1234 struct ldb_module *module,
1235 const struct ldb_request *request,
1236 const struct ldb_reply *reply)
1239 struct audit_private *audit_private =
1240 talloc_get_type_abort(ldb_module_get_private(module),
1241 struct audit_private);
1243 TALLOC_CTX *ctx = talloc_new(NULL);
1245 if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT, REPLICATION_LOG_LVL)) {
1247 entry = replicated_update_human_readable(
1252 audit_log_human_text(
1256 REPLICATION_LOG_LVL);
1259 if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT_JSON, REPLICATION_LOG_LVL) ||
1260 (audit_private->msg_ctx && audit_private->send_samdb_events)) {
1261 struct json_object json;
1262 json = replicated_update_json(module, request, reply);
1265 DBGC_DSDB_AUDIT_JSON,
1266 REPLICATION_LOG_LVL);
1267 if (audit_private->send_samdb_events) {
1269 audit_private->msg_ctx,
1280 * @brief log details of an ldb operation.
1282 * Log the details of an ldb operation in JSON and or human readable format
1283 * and send over the message bus.
1285 * @param module the ldb_module
1286 * @param request the operation request
1287 * @part reply the result of the operation
1290 static void log_operation(
1291 struct ldb_module *module,
1292 const struct ldb_request *request,
1293 const struct ldb_reply *reply)
1296 if (request->operation == LDB_EXTENDED) {
1298 request->op.extended.oid,
1299 DSDB_EXTENDED_REPLICATED_OBJECTS_OID) != 0) {
1301 log_replicated_operation(module, request, reply);
1304 log_standard_operation(module, request, reply);
1309 * @brief log details of a transaction event.
1311 * Log the details of a transaction event in JSON and or human readable format
1312 * and send over the message bus.
1314 * @param module the ldb_module
1315 * @param action the transaction event i.e. begin, commit, roll back.
1316 * @param log_level the logging level
1319 static void log_transaction(
1320 struct ldb_module *module,
1325 struct audit_private *audit_private =
1326 talloc_get_type_abort(ldb_module_get_private(module),
1327 struct audit_private);
1328 const struct timeval now = timeval_current();
1329 const int64_t duration = usec_time_diff(&now, &audit_private->transaction_start);
1331 TALLOC_CTX *ctx = talloc_new(NULL);
1333 if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT, log_level)) {
1335 entry = transaction_human_readable(ctx, action, duration);
1336 audit_log_human_text(
1339 DBGC_DSDB_TXN_AUDIT,
1343 if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT_JSON, log_level) ||
1344 (audit_private->msg_ctx && audit_private->send_samdb_events)) {
1345 struct json_object json;
1346 json = transaction_json(
1348 &audit_private->transaction_guid,
1352 DBGC_DSDB_TXN_AUDIT_JSON,
1354 if (audit_private->send_samdb_events) {
1356 audit_private->msg_ctx,
1367 * @brief log details of a commit failure.
1369 * Log the details of a commit failure in JSON and or human readable
1370 * format and send over the message bus.
1372 * @param module the ldb_module
1373 * @param action the commit action "prepare" or "commit"
1374 * @param status the ldb status code returned by prepare commit.
1377 static void log_commit_failure(
1378 struct ldb_module *module,
1383 struct audit_private *audit_private =
1384 talloc_get_type_abort(ldb_module_get_private(module),
1385 struct audit_private);
1386 const char* reason = dsdb_audit_get_ldb_error_string(module, status);
1387 const int log_level = TRANSACTION_LOG_FAILURE_LVL;
1388 const struct timeval now = timeval_current();
1389 const int64_t duration = usec_time_diff(&now,
1390 &audit_private->transaction_start);
1392 TALLOC_CTX *ctx = talloc_new(NULL);
1394 if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT, log_level)) {
1397 entry = commit_failure_human_readable(
1403 audit_log_human_text(
1406 DBGC_DSDB_TXN_AUDIT,
1407 TRANSACTION_LOG_FAILURE_LVL);
1410 if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT_JSON, log_level) ||
1411 (audit_private->msg_ctx
1412 && audit_private->send_samdb_events)) {
1413 struct json_object json;
1414 json = commit_failure_json(
1419 &audit_private->transaction_guid);
1422 DBGC_DSDB_TXN_AUDIT_JSON,
1424 if (audit_private->send_samdb_events) {
1425 audit_message_send(audit_private->msg_ctx,
1436 * Context needed by audit_callback
1438 struct audit_callback_context {
1439 struct ldb_request *request;
1440 struct ldb_module *module;
1444 * @brief call back function for the ldb_operations.
1446 * As the LDB operations are async, and we wish to examine the results of
1447 * the operations, a callback needs to be registered to process the results
1448 * of the LDB operations.
1450 * @param req the ldb request
1451 * @param res the result of the operation
1453 * @return the LDB_STATUS
1455 static int audit_callback(struct ldb_request *req, struct ldb_reply *ares)
1457 struct audit_callback_context *ac = NULL;
1459 ac = talloc_get_type(
1461 struct audit_callback_context);
1464 return ldb_module_done(
1468 LDB_ERR_OPERATIONS_ERROR);
1471 /* pass on to the callback */
1472 switch (ares->type) {
1473 case LDB_REPLY_ENTRY:
1474 return ldb_module_send_entry(
1479 case LDB_REPLY_REFERRAL:
1480 return ldb_module_send_referral(
1484 case LDB_REPLY_DONE:
1486 * Log the operation once DONE
1488 log_operation(ac->module, ac->request, ares);
1489 return ldb_module_done(
1497 return LDB_ERR_OPERATIONS_ERROR;
1502 * @brief Add the current transaction identifier to the request.
1504 * Add the current transaction identifier in the module private data,
1505 * to the request as a control.
1508 * @param req the request.
1510 * @return an LDB_STATUS code, LDB_SUCCESS if successful.
1512 static int add_transaction_id(
1513 struct ldb_module *module,
1514 struct ldb_request *req)
1516 struct audit_private *audit_private =
1517 talloc_get_type_abort(ldb_module_get_private(module),
1518 struct audit_private);
1519 struct dsdb_control_transaction_identifier *transaction_id;
1522 transaction_id = talloc_zero(
1524 struct dsdb_control_transaction_identifier);
1525 if (transaction_id == NULL) {
1526 struct ldb_context *ldb = ldb_module_get_ctx(module);
1527 return ldb_oom(ldb);
1529 transaction_id->transaction_guid = audit_private->transaction_guid;
1530 ret = ldb_request_add_control(req,
1531 DSDB_CONTROL_TRANSACTION_IDENTIFIER_OID,
1539 * @brief log details of an add operation.
1541 * Log the details of an add operation.
1543 * @param module the ldb_module
1544 * @param req the ldb_request
1546 * @return ldb status code
1549 struct ldb_module *module,
1550 struct ldb_request *req)
1552 struct audit_callback_context *context = NULL;
1553 struct ldb_request *new_req = NULL;
1554 struct ldb_context *ldb = NULL;
1557 ldb = ldb_module_get_ctx(module);
1558 context = talloc_zero(req, struct audit_callback_context);
1560 if (context == NULL) {
1561 return ldb_oom(ldb);
1563 context->request = req;
1564 context->module = module;
1566 * We want to log the return code status, so we need to register
1567 * a callback function to get the actual result.
1568 * We need to take a new copy so that we don't alter the callers copy
1570 ret = ldb_build_add_req(
1574 req->op.add.message,
1579 if (ret != LDB_SUCCESS) {
1582 ret = add_transaction_id(module, new_req);
1583 if (ret != LDB_SUCCESS) {
1586 return ldb_next_request(module, new_req);
1590 * @brief log details of an delete operation.
1592 * Log the details of an delete operation.
1594 * @param module the ldb_module
1595 * @param req the ldb_request
1597 * @return ldb status code
1599 static int log_delete(
1600 struct ldb_module *module,
1601 struct ldb_request *req)
1603 struct audit_callback_context *context = NULL;
1604 struct ldb_request *new_req = NULL;
1605 struct ldb_context *ldb = NULL;
1608 ldb = ldb_module_get_ctx(module);
1609 context = talloc_zero(req, struct audit_callback_context);
1611 if (context == NULL) {
1612 return ldb_oom(ldb);
1614 context->request = req;
1615 context->module = module;
1617 * We want to log the return code status, so we need to register
1618 * a callback function to get the actual result.
1619 * We need to take a new copy so that we don't alter the callers copy
1621 ret = ldb_build_del_req(&new_req,
1629 if (ret != LDB_SUCCESS) {
1632 ret = add_transaction_id(module, new_req);
1633 if (ret != LDB_SUCCESS) {
1636 return ldb_next_request(module, new_req);
1640 * @brief log details of a modify operation.
1642 * Log the details of a modify operation.
1644 * @param module the ldb_module
1645 * @param req the ldb_request
1647 * @return ldb status code
1649 static int log_modify(
1650 struct ldb_module *module,
1651 struct ldb_request *req)
1653 struct audit_callback_context *context = NULL;
1654 struct ldb_request *new_req = NULL;
1655 struct ldb_context *ldb = NULL;
1658 ldb = ldb_module_get_ctx(module);
1659 context = talloc_zero(req, struct audit_callback_context);
1661 if (context == NULL) {
1662 return ldb_oom(ldb);
1664 context->request = req;
1665 context->module = module;
1667 * We want to log the return code status, so we need to register
1668 * a callback function to get the actual result.
1669 * We need to take a new copy so that we don't alter the callers copy
1671 ret = ldb_build_mod_req(
1675 req->op.mod.message,
1680 if (ret != LDB_SUCCESS) {
1683 ret = add_transaction_id(module, new_req);
1684 if (ret != LDB_SUCCESS) {
1687 return ldb_next_request(module, new_req);
1691 * @brief process a transaction start.
1693 * process a transaction start, as we don't currently log transaction starts
1694 * just generate the new transaction_id.
1696 * @param module the ldb_module
1697 * @param req the ldb_request
1699 * @return ldb status code
1701 static int log_start_transaction(struct ldb_module *module)
1703 struct audit_private *audit_private =
1704 talloc_get_type_abort(ldb_module_get_private(module),
1705 struct audit_private);
1708 * We do not log transaction begins
1709 * however we do generate a new transaction_id and record the start
1710 * time so that we can log the transaction duration.
1713 audit_private->transaction_guid = GUID_random();
1714 audit_private->transaction_start = timeval_current();
1715 return ldb_next_start_trans(module);
1719 * @brief log details of a prepare commit.
1721 * Log the details of a prepare commit, currently only details of
1722 * failures are logged.
1724 * @param module the ldb_module
1725 * @param req the ldb_request
1727 * @return ldb status code
1729 static int log_prepare_commit(struct ldb_module *module)
1732 int ret = ldb_next_prepare_commit(module);
1733 if (ret != LDB_SUCCESS) {
1735 * We currently only log prepare commit failures
1737 log_commit_failure(module, "prepare", ret);
1743 * @brief process a transaction end aka commit.
1745 * process a transaction end, as we don't currently log transaction ends
1746 * just clear transaction_id.
1748 * @param module the ldb_module
1749 * @param req the ldb_request
1751 * @return ldb status code
1753 static int log_end_transaction(struct ldb_module *module)
1755 struct audit_private *audit_private =
1756 talloc_get_type_abort(ldb_module_get_private(module),
1757 struct audit_private);
1761 ret = ldb_next_end_trans(module);
1762 if (ret == LDB_SUCCESS) {
1766 TRANSACTION_LOG_COMPLETION_LVL);
1768 log_commit_failure(module, "commit", ret);
1771 * Clear the transaction id inserted by log_start_transaction
1773 audit_private->transaction_guid = GUID_zero();
1778 * @brief log details of a transaction delete aka roll back.
1780 * Log details of a transaction roll back.
1782 * @param module the ldb_module
1783 * @param req the ldb_request
1785 * @return ldb status code
1787 static int log_del_transaction(struct ldb_module *module)
1789 struct audit_private *audit_private =
1790 talloc_get_type_abort(ldb_module_get_private(module),
1791 struct audit_private);
1793 log_transaction(module, "rollback", TRANSACTION_LOG_FAILURE_LVL);
1794 audit_private->transaction_guid = GUID_zero();
1795 return ldb_next_del_trans(module);
1799 * @brief log details of an extended operation.
1801 * Log the details of an extended operation.
1803 * @param module the ldb_module
1804 * @param req the ldb_request
1806 * @return ldb status code
1808 static int log_extended(
1809 struct ldb_module *module,
1810 struct ldb_request *req)
1812 struct audit_callback_context *context = NULL;
1813 struct ldb_request *new_req = NULL;
1814 struct ldb_context *ldb = NULL;
1818 * Currently we only log replication extended operations
1821 req->op.extended.oid,
1822 DSDB_EXTENDED_REPLICATED_OBJECTS_OID) != 0) {
1824 return ldb_next_request(module, req);
1826 ldb = ldb_module_get_ctx(module);
1827 context = talloc_zero(req, struct audit_callback_context);
1829 if (context == NULL) {
1830 return ldb_oom(ldb);
1832 context->request = req;
1833 context->module = module;
1835 * We want to log the return code status, so we need to register
1836 * a callback function to get the actual result.
1837 * We need to take a new copy so that we don't alter the callers copy
1839 ret = ldb_build_extended_req(
1843 req->op.extended.oid,
1844 req->op.extended.data,
1849 if (ret != LDB_SUCCESS) {
1852 ret = add_transaction_id(module, new_req);
1853 if (ret != LDB_SUCCESS) {
1856 return ldb_next_request(module, new_req);
1860 * @brief module initialisation
1862 static int log_init(struct ldb_module *module)
1865 struct ldb_context *ldb = ldb_module_get_ctx(module);
1866 struct audit_private *audit_private = NULL;
1867 struct loadparm_context *lp_ctx
1868 = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
1869 struct loadparm_context);
1870 struct tevent_context *ev = ldb_get_event_context(ldb);
1871 bool sdb_events = false;
1872 bool pwd_events = false;
1874 audit_private = talloc_zero(module, struct audit_private);
1875 if (audit_private == NULL) {
1876 return ldb_module_oom(module);
1879 if (lp_ctx != NULL) {
1880 sdb_events = lpcfg_dsdb_event_notification(lp_ctx);
1881 pwd_events = lpcfg_dsdb_password_event_notification(lp_ctx);
1883 if (sdb_events || pwd_events) {
1884 audit_private->send_samdb_events = sdb_events;
1885 audit_private->send_password_events = pwd_events;
1886 audit_private->msg_ctx
1887 = imessaging_client_init(audit_private,
1892 ldb_module_set_private(module, audit_private);
1893 return ldb_next_init(module);
1896 static const struct ldb_module_ops ldb_audit_log_module_ops = {
1897 .name = "audit_log",
1898 .init_context = log_init,
1900 .modify = log_modify,
1902 .start_transaction = log_start_transaction,
1903 .prepare_commit = log_prepare_commit,
1904 .end_transaction = log_end_transaction,
1905 .del_transaction = log_del_transaction,
1906 .extended = log_extended,
1909 int ldb_audit_log_module_init(const char *version)
1911 LDB_MODULE_CHECK_VERSION(version);
1912 return ldb_register_module(&ldb_audit_log_module_ops);