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"
37 #define OPERATION_JSON_TYPE "dsdbChange"
38 #define OPERATION_HR_TAG "DSDB Change"
39 #define OPERATION_MAJOR 1
40 #define OPERATION_MINOR 0
41 #define OPERATION_LOG_LVL 5
43 #define PASSWORD_JSON_TYPE "passwordChange"
44 #define PASSWORD_HR_TAG "Password Change"
45 #define PASSWORD_MAJOR 1
46 #define PASSWORD_MINOR 0
47 #define PASSWORD_LOG_LVL 5
49 #define TRANSACTION_JSON_TYPE "dsdbTransaction"
50 #define TRANSACTION_HR_TAG "DSDB Transaction"
51 #define TRANSACTION_MAJOR 1
52 #define TRANSACTION_MINOR 0
53 #define TRANSACTION_LOG_FAILURE_LVL 5
54 #define TRANSACTION_LOG_COMPLETION_LVL 10
56 #define REPLICATION_JSON_TYPE "replicatedUpdate"
57 #define REPLICATION_HR_TAG "Replicated Update"
58 #define REPLICATION_MAJOR 1
59 #define REPLICATION_MINOR 0
60 #define REPLICATION_LOG_LVL 5
62 * Attribute values are truncated in the logs if they are longer than
65 #define MAX_LENGTH 1024
67 #define min(a, b) (((a)>(b))?(b):(a))
70 * Private data for the module, stored in the ldb_module private data
72 struct audit_context {
74 * Should details of database operations be sent over the
77 bool send_samdb_events;
79 * Should details of password changes and resets be sent over
82 bool send_password_events;
84 * The messaging context to send the messages over. Will only
85 * be set if send_samdb_events or send_password_events are
88 struct imessaging_context *msg_ctx;
90 * Unique transaction id for the current transaction
92 struct GUID transaction_guid;
94 * Transaction start time, used to calculate the transaction
97 struct timeval transaction_start;
101 * @brief Has the password changed.
103 * Does the message contain a change to one of the password attributes? The
104 * password attributes are defined in DSDB_PASSWORD_ATTRIBUTES
106 * @return true if the message contains a password attribute
109 static bool has_password_changed(const struct ldb_message *message)
112 if (message == NULL) {
115 for (i=0;i<message->num_elements;i++) {
116 if (dsdb_audit_is_password_attribute(
117 message->elements[i].name)) {
125 * @brief Is the request a password "Change" or a "Reset"
127 * Get a description of the action being performed on the user password. This
128 * routine assumes that the request contains password attributes and that the
129 * password ACL checks have been performed by acl.c
131 * @param request the ldb_request to inspect
132 * @param reply the ldb_reply, will contain the password controls
134 * @return "Change" if the password is being changed.
135 * "Reset" if the password is being reset.
137 static const char *get_password_action(
138 const struct ldb_request *request,
139 const struct ldb_reply *reply)
141 if(request->operation == LDB_ADD) {
144 struct ldb_control *pav_ctrl = NULL;
145 struct dsdb_control_password_acl_validation *pav = NULL;
147 pav_ctrl = ldb_reply_get_control(
148 discard_const(reply),
149 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
150 if (pav_ctrl == NULL) {
154 pav = talloc_get_type_abort(
156 struct dsdb_control_password_acl_validation);
158 if (pav->pwd_reset) {
169 * @brief generate a JSON object detailing an ldb operation.
171 * Generate a JSON object detailing an ldb operation.
173 * @param module the ldb module
174 * @param request the request
175 * @param reply the result of the operation.
177 * @return the generated JSON object, should be freed with json_free.
180 static struct json_object operation_json(
181 struct ldb_module *module,
182 const struct ldb_request *request,
183 const struct ldb_reply *reply)
185 struct ldb_context *ldb = NULL;
186 const struct dom_sid *sid = NULL;
187 bool as_system = false;
188 struct json_object wrapper;
189 struct json_object audit;
190 const struct tsocket_address *remote = NULL;
191 const char *dn = NULL;
192 const char* operation = NULL;
193 const struct GUID *unique_session_token = NULL;
194 const struct ldb_message *message = NULL;
195 struct audit_context *ac = talloc_get_type(
196 ldb_module_get_private(module),
197 struct audit_context);
199 ldb = ldb_module_get_ctx(module);
201 remote = dsdb_audit_get_remote_address(ldb);
202 if (remote != NULL && dsdb_audit_is_system_session(module)) {
204 sid = dsdb_audit_get_actual_sid(ldb);
205 unique_session_token =
206 dsdb_audit_get_actual_unique_session_token(ldb);
208 sid = dsdb_audit_get_user_sid(module);
209 unique_session_token =
210 dsdb_audit_get_unique_session_token(module);
212 dn = dsdb_audit_get_primary_dn(request);
213 operation = dsdb_audit_get_operation_name(request);
215 audit = json_new_object();
216 json_add_version(&audit, OPERATION_MAJOR, OPERATION_MINOR);
217 json_add_int(&audit, "statusCode", reply->error);
218 json_add_string(&audit, "status", ldb_strerror(reply->error));
219 json_add_string(&audit, "operation", operation);
220 json_add_address(&audit, "remoteAddress", remote);
221 json_add_bool(&audit, "performedAsSystem", as_system);
222 json_add_sid(&audit, "userSid", sid);
223 json_add_string(&audit, "dn", dn);
224 json_add_guid(&audit, "transactionId", &ac->transaction_guid);
225 json_add_guid(&audit, "sessionId", unique_session_token);
227 message = dsdb_audit_get_message(request);
228 if (message != NULL) {
229 struct json_object attributes =
230 dsdb_audit_attributes_json(
233 json_add_object(&audit, "attributes", &attributes);
236 wrapper = json_new_object();
237 json_add_timestamp(&wrapper);
238 json_add_string(&wrapper, "type", OPERATION_JSON_TYPE);
239 json_add_object(&wrapper, OPERATION_JSON_TYPE, &audit);
244 * @brief generate a JSON object detailing a replicated update.
246 * Generate a JSON object detailing a replicated update
248 * @param module the ldb module
249 * @param request the request
250 * @paran reply the result of the operation
252 * @return the generated JSON object, should be freed with json_free.
255 static struct json_object replicated_update_json(
256 struct ldb_module *module,
257 const struct ldb_request *request,
258 const struct ldb_reply *reply)
260 struct json_object wrapper;
261 struct json_object audit;
262 struct audit_context *ac = talloc_get_type(
263 ldb_module_get_private(module),
264 struct audit_context);
265 struct dsdb_extended_replicated_objects *ro = talloc_get_type(
266 request->op.extended.data,
267 struct dsdb_extended_replicated_objects);
268 const char *partition_dn = NULL;
269 const char *error = NULL;
271 partition_dn = ldb_dn_get_linearized(ro->partition_dn);
272 error = get_friendly_werror_msg(ro->error);
274 audit = json_new_object();
275 json_add_version(&audit, REPLICATION_MAJOR, REPLICATION_MINOR);
276 json_add_int(&audit, "statusCode", reply->error);
277 json_add_string(&audit, "status", ldb_strerror(reply->error));
278 json_add_guid(&audit, "transactionId", &ac->transaction_guid);
279 json_add_int(&audit, "objectCount", ro->num_objects);
280 json_add_int(&audit, "linkCount", ro->linked_attributes_count);
281 json_add_string(&audit, "partitionDN", partition_dn);
282 json_add_string(&audit, "error", error);
283 json_add_int(&audit, "errorCode", W_ERROR_V(ro->error));
287 &ro->source_dsa->source_dsa_obj_guid);
291 &ro->source_dsa->source_dsa_invocation_id);
293 wrapper = json_new_object();
294 json_add_timestamp(&wrapper);
295 json_add_string(&wrapper, "type", REPLICATION_JSON_TYPE);
296 json_add_object(&wrapper, REPLICATION_JSON_TYPE, &audit);
301 * @brief generate a JSON object detailing a password change.
303 * Generate a JSON object detailing a password change.
305 * @param module the ldb module
306 * @param request the request
307 * @param reply the result/response
308 * @param status the status code returned for the underlying ldb operation.
310 * @return the generated JSON object.
313 static struct json_object password_change_json(
314 struct ldb_module *module,
315 const struct ldb_request *request,
316 const struct ldb_reply *reply)
318 struct ldb_context *ldb = NULL;
319 const struct dom_sid *sid = NULL;
320 const char* dn = NULL;
321 struct json_object wrapper;
322 struct json_object audit;
323 const struct tsocket_address *remote = NULL;
324 const char* action = NULL;
325 const struct GUID *unique_session_token = NULL;
326 struct audit_context *ac = talloc_get_type(
327 ldb_module_get_private(module),
328 struct audit_context);
331 ldb = ldb_module_get_ctx(module);
333 remote = dsdb_audit_get_remote_address(ldb);
334 sid = dsdb_audit_get_user_sid(module);
335 dn = dsdb_audit_get_primary_dn(request);
336 action = get_password_action(request, reply);
337 unique_session_token = dsdb_audit_get_unique_session_token(module);
339 audit = json_new_object();
340 json_add_version(&audit, PASSWORD_MAJOR, PASSWORD_MINOR);
341 json_add_int(&audit, "statusCode", reply->error);
342 json_add_string(&audit, "status", ldb_strerror(reply->error));
343 json_add_address(&audit, "remoteAddress", remote);
344 json_add_sid(&audit, "userSid", sid);
345 json_add_string(&audit, "dn", dn);
346 json_add_string(&audit, "action", action);
347 json_add_guid(&audit, "transactionId", &ac->transaction_guid);
348 json_add_guid(&audit, "sessionId", unique_session_token);
350 wrapper = json_new_object();
351 json_add_timestamp(&wrapper);
352 json_add_string(&wrapper, "type", PASSWORD_JSON_TYPE);
353 json_add_object(&wrapper, PASSWORD_JSON_TYPE, &audit);
360 * @brief create a JSON object containing details of a transaction event.
362 * Create a JSON object detailing a transaction transaction life cycle events,
363 * i.e. begin, commit, roll back
365 * @param action a one word description of the event/action
366 * @param transaction_id the GUID identifying the current transaction.
367 * @param status the status code returned by the operation
368 * @param duration the duration of the operation.
370 * @return a JSON object detailing the event
372 static struct json_object transaction_json(
374 struct GUID *transaction_id,
375 const int64_t duration)
377 struct json_object wrapper;
378 struct json_object audit;
380 audit = json_new_object();
381 json_add_version(&audit, TRANSACTION_MAJOR, TRANSACTION_MINOR);
382 json_add_string(&audit, "action", action);
383 json_add_guid(&audit, "transactionId", transaction_id);
384 json_add_int(&audit, "duration", duration);
387 wrapper = json_new_object();
388 json_add_timestamp(&wrapper);
389 json_add_string(&wrapper, "type", TRANSACTION_JSON_TYPE);
390 json_add_object(&wrapper, TRANSACTION_JSON_TYPE, &audit);
397 * @brief generate a JSON object detailing a commit failure.
399 * Generate a JSON object containing details of a commit failure.
401 * @param action the commit action, "commit" or "prepare"
402 * @param status the status code returned by commit
403 * @param reason any extra failure information/reason available
404 * @param transaction_id the GUID identifying the current transaction.
406 static struct json_object commit_failure_json(
408 const int64_t duration,
411 struct GUID *transaction_id)
413 struct json_object wrapper;
414 struct json_object audit;
416 audit = json_new_object();
417 json_add_version(&audit, TRANSACTION_MAJOR, TRANSACTION_MINOR);
418 json_add_string(&audit, "action", action);
419 json_add_guid(&audit, "transactionId", transaction_id);
420 json_add_int(&audit, "duration", duration);
421 json_add_int(&audit, "statusCode", status);
422 json_add_string(&audit, "status", ldb_strerror(status));
423 json_add_string(&audit, "reason", reason);
425 wrapper = json_new_object();
426 json_add_timestamp(&wrapper);
427 json_add_string(&wrapper, "type", TRANSACTION_JSON_TYPE);
428 json_add_object(&wrapper, TRANSACTION_JSON_TYPE, &audit);
435 * @brief Print a human readable log line for a password change event.
437 * Generate a human readable log line detailing a password change.
439 * @param mem_ctx The talloc context that will own the generated log line.
440 * @param module the ldb module
441 * @param request the request
442 * @param reply the result/response
443 * @param status the status code returned for the underlying ldb operation.
445 * @return the generated log line.
447 static char *password_change_human_readable(
449 struct ldb_module *module,
450 const struct ldb_request *request,
451 const struct ldb_reply *reply)
453 struct ldb_context *ldb = NULL;
454 const char *remote_host = NULL;
455 const struct dom_sid *sid = NULL;
456 const char *user_sid = NULL;
457 const char *timestamp = NULL;
458 char *log_entry = NULL;
459 const char *action = NULL;
460 const char *dn = NULL;
462 TALLOC_CTX *ctx = talloc_new(NULL);
464 ldb = ldb_module_get_ctx(module);
466 remote_host = dsdb_audit_get_remote_host(ldb, ctx);
467 sid = dsdb_audit_get_user_sid(module);
468 user_sid = dom_sid_string(ctx, sid);
469 timestamp = audit_get_timestamp(ctx);
470 action = get_password_action(request, reply);
471 dn = dsdb_audit_get_primary_dn(request);
473 log_entry = talloc_asprintf(
475 "[%s] at [%s] status [%s] "
476 "remote host [%s] SID [%s] DN [%s]",
479 ldb_strerror(reply->error),
487 * @brief Generate a human readable string, detailing attributes in a message
489 * For modify operations each attribute is prefixed with the action.
490 * Normal values are enclosed in []
491 * Base64 values are enclosed in {}
492 * Truncated values are indicated by three trailing dots "..."
494 * @param ldb The ldb_context
495 * @param buffer The attributes will be appended to the buffer.
496 * assumed to have been allocated via talloc.
497 * @param operation The operation type
498 * @param message the message to process
501 static char *log_attributes(
502 struct ldb_context *ldb,
504 enum ldb_request_type operation,
505 const struct ldb_message *message)
508 for (i=0;i<message->num_elements;i++) {
510 buffer = talloc_asprintf_append_buffer(buffer, " ");
513 if (message->elements[i].name == NULL) {
517 "Error: Invalid element name (NULL) at "
522 if (operation == LDB_MODIFY) {
523 const char *action =NULL;
524 action = dsdb_audit_get_modification_action(
525 message->elements[i].flags);
526 buffer = talloc_asprintf_append_buffer(
530 message->elements[i].name);
532 buffer = talloc_asprintf_append_buffer(
535 message->elements[i].name);
538 if (dsdb_audit_redact_attribute(message->elements[i].name)) {
540 * Do not log the value of any secret or password
543 buffer = talloc_asprintf_append_buffer(
545 "[REDACTED SECRET ATTRIBUTE]");
549 for (j=0;j<message->elements[i].num_values;j++) {
551 bool use_b64_encode = false;
554 buffer = talloc_asprintf_append_buffer(
559 v = message->elements[i].values[j];
560 length = min(MAX_LENGTH, v.length);
561 use_b64_encode = ldb_should_b64_encode(ldb, &v);
562 if (use_b64_encode) {
563 const char *encoded = ldb_base64_encode(
567 buffer = talloc_asprintf_append_buffer(
571 (v.length > MAX_LENGTH ? "..." : ""));
573 buffer = talloc_asprintf_append_buffer(
579 (v.length > MAX_LENGTH ? "..." : ""));
587 * @brief generate a human readable log entry detailing an ldb operation.
589 * Generate a human readable log entry detailing an ldb operation.
591 * @param mem_ctx The talloc context owning the returned string.
592 * @param module the ldb module
593 * @param request the request
594 * @param reply the result of the operation
596 * @return the log entry.
599 static char *operation_human_readable(
601 struct ldb_module *module,
602 const struct ldb_request *request,
603 const struct ldb_reply *reply)
605 struct ldb_context *ldb = NULL;
606 const char *remote_host = NULL;
607 const struct dom_sid *sid = NULL;
608 const char *user_sid = NULL;
609 const char *timestamp = NULL;
610 const char *op_name = NULL;
611 char *log_entry = NULL;
612 const char *dn = NULL;
613 const char *new_dn = NULL;
614 const struct ldb_message *message = NULL;
616 TALLOC_CTX *ctx = talloc_new(NULL);
618 ldb = ldb_module_get_ctx(module);
620 remote_host = dsdb_audit_get_remote_host(ldb, ctx);
621 if (remote_host != NULL && dsdb_audit_is_system_session(module)) {
622 sid = dsdb_audit_get_actual_sid(ldb);
624 sid = dsdb_audit_get_user_sid(module);
626 user_sid = dom_sid_string(ctx, sid);
627 timestamp = audit_get_timestamp(ctx);
628 op_name = dsdb_audit_get_operation_name(request);
629 dn = dsdb_audit_get_primary_dn(request);
630 new_dn = dsdb_audit_get_secondary_dn(request);
632 message = dsdb_audit_get_message(request);
634 log_entry = talloc_asprintf(
636 "[%s] at [%s] status [%s] "
637 "remote host [%s] SID [%s] DN [%s]",
640 ldb_strerror(reply->error),
644 if (new_dn != NULL) {
645 log_entry = talloc_asprintf_append_buffer(
650 if (message != NULL) {
651 log_entry = talloc_asprintf_append_buffer(log_entry,
653 log_entry = log_attributes(ldb,
657 log_entry = talloc_asprintf_append_buffer(log_entry, "]");
664 * @brief generate a human readable log entry detailing a replicated update
667 * Generate a human readable log entry detailing a replicated update operation
669 * @param mem_ctx The talloc context owning the returned string.
670 * @param module the ldb module
671 * @param request the request
672 * @param reply the result of the operation.
674 * @return the log entry.
677 static char *replicated_update_human_readable(
679 struct ldb_module *module,
680 const struct ldb_request *request,
681 const struct ldb_reply *reply)
683 struct dsdb_extended_replicated_objects *ro = talloc_get_type(
684 request->op.extended.data,
685 struct dsdb_extended_replicated_objects);
686 const char *partition_dn = NULL;
687 const char *error = NULL;
688 char *log_entry = NULL;
689 char *timestamp = NULL;
690 struct GUID_txt_buf object_buf;
691 const char *object = NULL;
692 struct GUID_txt_buf invocation_buf;
693 const char *invocation = NULL;
696 TALLOC_CTX *ctx = talloc_new(NULL);
698 timestamp = audit_get_timestamp(ctx);
699 error = get_friendly_werror_msg(ro->error);
700 partition_dn = ldb_dn_get_linearized(ro->partition_dn);
701 object = GUID_buf_string(
702 &ro->source_dsa->source_dsa_obj_guid,
704 invocation = GUID_buf_string(
705 &ro->source_dsa->source_dsa_invocation_id,
709 log_entry = talloc_asprintf(
711 "at [%s] status [%s] error [%s] partition [%s] objects [%d] "
712 "links [%d] object [%s] invocation [%s]",
714 ldb_strerror(reply->error),
718 ro->linked_attributes_count,
726 * @brief create a human readable log entry detailing a transaction event.
728 * Create a human readable log entry detailing a transaction event.
729 * i.e. begin, commit, roll back
731 * @param mem_ctx The talloc context owning the returned string.
732 * @param action a one word description of the event/action
733 * @param duration the duration of the transaction.
735 * @return the log entry
737 static char *transaction_human_readable(
740 const int64_t duration)
742 const char *timestamp = NULL;
743 char *log_entry = NULL;
745 TALLOC_CTX *ctx = talloc_new(NULL);
747 timestamp = audit_get_timestamp(ctx);
749 log_entry = talloc_asprintf(
751 "[%s] at [%s] duration [%ld]",
761 * @brief generate a human readable log entry detailing a commit failure.
763 * Generate generate a human readable log entry detailing a commit failure.
765 * @param mem_ctx The talloc context owning the returned string.
766 * @param action the commit action, "prepare" or "commit"
767 * @param status the status code returned by commit
768 * @param reason any extra failure information/reason available
770 * @return the log entry
772 static char *commit_failure_human_readable(
775 const int64_t duration,
779 const char *timestamp = NULL;
780 char *log_entry = NULL;
782 TALLOC_CTX *ctx = talloc_new(NULL);
784 timestamp = audit_get_timestamp(ctx);
786 log_entry = talloc_asprintf(
788 "[%s] at [%s] duration [%ld] status [%d] reason [%s]",
800 * @brief log details of a standard ldb operation.
802 * Log the details of an ldb operation in JSON and or human readable format
803 * and send over the message bus.
805 * @param module the ldb_module
806 * @param request the operation request.
807 * @param reply the operation result.
808 * @param the status code returned for the operation.
811 static void log_standard_operation(
812 struct ldb_module *module,
813 const struct ldb_request *request,
814 const struct ldb_reply *reply)
817 const struct ldb_message *message = dsdb_audit_get_message(request);
818 bool password_changed = has_password_changed(message);
819 struct audit_context *ac =
820 talloc_get_type(ldb_module_get_private(module),
821 struct audit_context);
823 TALLOC_CTX *ctx = talloc_new(NULL);
825 if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT, OPERATION_LOG_LVL)) {
827 entry = operation_human_readable(
832 audit_log_human_text(
839 if (CHECK_DEBUGLVLC(DBGC_DSDB_PWD_AUDIT, PASSWORD_LOG_LVL)) {
840 if (password_changed) {
842 entry = password_change_human_readable(
847 audit_log_human_text(
856 if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT_JSON, OPERATION_LOG_LVL) ||
857 (ac->msg_ctx && ac->send_samdb_events)) {
858 struct json_object json;
859 json = operation_json(module, request, reply);
863 DBGC_DSDB_AUDIT_JSON,
865 if (ac->msg_ctx && ac->send_password_events) {
874 if (CHECK_DEBUGLVLC(DBGC_DSDB_PWD_AUDIT_JSON, PASSWORD_LOG_LVL) ||
875 (ac->msg_ctx && ac->send_password_events)) {
876 if (password_changed) {
877 struct json_object json;
878 json = password_change_json(module, request, reply);
882 DBGC_DSDB_PWD_AUDIT_JSON,
884 if (ac->send_password_events) {
899 * @brief log details of a replicated update.
901 * Log the details of a replicated update in JSON and or human readable
902 * format and send over the message bus.
904 * @param module the ldb_module
905 * @param request the operation request
906 * @param reply the result of the operation.
909 static void log_replicated_operation(
910 struct ldb_module *module,
911 const struct ldb_request *request,
912 const struct ldb_reply *reply)
915 struct audit_context *ac =
916 talloc_get_type(ldb_module_get_private(module),
917 struct audit_context);
919 TALLOC_CTX *ctx = talloc_new(NULL);
921 if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT, REPLICATION_LOG_LVL)) {
923 entry = replicated_update_human_readable(
928 audit_log_human_text(
932 REPLICATION_LOG_LVL);
936 if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT_JSON, REPLICATION_LOG_LVL) ||
937 (ac->msg_ctx && ac->send_samdb_events)) {
938 struct json_object json;
939 json = replicated_update_json(module, request, reply);
941 REPLICATION_JSON_TYPE,
943 DBGC_DSDB_AUDIT_JSON,
944 REPLICATION_LOG_LVL);
945 if (ac->send_samdb_events) {
959 * @brief log details of an ldb operation.
961 * Log the details of an ldb operation in JSON and or human readable format
962 * and send over the message bus.
964 * @param module the ldb_module
965 * @param request the operation request
966 * @part reply the result of the operation
969 static void log_operation(
970 struct ldb_module *module,
971 const struct ldb_request *request,
972 const struct ldb_reply *reply)
975 if (request->operation == LDB_EXTENDED) {
977 request->op.extended.oid,
978 DSDB_EXTENDED_REPLICATED_OBJECTS_OID) != 0) {
980 log_replicated_operation(module, request, reply);
983 log_standard_operation(module, request, reply);
988 * @brief log details of a transaction event.
990 * Log the details of a transaction event in JSON and or human readable format
991 * and send over the message bus.
993 * @param module the ldb_module
994 * @param action the transaction event i.e. begin, commit, roll back.
995 * @param log_level the logging level
998 static void log_transaction(
999 struct ldb_module *module,
1004 struct audit_context *ac =
1005 talloc_get_type(ldb_module_get_private(module),
1006 struct audit_context);
1007 const struct timeval now = timeval_current();
1008 const int64_t duration = usec_time_diff(&now, &ac->transaction_start);
1010 TALLOC_CTX *ctx = talloc_new(NULL);
1012 if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT, log_level)) {
1014 entry = transaction_human_readable(ctx, action, duration);
1015 audit_log_human_text(
1018 DBGC_DSDB_TXN_AUDIT,
1023 if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT_JSON, log_level) ||
1024 (ac->msg_ctx && ac->send_samdb_events)) {
1025 struct json_object json;
1026 json = transaction_json(
1028 &ac->transaction_guid,
1031 TRANSACTION_JSON_TYPE,
1033 DBGC_DSDB_TXN_AUDIT_JSON,
1035 if (ac->send_samdb_events) {
1049 * @brief log details of a commit failure.
1051 * Log the details of a commit failure in JSON and or human readable
1052 * format and send over the message bus.
1054 * @param module the ldb_module
1055 * @param action the commit action "prepare" or "commit"
1056 * @param status the ldb status code returned by prepare commit.
1059 static void log_commit_failure(
1060 struct ldb_module *module,
1065 struct audit_context *ac =
1066 talloc_get_type(ldb_module_get_private(module),
1067 struct audit_context);
1068 const char* reason = dsdb_audit_get_ldb_error_string(module, status);
1069 const int log_level = TRANSACTION_LOG_FAILURE_LVL;
1070 const struct timeval now = timeval_current();
1071 const int64_t duration = usec_time_diff(&now, &ac->transaction_start);
1073 TALLOC_CTX *ctx = talloc_new(NULL);
1075 if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT, log_level)) {
1078 entry = commit_failure_human_readable(
1084 audit_log_human_text(
1087 DBGC_DSDB_TXN_AUDIT,
1088 TRANSACTION_LOG_FAILURE_LVL);
1092 if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT_JSON, log_level) ||
1093 (ac->msg_ctx && ac->send_samdb_events)) {
1094 struct json_object json;
1095 json = commit_failure_json(
1100 &ac->transaction_guid);
1102 TRANSACTION_JSON_TYPE,
1104 DBGC_DSDB_TXN_AUDIT_JSON,
1106 if (ac->send_samdb_events) {
1107 audit_message_send(ac->msg_ctx,
1119 * Context needed by audit_callback
1121 struct audit_callback_context {
1122 struct ldb_request *request;
1123 struct ldb_module *module;
1127 * @brief call back function for the ldb_operations.
1129 * As the LDB operations are async, and we wish to examine the results of
1130 * the operations, a callback needs to be registered to process the results
1131 * of the LDB operations.
1133 * @param req the ldb request
1134 * @param res the result of the operation
1136 * @return the LDB_STATUS
1138 static int audit_callback(struct ldb_request *req, struct ldb_reply *ares)
1140 struct audit_callback_context *ac = NULL;
1142 ac = talloc_get_type(
1144 struct audit_callback_context);
1147 return ldb_module_done(
1151 LDB_ERR_OPERATIONS_ERROR);
1154 /* pass on to the callback */
1155 switch (ares->type) {
1156 case LDB_REPLY_ENTRY:
1157 return ldb_module_send_entry(
1162 case LDB_REPLY_REFERRAL:
1163 return ldb_module_send_referral(
1167 case LDB_REPLY_DONE:
1169 * Log the operation once DONE
1171 log_operation(ac->module, ac->request, ares);
1172 return ldb_module_done(
1180 return LDB_ERR_OPERATIONS_ERROR;
1185 * @brief Add the current transaction identifier to the request.
1187 * Add the current transaction identifier in the module private data,
1188 * to the request as a control.
1191 * @param req the request.
1193 * @return an LDB_STATUS code, LDB_SUCCESS if successful.
1195 static int add_transaction_id(
1196 struct ldb_module *module,
1197 struct ldb_request *req)
1199 struct audit_context *ac =
1200 talloc_get_type(ldb_module_get_private(module),
1201 struct audit_context);
1202 struct dsdb_control_transaction_identifier *transaction_id;
1205 transaction_id = talloc_zero(
1207 struct dsdb_control_transaction_identifier);
1208 if (transaction_id == NULL) {
1209 struct ldb_context *ldb = ldb_module_get_ctx(module);
1210 return ldb_oom(ldb);
1212 transaction_id->transaction_guid = ac->transaction_guid;
1213 ret = ldb_request_add_control(req,
1214 DSDB_CONTROL_TRANSACTION_IDENTIFIER_OID,
1222 * @brief log details of an add operation.
1224 * Log the details of an add operation.
1226 * @param module the ldb_module
1227 * @param req the ldb_request
1229 * @return ldb status code
1232 struct ldb_module *module,
1233 struct ldb_request *req)
1235 struct audit_callback_context *context = NULL;
1236 struct ldb_request *new_req = NULL;
1237 struct ldb_context *ldb = NULL;
1240 ldb = ldb_module_get_ctx(module);
1241 context = talloc_zero(req, struct audit_callback_context);
1243 if (context == NULL) {
1244 return ldb_oom(ldb);
1246 context->request = req;
1247 context->module = module;
1249 * We want to log the return code status, so we need to register
1250 * a callback function to get the actual result.
1251 * We need to take a new copy so that we don't alter the callers copy
1253 ret = ldb_build_add_req(
1257 req->op.add.message,
1262 if (ret != LDB_SUCCESS) {
1265 ret = add_transaction_id(module, new_req);
1266 if (ret != LDB_SUCCESS) {
1269 return ldb_next_request(module, new_req);
1273 * @brief log details of an delete operation.
1275 * Log the details of an delete operation.
1277 * @param module the ldb_module
1278 * @param req the ldb_request
1280 * @return ldb status code
1282 static int log_delete(
1283 struct ldb_module *module,
1284 struct ldb_request *req)
1286 struct audit_callback_context *context = NULL;
1287 struct ldb_request *new_req = NULL;
1288 struct ldb_context *ldb = NULL;
1291 ldb = ldb_module_get_ctx(module);
1292 context = talloc_zero(req, struct audit_callback_context);
1294 if (context == NULL) {
1295 return ldb_oom(ldb);
1297 context->request = req;
1298 context->module = module;
1300 * We want to log the return code status, so we need to register
1301 * a callback function to get the actual result.
1302 * We need to take a new copy so that we don't alter the callers copy
1304 ret = ldb_build_del_req(&new_req,
1312 if (ret != LDB_SUCCESS) {
1315 ret = add_transaction_id(module, new_req);
1316 if (ret != LDB_SUCCESS) {
1319 return ldb_next_request(module, new_req);
1323 * @brief log details of a modify operation.
1325 * Log the details of a modify operation.
1327 * @param module the ldb_module
1328 * @param req the ldb_request
1330 * @return ldb status code
1332 static int log_modify(
1333 struct ldb_module *module,
1334 struct ldb_request *req)
1336 struct audit_callback_context *context = NULL;
1337 struct ldb_request *new_req = NULL;
1338 struct ldb_context *ldb = NULL;
1341 ldb = ldb_module_get_ctx(module);
1342 context = talloc_zero(req, struct audit_callback_context);
1344 if (context == NULL) {
1345 return ldb_oom(ldb);
1347 context->request = req;
1348 context->module = module;
1350 * We want to log the return code status, so we need to register
1351 * a callback function to get the actual result.
1352 * We need to take a new copy so that we don't alter the callers copy
1354 ret = ldb_build_mod_req(
1358 req->op.mod.message,
1363 if (ret != LDB_SUCCESS) {
1366 ret = add_transaction_id(module, new_req);
1367 if (ret != LDB_SUCCESS) {
1370 return ldb_next_request(module, new_req);
1374 * @brief process a transaction start.
1376 * process a transaction start, as we don't currently log transaction starts
1377 * just generate the new transaction_id.
1379 * @param module the ldb_module
1380 * @param req the ldb_request
1382 * @return ldb status code
1384 static int log_start_transaction(struct ldb_module *module)
1386 struct audit_context *ac =
1387 talloc_get_type(ldb_module_get_private(module),
1388 struct audit_context);
1391 * We do not log transaction begins
1392 * however we do generate a new transaction_id and record the start
1393 * time so that we can log the transaction duration.
1396 ac->transaction_guid = GUID_random();
1397 ac->transaction_start = timeval_current();
1398 return ldb_next_start_trans(module);
1402 * @brief log details of a prepare commit.
1404 * Log the details of a prepare commit, currently only details of
1405 * failures are logged.
1407 * @param module the ldb_module
1408 * @param req the ldb_request
1410 * @return ldb status code
1412 static int log_prepare_commit(struct ldb_module *module)
1415 int ret = ldb_next_prepare_commit(module);
1416 if (ret != LDB_SUCCESS) {
1418 * We currently only log prepare commit failures
1420 log_commit_failure(module, "prepare", ret);
1426 * @brief process a transaction end aka commit.
1428 * process a transaction end, as we don't currently log transaction ends
1429 * just clear transaction_id.
1431 * @param module the ldb_module
1432 * @param req the ldb_request
1434 * @return ldb status code
1436 static int log_end_transaction(struct ldb_module *module)
1438 struct audit_context *ac =
1439 talloc_get_type(ldb_module_get_private(module),
1440 struct audit_context);
1444 ret = ldb_next_end_trans(module);
1445 if (ret == LDB_SUCCESS) {
1449 TRANSACTION_LOG_COMPLETION_LVL);
1451 log_commit_failure(module, "commit", ret);
1454 * Clear the transaction id inserted by log_start_transaction
1456 memset(&ac->transaction_guid, 0, sizeof(struct GUID));
1461 * @brief log details of a transaction delete aka roll back.
1463 * Log details of a transaction roll back.
1465 * @param module the ldb_module
1466 * @param req the ldb_request
1468 * @return ldb status code
1470 static int log_del_transaction(struct ldb_module *module)
1472 struct audit_context *ac =
1473 talloc_get_type(ldb_module_get_private(module),
1474 struct audit_context);
1476 log_transaction(module, "rollback", TRANSACTION_LOG_FAILURE_LVL);
1477 memset(&ac->transaction_guid, 0, sizeof(struct GUID));
1478 return ldb_next_del_trans(module);
1482 * @brief log details of an extended operation.
1484 * Log the details of an extended operation.
1486 * @param module the ldb_module
1487 * @param req the ldb_request
1489 * @return ldb status code
1491 static int log_extended(
1492 struct ldb_module *module,
1493 struct ldb_request *req)
1495 struct audit_callback_context *context = NULL;
1496 struct ldb_request *new_req = NULL;
1497 struct ldb_context *ldb = NULL;
1501 * Currently we only log replication extended operations
1504 req->op.extended.oid,
1505 DSDB_EXTENDED_REPLICATED_OBJECTS_OID) != 0) {
1507 return ldb_next_request(module, req);
1509 ldb = ldb_module_get_ctx(module);
1510 context = talloc_zero(req, struct audit_callback_context);
1512 if (context == NULL) {
1513 return ldb_oom(ldb);
1515 context->request = req;
1516 context->module = module;
1518 * We want to log the return code status, so we need to register
1519 * a callback function to get the actual result.
1520 * We need to take a new copy so that we don't alter the callers copy
1522 ret = ldb_build_extended_req(
1526 req->op.extended.oid,
1527 req->op.extended.data,
1532 if (ret != LDB_SUCCESS) {
1535 ret = add_transaction_id(module, new_req);
1536 if (ret != LDB_SUCCESS) {
1539 return ldb_next_request(module, new_req);
1543 * @brief module initialisation
1545 static int log_init(struct ldb_module *module)
1548 struct ldb_context *ldb = ldb_module_get_ctx(module);
1549 struct audit_context *context = NULL;
1550 struct loadparm_context *lp_ctx
1551 = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
1552 struct loadparm_context);
1553 struct tevent_context *ev = ldb_get_event_context(ldb);
1554 bool sdb_events = false;
1555 bool pwd_events = false;
1557 context = talloc_zero(module, struct audit_context);
1558 if (context == NULL) {
1559 return ldb_module_oom(module);
1562 if (lp_ctx != NULL) {
1563 sdb_events = lpcfg_dsdb_event_notification(lp_ctx);
1564 pwd_events = lpcfg_dsdb_password_event_notification(lp_ctx);
1566 if (sdb_events || pwd_events) {
1567 context->send_samdb_events = sdb_events;
1568 context->send_password_events = pwd_events;
1569 context->msg_ctx = imessaging_client_init(context,
1574 ldb_module_set_private(module, context);
1575 return ldb_next_init(module);
1578 static const struct ldb_module_ops ldb_audit_log_module_ops = {
1579 .name = "audit_log",
1580 .init_context = log_init,
1582 .modify = log_modify,
1584 .start_transaction = log_start_transaction,
1585 .prepare_commit = log_prepare_commit,
1586 .end_transaction = log_end_transaction,
1587 .del_transaction = log_del_transaction,
1588 .extended = log_extended,
1591 int ldb_audit_log_module_init(const char *version)
1593 LDB_MODULE_CHECK_VERSION(version);
1594 return ldb_register_module(&ldb_audit_log_module_ops);