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
53 * Currently we only log roll backs and prepare commit failures
55 #define TRANSACTION_LOG_LVL 5
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_context {
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;
97 * @brief Has the password changed.
99 * Does the message contain a change to one of the password attributes? The
100 * password attributes are defined in DSDB_PASSWORD_ATTRIBUTES
102 * @return true if the message contains a password attribute
105 static bool has_password_changed(const struct ldb_message *message)
108 if (message == NULL) {
111 for (i=0;i<message->num_elements;i++) {
112 if (dsdb_audit_is_password_attribute(
113 message->elements[i].name)) {
121 * @brief Is the request a password "Change" or a "Reset"
123 * Get a description of the action being performed on the user password. This
124 * routine assumes that the request contains password attributes and that the
125 * password ACL checks have been performed by acl.c
127 * @param request the ldb_request to inspect
128 * @param reply the ldb_reply, will contain the password controls
130 * @return "Change" if the password is being changed.
131 * "Reset" if the password is being reset.
133 static const char *get_password_action(
134 const struct ldb_request *request,
135 const struct ldb_reply *reply)
137 if(request->operation == LDB_ADD) {
140 struct ldb_control *pav_ctrl = NULL;
141 struct dsdb_control_password_acl_validation *pav = NULL;
143 pav_ctrl = ldb_reply_get_control(
144 discard_const(reply),
145 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
146 if (pav_ctrl == NULL) {
150 pav = talloc_get_type_abort(
152 struct dsdb_control_password_acl_validation);
154 if (pav->pwd_reset) {
165 * @brief generate a JSON object detailing an ldb operation.
167 * Generate a JSON object detailing an ldb operation.
169 * @param module the ldb module
170 * @param request the request
171 * @param reply the result of the operation.
173 * @return the generated JSON object, should be freed with json_free.
176 static struct json_object operation_json(
177 struct ldb_module *module,
178 const struct ldb_request *request,
179 const struct ldb_reply *reply)
181 struct ldb_context *ldb = NULL;
182 const struct dom_sid *sid = NULL;
183 bool as_system = false;
184 struct json_object wrapper;
185 struct json_object audit;
186 const struct tsocket_address *remote = NULL;
187 const char *dn = NULL;
188 const char* operation = NULL;
189 const struct GUID *unique_session_token = NULL;
190 const struct ldb_message *message = NULL;
191 struct audit_context *ac = talloc_get_type(
192 ldb_module_get_private(module),
193 struct audit_context);
195 ldb = ldb_module_get_ctx(module);
197 remote = dsdb_audit_get_remote_address(ldb);
198 if (remote != NULL && dsdb_audit_is_system_session(module)) {
200 sid = dsdb_audit_get_actual_sid(ldb);
201 unique_session_token =
202 dsdb_audit_get_actual_unique_session_token(ldb);
204 sid = dsdb_audit_get_user_sid(module);
205 unique_session_token =
206 dsdb_audit_get_unique_session_token(module);
208 dn = dsdb_audit_get_primary_dn(request);
209 operation = dsdb_audit_get_operation_name(request);
211 audit = json_new_object();
212 json_add_version(&audit, OPERATION_MAJOR, OPERATION_MINOR);
213 json_add_int(&audit, "statusCode", reply->error);
214 json_add_string(&audit, "status", ldb_strerror(reply->error));
215 json_add_string(&audit, "operation", operation);
216 json_add_address(&audit, "remoteAddress", remote);
217 json_add_bool(&audit, "performedAsSystem", as_system);
218 json_add_sid(&audit, "userSid", sid);
219 json_add_string(&audit, "dn", dn);
220 json_add_guid(&audit, "transactionId", &ac->transaction_guid);
221 json_add_guid(&audit, "sessionId", unique_session_token);
223 message = dsdb_audit_get_message(request);
224 if (message != NULL) {
225 struct json_object attributes =
226 dsdb_audit_attributes_json(
229 json_add_object(&audit, "attributes", &attributes);
232 wrapper = json_new_object();
233 json_add_timestamp(&wrapper);
234 json_add_string(&wrapper, "type", OPERATION_JSON_TYPE);
235 json_add_object(&wrapper, OPERATION_JSON_TYPE, &audit);
240 * @brief generate a JSON object detailing a replicated update.
242 * Generate a JSON object detailing a replicated update
244 * @param module the ldb module
245 * @param request the request
246 * @paran reply the result of the operation
248 * @return the generated JSON object, should be freed with json_free.
251 static struct json_object replicated_update_json(
252 struct ldb_module *module,
253 const struct ldb_request *request,
254 const struct ldb_reply *reply)
256 struct json_object wrapper;
257 struct json_object audit;
258 struct audit_context *ac = talloc_get_type(
259 ldb_module_get_private(module),
260 struct audit_context);
261 struct dsdb_extended_replicated_objects *ro = talloc_get_type(
262 request->op.extended.data,
263 struct dsdb_extended_replicated_objects);
264 const char *partition_dn = NULL;
265 const char *error = NULL;
267 partition_dn = ldb_dn_get_linearized(ro->partition_dn);
268 error = get_friendly_werror_msg(ro->error);
270 audit = json_new_object();
271 json_add_version(&audit, REPLICATION_MAJOR, REPLICATION_MINOR);
272 json_add_int(&audit, "statusCode", reply->error);
273 json_add_string(&audit, "status", ldb_strerror(reply->error));
274 json_add_guid(&audit, "transactionId", &ac->transaction_guid);
275 json_add_int(&audit, "objectCount", ro->num_objects);
276 json_add_int(&audit, "linkCount", ro->linked_attributes_count);
277 json_add_string(&audit, "partitionDN", partition_dn);
278 json_add_string(&audit, "error", error);
279 json_add_int(&audit, "errorCode", W_ERROR_V(ro->error));
283 &ro->source_dsa->source_dsa_obj_guid);
287 &ro->source_dsa->source_dsa_invocation_id);
289 wrapper = json_new_object();
290 json_add_timestamp(&wrapper);
291 json_add_string(&wrapper, "type", REPLICATION_JSON_TYPE);
292 json_add_object(&wrapper, REPLICATION_JSON_TYPE, &audit);
297 * @brief generate a JSON object detailing a password change.
299 * Generate a JSON object detailing a password change.
301 * @param module the ldb module
302 * @param request the request
303 * @param reply the result/response
304 * @param status the status code returned for the underlying ldb operation.
306 * @return the generated JSON object.
309 static struct json_object password_change_json(
310 struct ldb_module *module,
311 const struct ldb_request *request,
312 const struct ldb_reply *reply)
314 struct ldb_context *ldb = NULL;
315 const struct dom_sid *sid = NULL;
316 const char* dn = NULL;
317 struct json_object wrapper;
318 struct json_object audit;
319 const struct tsocket_address *remote = NULL;
320 const char* action = NULL;
321 const struct GUID *unique_session_token = NULL;
322 struct audit_context *ac = talloc_get_type(
323 ldb_module_get_private(module),
324 struct audit_context);
327 ldb = ldb_module_get_ctx(module);
329 remote = dsdb_audit_get_remote_address(ldb);
330 sid = dsdb_audit_get_user_sid(module);
331 dn = dsdb_audit_get_primary_dn(request);
332 action = get_password_action(request, reply);
333 unique_session_token = dsdb_audit_get_unique_session_token(module);
335 audit = json_new_object();
336 json_add_version(&audit, PASSWORD_MAJOR, PASSWORD_MINOR);
337 json_add_int(&audit, "statusCode", reply->error);
338 json_add_string(&audit, "status", ldb_strerror(reply->error));
339 json_add_address(&audit, "remoteAddress", remote);
340 json_add_sid(&audit, "userSid", sid);
341 json_add_string(&audit, "dn", dn);
342 json_add_string(&audit, "action", action);
343 json_add_guid(&audit, "transactionId", &ac->transaction_guid);
344 json_add_guid(&audit, "sessionId", unique_session_token);
346 wrapper = json_new_object();
347 json_add_timestamp(&wrapper);
348 json_add_string(&wrapper, "type", PASSWORD_JSON_TYPE);
349 json_add_object(&wrapper, PASSWORD_JSON_TYPE, &audit);
356 * @brief create a JSON object containing details of a transaction event.
358 * Create a JSON object detailing a transaction transaction life cycle events,
359 * i.e. begin, commit, roll back
361 * @param action a one word description of the event/action
362 * @param transaction_id the GUID identifying the current transaction.
364 * @return a JSON object detailing the event
366 static struct json_object transaction_json(
368 struct GUID *transaction_id)
370 struct json_object wrapper;
371 struct json_object audit;
373 audit = json_new_object();
374 json_add_version(&audit, TRANSACTION_MAJOR, TRANSACTION_MINOR);
375 json_add_string(&audit, "action", action);
376 json_add_guid(&audit, "transactionId", transaction_id);
378 wrapper = json_new_object();
379 json_add_timestamp(&wrapper);
380 json_add_string(&wrapper, "type", TRANSACTION_JSON_TYPE);
381 json_add_object(&wrapper, TRANSACTION_JSON_TYPE, &audit);
388 * @brief generate a JSON object detailing a commit failure.
390 * Generate a JSON object containing details of a commit failure.
392 * @param action the commit action, "commit" or "prepare"
393 * @param status the status code returned by commit
394 * @param reason any extra failure information/reason available
395 * @param transaction_id the GUID identifying the current transaction.
397 static struct json_object commit_failure_json(
401 struct GUID *transaction_id)
403 struct json_object wrapper;
404 struct json_object audit;
406 audit = json_new_object();
407 json_add_version(&audit, TRANSACTION_MAJOR, TRANSACTION_MINOR);
408 json_add_string(&audit, "action", action);
409 json_add_guid(&audit, "transactionId", transaction_id);
410 json_add_int(&audit, "statusCode", status);
411 json_add_string(&audit, "status", ldb_strerror(status));
412 json_add_string(&audit, "reason", reason);
414 wrapper = json_new_object();
415 json_add_timestamp(&wrapper);
416 json_add_string(&wrapper, "type", TRANSACTION_JSON_TYPE);
417 json_add_object(&wrapper, TRANSACTION_JSON_TYPE, &audit);
424 * @brief Print a human readable log line for a password change event.
426 * Generate a human readable log line detailing a password change.
428 * @param mem_ctx The talloc context that will own the generated log line.
429 * @param module the ldb module
430 * @param request the request
431 * @param reply the result/response
432 * @param status the status code returned for the underlying ldb operation.
434 * @return the generated log line.
436 static char *password_change_human_readable(
438 struct ldb_module *module,
439 const struct ldb_request *request,
440 const struct ldb_reply *reply)
442 struct ldb_context *ldb = NULL;
443 const char *remote_host = NULL;
444 const struct dom_sid *sid = NULL;
445 const char *user_sid = NULL;
446 const char *timestamp = NULL;
447 char *log_entry = NULL;
448 const char *action = NULL;
449 const char *dn = NULL;
451 TALLOC_CTX *ctx = talloc_new(NULL);
453 ldb = ldb_module_get_ctx(module);
455 remote_host = dsdb_audit_get_remote_host(ldb, ctx);
456 sid = dsdb_audit_get_user_sid(module);
457 user_sid = dom_sid_string(ctx, sid);
458 timestamp = audit_get_timestamp(ctx);
459 action = get_password_action(request, reply);
460 dn = dsdb_audit_get_primary_dn(request);
462 log_entry = talloc_asprintf(
464 "[%s] at [%s] status [%s] "
465 "remote host [%s] SID [%s] DN [%s]",
468 ldb_strerror(reply->error),
476 * @brief Generate a human readable string, detailing attributes in a message
478 * For modify operations each attribute is prefixed with the action.
479 * Normal values are enclosed in []
480 * Base64 values are enclosed in {}
481 * Truncated values are indicated by three trailing dots "..."
483 * @param ldb The ldb_context
484 * @param buffer The attributes will be appended to the buffer.
485 * assumed to have been allocated via talloc.
486 * @param operation The operation type
487 * @param message the message to process
490 static char *log_attributes(
491 struct ldb_context *ldb,
493 enum ldb_request_type operation,
494 const struct ldb_message *message)
497 for (i=0;i<message->num_elements;i++) {
499 buffer = talloc_asprintf_append_buffer(buffer, " ");
502 if (message->elements[i].name == NULL) {
506 "Error: Invalid element name (NULL) at "
511 if (operation == LDB_MODIFY) {
512 const char *action =NULL;
513 action = dsdb_audit_get_modification_action(
514 message->elements[i].flags);
515 buffer = talloc_asprintf_append_buffer(
519 message->elements[i].name);
521 buffer = talloc_asprintf_append_buffer(
524 message->elements[i].name);
527 if (dsdb_audit_redact_attribute(message->elements[i].name)) {
529 * Do not log the value of any secret or password
532 buffer = talloc_asprintf_append_buffer(
534 "[REDACTED SECRET ATTRIBUTE]");
538 for (j=0;j<message->elements[i].num_values;j++) {
540 bool use_b64_encode = false;
543 buffer = talloc_asprintf_append_buffer(
548 v = message->elements[i].values[j];
549 length = min(MAX_LENGTH, v.length);
550 use_b64_encode = ldb_should_b64_encode(ldb, &v);
551 if (use_b64_encode) {
552 const char *encoded = ldb_base64_encode(
556 buffer = talloc_asprintf_append_buffer(
560 (v.length > MAX_LENGTH ? "..." : ""));
562 buffer = talloc_asprintf_append_buffer(
568 (v.length > MAX_LENGTH ? "..." : ""));
576 * @brief generate a human readable log entry detailing an ldb operation.
578 * Generate a human readable log entry detailing an ldb operation.
580 * @param mem_ctx The talloc context owning the returned string.
581 * @param module the ldb module
582 * @param request the request
583 * @param reply the result of the operation
585 * @return the log entry.
588 static char *operation_human_readable(
590 struct ldb_module *module,
591 const struct ldb_request *request,
592 const struct ldb_reply *reply)
594 struct ldb_context *ldb = NULL;
595 const char *remote_host = NULL;
596 const struct dom_sid *sid = NULL;
597 const char *user_sid = NULL;
598 const char *timestamp = NULL;
599 const char *op_name = NULL;
600 char *log_entry = NULL;
601 const char *dn = NULL;
602 const char *new_dn = NULL;
603 const struct ldb_message *message = NULL;
605 TALLOC_CTX *ctx = talloc_new(NULL);
607 ldb = ldb_module_get_ctx(module);
609 remote_host = dsdb_audit_get_remote_host(ldb, ctx);
610 if (remote_host != NULL && dsdb_audit_is_system_session(module)) {
611 sid = dsdb_audit_get_actual_sid(ldb);
613 sid = dsdb_audit_get_user_sid(module);
615 user_sid = dom_sid_string(ctx, sid);
616 timestamp = audit_get_timestamp(ctx);
617 op_name = dsdb_audit_get_operation_name(request);
618 dn = dsdb_audit_get_primary_dn(request);
619 new_dn = dsdb_audit_get_secondary_dn(request);
621 message = dsdb_audit_get_message(request);
623 log_entry = talloc_asprintf(
625 "[%s] at [%s] status [%s] "
626 "remote host [%s] SID [%s] DN [%s]",
629 ldb_strerror(reply->error),
633 if (new_dn != NULL) {
634 log_entry = talloc_asprintf_append_buffer(
639 if (message != NULL) {
640 log_entry = talloc_asprintf_append_buffer(log_entry,
642 log_entry = log_attributes(ldb,
646 log_entry = talloc_asprintf_append_buffer(log_entry, "]");
653 * @brief generate a human readable log entry detailing a replicated update
656 * Generate a human readable log entry detailing a replicated update operation
658 * @param mem_ctx The talloc context owning the returned string.
659 * @param module the ldb module
660 * @param request the request
661 * @param reply the result of the operation.
663 * @return the log entry.
666 static char *replicated_update_human_readable(
668 struct ldb_module *module,
669 const struct ldb_request *request,
670 const struct ldb_reply *reply)
672 struct dsdb_extended_replicated_objects *ro = talloc_get_type(
673 request->op.extended.data,
674 struct dsdb_extended_replicated_objects);
675 const char *partition_dn = NULL;
676 const char *error = NULL;
677 char *log_entry = NULL;
678 char *timestamp = NULL;
679 struct GUID_txt_buf object_buf;
680 const char *object = NULL;
681 struct GUID_txt_buf invocation_buf;
682 const char *invocation = NULL;
685 TALLOC_CTX *ctx = talloc_new(NULL);
687 timestamp = audit_get_timestamp(ctx);
688 error = get_friendly_werror_msg(ro->error);
689 partition_dn = ldb_dn_get_linearized(ro->partition_dn);
690 object = GUID_buf_string(
691 &ro->source_dsa->source_dsa_obj_guid,
693 invocation = GUID_buf_string(
694 &ro->source_dsa->source_dsa_invocation_id,
698 log_entry = talloc_asprintf(
700 "at [%s] status [%s] error [%s] partition [%s] objects [%d] "
701 "links [%d] object [%s] invocation [%s]",
703 ldb_strerror(reply->error),
707 ro->linked_attributes_count,
715 * @brief create a human readable log entry detailing a transaction event.
717 * Create a human readable log entry detailing a transaction event.
718 * i.e. begin, commit, roll back
720 * @param mem_ctx The talloc context owning the returned string.
721 * @param action a one word description of the event/action
722 * @param transaction_id the GUID identifying the current transaction.
724 * @return the log entry
726 static char *transaction_human_readable(
730 const char *timestamp = NULL;
731 char *log_entry = NULL;
733 TALLOC_CTX *ctx = talloc_new(NULL);
735 timestamp = audit_get_timestamp(ctx);
737 log_entry = talloc_asprintf(
748 * @brief generate a human readable log entry detailing a commit failure.
750 * Generate generate a human readable log entry detailing a commit failure.
752 * @param mem_ctx The talloc context owning the returned string.
753 * @param action the commit action, "prepare" or "commit"
754 * @param status the status code returned by commit
755 * @param reason any extra failure information/reason available
757 * @return the log entry
759 static char *commit_failure_human_readable(
765 const char *timestamp = NULL;
766 char *log_entry = NULL;
768 TALLOC_CTX *ctx = talloc_new(NULL);
770 timestamp = audit_get_timestamp(ctx);
772 log_entry = talloc_asprintf(
774 "[%s] at [%s] status [%d] reason [%s]",
785 * @brief log details of a standard ldb operation.
787 * Log the details of an ldb operation in JSON and or human readable format
788 * and send over the message bus.
790 * @param module the ldb_module
791 * @param request the operation request.
792 * @param reply the operation result.
793 * @param the status code returned for the operation.
796 static void log_standard_operation(
797 struct ldb_module *module,
798 const struct ldb_request *request,
799 const struct ldb_reply *reply)
802 const struct ldb_message *message = dsdb_audit_get_message(request);
803 bool password_changed = has_password_changed(message);
804 struct audit_context *ac =
805 talloc_get_type(ldb_module_get_private(module),
806 struct audit_context);
808 TALLOC_CTX *ctx = talloc_new(NULL);
810 if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT, OPERATION_LOG_LVL)) {
812 entry = operation_human_readable(
817 audit_log_human_text(
824 if (CHECK_DEBUGLVLC(DBGC_DSDB_PWD_AUDIT, PASSWORD_LOG_LVL)) {
825 if (password_changed) {
827 entry = password_change_human_readable(
832 audit_log_human_text(
841 if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT_JSON, OPERATION_LOG_LVL) ||
842 (ac->msg_ctx && ac->send_samdb_events)) {
843 struct json_object json;
844 json = operation_json(module, request, reply);
848 DBGC_DSDB_AUDIT_JSON,
850 if (ac->msg_ctx && ac->send_password_events) {
859 if (CHECK_DEBUGLVLC(DBGC_DSDB_PWD_AUDIT_JSON, PASSWORD_LOG_LVL) ||
860 (ac->msg_ctx && ac->send_password_events)) {
861 if (password_changed) {
862 struct json_object json;
863 json = password_change_json(module, request, reply);
867 DBGC_DSDB_PWD_AUDIT_JSON,
869 if (ac->send_password_events) {
884 * @brief log details of a replicated update.
886 * Log the details of a replicated update in JSON and or human readable
887 * format and send over the message bus.
889 * @param module the ldb_module
890 * @param request the operation request
891 * @param reply the result of the operation.
894 static void log_replicated_operation(
895 struct ldb_module *module,
896 const struct ldb_request *request,
897 const struct ldb_reply *reply)
900 struct audit_context *ac =
901 talloc_get_type(ldb_module_get_private(module),
902 struct audit_context);
904 TALLOC_CTX *ctx = talloc_new(NULL);
906 if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT, REPLICATION_LOG_LVL)) {
908 entry = replicated_update_human_readable(
913 audit_log_human_text(
917 REPLICATION_LOG_LVL);
921 if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT_JSON, REPLICATION_LOG_LVL) ||
922 (ac->msg_ctx && ac->send_samdb_events)) {
923 struct json_object json;
924 json = replicated_update_json(module, request, reply);
926 REPLICATION_JSON_TYPE,
928 DBGC_DSDB_AUDIT_JSON,
929 REPLICATION_LOG_LVL);
930 if (ac->send_samdb_events) {
944 * @brief log details of an ldb operation.
946 * Log the details of an ldb operation in JSON and or human readable format
947 * and send over the message bus.
949 * @param module the ldb_module
950 * @param request the operation request
951 * @part reply the result of the operation
954 static void log_operation(
955 struct ldb_module *module,
956 const struct ldb_request *request,
957 const struct ldb_reply *reply)
960 if (request->operation == LDB_EXTENDED) {
962 request->op.extended.oid,
963 DSDB_EXTENDED_REPLICATED_OBJECTS_OID) != 0) {
965 log_replicated_operation(module, request, reply);
968 log_standard_operation(module, request, reply);
973 * @brief log details of a transaction event.
975 * Log the details of a transaction event in JSON and or human readable format
976 * and send over the message bus.
978 * @param module the ldb_module
979 * @param action the transaction event i.e. begin, commit, roll back.
982 static void log_transaction(
983 struct ldb_module *module,
987 struct audit_context *ac =
988 talloc_get_type(ldb_module_get_private(module),
989 struct audit_context);
991 TALLOC_CTX *ctx = talloc_new(NULL);
993 if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT, TRANSACTION_LOG_LVL)) {
995 entry = transaction_human_readable(ctx, action);
996 audit_log_human_text(
1000 TRANSACTION_LOG_LVL);
1004 if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT_JSON, TRANSACTION_LOG_LVL) ||
1005 (ac->msg_ctx && ac->send_samdb_events)) {
1006 struct json_object json;
1007 json = transaction_json(action, &ac->transaction_guid);
1009 TRANSACTION_JSON_TYPE,
1011 DBGC_DSDB_TXN_AUDIT_JSON,
1012 TRANSACTION_LOG_LVL);
1013 if (ac->send_samdb_events) {
1027 * @brief log details of a commit failure.
1029 * Log the details of a commit failure in JSON and or human readable
1030 * format and send over the message bus.
1032 * @param module the ldb_module
1033 * @param action the commit action "prepare" or "commit"
1034 * @param status the ldb status code returned by prepare commit.
1037 static void log_commit_failure(
1038 struct ldb_module *module,
1043 struct audit_context *ac =
1044 talloc_get_type(ldb_module_get_private(module),
1045 struct audit_context);
1046 const char* reason = dsdb_audit_get_ldb_error_string(module, status);
1048 TALLOC_CTX *ctx = talloc_new(NULL);
1050 if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT, TRANSACTION_LOG_LVL)) {
1052 entry = commit_failure_human_readable(
1057 audit_log_human_text(
1060 DBGC_DSDB_TXN_AUDIT,
1061 TRANSACTION_LOG_LVL);
1065 if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT_JSON, TRANSACTION_LOG_LVL) ||
1066 (ac->msg_ctx && ac->send_samdb_events)) {
1067 struct json_object json;
1068 json = commit_failure_json(
1072 &ac->transaction_guid);
1074 TRANSACTION_JSON_TYPE,
1076 DBGC_DSDB_TXN_AUDIT_JSON,
1077 TRANSACTION_LOG_LVL);
1078 if (ac->send_samdb_events) {
1079 audit_message_send(ac->msg_ctx,
1091 * Context needed by audit_callback
1093 struct audit_callback_context {
1094 struct ldb_request *request;
1095 struct ldb_module *module;
1099 * @brief call back function for the ldb_operations.
1101 * As the LDB operations are async, and we wish to examine the results of
1102 * the operations, a callback needs to be registered to process the results
1103 * of the LDB operations.
1105 * @param req the ldb request
1106 * @param res the result of the operation
1108 * @return the LDB_STATUS
1110 static int audit_callback(struct ldb_request *req, struct ldb_reply *ares)
1112 struct audit_callback_context *ac = NULL;
1114 ac = talloc_get_type(
1116 struct audit_callback_context);
1119 return ldb_module_done(
1123 LDB_ERR_OPERATIONS_ERROR);
1126 /* pass on to the callback */
1127 switch (ares->type) {
1128 case LDB_REPLY_ENTRY:
1129 return ldb_module_send_entry(
1134 case LDB_REPLY_REFERRAL:
1135 return ldb_module_send_referral(
1139 case LDB_REPLY_DONE:
1141 * Log the operation once DONE
1143 log_operation(ac->module, ac->request, ares);
1144 return ldb_module_done(
1152 return LDB_ERR_OPERATIONS_ERROR;
1157 * @brief Add the current transaction identifier to the request.
1159 * Add the current transaction identifier in the module private data,
1160 * to the request as a control.
1163 * @param req the request.
1165 * @return an LDB_STATUS code, LDB_SUCCESS if successful.
1167 static int add_transaction_id(
1168 struct ldb_module *module,
1169 struct ldb_request *req)
1171 struct audit_context *ac =
1172 talloc_get_type(ldb_module_get_private(module),
1173 struct audit_context);
1174 struct dsdb_control_transaction_identifier *transaction_id;
1176 transaction_id = talloc_zero(
1178 struct dsdb_control_transaction_identifier);
1179 if (transaction_id == NULL) {
1180 struct ldb_context *ldb = ldb_module_get_ctx(module);
1181 return ldb_oom(ldb);
1183 transaction_id->transaction_guid = ac->transaction_guid;
1184 ldb_request_add_control(req,
1185 DSDB_CONTROL_TRANSACTION_IDENTIFIER_OID,
1193 * @brief log details of an add operation.
1195 * Log the details of an add operation.
1197 * @param module the ldb_module
1198 * @param req the ldb_request
1200 * @return ldb status code
1203 struct ldb_module *module,
1204 struct ldb_request *req)
1206 struct audit_callback_context *context = NULL;
1207 struct ldb_request *new_req = NULL;
1208 struct ldb_context *ldb = NULL;
1211 ldb = ldb_module_get_ctx(module);
1212 context = talloc_zero(req, struct audit_callback_context);
1214 if (context == NULL) {
1215 return ldb_oom(ldb);
1217 context->request = req;
1218 context->module = module;
1220 * We want to log the return code status, so we need to register
1221 * a callback function to get the actual result.
1222 * We need to take a new copy so that we don't alter the callers copy
1224 ret = ldb_build_add_req(
1228 req->op.add.message,
1233 if (ret != LDB_SUCCESS) {
1236 ret = add_transaction_id(module, new_req);
1237 if (ret != LDB_SUCCESS) {
1240 return ldb_next_request(module, new_req);
1244 * @brief log details of an delete operation.
1246 * Log the details of an delete operation.
1248 * @param module the ldb_module
1249 * @param req the ldb_request
1251 * @return ldb status code
1253 static int log_delete(
1254 struct ldb_module *module,
1255 struct ldb_request *req)
1257 struct audit_callback_context *context = NULL;
1258 struct ldb_request *new_req = NULL;
1259 struct ldb_context *ldb = NULL;
1262 ldb = ldb_module_get_ctx(module);
1263 context = talloc_zero(req, struct audit_callback_context);
1265 if (context == NULL) {
1266 return ldb_oom(ldb);
1268 context->request = req;
1269 context->module = module;
1271 * We want to log the return code status, so we need to register
1272 * a callback function to get the actual result.
1273 * We need to take a new copy so that we don't alter the callers copy
1275 ret = ldb_build_del_req(&new_req,
1283 if (ret != LDB_SUCCESS) {
1286 ret = add_transaction_id(module, new_req);
1287 if (ret != LDB_SUCCESS) {
1290 return ldb_next_request(module, new_req);
1294 * @brief log details of a modify operation.
1296 * Log the details of a modify operation.
1298 * @param module the ldb_module
1299 * @param req the ldb_request
1301 * @return ldb status code
1303 static int log_modify(
1304 struct ldb_module *module,
1305 struct ldb_request *req)
1307 struct audit_callback_context *context = NULL;
1308 struct ldb_request *new_req = NULL;
1309 struct ldb_context *ldb = NULL;
1312 ldb = ldb_module_get_ctx(module);
1313 context = talloc_zero(req, struct audit_callback_context);
1315 if (context == NULL) {
1316 return ldb_oom(ldb);
1318 context->request = req;
1319 context->module = module;
1321 * We want to log the return code status, so we need to register
1322 * a callback function to get the actual result.
1323 * We need to take a new copy so that we don't alter the callers copy
1325 ret = ldb_build_mod_req(
1329 req->op.mod.message,
1334 if (ret != LDB_SUCCESS) {
1337 ret = add_transaction_id(module, new_req);
1338 if (ret != LDB_SUCCESS) {
1341 return ldb_next_request(module, new_req);
1345 * @brief process a transaction start.
1347 * process a transaction start, as we don't currently log transaction starts
1348 * just generate the new transaction_id.
1350 * @param module the ldb_module
1351 * @param req the ldb_request
1353 * @return ldb status code
1355 static int log_start_transaction(struct ldb_module *module)
1357 struct audit_context *ac =
1358 talloc_get_type(ldb_module_get_private(module),
1359 struct audit_context);
1362 * We do not log transaction begins
1363 * however we do generate a new transaction_id
1366 ac->transaction_guid = GUID_random();
1367 return ldb_next_start_trans(module);
1371 * @brief log details of a prepare commit.
1373 * Log the details of a prepare commit, currently only details of
1374 * failures are logged.
1376 * @param module the ldb_module
1377 * @param req the ldb_request
1379 * @return ldb status code
1381 static int log_prepare_commit(struct ldb_module *module)
1384 int ret = ldb_next_prepare_commit(module);
1385 if (ret != LDB_SUCCESS) {
1387 * We currently only log prepare commit failures
1389 log_commit_failure(module, "prepare", ret);
1395 * @brief process a transaction end aka commit.
1397 * process a transaction end, as we don't currently log transaction ends
1398 * just clear transaction_id.
1400 * @param module the ldb_module
1401 * @param req the ldb_request
1403 * @return ldb status code
1405 static int log_end_transaction(struct ldb_module *module)
1407 struct audit_context *ac =
1408 talloc_get_type(ldb_module_get_private(module),
1409 struct audit_context);
1413 * Clear the transaction id inserted by log_start_transaction
1415 memset(&ac->transaction_guid, 0, sizeof(struct GUID));
1417 ret = ldb_next_end_trans(module);
1418 if (ret != LDB_SUCCESS) {
1420 * We currently only log commit failures
1422 log_commit_failure(module, "commit", ret);
1428 * @brief log details of a transaction delete aka roll back.
1430 * Log details of a transaction roll back.
1432 * @param module the ldb_module
1433 * @param req the ldb_request
1435 * @return ldb status code
1437 static int log_del_transaction(struct ldb_module *module)
1439 struct audit_context *ac =
1440 talloc_get_type(ldb_module_get_private(module),
1441 struct audit_context);
1443 log_transaction(module, "rollback");
1444 memset(&ac->transaction_guid, 0, sizeof(struct GUID));
1445 return ldb_next_del_trans(module);
1449 * @brief log details of an extended operation.
1451 * Log the details of an extended operation.
1453 * @param module the ldb_module
1454 * @param req the ldb_request
1456 * @return ldb status code
1458 static int log_extended(
1459 struct ldb_module *module,
1460 struct ldb_request *req)
1462 struct audit_callback_context *context = NULL;
1463 struct ldb_request *new_req = NULL;
1464 struct ldb_context *ldb = NULL;
1468 * Currently we only log replication extended operations
1471 req->op.extended.oid,
1472 DSDB_EXTENDED_REPLICATED_OBJECTS_OID) != 0) {
1474 return ldb_next_request(module, req);
1476 ldb = ldb_module_get_ctx(module);
1477 context = talloc_zero(req, struct audit_callback_context);
1479 if (context == NULL) {
1480 return ldb_oom(ldb);
1482 context->request = req;
1483 context->module = module;
1485 * We want to log the return code status, so we need to register
1486 * a callback function to get the actual result.
1487 * We need to take a new copy so that we don't alter the callers copy
1489 ret = ldb_build_extended_req(
1493 req->op.extended.oid,
1494 req->op.extended.data,
1499 if (ret != LDB_SUCCESS) {
1502 ret = add_transaction_id(module, new_req);
1503 if (ret != LDB_SUCCESS) {
1506 return ldb_next_request(module, new_req);
1510 * @brief module initialisation
1512 static int log_init(struct ldb_module *module)
1515 struct ldb_context *ldb = ldb_module_get_ctx(module);
1516 struct audit_context *context = NULL;
1517 struct loadparm_context *lp_ctx
1518 = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
1519 struct loadparm_context);
1520 struct tevent_context *ec = ldb_get_event_context(ldb);
1521 bool sdb_events = false;
1522 bool pwd_events = false;
1524 context = talloc_zero(module, struct audit_context);
1525 if (context == NULL) {
1526 return ldb_module_oom(module);
1529 if (lp_ctx != NULL) {
1530 sdb_events = lpcfg_dsdb_event_notification(lp_ctx);
1531 pwd_events = lpcfg_dsdb_password_event_notification(lp_ctx);
1533 if (sdb_events || pwd_events) {
1534 context->send_samdb_events = sdb_events;
1535 context->send_password_events = pwd_events;
1536 context->msg_ctx = imessaging_client_init(ec, lp_ctx, ec);
1539 ldb_module_set_private(module, context);
1540 return ldb_next_init(module);
1543 static const struct ldb_module_ops ldb_audit_log_module_ops = {
1544 .name = "audit_log",
1545 .init_context = log_init,
1547 .modify = log_modify,
1549 .start_transaction = log_start_transaction,
1550 .prepare_commit = log_prepare_commit,
1551 .end_transaction = log_end_transaction,
1552 .del_transaction = log_del_transaction,
1553 .extended = log_extended,
1556 int ldb_audit_log_module_init(const char *version)
1558 LDB_MODULE_CHECK_VERSION(version);
1559 return ldb_register_module(&ldb_audit_log_module_ops);