json: Modify API to use return codes
[samba.git] / source4 / dsdb / samdb / ldb_modules / audit_log.c
1 /*
2    ldb database library
3
4    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
5
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.
10
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.
15
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/>.
18 */
19
20 /*
21  * Provide an audit log of changes made to the database and at a
22  * higher level details of any password changes and resets.
23  *
24  */
25
26 #include "includes.h"
27 #include "ldb_module.h"
28 #include "lib/audit_logging/audit_logging.h"
29
30 #include "dsdb/samdb/samdb.h"
31 #include "dsdb/samdb/ldb_modules/util.h"
32 #include "dsdb/samdb/ldb_modules/audit_util_proto.h"
33 #include "libcli/security/dom_sid.h"
34 #include "auth/common_auth.h"
35 #include "param/param.h"
36
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
42
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
48
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
55
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
61 /*
62  * Attribute values are truncated in the logs if they are longer than
63  * MAX_LENGTH
64  */
65 #define MAX_LENGTH 1024
66
67 #define min(a, b) (((a)>(b))?(b):(a))
68
69 /*
70  * Private data for the module, stored in the ldb_module private data
71  */
72 struct audit_private {
73         /*
74          * Should details of database operations be sent over the
75          * messaging bus.
76          */
77         bool send_samdb_events;
78         /*
79          * Should details of password changes and resets be sent over
80          * the messaging bus.
81          */
82         bool send_password_events;
83         /*
84          * The messaging context to send the messages over.  Will only
85          * be set if send_samdb_events or send_password_events are
86          * true.
87          */
88         struct imessaging_context *msg_ctx;
89         /*
90          * Unique transaction id for the current transaction
91          */
92         struct GUID transaction_guid;
93         /*
94          * Transaction start time, used to calculate the transaction
95          * duration.
96          */
97         struct timeval transaction_start;
98 };
99
100 /*
101  * @brief Has the password changed.
102  *
103  * Does the message contain a change to one of the password attributes? The
104  * password attributes are defined in DSDB_PASSWORD_ATTRIBUTES
105  *
106  * @return true if the message contains a password attribute
107  *
108  */
109 static bool has_password_changed(const struct ldb_message *message)
110 {
111         int i;
112         if (message == NULL) {
113                 return false;
114         }
115         for (i=0;i<message->num_elements;i++) {
116                 if (dsdb_audit_is_password_attribute(
117                         message->elements[i].name)) {
118                         return true;
119                 }
120         }
121         return false;
122 }
123
124 /*
125  * @brief Is the request a password "Change" or a "Reset"
126  *
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
130  *
131  * @param request the ldb_request to inspect
132  * @param reply the ldb_reply, will contain the password controls
133  *
134  * @return "Change" if the password is being changed.
135  *         "Reset"  if the password is being reset.
136  */
137 static const char *get_password_action(
138         const struct ldb_request *request,
139         const struct ldb_reply *reply)
140 {
141         if(request->operation == LDB_ADD) {
142                 return "Reset";
143         } else {
144                 struct ldb_control *pav_ctrl = NULL;
145                 struct dsdb_control_password_acl_validation *pav = NULL;
146
147                 pav_ctrl = ldb_reply_get_control(
148                         discard_const(reply),
149                         DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
150                 if (pav_ctrl == NULL) {
151                         return "Reset";
152                 }
153
154                 pav = talloc_get_type_abort(
155                         pav_ctrl->data,
156                         struct dsdb_control_password_acl_validation);
157
158                 if (pav->pwd_reset) {
159                         return "Reset";
160                 } else {
161                         return "Change";
162                 }
163         }
164 }
165
166
167 #ifdef HAVE_JANSSON
168 /*
169  * @brief generate a JSON object detailing an ldb operation.
170  *
171  * Generate a JSON object detailing an ldb operation.
172  *
173  * @param module the ldb module
174  * @param request the request
175  * @param reply the result of the operation.
176  *
177  * @return the generated JSON object, should be freed with json_free.
178  *
179  *
180  */
181 static struct json_object operation_json(
182         struct ldb_module *module,
183         const struct ldb_request *request,
184         const struct ldb_reply *reply)
185 {
186         struct ldb_context *ldb = NULL;
187         const struct dom_sid *sid = NULL;
188         bool as_system = false;
189         struct json_object wrapper = json_empty_object;
190         struct json_object audit = json_empty_object;
191         const struct tsocket_address *remote = NULL;
192         const char *dn = NULL;
193         const char* operation = NULL;
194         const struct GUID *unique_session_token = NULL;
195         const struct ldb_message *message = NULL;
196         struct audit_private *audit_private
197                 = talloc_get_type_abort(ldb_module_get_private(module),
198                                         struct audit_private);
199         int rc = 0;
200
201         ldb = ldb_module_get_ctx(module);
202
203         remote = dsdb_audit_get_remote_address(ldb);
204         if (remote != NULL && dsdb_audit_is_system_session(module)) {
205                 as_system = true;
206                 sid = dsdb_audit_get_actual_sid(ldb);
207                 unique_session_token =
208                         dsdb_audit_get_actual_unique_session_token(ldb);
209         } else {
210                 sid = dsdb_audit_get_user_sid(module);
211                 unique_session_token =
212                         dsdb_audit_get_unique_session_token(module);
213         }
214         dn = dsdb_audit_get_primary_dn(request);
215         operation = dsdb_audit_get_operation_name(request);
216
217         audit = json_new_object();
218         if (json_is_invalid(&audit)) {
219                 goto failure;
220         }
221         rc = json_add_version(&audit, OPERATION_MAJOR, OPERATION_MINOR);
222         if (rc != 0) {
223                 goto failure;
224         }
225         rc = json_add_int(&audit, "statusCode", reply->error);
226         if (rc != 0) {
227                 goto failure;
228         }
229         rc = json_add_string(&audit, "status", ldb_strerror(reply->error));
230         if (rc != 0) {
231                 goto failure;
232         }
233         rc = json_add_string(&audit, "operation", operation);
234         if (rc != 0) {
235                 goto failure;
236         }
237         rc = json_add_address(&audit, "remoteAddress", remote);
238         if (rc != 0) {
239                 goto failure;
240         }
241         rc = json_add_bool(&audit, "performedAsSystem", as_system);
242         if (rc != 0) {
243                 goto failure;
244         }
245         rc = json_add_sid(&audit, "userSid", sid);
246         if (rc != 0) {
247                 goto failure;
248         }
249         rc = json_add_string(&audit, "dn", dn);
250         if (rc != 0) {
251                 goto failure;
252         }
253         rc = json_add_guid(
254             &audit, "transactionId", &audit_private->transaction_guid);
255         if (rc != 0) {
256                 goto failure;
257         }
258         rc = json_add_guid(&audit, "sessionId", unique_session_token);
259         if (rc != 0) {
260                 goto failure;
261         }
262
263         message = dsdb_audit_get_message(request);
264         if (message != NULL) {
265                 struct json_object attributes =
266                         dsdb_audit_attributes_json(
267                                 request->operation,
268                                 message);
269                 if (json_is_invalid(&attributes)) {
270                         goto failure;
271                 }
272                 rc = json_add_object(&audit, "attributes", &attributes);
273                 if (rc != 0) {
274                         goto failure;
275                 }
276         }
277
278         wrapper = json_new_object();
279         if (json_is_invalid(&wrapper)) {
280                 goto failure;
281         }
282         rc = json_add_timestamp(&wrapper);
283         if (rc != 0) {
284                 goto failure;
285         }
286         rc = json_add_string(&wrapper, "type", OPERATION_JSON_TYPE);
287         if (rc != 0) {
288                 goto failure;
289         }
290         rc = json_add_object(&wrapper, OPERATION_JSON_TYPE, &audit);
291         if (rc != 0) {
292                 goto failure;
293         }
294         return wrapper;
295
296 failure:
297         /*
298          * On a failure audit will not have been added to wrapper so it
299          * needs to free it to avoid a leak.
300          *
301          * wrapper is freed to invalidate it as it will have only been
302          * partially constructed and may be inconsistent.
303          *
304          * All the json manipulation routines handle a freed object correctly
305          */
306         json_free(&audit);
307         json_free(&wrapper);
308         DBG_ERR("Unable to create ldb operation JSON audit message\n");
309         return wrapper;
310 }
311
312 /*
313  * @brief generate a JSON object detailing a replicated update.
314  *
315  * Generate a JSON object detailing a replicated update
316  *
317  * @param module the ldb module
318  * @param request the request
319  * @paran reply the result of the operation
320  *
321  * @return the generated JSON object, should be freed with json_free.
322  *         NULL if there was an error generating the message.
323  *
324  */
325 static struct json_object replicated_update_json(
326         struct ldb_module *module,
327         const struct ldb_request *request,
328         const struct ldb_reply *reply)
329 {
330         struct json_object wrapper = json_empty_object;
331         struct json_object audit = json_empty_object;
332         struct audit_private *audit_private
333                 = talloc_get_type_abort(ldb_module_get_private(module),
334                                         struct audit_private);
335         struct dsdb_extended_replicated_objects *ro = talloc_get_type(
336                 request->op.extended.data,
337                 struct dsdb_extended_replicated_objects);
338         const char *partition_dn = NULL;
339         const char *error = NULL;
340         int rc = 0;
341
342         partition_dn = ldb_dn_get_linearized(ro->partition_dn);
343         error = get_friendly_werror_msg(ro->error);
344
345         audit = json_new_object();
346         if (json_is_invalid(&audit)) {
347                 goto failure;
348         }
349         rc = json_add_version(&audit, REPLICATION_MAJOR, REPLICATION_MINOR);
350         if (rc != 0) {
351                 goto failure;
352         }
353         rc = json_add_int(&audit, "statusCode", reply->error);
354         if (rc != 0) {
355                 goto failure;
356         }
357         rc = json_add_string(&audit, "status", ldb_strerror(reply->error));
358         if (rc != 0) {
359                 goto failure;
360         }
361         rc = json_add_guid(
362             &audit, "transactionId", &audit_private->transaction_guid);
363         if (rc != 0) {
364                 goto failure;
365         }
366         rc = json_add_int(&audit, "objectCount", ro->num_objects);
367         if (rc != 0) {
368                 goto failure;
369         }
370         rc = json_add_int(&audit, "linkCount", ro->linked_attributes_count);
371         if (rc != 0) {
372                 goto failure;
373         }
374         rc = json_add_string(&audit, "partitionDN", partition_dn);
375         if (rc != 0) {
376                 goto failure;
377         }
378         rc = json_add_string(&audit, "error", error);
379         if (rc != 0) {
380                 goto failure;
381         }
382         rc = json_add_int(&audit, "errorCode", W_ERROR_V(ro->error));
383         if (rc != 0) {
384                 goto failure;
385         }
386         rc = json_add_guid(
387             &audit, "sourceDsa", &ro->source_dsa->source_dsa_obj_guid);
388         if (rc != 0) {
389                 goto failure;
390         }
391         rc = json_add_guid(
392             &audit, "invocationId", &ro->source_dsa->source_dsa_invocation_id);
393         if (rc != 0) {
394                 goto failure;
395         }
396
397         wrapper = json_new_object();
398         if (json_is_invalid(&wrapper)) {
399                 goto failure;
400         }
401         rc = json_add_timestamp(&wrapper);
402         if (rc != 0) {
403                 goto failure;
404         }
405         rc = json_add_string(&wrapper, "type", REPLICATION_JSON_TYPE);
406         if (rc != 0) {
407                 goto failure;
408         }
409         rc = json_add_object(&wrapper, REPLICATION_JSON_TYPE, &audit);
410         if (rc != 0) {
411                 goto failure;
412         }
413         return wrapper;
414 failure:
415         /*
416          * On a failure audit will not have been added to wrapper so it
417          * needs to be freed it to avoid a leak.
418          *
419          * wrapper is freed to invalidate it as it will have only been
420          * partially constructed and may be inconsistent.
421          *
422          * All the json manipulation routines handle a freed object correctly
423          */
424         json_free(&audit);
425         json_free(&wrapper);
426         DBG_ERR("Unable to create replicated update JSON audit message\n");
427         return wrapper;
428 }
429
430 /*
431  * @brief generate a JSON object detailing a password change.
432  *
433  * Generate a JSON object detailing a password change.
434  *
435  * @param module the ldb module
436  * @param request the request
437  * @param reply the result/response
438  * @param status the status code returned for the underlying ldb operation.
439  *
440  * @return the generated JSON object.
441  *
442  */
443 static struct json_object password_change_json(
444         struct ldb_module *module,
445         const struct ldb_request *request,
446         const struct ldb_reply *reply)
447 {
448         struct ldb_context *ldb = NULL;
449         const struct dom_sid *sid = NULL;
450         const char *dn = NULL;
451         struct json_object wrapper = json_empty_object;
452         struct json_object audit = json_empty_object;
453         const struct tsocket_address *remote = NULL;
454         const char* action = NULL;
455         const struct GUID *unique_session_token = NULL;
456         struct audit_private *audit_private
457                 = talloc_get_type_abort(ldb_module_get_private(module),
458                                         struct audit_private);
459         int rc = 0;
460
461         ldb = ldb_module_get_ctx(module);
462
463         remote = dsdb_audit_get_remote_address(ldb);
464         sid = dsdb_audit_get_user_sid(module);
465         dn = dsdb_audit_get_primary_dn(request);
466         action = get_password_action(request, reply);
467         unique_session_token = dsdb_audit_get_unique_session_token(module);
468
469         audit = json_new_object();
470         if (json_is_invalid(&audit)) {
471                 goto failure;
472         }
473         rc = json_add_version(&audit, PASSWORD_MAJOR, PASSWORD_MINOR);
474         if (rc != 0) {
475                 goto failure;
476         }
477         rc = json_add_int(&audit, "statusCode", reply->error);
478         if (rc != 0) {
479                 goto failure;
480         }
481         rc = json_add_string(&audit, "status", ldb_strerror(reply->error));
482         if (rc != 0) {
483                 goto failure;
484         }
485         rc = json_add_address(&audit, "remoteAddress", remote);
486         if (rc != 0) {
487                 goto failure;
488         }
489         rc = json_add_sid(&audit, "userSid", sid);
490         if (rc != 0) {
491                 goto failure;
492         }
493         rc = json_add_string(&audit, "dn", dn);
494         if (rc != 0) {
495                 goto failure;
496         }
497         rc = json_add_string(&audit, "action", action);
498         if (rc != 0) {
499                 goto failure;
500         }
501         rc = json_add_guid(
502             &audit, "transactionId", &audit_private->transaction_guid);
503         if (rc != 0) {
504                 goto failure;
505         }
506         rc = json_add_guid(&audit, "sessionId", unique_session_token);
507         if (rc != 0) {
508                 goto failure;
509         }
510
511         wrapper = json_new_object();
512         if (json_is_invalid(&wrapper)) {
513                 goto failure;
514         }
515         rc = json_add_timestamp(&wrapper);
516         if (rc != 0) {
517                 goto failure;
518         }
519         rc = json_add_string(&wrapper, "type", PASSWORD_JSON_TYPE);
520         if (rc != 0) {
521                 goto failure;
522         }
523         rc = json_add_object(&wrapper, PASSWORD_JSON_TYPE, &audit);
524         if (rc != 0) {
525                 goto failure;
526         }
527
528         return wrapper;
529 failure:
530         /*
531          * On a failure audit will not have been added to wrapper so it
532          * needs to free it to avoid a leak.
533          *
534          * wrapper is freed to invalidate it as it will have only been
535          * partially constructed and may be inconsistent.
536          *
537          * All the json manipulation routines handle a freed object correctly
538          */
539         json_free(&wrapper);
540         json_free(&audit);
541         DBG_ERR("Unable to create password change JSON audit message\n");
542         return wrapper;
543 }
544
545
546 /*
547  * @brief create a JSON object containing details of a transaction event.
548  *
549  * Create a JSON object detailing a transaction transaction life cycle events,
550  * i.e. begin, commit, roll back
551  *
552  * @param action a one word description of the event/action
553  * @param transaction_id the GUID identifying the current transaction.
554  * @param status the status code returned by the operation
555  * @param duration the duration of the operation.
556  *
557  * @return a JSON object detailing the event
558  */
559 static struct json_object transaction_json(
560         const char *action,
561         struct GUID *transaction_id,
562         const int64_t duration)
563 {
564         struct json_object wrapper = json_empty_object;
565         struct json_object audit = json_empty_object;
566         int rc = 0;
567
568         audit = json_new_object();
569         if (json_is_invalid(&audit)) {
570                 goto failure;
571         }
572
573         rc = json_add_version(&audit, TRANSACTION_MAJOR, TRANSACTION_MINOR);
574         if (rc != 0) {
575                 goto failure;
576         }
577         rc = json_add_string(&audit, "action", action);
578         if (rc != 0) {
579                 goto failure;
580         }
581         rc = json_add_guid(&audit, "transactionId", transaction_id);
582         if (rc != 0) {
583                 goto failure;
584         }
585         rc = json_add_int(&audit, "duration", duration);
586         if (rc != 0) {
587                 goto failure;
588         }
589
590         wrapper = json_new_object();
591         if (json_is_invalid(&wrapper)) {
592                 goto failure;
593         }
594         rc = json_add_timestamp(&wrapper);
595         if (rc != 0) {
596                 goto failure;
597         }
598         rc = json_add_string(&wrapper, "type", TRANSACTION_JSON_TYPE);
599         if (rc != 0) {
600                 goto failure;
601         }
602         rc = json_add_object(&wrapper, TRANSACTION_JSON_TYPE, &audit);
603         if (rc != 0) {
604                 goto failure;
605         }
606
607         return wrapper;
608 failure:
609         /*
610          * On a failure audit will not have been added to wrapper so it
611          * needs to free it to avoid a leak.
612          *
613          * wrapper is freed to invalidate it as it will have only been
614          * partially constructed and may be inconsistent.
615          *
616          * All the json manipulation routines handle a freed object correctly
617          */
618         json_free(&wrapper);
619         json_free(&audit);
620         DBG_ERR("Unable to create transaction JSON audit message\n");
621         return wrapper;
622 }
623
624
625 /*
626  * @brief generate a JSON object detailing a commit failure.
627  *
628  * Generate a JSON object containing details of a commit failure.
629  *
630  * @param action the commit action, "commit" or "prepare"
631  * @param status the status code returned by commit
632  * @param reason any extra failure information/reason available
633  * @param transaction_id the GUID identifying the current transaction.
634  */
635 static struct json_object commit_failure_json(
636         const char *action,
637         const int64_t duration,
638         int status,
639         const char *reason,
640         struct GUID *transaction_id)
641 {
642         struct json_object wrapper = json_empty_object;
643         struct json_object audit = json_empty_object;
644         int rc = 0;
645
646         audit = json_new_object();
647         if (json_is_invalid(&audit)) {
648                 goto failure;
649         }
650         rc = json_add_version(&audit, TRANSACTION_MAJOR, TRANSACTION_MINOR);
651         if (rc != 0) {
652                 goto failure;
653         }
654         rc = json_add_string(&audit, "action", action);
655         if (rc != 0) {
656                 goto failure;
657         }
658         rc = json_add_guid(&audit, "transactionId", transaction_id);
659         if (rc != 0) {
660                 goto failure;
661         }
662         rc = json_add_int(&audit, "duration", duration);
663         if (rc != 0) {
664                 goto failure;
665         }
666         rc = json_add_int(&audit, "statusCode", status);
667         if (rc != 0) {
668                 goto failure;
669         }
670         rc = json_add_string(&audit, "status", ldb_strerror(status));
671         if (rc != 0) {
672                 goto failure;
673         }
674         rc = json_add_string(&audit, "reason", reason);
675         if (rc != 0) {
676                 goto failure;
677         }
678
679         wrapper = json_new_object();
680         if (json_is_invalid(&wrapper)) {
681                 goto failure;
682         }
683         rc = json_add_timestamp(&wrapper);
684         if (rc != 0) {
685                 goto failure;
686         }
687         rc = json_add_string(&wrapper, "type", TRANSACTION_JSON_TYPE);
688         if (rc != 0) {
689                 goto failure;
690         }
691         rc = json_add_object(&wrapper, TRANSACTION_JSON_TYPE, &audit);
692         if (rc != 0) {
693                 goto failure;
694         }
695
696         return wrapper;
697 failure:
698         /*
699          * On a failure audit will not have been added to wrapper so it
700          * needs to free it to avoid a leak.
701          *
702          * wrapper is freed to invalidate it as it will have only been
703          * partially constructed and may be inconsistent.
704          *
705          * All the json manipulation routines handle a freed object correctly
706          */
707         json_free(&audit);
708         json_free(&wrapper);
709         DBG_ERR("Unable to create commit failure JSON audit message\n");
710         return wrapper;
711 }
712
713 #endif
714 /*
715  * @brief Print a human readable log line for a password change event.
716  *
717  * Generate a human readable log line detailing a password change.
718  *
719  * @param mem_ctx The talloc context that will own the generated log line.
720  * @param module the ldb module
721  * @param request the request
722  * @param reply the result/response
723  * @param status the status code returned for the underlying ldb operation.
724  *
725  * @return the generated log line.
726  */
727 static char *password_change_human_readable(
728         TALLOC_CTX *mem_ctx,
729         struct ldb_module *module,
730         const struct ldb_request *request,
731         const struct ldb_reply *reply)
732 {
733         struct ldb_context *ldb = NULL;
734         const char *remote_host = NULL;
735         const struct dom_sid *sid = NULL;
736         const char *user_sid = NULL;
737         const char *timestamp = NULL;
738         char *log_entry = NULL;
739         const char *action = NULL;
740         const char *dn = NULL;
741
742         TALLOC_CTX *ctx = talloc_new(NULL);
743
744         ldb = ldb_module_get_ctx(module);
745
746         remote_host = dsdb_audit_get_remote_host(ldb, ctx);
747         sid = dsdb_audit_get_user_sid(module);
748         user_sid = dom_sid_string(ctx, sid);
749         timestamp = audit_get_timestamp(ctx);
750         action = get_password_action(request, reply);
751         dn = dsdb_audit_get_primary_dn(request);
752
753         log_entry = talloc_asprintf(
754                 mem_ctx,
755                 "[%s] at [%s] status [%s] "
756                 "remote host [%s] SID [%s] DN [%s]",
757                 action,
758                 timestamp,
759                 ldb_strerror(reply->error),
760                 remote_host,
761                 user_sid,
762                 dn);
763         TALLOC_FREE(ctx);
764         return log_entry;
765 }
766 /*
767  * @brief Generate a human readable string, detailing attributes in a message
768  *
769  * For modify operations each attribute is prefixed with the action.
770  * Normal values are enclosed in []
771  * Base64 values are enclosed in {}
772  * Truncated values are indicated by three trailing dots "..."
773  *
774  * @param ldb The ldb_context
775  * @param buffer The attributes will be appended to the buffer.
776  *               assumed to have been allocated via talloc.
777  * @param operation The operation type
778  * @param message the message to process
779  *
780  */
781 static char *log_attributes(
782         struct ldb_context *ldb,
783         char *buffer,
784         enum ldb_request_type operation,
785         const struct ldb_message *message)
786 {
787         int i, j;
788         for (i=0;i<message->num_elements;i++) {
789                 if (i > 0) {
790                         buffer = talloc_asprintf_append_buffer(buffer, " ");
791                 }
792
793                 if (message->elements[i].name == NULL) {
794                         ldb_debug(
795                                 ldb,
796                                 LDB_DEBUG_ERROR,
797                                 "Error: Invalid element name (NULL) at "
798                                 "position %d", i);
799                         return NULL;
800                 }
801
802                 if (operation == LDB_MODIFY) {
803                         const char *action =NULL;
804                         action = dsdb_audit_get_modification_action(
805                                 message->elements[i].flags);
806                         buffer = talloc_asprintf_append_buffer(
807                                 buffer,
808                                 "%s: %s ",
809                                 action,
810                                 message->elements[i].name);
811                 } else {
812                         buffer = talloc_asprintf_append_buffer(
813                                 buffer,
814                                 "%s ",
815                                 message->elements[i].name);
816                 }
817
818                 if (dsdb_audit_redact_attribute(message->elements[i].name)) {
819                         /*
820                          * Do not log the value of any secret or password
821                          * attributes
822                          */
823                         buffer = talloc_asprintf_append_buffer(
824                                 buffer,
825                                 "[REDACTED SECRET ATTRIBUTE]");
826                         continue;
827                 }
828
829                 for (j=0;j<message->elements[i].num_values;j++) {
830                         struct ldb_val v;
831                         bool use_b64_encode = false;
832                         int length;
833                         if (j > 0) {
834                                 buffer = talloc_asprintf_append_buffer(
835                                         buffer,
836                                         " ");
837                         }
838
839                         v = message->elements[i].values[j];
840                         length = min(MAX_LENGTH, v.length);
841                         use_b64_encode = ldb_should_b64_encode(ldb, &v);
842                         if (use_b64_encode) {
843                                 const char *encoded = ldb_base64_encode(
844                                         buffer,
845                                         (char *)v.data,
846                                         length);
847                                 buffer = talloc_asprintf_append_buffer(
848                                         buffer,
849                                         "{%s%s}",
850                                         encoded,
851                                         (v.length > MAX_LENGTH ? "..." : ""));
852                         } else {
853                                 buffer = talloc_asprintf_append_buffer(
854                                         buffer,
855                                         "[%*.*s%s]",
856                                         length,
857                                         length,
858                                         (char *)v.data,
859                                         (v.length > MAX_LENGTH ? "..." : ""));
860                         }
861                 }
862         }
863         return buffer;
864 }
865
866 /*
867  * @brief generate a human readable log entry detailing an ldb operation.
868  *
869  * Generate a human readable log entry detailing an ldb operation.
870  *
871  * @param mem_ctx The talloc context owning the returned string.
872  * @param module the ldb module
873  * @param request the request
874  * @param reply the result of the operation
875  *
876  * @return the log entry.
877  *
878  */
879 static char *operation_human_readable(
880         TALLOC_CTX *mem_ctx,
881         struct ldb_module *module,
882         const struct ldb_request *request,
883         const struct ldb_reply *reply)
884 {
885         struct ldb_context *ldb = NULL;
886         const char *remote_host = NULL;
887         const struct dom_sid *sid = NULL;
888         const char *user_sid = NULL;
889         const char *timestamp = NULL;
890         const char *op_name = NULL;
891         char *log_entry = NULL;
892         const char *dn = NULL;
893         const char *new_dn = NULL;
894         const struct ldb_message *message = NULL;
895
896         TALLOC_CTX *ctx = talloc_new(NULL);
897
898         ldb = ldb_module_get_ctx(module);
899
900         remote_host = dsdb_audit_get_remote_host(ldb, ctx);
901         if (remote_host != NULL && dsdb_audit_is_system_session(module)) {
902                 sid = dsdb_audit_get_actual_sid(ldb);
903         } else {
904                 sid = dsdb_audit_get_user_sid(module);
905         }
906         user_sid = dom_sid_string(ctx, sid);
907         timestamp = audit_get_timestamp(ctx);
908         op_name = dsdb_audit_get_operation_name(request);
909         dn = dsdb_audit_get_primary_dn(request);
910         new_dn = dsdb_audit_get_secondary_dn(request);
911
912         message = dsdb_audit_get_message(request);
913
914         log_entry = talloc_asprintf(
915                 mem_ctx,
916                 "[%s] at [%s] status [%s] "
917                 "remote host [%s] SID [%s] DN [%s]",
918                 op_name,
919                 timestamp,
920                 ldb_strerror(reply->error),
921                 remote_host,
922                 user_sid,
923                 dn);
924         if (new_dn != NULL) {
925                 log_entry = talloc_asprintf_append_buffer(
926                         log_entry,
927                         " New DN [%s]",
928                         new_dn);
929         }
930         if (message != NULL) {
931                 log_entry = talloc_asprintf_append_buffer(log_entry,
932                                                           " attributes [");
933                 log_entry = log_attributes(ldb,
934                                            log_entry,
935                                            request->operation,
936                                            message);
937                 log_entry = talloc_asprintf_append_buffer(log_entry, "]");
938         }
939         TALLOC_FREE(ctx);
940         return log_entry;
941 }
942
943 /*
944  * @brief generate a human readable log entry detailing a replicated update
945  *        operation.
946  *
947  * Generate a human readable log entry detailing a replicated update operation
948  *
949  * @param mem_ctx The talloc context owning the returned string.
950  * @param module the ldb module
951  * @param request the request
952  * @param reply the result of the operation.
953  *
954  * @return the log entry.
955  *
956  */
957 static char *replicated_update_human_readable(
958         TALLOC_CTX *mem_ctx,
959         struct ldb_module *module,
960         const struct ldb_request *request,
961         const struct ldb_reply *reply)
962 {
963         struct dsdb_extended_replicated_objects *ro = talloc_get_type(
964                 request->op.extended.data,
965                 struct dsdb_extended_replicated_objects);
966         const char *partition_dn = NULL;
967         const char *error = NULL;
968         char *log_entry = NULL;
969         char *timestamp = NULL;
970         struct GUID_txt_buf object_buf;
971         const char *object = NULL;
972         struct GUID_txt_buf invocation_buf;
973         const char *invocation = NULL;
974
975
976         TALLOC_CTX *ctx = talloc_new(NULL);
977
978         timestamp = audit_get_timestamp(ctx);
979         error = get_friendly_werror_msg(ro->error);
980         partition_dn = ldb_dn_get_linearized(ro->partition_dn);
981         object = GUID_buf_string(
982                 &ro->source_dsa->source_dsa_obj_guid,
983                 &object_buf);
984         invocation = GUID_buf_string(
985                 &ro->source_dsa->source_dsa_invocation_id,
986                 &invocation_buf);
987
988
989         log_entry = talloc_asprintf(
990                 mem_ctx,
991                 "at [%s] status [%s] error [%s] partition [%s] objects [%d] "
992                 "links [%d] object [%s] invocation [%s]",
993                 timestamp,
994                 ldb_strerror(reply->error),
995                 error,
996                 partition_dn,
997                 ro->num_objects,
998                 ro->linked_attributes_count,
999                 object,
1000                 invocation);
1001
1002         TALLOC_FREE(ctx);
1003         return log_entry;
1004 }
1005 /*
1006  * @brief create a human readable log entry detailing a transaction event.
1007  *
1008  * Create a human readable log entry detailing a transaction event.
1009  * i.e. begin, commit, roll back
1010  *
1011  * @param mem_ctx The talloc context owning the returned string.
1012  * @param action a one word description of the event/action
1013  * @param duration the duration of the transaction.
1014  *
1015  * @return the log entry
1016  */
1017 static char *transaction_human_readable(
1018         TALLOC_CTX *mem_ctx,
1019         const char* action,
1020         const int64_t duration)
1021 {
1022         const char *timestamp = NULL;
1023         char *log_entry = NULL;
1024
1025         TALLOC_CTX *ctx = talloc_new(NULL);
1026
1027         timestamp = audit_get_timestamp(ctx);
1028
1029         log_entry = talloc_asprintf(
1030                 mem_ctx,
1031                 "[%s] at [%s] duration [%"PRIi64"]",
1032                 action,
1033                 timestamp,
1034                 duration);
1035
1036         TALLOC_FREE(ctx);
1037         return log_entry;
1038 }
1039
1040 /*
1041  * @brief generate a human readable log entry detailing a commit failure.
1042  *
1043  * Generate generate a human readable log entry detailing a commit failure.
1044  *
1045  * @param mem_ctx The talloc context owning the returned string.
1046  * @param action the commit action, "prepare" or "commit"
1047  * @param status the status code returned by commit
1048  * @param reason any extra failure information/reason available
1049  *
1050  * @return the log entry
1051  */
1052 static char *commit_failure_human_readable(
1053         TALLOC_CTX *mem_ctx,
1054         const char *action,
1055         const int64_t duration,
1056         int status,
1057         const char *reason)
1058 {
1059         const char *timestamp = NULL;
1060         char *log_entry = NULL;
1061
1062         TALLOC_CTX *ctx = talloc_new(NULL);
1063
1064         timestamp = audit_get_timestamp(ctx);
1065
1066         log_entry = talloc_asprintf(
1067                 mem_ctx,
1068                 "[%s] at [%s] duration [%"PRIi64"] status [%d] reason [%s]",
1069                 action,
1070                 timestamp,
1071                 duration,
1072                 status,
1073                 reason);
1074
1075         TALLOC_FREE(ctx);
1076         return log_entry;
1077 }
1078
1079 /*
1080  * @brief log details of a standard ldb operation.
1081  *
1082  * Log the details of an ldb operation in JSON and or human readable format
1083  * and send over the message bus.
1084  *
1085  * @param module the ldb_module
1086  * @param request the operation request.
1087  * @param reply the operation result.
1088  * @param the status code returned for the operation.
1089  *
1090  */
1091 static void log_standard_operation(
1092         struct ldb_module *module,
1093         const struct ldb_request *request,
1094         const struct ldb_reply *reply)
1095 {
1096
1097         const struct ldb_message *message = dsdb_audit_get_message(request);
1098         bool password_changed = has_password_changed(message);
1099         struct audit_private *audit_private =
1100                 talloc_get_type_abort(ldb_module_get_private(module),
1101                                       struct audit_private);
1102
1103         TALLOC_CTX *ctx = talloc_new(NULL);
1104
1105         if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT, OPERATION_LOG_LVL)) {
1106                 char *entry = NULL;
1107                 entry = operation_human_readable(
1108                         ctx,
1109                         module,
1110                         request,
1111                         reply);
1112                 audit_log_human_text(
1113                         OPERATION_HR_TAG,
1114                         entry,
1115                         DBGC_DSDB_AUDIT,
1116                         OPERATION_LOG_LVL);
1117                 TALLOC_FREE(entry);
1118         }
1119         if (CHECK_DEBUGLVLC(DBGC_DSDB_PWD_AUDIT, PASSWORD_LOG_LVL)) {
1120                 if (password_changed) {
1121                         char *entry = NULL;
1122                         entry = password_change_human_readable(
1123                                 ctx,
1124                                 module,
1125                                 request,
1126                                 reply);
1127                         audit_log_human_text(
1128                                 PASSWORD_HR_TAG,
1129                                 entry,
1130                                 DBGC_DSDB_PWD_AUDIT,
1131                                 PASSWORD_LOG_LVL);
1132                         TALLOC_FREE(entry);
1133                 }
1134         }
1135 #ifdef HAVE_JANSSON
1136         if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT_JSON, OPERATION_LOG_LVL) ||
1137                 (audit_private->msg_ctx
1138                  && audit_private->send_samdb_events)) {
1139                 struct json_object json;
1140                 json = operation_json(module, request, reply);
1141                 audit_log_json(
1142                         OPERATION_JSON_TYPE,
1143                         &json,
1144                         DBGC_DSDB_AUDIT_JSON,
1145                         OPERATION_LOG_LVL);
1146                 if (audit_private->msg_ctx
1147                     && audit_private->send_samdb_events) {
1148                         audit_message_send(
1149                                 audit_private->msg_ctx,
1150                                 DSDB_EVENT_NAME,
1151                                 MSG_DSDB_LOG,
1152                                 &json);
1153                 }
1154                 json_free(&json);
1155         }
1156         if (CHECK_DEBUGLVLC(DBGC_DSDB_PWD_AUDIT_JSON, PASSWORD_LOG_LVL) ||
1157                 (audit_private->msg_ctx
1158                  && audit_private->send_password_events)) {
1159                 if (password_changed) {
1160                         struct json_object json;
1161                         json = password_change_json(module, request, reply);
1162                         audit_log_json(
1163                                 PASSWORD_JSON_TYPE,
1164                                 &json,
1165                                 DBGC_DSDB_PWD_AUDIT_JSON,
1166                                 PASSWORD_LOG_LVL);
1167                         if (audit_private->send_password_events) {
1168                                 audit_message_send(
1169                                         audit_private->msg_ctx,
1170                                         DSDB_PWD_EVENT_NAME,
1171                                         MSG_DSDB_PWD_LOG,
1172                                         &json);
1173                         }
1174                         json_free(&json);
1175                 }
1176         }
1177 #endif
1178         TALLOC_FREE(ctx);
1179 }
1180
1181 /*
1182  * @brief log details of a replicated update.
1183  *
1184  * Log the details of a replicated update in JSON and or human readable
1185  * format and send over the message bus.
1186  *
1187  * @param module the ldb_module
1188  * @param request the operation request
1189  * @param reply the result of the operation.
1190  *
1191  */
1192 static void log_replicated_operation(
1193         struct ldb_module *module,
1194         const struct ldb_request *request,
1195         const struct ldb_reply *reply)
1196 {
1197
1198         struct audit_private *audit_private =
1199                 talloc_get_type_abort(ldb_module_get_private(module),
1200                                 struct audit_private);
1201
1202         TALLOC_CTX *ctx = talloc_new(NULL);
1203
1204         if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT, REPLICATION_LOG_LVL)) {
1205                 char *entry = NULL;
1206                 entry = replicated_update_human_readable(
1207                         ctx,
1208                         module,
1209                         request,
1210                         reply);
1211                 audit_log_human_text(
1212                         REPLICATION_HR_TAG,
1213                         entry,
1214                         DBGC_DSDB_AUDIT,
1215                         REPLICATION_LOG_LVL);
1216                 TALLOC_FREE(entry);
1217         }
1218 #ifdef HAVE_JANSSON
1219         if (CHECK_DEBUGLVLC(DBGC_DSDB_AUDIT_JSON, REPLICATION_LOG_LVL) ||
1220                 (audit_private->msg_ctx && audit_private->send_samdb_events)) {
1221                 struct json_object json;
1222                 json = replicated_update_json(module, request, reply);
1223                 audit_log_json(
1224                         REPLICATION_JSON_TYPE,
1225                         &json,
1226                         DBGC_DSDB_AUDIT_JSON,
1227                         REPLICATION_LOG_LVL);
1228                 if (audit_private->send_samdb_events) {
1229                         audit_message_send(
1230                                 audit_private->msg_ctx,
1231                                 DSDB_EVENT_NAME,
1232                                 MSG_DSDB_LOG,
1233                                 &json);
1234                 }
1235                 json_free(&json);
1236         }
1237 #endif
1238         TALLOC_FREE(ctx);
1239 }
1240
1241 /*
1242  * @brief log details of an ldb operation.
1243  *
1244  * Log the details of an ldb operation in JSON and or human readable format
1245  * and send over the message bus.
1246  *
1247  * @param module the ldb_module
1248  * @param request the operation request
1249  * @part reply the result of the operation
1250  *
1251  */
1252 static void log_operation(
1253         struct ldb_module *module,
1254         const struct ldb_request *request,
1255         const struct ldb_reply *reply)
1256 {
1257
1258         if (request->operation == LDB_EXTENDED) {
1259                 if (strcmp(
1260                         request->op.extended.oid,
1261                         DSDB_EXTENDED_REPLICATED_OBJECTS_OID) != 0) {
1262
1263                         log_replicated_operation(module, request, reply);
1264                 }
1265         } else {
1266                 log_standard_operation(module, request, reply);
1267         }
1268 }
1269
1270 /*
1271  * @brief log details of a transaction event.
1272  *
1273  * Log the details of a transaction event in JSON and or human readable format
1274  * and send over the message bus.
1275  *
1276  * @param module the ldb_module
1277  * @param action the transaction event i.e. begin, commit, roll back.
1278  * @param log_level the logging level
1279  *
1280  */
1281 static void log_transaction(
1282         struct ldb_module *module,
1283         const char *action,
1284         int log_level)
1285 {
1286
1287         struct audit_private *audit_private =
1288                 talloc_get_type_abort(ldb_module_get_private(module),
1289                                       struct audit_private);
1290         const struct timeval now = timeval_current();
1291         const int64_t duration = usec_time_diff(&now, &audit_private->transaction_start);
1292
1293         TALLOC_CTX *ctx = talloc_new(NULL);
1294
1295         if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT, log_level)) {
1296                 char* entry = NULL;
1297                 entry = transaction_human_readable(ctx, action, duration);
1298                 audit_log_human_text(
1299                         TRANSACTION_HR_TAG,
1300                         entry,
1301                         DBGC_DSDB_TXN_AUDIT,
1302                         log_level);
1303                 TALLOC_FREE(entry);
1304         }
1305 #ifdef HAVE_JANSSON
1306         if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT_JSON, log_level) ||
1307                 (audit_private->msg_ctx && audit_private->send_samdb_events)) {
1308                 struct json_object json;
1309                 json = transaction_json(
1310                         action,
1311                         &audit_private->transaction_guid,
1312                         duration);
1313                 audit_log_json(
1314                         TRANSACTION_JSON_TYPE,
1315                         &json,
1316                         DBGC_DSDB_TXN_AUDIT_JSON,
1317                         log_level);
1318                 if (audit_private->send_samdb_events) {
1319                         audit_message_send(
1320                                 audit_private->msg_ctx,
1321                                 DSDB_EVENT_NAME,
1322                                 MSG_DSDB_LOG,
1323                                 &json);
1324                 }
1325                 json_free(&json);
1326         }
1327 #endif
1328         TALLOC_FREE(ctx);
1329 }
1330
1331 /*
1332  * @brief log details of a commit failure.
1333  *
1334  * Log the details of a commit failure in JSON and or human readable
1335  * format and send over the message bus.
1336  *
1337  * @param module the ldb_module
1338  * @param action the commit action "prepare" or "commit"
1339  * @param status the ldb status code returned by prepare commit.
1340  *
1341  */
1342 static void log_commit_failure(
1343         struct ldb_module *module,
1344         const char *action,
1345         int status)
1346 {
1347
1348         struct audit_private *audit_private =
1349                 talloc_get_type_abort(ldb_module_get_private(module),
1350                                       struct audit_private);
1351         const char* reason = dsdb_audit_get_ldb_error_string(module, status);
1352         const int log_level = TRANSACTION_LOG_FAILURE_LVL;
1353         const struct timeval now = timeval_current();
1354         const int64_t duration = usec_time_diff(&now,
1355                                                 &audit_private->transaction_start);
1356
1357         TALLOC_CTX *ctx = talloc_new(NULL);
1358
1359         if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT, log_level)) {
1360
1361                 char* entry = NULL;
1362                 entry = commit_failure_human_readable(
1363                         ctx,
1364                         action,
1365                         duration,
1366                         status,
1367                         reason);
1368                 audit_log_human_text(
1369                         TRANSACTION_HR_TAG,
1370                         entry,
1371                         DBGC_DSDB_TXN_AUDIT,
1372                         TRANSACTION_LOG_FAILURE_LVL);
1373                 TALLOC_FREE(entry);
1374         }
1375 #ifdef HAVE_JANSSON
1376         if (CHECK_DEBUGLVLC(DBGC_DSDB_TXN_AUDIT_JSON, log_level) ||
1377                 (audit_private->msg_ctx
1378                  && audit_private->send_samdb_events)) {
1379                 struct json_object json;
1380                 json = commit_failure_json(
1381                         action,
1382                         duration,
1383                         status,
1384                         reason,
1385                         &audit_private->transaction_guid);
1386                 audit_log_json(
1387                         TRANSACTION_JSON_TYPE,
1388                         &json,
1389                         DBGC_DSDB_TXN_AUDIT_JSON,
1390                         log_level);
1391                 if (audit_private->send_samdb_events) {
1392                         audit_message_send(audit_private->msg_ctx,
1393                                            DSDB_EVENT_NAME,
1394                                            MSG_DSDB_LOG,
1395                                            &json);
1396                 }
1397                 json_free(&json);
1398         }
1399 #endif
1400         TALLOC_FREE(ctx);
1401 }
1402
1403 /*
1404  * Context needed by audit_callback
1405  */
1406 struct audit_callback_context {
1407         struct ldb_request *request;
1408         struct ldb_module *module;
1409 };
1410
1411 /*
1412  * @brief call back function for the ldb_operations.
1413  *
1414  * As the LDB operations are async, and we wish to examine the results of
1415  * the operations, a callback needs to be registered to process the results
1416  * of the LDB operations.
1417  *
1418  * @param req the ldb request
1419  * @param res the result of the operation
1420  *
1421  * @return the LDB_STATUS
1422  */
1423 static int audit_callback(struct ldb_request *req, struct ldb_reply *ares)
1424 {
1425         struct audit_callback_context *ac = NULL;
1426
1427         ac = talloc_get_type(
1428                 req->context,
1429                 struct audit_callback_context);
1430
1431         if (!ares) {
1432                 return ldb_module_done(
1433                         ac->request,
1434                         NULL,
1435                         NULL,
1436                         LDB_ERR_OPERATIONS_ERROR);
1437         }
1438
1439         /* pass on to the callback */
1440         switch (ares->type) {
1441         case LDB_REPLY_ENTRY:
1442                 return ldb_module_send_entry(
1443                         ac->request,
1444                         ares->message,
1445                         ares->controls);
1446
1447         case LDB_REPLY_REFERRAL:
1448                 return ldb_module_send_referral(
1449                         ac->request,
1450                         ares->referral);
1451
1452         case LDB_REPLY_DONE:
1453                 /*
1454                  * Log the operation once DONE
1455                  */
1456                 log_operation(ac->module, ac->request, ares);
1457                 return ldb_module_done(
1458                         ac->request,
1459                         ares->controls,
1460                         ares->response,
1461                         ares->error);
1462
1463         default:
1464                 /* Can't happen */
1465                 return LDB_ERR_OPERATIONS_ERROR;
1466         }
1467 }
1468
1469 /*
1470  * @brief Add the current transaction identifier to the request.
1471  *
1472  * Add the current transaction identifier in the module private data,
1473  * to the request as a control.
1474  *
1475  * @param module
1476  * @param req the request.
1477  *
1478  * @return an LDB_STATUS code, LDB_SUCCESS if successful.
1479  */
1480 static int add_transaction_id(
1481         struct ldb_module *module,
1482         struct ldb_request *req)
1483 {
1484         struct audit_private *audit_private =
1485                 talloc_get_type_abort(ldb_module_get_private(module),
1486                                       struct audit_private);
1487         struct dsdb_control_transaction_identifier *transaction_id;
1488         int ret;
1489
1490         transaction_id = talloc_zero(
1491                 req,
1492                 struct dsdb_control_transaction_identifier);
1493         if (transaction_id == NULL) {
1494                 struct ldb_context *ldb = ldb_module_get_ctx(module);
1495                 return ldb_oom(ldb);
1496         }
1497         transaction_id->transaction_guid = audit_private->transaction_guid;
1498         ret = ldb_request_add_control(req,
1499                                       DSDB_CONTROL_TRANSACTION_IDENTIFIER_OID,
1500                                       false,
1501                                       transaction_id);
1502         return ret;
1503
1504 }
1505
1506 /*
1507  * @brief log details of an add operation.
1508  *
1509  * Log the details of an add operation.
1510  *
1511  * @param module the ldb_module
1512  * @param req the ldb_request
1513  *
1514  * @return ldb status code
1515  */
1516 static int log_add(
1517         struct ldb_module *module,
1518         struct ldb_request *req)
1519 {
1520         struct audit_callback_context *context = NULL;
1521         struct ldb_request *new_req = NULL;
1522         struct ldb_context *ldb = NULL;
1523         int ret;
1524
1525         ldb = ldb_module_get_ctx(module);
1526         context = talloc_zero(req, struct audit_callback_context);
1527
1528         if (context == NULL) {
1529                 return ldb_oom(ldb);
1530         }
1531         context->request = req;
1532         context->module  = module;
1533         /*
1534          * We want to log the return code status, so we need to register
1535          * a callback function to get the actual result.
1536          * We need to take a new copy so that we don't alter the callers copy
1537          */
1538         ret = ldb_build_add_req(
1539                 &new_req,
1540                 ldb,
1541                 req,
1542                 req->op.add.message,
1543                 req->controls,
1544                 context,
1545                 audit_callback,
1546                 req);
1547         if (ret != LDB_SUCCESS) {
1548                 return ret;
1549         }
1550         ret = add_transaction_id(module, new_req);
1551         if (ret != LDB_SUCCESS) {
1552                 return ret;
1553         }
1554         return ldb_next_request(module, new_req);
1555 }
1556
1557 /*
1558  * @brief log details of an delete operation.
1559  *
1560  * Log the details of an delete operation.
1561  *
1562  * @param module the ldb_module
1563  * @param req the ldb_request
1564  *
1565  * @return ldb status code
1566  */
1567 static int log_delete(
1568         struct ldb_module *module,
1569         struct ldb_request *req)
1570 {
1571         struct audit_callback_context *context = NULL;
1572         struct ldb_request *new_req = NULL;
1573         struct ldb_context *ldb = NULL;
1574         int ret;
1575
1576         ldb = ldb_module_get_ctx(module);
1577         context = talloc_zero(req, struct audit_callback_context);
1578
1579         if (context == NULL) {
1580                 return ldb_oom(ldb);
1581         }
1582         context->request = req;
1583         context->module  = module;
1584         /*
1585          * We want to log the return code status, so we need to register
1586          * a callback function to get the actual result.
1587          * We need to take a new copy so that we don't alter the callers copy
1588          */
1589         ret = ldb_build_del_req(&new_req,
1590                                 ldb,
1591                                 req,
1592                                 req->op.del.dn,
1593                                 req->controls,
1594                                 context,
1595                                 audit_callback,
1596                                 req);
1597         if (ret != LDB_SUCCESS) {
1598                 return ret;
1599         }
1600         ret = add_transaction_id(module, new_req);
1601         if (ret != LDB_SUCCESS) {
1602                 return ret;
1603         }
1604         return ldb_next_request(module, new_req);
1605 }
1606
1607 /*
1608  * @brief log details of a modify operation.
1609  *
1610  * Log the details of a modify operation.
1611  *
1612  * @param module the ldb_module
1613  * @param req the ldb_request
1614  *
1615  * @return ldb status code
1616  */
1617 static int log_modify(
1618         struct ldb_module *module,
1619         struct ldb_request *req)
1620 {
1621         struct audit_callback_context *context = NULL;
1622         struct ldb_request *new_req = NULL;
1623         struct ldb_context *ldb = NULL;
1624         int ret;
1625
1626         ldb = ldb_module_get_ctx(module);
1627         context = talloc_zero(req, struct audit_callback_context);
1628
1629         if (context == NULL) {
1630                 return ldb_oom(ldb);
1631         }
1632         context->request = req;
1633         context->module  = module;
1634         /*
1635          * We want to log the return code status, so we need to register
1636          * a callback function to get the actual result.
1637          * We need to take a new copy so that we don't alter the callers copy
1638          */
1639         ret = ldb_build_mod_req(
1640                 & new_req,
1641                 ldb,
1642                 req,
1643                 req->op.mod.message,
1644                 req->controls,
1645                 context,
1646                 audit_callback,
1647                 req);
1648         if (ret != LDB_SUCCESS) {
1649                 return ret;
1650         }
1651         ret = add_transaction_id(module, new_req);
1652         if (ret != LDB_SUCCESS) {
1653                 return ret;
1654         }
1655         return ldb_next_request(module, new_req);
1656 }
1657
1658 /*
1659  * @brief process a transaction start.
1660  *
1661  * process a transaction start, as we don't currently log transaction starts
1662  * just generate the new transaction_id.
1663  *
1664  * @param module the ldb_module
1665  * @param req the ldb_request
1666  *
1667  * @return ldb status code
1668  */
1669 static int log_start_transaction(struct ldb_module *module)
1670 {
1671         struct audit_private *audit_private =
1672                 talloc_get_type_abort(ldb_module_get_private(module),
1673                                       struct audit_private);
1674
1675         /*
1676          * We do not log transaction begins
1677          * however we do generate a new transaction_id and record the start
1678          * time so that we can log the transaction duration.
1679          *
1680          */
1681         audit_private->transaction_guid = GUID_random();
1682         audit_private->transaction_start = timeval_current();
1683         return ldb_next_start_trans(module);
1684 }
1685
1686 /*
1687  * @brief log details of a prepare commit.
1688  *
1689  * Log the details of a prepare commit, currently only details of
1690  * failures are logged.
1691  *
1692  * @param module the ldb_module
1693  * @param req the ldb_request
1694  *
1695  * @return ldb status code
1696  */
1697 static int log_prepare_commit(struct ldb_module *module)
1698 {
1699
1700         int ret = ldb_next_prepare_commit(module);
1701         if (ret != LDB_SUCCESS) {
1702                 /*
1703                  * We currently only log prepare commit failures
1704                  */
1705                 log_commit_failure(module, "prepare", ret);
1706         }
1707         return ret;
1708 }
1709
1710 /*
1711  * @brief process a transaction end aka commit.
1712  *
1713  * process a transaction end, as we don't currently log transaction ends
1714  * just clear transaction_id.
1715  *
1716  * @param module the ldb_module
1717  * @param req the ldb_request
1718  *
1719  * @return ldb status code
1720  */
1721 static int log_end_transaction(struct ldb_module *module)
1722 {
1723         struct audit_private *audit_private =
1724                 talloc_get_type_abort(ldb_module_get_private(module),
1725                                       struct audit_private);
1726         int ret = 0;
1727
1728
1729         ret = ldb_next_end_trans(module);
1730         if (ret == LDB_SUCCESS) {
1731                 log_transaction(
1732                         module,
1733                         "commit",
1734                         TRANSACTION_LOG_COMPLETION_LVL);
1735         } else {
1736                 log_commit_failure(module, "commit", ret);
1737         }
1738         /*
1739          * Clear the transaction id inserted by log_start_transaction
1740          */
1741         audit_private->transaction_guid = GUID_zero();
1742         return ret;
1743 }
1744
1745 /*
1746  * @brief log details of a transaction delete aka roll back.
1747  *
1748  * Log details of a transaction roll back.
1749  *
1750  * @param module the ldb_module
1751  * @param req the ldb_request
1752  *
1753  * @return ldb status code
1754  */
1755 static int log_del_transaction(struct ldb_module *module)
1756 {
1757         struct audit_private *audit_private =
1758                 talloc_get_type_abort(ldb_module_get_private(module),
1759                                       struct audit_private);
1760
1761         log_transaction(module, "rollback", TRANSACTION_LOG_FAILURE_LVL);
1762         audit_private->transaction_guid = GUID_zero();
1763         return ldb_next_del_trans(module);
1764 }
1765
1766 /*
1767  * @brief log details of an extended operation.
1768  *
1769  * Log the details of an extended operation.
1770  *
1771  * @param module the ldb_module
1772  * @param req the ldb_request
1773  *
1774  * @return ldb status code
1775  */
1776 static int log_extended(
1777         struct ldb_module *module,
1778         struct ldb_request *req)
1779 {
1780         struct audit_callback_context *context = NULL;
1781         struct ldb_request *new_req = NULL;
1782         struct ldb_context *ldb = NULL;
1783         int ret;
1784
1785         /*
1786          * Currently we only log replication extended operations
1787          */
1788         if (strcmp(
1789                 req->op.extended.oid,
1790                 DSDB_EXTENDED_REPLICATED_OBJECTS_OID) != 0) {
1791
1792                 return ldb_next_request(module, req);
1793         }
1794         ldb = ldb_module_get_ctx(module);
1795         context = talloc_zero(req, struct audit_callback_context);
1796
1797         if (context == NULL) {
1798                 return ldb_oom(ldb);
1799         }
1800         context->request = req;
1801         context->module  = module;
1802         /*
1803          * We want to log the return code status, so we need to register
1804          * a callback function to get the actual result.
1805          * We need to take a new copy so that we don't alter the callers copy
1806          */
1807         ret = ldb_build_extended_req(
1808                 &new_req,
1809                 ldb,
1810                 req,
1811                 req->op.extended.oid,
1812                 req->op.extended.data,
1813                 req->controls,
1814                 context,
1815                 audit_callback,
1816                 req);
1817         if (ret != LDB_SUCCESS) {
1818                 return ret;
1819         }
1820         ret = add_transaction_id(module, new_req);
1821         if (ret != LDB_SUCCESS) {
1822                 return ret;
1823         }
1824         return ldb_next_request(module, new_req);
1825 }
1826
1827 /*
1828  * @brief module initialisation
1829  */
1830 static int log_init(struct ldb_module *module)
1831 {
1832
1833         struct ldb_context *ldb = ldb_module_get_ctx(module);
1834         struct audit_private *audit_private = NULL;
1835         struct loadparm_context *lp_ctx
1836                 = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
1837                                         struct loadparm_context);
1838         struct tevent_context *ev = ldb_get_event_context(ldb);
1839         bool sdb_events = false;
1840         bool pwd_events = false;
1841
1842         audit_private = talloc_zero(module, struct audit_private);
1843         if (audit_private == NULL) {
1844                 return ldb_module_oom(module);
1845         }
1846
1847         if (lp_ctx != NULL) {
1848                 sdb_events = lpcfg_dsdb_event_notification(lp_ctx);
1849                 pwd_events = lpcfg_dsdb_password_event_notification(lp_ctx);
1850         }
1851         if (sdb_events || pwd_events) {
1852                 audit_private->send_samdb_events = sdb_events;
1853                 audit_private->send_password_events = pwd_events;
1854                 audit_private->msg_ctx
1855                         = imessaging_client_init(audit_private,
1856                                                  lp_ctx,
1857                                                  ev);
1858         }
1859
1860         ldb_module_set_private(module, audit_private);
1861         return ldb_next_init(module);
1862 }
1863
1864 static const struct ldb_module_ops ldb_audit_log_module_ops = {
1865         .name              = "audit_log",
1866         .init_context      = log_init,
1867         .add               = log_add,
1868         .modify            = log_modify,
1869         .del               = log_delete,
1870         .start_transaction = log_start_transaction,
1871         .prepare_commit    = log_prepare_commit,
1872         .end_transaction   = log_end_transaction,
1873         .del_transaction   = log_del_transaction,
1874         .extended          = log_extended,
1875 };
1876
1877 int ldb_audit_log_module_init(const char *version)
1878 {
1879         LDB_MODULE_CHECK_VERSION(version);
1880         return ldb_register_module(&ldb_audit_log_module_ops);
1881 }