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 "libcli/security/dom_sid.h"
33 #include "auth/common_auth.h"
34 #include "param/param.h"
36 #define OPERATION_JSON_TYPE "dsdbChange"
37 #define OPERATION_HR_TAG "DSDB Change"
38 #define OPERATION_MAJOR 1
39 #define OPERATION_MINOR 0
40 #define OPERATION_LOG_LVL 5
42 #define PASSWORD_JSON_TYPE "passwordChange"
43 #define PASSWORD_HR_TAG "Password Change"
44 #define PASSWORD_MAJOR 1
45 #define PASSWORD_MINOR 0
46 #define PASSWORD_LOG_LVL 5
48 #define TRANSACTION_JSON_TYPE "dsdbTransaction"
49 #define TRANSACTION_HR_TAG "DSDB Transaction"
50 #define TRANSACTION_MAJOR 1
51 #define TRANSACTION_MINOR 0
52 #define TRANSACTION_LOG_FAILURE_LVL 5
53 #define TRANSACTION_LOG_COMPLETION_LVL 10
55 #define REPLICATION_JSON_TYPE "replicatedUpdate"
56 #define REPLICATION_HR_TAG "Replicated Update"
57 #define REPLICATION_MAJOR 1
58 #define REPLICATION_MINOR 0
59 #define REPLICATION_LOG_LVL 5
61 * Attribute values are truncated in the logs if they are longer than
64 #define MAX_LENGTH 1024
66 #define min(a, b) (((a)>(b))?(b):(a))
69 * Private data for the module, stored in the ldb_module private data
71 struct audit_context {
73 * Should details of database operations be sent over the
76 bool send_samdb_events;
78 * Should details of password changes and resets be sent over
81 bool send_password_events;
83 * The messaging context to send the messages over. Will only
84 * be set if send_samdb_events or send_password_events are
87 struct imessaging_context *msg_ctx;
89 * Unique transaction id for the current transaction
91 struct GUID transaction_guid;
93 * Transaction start time, used to calculate the transaction
96 struct timeval transaction_start;
100 * @brief Has the password changed.
102 * Does the message contain a change to one of the password attributes? The
103 * password attributes are defined in DSDB_PASSWORD_ATTRIBUTES
105 * @return true if the message contains a password attribute
108 static bool has_password_changed(const struct ldb_message *message)
111 if (message == NULL) {
114 for (i=0;i<message->num_elements;i++) {
115 if (dsdb_audit_is_password_attribute(
116 message->elements[i].name)) {
124 * @brief Is the request a password "Change" or a "Reset"
126 * Get a description of the action being performed on the user password. This
127 * routine assumes that the request contains password attributes and that the
128 * password ACL checks have been performed by acl.c
130 * @param request the ldb_request to inspect
131 * @param reply the ldb_reply, will contain the password controls
133 * @return "Change" if the password is being changed.
134 * "Reset" if the password is being reset.
136 static const char *get_password_action(
137 const struct ldb_request *request,
138 const struct ldb_reply *reply)
140 if(request->operation == LDB_ADD) {
143 struct ldb_control *pav_ctrl = NULL;
144 struct dsdb_control_password_acl_validation *pav = NULL;
146 pav_ctrl = ldb_reply_get_control(
147 discard_const(reply),
148 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
149 if (pav_ctrl == NULL) {
153 pav = talloc_get_type_abort(
155 struct dsdb_control_password_acl_validation);
157 if (pav->pwd_reset) {
168 * @brief generate a JSON object detailing an ldb operation.
170 * Generate a JSON object detailing an ldb operation.
172 * @param module the ldb module
173 * @param request the request
174 * @param reply the result of the operation.
176 * @return the generated JSON object, should be freed with json_free.
179 static struct json_object operation_json(
180 struct ldb_module *module,
181 const struct ldb_request *request,
182 const struct ldb_reply *reply)
184 struct ldb_context *ldb = NULL;
185 const struct dom_sid *sid = NULL;
186 bool as_system = false;
187 struct json_object wrapper;
188 struct json_object audit;
189 const struct tsocket_address *remote = NULL;
190 const char *dn = NULL;
191 const char* operation = NULL;
192 const struct GUID *unique_session_token = NULL;
193 const struct ldb_message *message = NULL;
194 struct audit_context *ac = talloc_get_type(
195 ldb_module_get_private(module),
196 struct audit_context);
198 ldb = ldb_module_get_ctx(module);
200 remote = dsdb_audit_get_remote_address(ldb);
201 if (remote != NULL && dsdb_audit_is_system_session(module)) {
203 sid = dsdb_audit_get_actual_sid(ldb);
204 unique_session_token =
205 dsdb_audit_get_actual_unique_session_token(ldb);
207 sid = dsdb_audit_get_user_sid(module);
208 unique_session_token =
209 dsdb_audit_get_unique_session_token(module);
211 dn = dsdb_audit_get_primary_dn(request);
212 operation = dsdb_audit_get_operation_name(request);
214 audit = json_new_object();
215 json_add_version(&audit, OPERATION_MAJOR, OPERATION_MINOR);
216 json_add_int(&audit, "statusCode", reply->error);
217 json_add_string(&audit, "status", ldb_strerror(reply->error));
218 json_add_string(&audit, "operation", operation);
219 json_add_address(&audit, "remoteAddress", remote);
220 json_add_bool(&audit, "performedAsSystem", as_system);
221 json_add_sid(&audit, "userSid", sid);
222 json_add_string(&audit, "dn", dn);
223 json_add_guid(&audit, "transactionId", &ac->transaction_guid);
224 json_add_guid(&audit, "sessionId", unique_session_token);
226 message = dsdb_audit_get_message(request);
227 if (message != NULL) {
228 struct json_object attributes =
229 dsdb_audit_attributes_json(
232 json_add_object(&audit, "attributes", &attributes);
235 wrapper = json_new_object();
236 json_add_timestamp(&wrapper);
237 json_add_string(&wrapper, "type", OPERATION_JSON_TYPE);
238 json_add_object(&wrapper, OPERATION_JSON_TYPE, &audit);
243 * @brief generate a JSON object detailing a replicated update.
245 * Generate a JSON object detailing a replicated update
247 * @param module the ldb module
248 * @param request the request
249 * @paran reply the result of the operation
251 * @return the generated JSON object, should be freed with json_free.
254 static struct json_object replicated_update_json(
255 struct ldb_module *module,
256 const struct ldb_request *request,
257 const struct ldb_reply *reply)
259 struct json_object wrapper;
260 struct json_object audit;
261 struct audit_context *ac = talloc_get_type(
262 ldb_module_get_private(module),
263 struct audit_context);
264 struct dsdb_extended_replicated_objects *ro = talloc_get_type(
265 request->op.extended.data,
266 struct dsdb_extended_replicated_objects);
267 const char *partition_dn = NULL;
268 const char *error = NULL;
270 partition_dn = ldb_dn_get_linearized(ro->partition_dn);
271 error = get_friendly_werror_msg(ro->error);
273 audit = json_new_object();
274 json_add_version(&audit, REPLICATION_MAJOR, REPLICATION_MINOR);
275 json_add_int(&audit, "statusCode", reply->error);
276 json_add_string(&audit, "status", ldb_strerror(reply->error));
277 json_add_guid(&audit, "transactionId", &ac->transaction_guid);
278 json_add_int(&audit, "objectCount", ro->num_objects);
279 json_add_int(&audit, "linkCount", ro->linked_attributes_count);
280 json_add_string(&audit, "partitionDN", partition_dn);
281 json_add_string(&audit, "error", error);
282 json_add_int(&audit, "errorCode", W_ERROR_V(ro->error));
286 &ro->source_dsa->source_dsa_obj_guid);
290 &ro->source_dsa->source_dsa_invocation_id);
292 wrapper = json_new_object();
293 json_add_timestamp(&wrapper);
294 json_add_string(&wrapper, "type", REPLICATION_JSON_TYPE);
295 json_add_object(&wrapper, REPLICATION_JSON_TYPE, &audit);
300 * @brief generate a JSON object detailing a password change.
302 * Generate a JSON object detailing a password change.
304 * @param module the ldb module
305 * @param request the request
306 * @param reply the result/response
307 * @param status the status code returned for the underlying ldb operation.
309 * @return the generated JSON object.
312 static struct json_object password_change_json(
313 struct ldb_module *module,
314 const struct ldb_request *request,
315 const struct ldb_reply *reply)
317 struct ldb_context *ldb = NULL;
318 const struct dom_sid *sid = NULL;
319 const char* dn = NULL;
320 struct json_object wrapper;
321 struct json_object audit;
322 const struct tsocket_address *remote = NULL;
323 const char* action = NULL;
324 const struct GUID *unique_session_token = NULL;
325 struct audit_context *ac = talloc_get_type(
326 ldb_module_get_private(module),
327 struct audit_context);
330 ldb = ldb_module_get_ctx(module);
332 remote = dsdb_audit_get_remote_address(ldb);
333 sid = dsdb_audit_get_user_sid(module);
334 dn = dsdb_audit_get_primary_dn(request);
335 action = get_password_action(request, reply);
336 unique_session_token = dsdb_audit_get_unique_session_token(module);
338 audit = json_new_object();
339 json_add_version(&audit, PASSWORD_MAJOR, PASSWORD_MINOR);
340 json_add_int(&audit, "statusCode", reply->error);
341 json_add_string(&audit, "status", ldb_strerror(reply->error));
342 json_add_address(&audit, "remoteAddress", remote);
343 json_add_sid(&audit, "userSid", sid);
344 json_add_string(&audit, "dn", dn);
345 json_add_string(&audit, "action", action);
346 json_add_guid(&audit, "transactionId", &ac->transaction_guid);
347 json_add_guid(&audit, "sessionId", unique_session_token);
349 wrapper = json_new_object();
350 json_add_timestamp(&wrapper);
351 json_add_string(&wrapper, "type", PASSWORD_JSON_TYPE);
352 json_add_object(&wrapper, PASSWORD_JSON_TYPE, &audit);
359 * @brief create a JSON object containing details of a transaction event.
361 * Create a JSON object detailing a transaction transaction life cycle events,
362 * i.e. begin, commit, roll back
364 * @param action a one word description of the event/action
365 * @param transaction_id the GUID identifying the current transaction.
366 * @param status the status code returned by the operation
367 * @param duration the duration of the operation.
369 * @return a JSON object detailing the event
371 static struct json_object transaction_json(
373 struct GUID *transaction_id,
374 const int64_t duration)
376 struct json_object wrapper;
377 struct json_object audit;
379 audit = json_new_object();
380 json_add_version(&audit, TRANSACTION_MAJOR, TRANSACTION_MINOR);
381 json_add_string(&audit, "action", action);
382 json_add_guid(&audit, "transactionId", transaction_id);
383 json_add_int(&audit, "duration", duration);
386 wrapper = json_new_object();
387 json_add_timestamp(&wrapper);
388 json_add_string(&wrapper, "type", TRANSACTION_JSON_TYPE);
389 json_add_object(&wrapper, TRANSACTION_JSON_TYPE, &audit);
396 * @brief generate a JSON object detailing a commit failure.
398 * Generate a JSON object containing details of a commit failure.
400 * @param action the commit action, "commit" or "prepare"
401 * @param status the status code returned by commit
402 * @param reason any extra failure information/reason available
403 * @param transaction_id the GUID identifying the current transaction.
405 static struct json_object commit_failure_json(
407 const int64_t duration,
410 struct GUID *transaction_id)
412 struct json_object wrapper;
413 struct json_object audit;
415 audit = json_new_object();
416 json_add_version(&audit, TRANSACTION_MAJOR, TRANSACTION_MINOR);
417 json_add_string(&audit, "action", action);
418 json_add_guid(&audit, "transactionId", transaction_id);
419 json_add_int(&audit, "duration", duration);
420 json_add_int(&audit, "statusCode", status);
421 json_add_string(&audit, "status", ldb_strerror(status));
422 json_add_string(&audit, "reason", reason);
424 wrapper = json_new_object();
425 json_add_timestamp(&wrapper);
426 json_add_string(&wrapper, "type", TRANSACTION_JSON_TYPE);
427 json_add_object(&wrapper, TRANSACTION_JSON_TYPE, &audit);
434 * @brief Print a human readable log line for a password change event.
436 * Generate a human readable log line detailing a password change.
438 * @param mem_ctx The talloc context that will own the generated log line.
439 * @param module the ldb module
440 * @param request the request
441 * @param reply the result/response
442 * @param status the status code returned for the underlying ldb operation.
444 * @return the generated log line.
446 static char *password_change_human_readable(
448 struct ldb_module *module,
449 const struct ldb_request *request,
450 const struct ldb_reply *reply)
452 struct ldb_context *ldb = NULL;
453 const char *remote_host = NULL;
454 const struct dom_sid *sid = NULL;
455 const char *user_sid = NULL;
456 const char *timestamp = NULL;
457 char *log_entry = NULL;
458 const char *action = NULL;
459 const char *dn = NULL;
461 TALLOC_CTX *ctx = talloc_new(NULL);
463 ldb = ldb_module_get_ctx(module);
465 remote_host = dsdb_audit_get_remote_host(ldb, ctx);
466 sid = dsdb_audit_get_user_sid(module);
467 user_sid = dom_sid_string(ctx, sid);
468 timestamp = audit_get_timestamp(ctx);
469 action = get_password_action(request, reply);
470 dn = dsdb_audit_get_primary_dn(request);
472 log_entry = talloc_asprintf(
474 "[%s] at [%s] status [%s] "
475 "remote host [%s] SID [%s] DN [%s]",
478 ldb_strerror(reply->error),
486 * @brief Generate a human readable string, detailing attributes in a message
488 * For modify operations each attribute is prefixed with the action.
489 * Normal values are enclosed in []
490 * Base64 values are enclosed in {}
491 * Truncated values are indicated by three trailing dots "..."
493 * @param ldb The ldb_context
494 * @param buffer The attributes will be appended to the buffer.
495 * assumed to have been allocated via talloc.
496 * @param operation The operation type
497 * @param message the message to process
500 static char *log_attributes(
501 struct ldb_context *ldb,
503 enum ldb_request_type operation,
504 const struct ldb_message *message)
507 for (i=0;i<message->num_elements;i++) {
509 buffer = talloc_asprintf_append_buffer(buffer, " ");
512 if (message->elements[i].name == NULL) {
516 "Error: Invalid element name (NULL) at "
521 if (operation == LDB_MODIFY) {
522 const char *action =NULL;
523 action = dsdb_audit_get_modification_action(
524 message->elements[i].flags);
525 buffer = talloc_asprintf_append_buffer(
529 message->elements[i].name);
531 buffer = talloc_asprintf_append_buffer(
534 message->elements[i].name);
537 if (dsdb_audit_redact_attribute(message->elements[i].name)) {
539 * Do not log the value of any secret or password
542 buffer = talloc_asprintf_append_buffer(
544 "[REDACTED SECRET ATTRIBUTE]");
548 for (j=0;j<message->elements[i].num_values;j++) {
550 bool use_b64_encode = false;
553 buffer = talloc_asprintf_append_buffer(
558 v = message->elements[i].values[j];
559 length = min(MAX_LENGTH, v.length);
560 use_b64_encode = ldb_should_b64_encode(ldb, &v);
561 if (use_b64_encode) {
562 const char *encoded = ldb_base64_encode(
566 buffer = talloc_asprintf_append_buffer(
570 (v.length > MAX_LENGTH ? "..." : ""));
572 buffer = talloc_asprintf_append_buffer(
578 (v.length > MAX_LENGTH ? "..." : ""));
586 * @brief generate a human readable log entry detailing an ldb operation.
588 * Generate a human readable log entry detailing an ldb operation.
590 * @param mem_ctx The talloc context owning the returned string.
591 * @param module the ldb module
592 * @param request the request
593 * @param reply the result of the operation
595 * @return the log entry.
598 static char *operation_human_readable(
600 struct ldb_module *module,
601 const struct ldb_request *request,
602 const struct ldb_reply *reply)
604 struct ldb_context *ldb = NULL;
605 const char *remote_host = NULL;
606 const struct dom_sid *sid = NULL;
607 const char *user_sid = NULL;
608 const char *timestamp = NULL;
609 const char *op_name = NULL;
610 char *log_entry = NULL;
611 const char *dn = NULL;
612 const char *new_dn = NULL;
613 const struct ldb_message *message = NULL;
615 TALLOC_CTX *ctx = talloc_new(NULL);
617 ldb = ldb_module_get_ctx(module);
619 remote_host = dsdb_audit_get_remote_host(ldb, ctx);
620 if (remote_host != NULL && dsdb_audit_is_system_session(module)) {
621 sid = dsdb_audit_get_actual_sid(ldb);
623 sid = dsdb_audit_get_user_sid(module);
625 user_sid = dom_sid_string(ctx, sid);
626 timestamp = audit_get_timestamp(ctx);
627 op_name = dsdb_audit_get_operation_name(request);
628 dn = dsdb_audit_get_primary_dn(request);
629 new_dn = dsdb_audit_get_secondary_dn(request);
631 message = dsdb_audit_get_message(request);
633 log_entry = talloc_asprintf(
635 "[%s] at [%s] status [%s] "
636 "remote host [%s] SID [%s] DN [%s]",
639 ldb_strerror(reply->error),
643 if (new_dn != NULL) {
644 log_entry = talloc_asprintf_append_buffer(
649 if (message != NULL) {
650 log_entry = talloc_asprintf_append_buffer(log_entry,
652 log_entry = log_attributes(ldb,
656 log_entry = talloc_asprintf_append_buffer(log_entry, "]");
663 * @brief generate a human readable log entry detailing a replicated update
666 * Generate a human readable log entry detailing a replicated update operation
668 * @param mem_ctx The talloc context owning the returned string.
669 * @param module the ldb module
670 * @param request the request
671 * @param reply the result of the operation.
673 * @return the log entry.
676 static char *replicated_update_human_readable(
678 struct ldb_module *module,
679 const struct ldb_request *request,
680 const struct ldb_reply *reply)
682 struct dsdb_extended_replicated_objects *ro = talloc_get_type(
683 request->op.extended.data,
684 struct dsdb_extended_replicated_objects);
685 const char *partition_dn = NULL;
686 const char *error = NULL;
687 char *log_entry = NULL;
688 char *timestamp = NULL;
689 struct GUID_txt_buf object_buf;
690 const char *object = NULL;
691 struct GUID_txt_buf invocation_buf;
692 const char *invocation = NULL;
695 TALLOC_CTX *ctx = talloc_new(NULL);
697 timestamp = audit_get_timestamp(ctx);
698 error = get_friendly_werror_msg(ro->error);
699 partition_dn = ldb_dn_get_linearized(ro->partition_dn);
700 object = GUID_buf_string(
701 &ro->source_dsa->source_dsa_obj_guid,
703 invocation = GUID_buf_string(
704 &ro->source_dsa->source_dsa_invocation_id,
708 log_entry = talloc_asprintf(
710 "at [%s] status [%s] error [%s] partition [%s] objects [%d] "
711 "links [%d] object [%s] invocation [%s]",
713 ldb_strerror(reply->error),
717 ro->linked_attributes_count,
725 * @brief create a human readable log entry detailing a transaction event.
727 * Create a human readable log entry detailing a transaction event.
728 * i.e. begin, commit, roll back
730 * @param mem_ctx The talloc context owning the returned string.
731 * @param action a one word description of the event/action
732 * @param duration the duration of the transaction.
734 * @return the log entry
736 static char *transaction_human_readable(
739 const int64_t duration)
741 const char *timestamp = NULL;
742 char *log_entry = NULL;
744 TALLOC_CTX *ctx = talloc_new(NULL);
746 timestamp = audit_get_timestamp(ctx);
748 log_entry = talloc_asprintf(
750 "[%s] at [%s] duration [%ld]",
760 * @brief generate a human readable log entry detailing a commit failure.
762 * Generate generate a human readable log entry detailing a commit failure.
764 * @param mem_ctx The talloc context owning the returned string.
765 * @param action the commit action, "prepare" or "commit"
766 * @param status the status code returned by commit
767 * @param reason any extra failure information/reason available
769 * @return the log entry
771 static char *commit_failure_human_readable(
774 const int64_t duration,
778 const char *timestamp = NULL;
779 char *log_entry = NULL;
781 TALLOC_CTX *ctx = talloc_new(NULL);
783 timestamp = audit_get_timestamp(ctx);
785 log_entry = talloc_asprintf(
787 "[%s] at [%s] duration [%ld] status [%d] reason [%s]",
799 * @brief log details of a standard ldb operation.
801 * Log the details of an ldb operation in JSON and or human readable format
802 * and send over the message bus.
804 * @param module the ldb_module
805 * @param request the operation request.
806 * @param reply the operation result.
807 * @param the status code returned for the operation.
810 static void log_standard_operation(
811 struct ldb_module *module,
812 const struct ldb_request *request,
813 const struct ldb_reply *reply)
816 const struct ldb_message *message = dsdb_audit_get_message(request);
817 bool password_changed = has_password_changed(message);
818 struct audit_context *ac =
819 talloc_get_type(ldb_module_get_private(module),
820 struct audit_context);
822 TALLOC_CTX *ctx = talloc_new(NULL);
824 if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT, OPERATION_LOG_LVL)) {
826 entry = operation_human_readable(
831 audit_log_human_text(
838 if (CHECK_DEBUGLVLC(DBGC_DSDB_PWD_AUDIT, PASSWORD_LOG_LVL)) {
839 if (password_changed) {
841 entry = password_change_human_readable(
846 audit_log_human_text(
855 if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT_JSON, OPERATION_LOG_LVL) ||
856 (ac->msg_ctx && ac->send_samdb_events)) {
857 struct json_object json;
858 json = operation_json(module, request, reply);
862 DBGC_DSDB_AUDIT_JSON,
864 if (ac->msg_ctx && ac->send_password_events) {
873 if (CHECK_DEBUGLVLC(DBGC_DSDB_PWD_AUDIT_JSON, PASSWORD_LOG_LVL) ||
874 (ac->msg_ctx && ac->send_password_events)) {
875 if (password_changed) {
876 struct json_object json;
877 json = password_change_json(module, request, reply);
881 DBGC_DSDB_PWD_AUDIT_JSON,
883 if (ac->send_password_events) {
898 * @brief log details of a replicated update.
900 * Log the details of a replicated update in JSON and or human readable
901 * format and send over the message bus.
903 * @param module the ldb_module
904 * @param request the operation request
905 * @param reply the result of the operation.
908 static void log_replicated_operation(
909 struct ldb_module *module,
910 const struct ldb_request *request,
911 const struct ldb_reply *reply)
914 struct audit_context *ac =
915 talloc_get_type(ldb_module_get_private(module),
916 struct audit_context);
918 TALLOC_CTX *ctx = talloc_new(NULL);
920 if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT, REPLICATION_LOG_LVL)) {
922 entry = replicated_update_human_readable(
927 audit_log_human_text(
931 REPLICATION_LOG_LVL);
935 if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT_JSON, REPLICATION_LOG_LVL) ||
936 (ac->msg_ctx && ac->send_samdb_events)) {
937 struct json_object json;
938 json = replicated_update_json(module, request, reply);
940 REPLICATION_JSON_TYPE,
942 DBGC_DSDB_AUDIT_JSON,
943 REPLICATION_LOG_LVL);
944 if (ac->send_samdb_events) {
958 * @brief log details of an ldb operation.
960 * Log the details of an ldb operation in JSON and or human readable format
961 * and send over the message bus.
963 * @param module the ldb_module
964 * @param request the operation request
965 * @part reply the result of the operation
968 static void log_operation(
969 struct ldb_module *module,
970 const struct ldb_request *request,
971 const struct ldb_reply *reply)
974 if (request->operation == LDB_EXTENDED) {
976 request->op.extended.oid,
977 DSDB_EXTENDED_REPLICATED_OBJECTS_OID) != 0) {
979 log_replicated_operation(module, request, reply);
982 log_standard_operation(module, request, reply);
987 * @brief log details of a transaction event.
989 * Log the details of a transaction event in JSON and or human readable format
990 * and send over the message bus.
992 * @param module the ldb_module
993 * @param action the transaction event i.e. begin, commit, roll back.
994 * @param log_level the logging level
997 static void log_transaction(
998 struct ldb_module *module,
1003 struct audit_context *ac =
1004 talloc_get_type(ldb_module_get_private(module),
1005 struct audit_context);
1006 const struct timeval now = timeval_current();
1007 const int64_t duration = usec_time_diff(&now, &ac->transaction_start);
1009 TALLOC_CTX *ctx = talloc_new(NULL);
1011 if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT, log_level)) {
1013 entry = transaction_human_readable(ctx, action, duration);
1014 audit_log_human_text(
1017 DBGC_DSDB_TXN_AUDIT,
1022 if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT_JSON, log_level) ||
1023 (ac->msg_ctx && ac->send_samdb_events)) {
1024 struct json_object json;
1025 json = transaction_json(
1027 &ac->transaction_guid,
1030 TRANSACTION_JSON_TYPE,
1032 DBGC_DSDB_TXN_AUDIT_JSON,
1034 if (ac->send_samdb_events) {
1048 * @brief log details of a commit failure.
1050 * Log the details of a commit failure in JSON and or human readable
1051 * format and send over the message bus.
1053 * @param module the ldb_module
1054 * @param action the commit action "prepare" or "commit"
1055 * @param status the ldb status code returned by prepare commit.
1058 static void log_commit_failure(
1059 struct ldb_module *module,
1064 struct audit_context *ac =
1065 talloc_get_type(ldb_module_get_private(module),
1066 struct audit_context);
1067 const char* reason = dsdb_audit_get_ldb_error_string(module, status);
1068 const int log_level = TRANSACTION_LOG_FAILURE_LVL;
1069 const struct timeval now = timeval_current();
1070 const int64_t duration = usec_time_diff(&now, &ac->transaction_start);
1072 TALLOC_CTX *ctx = talloc_new(NULL);
1074 if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT, log_level)) {
1077 entry = commit_failure_human_readable(
1083 audit_log_human_text(
1086 DBGC_DSDB_TXN_AUDIT,
1087 TRANSACTION_LOG_FAILURE_LVL);
1091 if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT_JSON, log_level) ||
1092 (ac->msg_ctx && ac->send_samdb_events)) {
1093 struct json_object json;
1094 json = commit_failure_json(
1099 &ac->transaction_guid);
1101 TRANSACTION_JSON_TYPE,
1103 DBGC_DSDB_TXN_AUDIT_JSON,
1105 if (ac->send_samdb_events) {
1106 audit_message_send(ac->msg_ctx,
1118 * Context needed by audit_callback
1120 struct audit_callback_context {
1121 struct ldb_request *request;
1122 struct ldb_module *module;
1126 * @brief call back function for the ldb_operations.
1128 * As the LDB operations are async, and we wish to examine the results of
1129 * the operations, a callback needs to be registered to process the results
1130 * of the LDB operations.
1132 * @param req the ldb request
1133 * @param res the result of the operation
1135 * @return the LDB_STATUS
1137 static int audit_callback(struct ldb_request *req, struct ldb_reply *ares)
1139 struct audit_callback_context *ac = NULL;
1141 ac = talloc_get_type(
1143 struct audit_callback_context);
1146 return ldb_module_done(
1150 LDB_ERR_OPERATIONS_ERROR);
1153 /* pass on to the callback */
1154 switch (ares->type) {
1155 case LDB_REPLY_ENTRY:
1156 return ldb_module_send_entry(
1161 case LDB_REPLY_REFERRAL:
1162 return ldb_module_send_referral(
1166 case LDB_REPLY_DONE:
1168 * Log the operation once DONE
1170 log_operation(ac->module, ac->request, ares);
1171 return ldb_module_done(
1179 return LDB_ERR_OPERATIONS_ERROR;
1184 * @brief Add the current transaction identifier to the request.
1186 * Add the current transaction identifier in the module private data,
1187 * to the request as a control.
1190 * @param req the request.
1192 * @return an LDB_STATUS code, LDB_SUCCESS if successful.
1194 static int add_transaction_id(
1195 struct ldb_module *module,
1196 struct ldb_request *req)
1198 struct audit_context *ac =
1199 talloc_get_type(ldb_module_get_private(module),
1200 struct audit_context);
1201 struct dsdb_control_transaction_identifier *transaction_id;
1204 transaction_id = talloc_zero(
1206 struct dsdb_control_transaction_identifier);
1207 if (transaction_id == NULL) {
1208 struct ldb_context *ldb = ldb_module_get_ctx(module);
1209 return ldb_oom(ldb);
1211 transaction_id->transaction_guid = ac->transaction_guid;
1212 ret = ldb_request_add_control(req,
1213 DSDB_CONTROL_TRANSACTION_IDENTIFIER_OID,
1221 * @brief log details of an add operation.
1223 * Log the details of an add operation.
1225 * @param module the ldb_module
1226 * @param req the ldb_request
1228 * @return ldb status code
1231 struct ldb_module *module,
1232 struct ldb_request *req)
1234 struct audit_callback_context *context = NULL;
1235 struct ldb_request *new_req = NULL;
1236 struct ldb_context *ldb = NULL;
1239 ldb = ldb_module_get_ctx(module);
1240 context = talloc_zero(req, struct audit_callback_context);
1242 if (context == NULL) {
1243 return ldb_oom(ldb);
1245 context->request = req;
1246 context->module = module;
1248 * We want to log the return code status, so we need to register
1249 * a callback function to get the actual result.
1250 * We need to take a new copy so that we don't alter the callers copy
1252 ret = ldb_build_add_req(
1256 req->op.add.message,
1261 if (ret != LDB_SUCCESS) {
1264 ret = add_transaction_id(module, new_req);
1265 if (ret != LDB_SUCCESS) {
1268 return ldb_next_request(module, new_req);
1272 * @brief log details of an delete operation.
1274 * Log the details of an delete operation.
1276 * @param module the ldb_module
1277 * @param req the ldb_request
1279 * @return ldb status code
1281 static int log_delete(
1282 struct ldb_module *module,
1283 struct ldb_request *req)
1285 struct audit_callback_context *context = NULL;
1286 struct ldb_request *new_req = NULL;
1287 struct ldb_context *ldb = NULL;
1290 ldb = ldb_module_get_ctx(module);
1291 context = talloc_zero(req, struct audit_callback_context);
1293 if (context == NULL) {
1294 return ldb_oom(ldb);
1296 context->request = req;
1297 context->module = module;
1299 * We want to log the return code status, so we need to register
1300 * a callback function to get the actual result.
1301 * We need to take a new copy so that we don't alter the callers copy
1303 ret = ldb_build_del_req(&new_req,
1311 if (ret != LDB_SUCCESS) {
1314 ret = add_transaction_id(module, new_req);
1315 if (ret != LDB_SUCCESS) {
1318 return ldb_next_request(module, new_req);
1322 * @brief log details of a modify operation.
1324 * Log the details of a modify operation.
1326 * @param module the ldb_module
1327 * @param req the ldb_request
1329 * @return ldb status code
1331 static int log_modify(
1332 struct ldb_module *module,
1333 struct ldb_request *req)
1335 struct audit_callback_context *context = NULL;
1336 struct ldb_request *new_req = NULL;
1337 struct ldb_context *ldb = NULL;
1340 ldb = ldb_module_get_ctx(module);
1341 context = talloc_zero(req, struct audit_callback_context);
1343 if (context == NULL) {
1344 return ldb_oom(ldb);
1346 context->request = req;
1347 context->module = module;
1349 * We want to log the return code status, so we need to register
1350 * a callback function to get the actual result.
1351 * We need to take a new copy so that we don't alter the callers copy
1353 ret = ldb_build_mod_req(
1357 req->op.mod.message,
1362 if (ret != LDB_SUCCESS) {
1365 ret = add_transaction_id(module, new_req);
1366 if (ret != LDB_SUCCESS) {
1369 return ldb_next_request(module, new_req);
1373 * @brief process a transaction start.
1375 * process a transaction start, as we don't currently log transaction starts
1376 * just generate the new transaction_id.
1378 * @param module the ldb_module
1379 * @param req the ldb_request
1381 * @return ldb status code
1383 static int log_start_transaction(struct ldb_module *module)
1385 struct audit_context *ac =
1386 talloc_get_type(ldb_module_get_private(module),
1387 struct audit_context);
1390 * We do not log transaction begins
1391 * however we do generate a new transaction_id and record the start
1392 * time so that we can log the transaction duration.
1395 ac->transaction_guid = GUID_random();
1396 ac->transaction_start = timeval_current();
1397 return ldb_next_start_trans(module);
1401 * @brief log details of a prepare commit.
1403 * Log the details of a prepare commit, currently only details of
1404 * failures are logged.
1406 * @param module the ldb_module
1407 * @param req the ldb_request
1409 * @return ldb status code
1411 static int log_prepare_commit(struct ldb_module *module)
1414 int ret = ldb_next_prepare_commit(module);
1415 if (ret != LDB_SUCCESS) {
1417 * We currently only log prepare commit failures
1419 log_commit_failure(module, "prepare", ret);
1425 * @brief process a transaction end aka commit.
1427 * process a transaction end, as we don't currently log transaction ends
1428 * just clear transaction_id.
1430 * @param module the ldb_module
1431 * @param req the ldb_request
1433 * @return ldb status code
1435 static int log_end_transaction(struct ldb_module *module)
1437 struct audit_context *ac =
1438 talloc_get_type(ldb_module_get_private(module),
1439 struct audit_context);
1443 ret = ldb_next_end_trans(module);
1444 if (ret == LDB_SUCCESS) {
1448 TRANSACTION_LOG_COMPLETION_LVL);
1450 log_commit_failure(module, "commit", ret);
1453 * Clear the transaction id inserted by log_start_transaction
1455 memset(&ac->transaction_guid, 0, sizeof(struct GUID));
1460 * @brief log details of a transaction delete aka roll back.
1462 * Log details of a transaction roll back.
1464 * @param module the ldb_module
1465 * @param req the ldb_request
1467 * @return ldb status code
1469 static int log_del_transaction(struct ldb_module *module)
1471 struct audit_context *ac =
1472 talloc_get_type(ldb_module_get_private(module),
1473 struct audit_context);
1475 log_transaction(module, "rollback", TRANSACTION_LOG_FAILURE_LVL);
1476 memset(&ac->transaction_guid, 0, sizeof(struct GUID));
1477 return ldb_next_del_trans(module);
1481 * @brief log details of an extended operation.
1483 * Log the details of an extended operation.
1485 * @param module the ldb_module
1486 * @param req the ldb_request
1488 * @return ldb status code
1490 static int log_extended(
1491 struct ldb_module *module,
1492 struct ldb_request *req)
1494 struct audit_callback_context *context = NULL;
1495 struct ldb_request *new_req = NULL;
1496 struct ldb_context *ldb = NULL;
1500 * Currently we only log replication extended operations
1503 req->op.extended.oid,
1504 DSDB_EXTENDED_REPLICATED_OBJECTS_OID) != 0) {
1506 return ldb_next_request(module, req);
1508 ldb = ldb_module_get_ctx(module);
1509 context = talloc_zero(req, struct audit_callback_context);
1511 if (context == NULL) {
1512 return ldb_oom(ldb);
1514 context->request = req;
1515 context->module = module;
1517 * We want to log the return code status, so we need to register
1518 * a callback function to get the actual result.
1519 * We need to take a new copy so that we don't alter the callers copy
1521 ret = ldb_build_extended_req(
1525 req->op.extended.oid,
1526 req->op.extended.data,
1531 if (ret != LDB_SUCCESS) {
1534 ret = add_transaction_id(module, new_req);
1535 if (ret != LDB_SUCCESS) {
1538 return ldb_next_request(module, new_req);
1542 * @brief module initialisation
1544 static int log_init(struct ldb_module *module)
1547 struct ldb_context *ldb = ldb_module_get_ctx(module);
1548 struct audit_context *context = NULL;
1549 struct loadparm_context *lp_ctx
1550 = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
1551 struct loadparm_context);
1552 struct tevent_context *ec = ldb_get_event_context(ldb);
1553 bool sdb_events = false;
1554 bool pwd_events = false;
1556 context = talloc_zero(module, struct audit_context);
1557 if (context == NULL) {
1558 return ldb_module_oom(module);
1561 if (lp_ctx != NULL) {
1562 sdb_events = lpcfg_dsdb_event_notification(lp_ctx);
1563 pwd_events = lpcfg_dsdb_password_event_notification(lp_ctx);
1565 if (sdb_events || pwd_events) {
1566 context->send_samdb_events = sdb_events;
1567 context->send_password_events = pwd_events;
1568 context->msg_ctx = imessaging_client_init(ec, lp_ctx, ec);
1571 ldb_module_set_private(module, context);
1572 return ldb_next_init(module);
1575 static const struct ldb_module_ops ldb_audit_log_module_ops = {
1576 .name = "audit_log",
1577 .init_context = log_init,
1579 .modify = log_modify,
1581 .start_transaction = log_start_transaction,
1582 .prepare_commit = log_prepare_commit,
1583 .end_transaction = log_end_transaction,
1584 .del_transaction = log_del_transaction,
1585 .extended = log_extended,
1588 int ldb_audit_log_module_init(const char *version)
1590 LDB_MODULE_CHECK_VERSION(version);
1591 return ldb_register_module(&ldb_audit_log_module_ops);