Line data Source code
1 : /*
2 : ldb database module utility 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 : * Common utility functions for SamDb audit logging.
22 : *
23 : */
24 :
25 : #include "includes.h"
26 : #include "ldb_module.h"
27 : #include "lib/audit_logging/audit_logging.h"
28 :
29 : #include "dsdb/samdb/samdb.h"
30 : #include "dsdb/samdb/ldb_modules/util.h"
31 : #include "libcli/security/dom_sid.h"
32 : #include "libcli/security/security_token.h"
33 : #include "auth/common_auth.h"
34 : #include "param/param.h"
35 : #include "dsdb/samdb/ldb_modules/util.h"
36 : #include "dsdb/samdb/ldb_modules/audit_util_proto.h"
37 :
38 : #define MAX_LENGTH 1024
39 :
40 : #define min(a, b) (((a)>(b))?(b):(a))
41 :
42 : /*
43 : * List of attributes considered secret or confidential the values of these
44 : * attributes should not be displayed in log messages.
45 : */
46 : static const char * const secret_attributes[] = {
47 : DSDB_SECRET_ATTRIBUTES,
48 : NULL};
49 : /*
50 : * List of attributes that contain a password, used to detect password changes
51 : */
52 : static const char * const password_attributes[] = {
53 : DSDB_PASSWORD_ATTRIBUTES,
54 : NULL};
55 :
56 : /*
57 : * @brief Should the value of the specified value be redacted.
58 : *
59 : * The values of secret or password attributes should not be displayed.
60 : *
61 : * @param name The attributes name.
62 : *
63 : * @return True if the attribute should be redacted
64 : */
65 1229455 : bool dsdb_audit_redact_attribute(const char * name)
66 : {
67 :
68 1229455 : if (ldb_attr_in_list(secret_attributes, name)) {
69 6533 : return true;
70 : }
71 :
72 1222922 : if (ldb_attr_in_list(password_attributes, name)) {
73 2163 : return true;
74 : }
75 :
76 1220759 : return false;
77 : }
78 :
79 : /*
80 : * @brief is the attribute a password attribute?
81 : *
82 : * Is the attribute a password attribute.
83 : *
84 : * @return True if the attribute is a "Password" attribute.
85 : */
86 3376958 : bool dsdb_audit_is_password_attribute(const char * name)
87 : {
88 :
89 3376958 : bool is_password = ldb_attr_in_list(password_attributes, name);
90 3376958 : return is_password;
91 : }
92 :
93 : /*
94 : * @brief Get the remote address from the ldb context.
95 : *
96 : * The remote address is stored in the ldb opaque value "remoteAddress"
97 : * it is the responsibility of the higher level code to ensure that this
98 : * value is set.
99 : *
100 : * @param ldb the ldb_context.
101 : *
102 : * @return the remote address if known, otherwise NULL.
103 : */
104 275573 : const struct tsocket_address *dsdb_audit_get_remote_address(
105 : struct ldb_context *ldb)
106 : {
107 275573 : void *opaque_remote_address = NULL;
108 : struct tsocket_address *remote_address;
109 :
110 275573 : opaque_remote_address = ldb_get_opaque(ldb,
111 : "remoteAddress");
112 275573 : if (opaque_remote_address == NULL) {
113 159942 : return NULL;
114 : }
115 :
116 115631 : remote_address = talloc_get_type(opaque_remote_address,
117 : struct tsocket_address);
118 115631 : return remote_address;
119 : }
120 :
121 : /*
122 : * @brief Get the actual user SID from ldb context.
123 : *
124 : * The actual user SID is stored in the ldb opaque value "networkSessionInfo"
125 : * it is the responsibility of the higher level code to ensure that this
126 : * value is set.
127 : *
128 : * @param ldb the ldb_context.
129 : *
130 : * @return the users actual sid.
131 : */
132 2518 : const struct dom_sid *dsdb_audit_get_actual_sid(struct ldb_context *ldb)
133 : {
134 2518 : void *opaque_session = NULL;
135 2518 : struct auth_session_info *session = NULL;
136 2518 : struct security_token *user_token = NULL;
137 :
138 2518 : opaque_session = ldb_get_opaque(ldb, DSDB_NETWORK_SESSION_INFO);
139 2518 : if (opaque_session == NULL) {
140 8 : return NULL;
141 : }
142 :
143 2510 : session = talloc_get_type(opaque_session, struct auth_session_info);
144 2510 : if (session == NULL) {
145 0 : return NULL;
146 : }
147 :
148 2510 : user_token = session->security_token;
149 2510 : if (user_token == NULL) {
150 0 : return NULL;
151 : }
152 2510 : return &user_token->sids[0];
153 : }
154 : /*
155 : * @brief get the ldb error string.
156 : *
157 : * Get the ldb error string if set, otherwise get the generic error code
158 : * for the status code.
159 : *
160 : * @param ldb the ldb_context.
161 : * @param status the ldb_status code.
162 : *
163 : * @return a string describing the error.
164 : */
165 1 : const char *dsdb_audit_get_ldb_error_string(
166 : struct ldb_module *module,
167 : int status)
168 : {
169 1 : struct ldb_context *ldb = ldb_module_get_ctx(module);
170 1 : const char *err_string = ldb_errstring(ldb);
171 :
172 1 : if (err_string == NULL) {
173 0 : return ldb_strerror(status);
174 : }
175 1 : return err_string;
176 : }
177 :
178 : /*
179 : * @brief get the SID of the user performing the operation.
180 : *
181 : * Get the SID of the user performing the operation.
182 : *
183 : * @param module the ldb_module.
184 : *
185 : * @return the SID of the currently logged on user.
186 : */
187 273055 : const struct dom_sid *dsdb_audit_get_user_sid(const struct ldb_module *module)
188 : {
189 273055 : struct security_token *user_token = NULL;
190 :
191 : /*
192 : * acl_user_token does not alter module so it's safe
193 : * to discard the const.
194 : */
195 273055 : user_token = acl_user_token(discard_const(module));
196 273055 : if (user_token == NULL) {
197 0 : return NULL;
198 : }
199 273055 : return &user_token->sids[0];
200 :
201 : }
202 :
203 : /*
204 : * @brief is operation being performed using the system session.
205 : *
206 : * Is the operation being performed using the system session.
207 : *
208 : * @param module the ldb_module.
209 : *
210 : * @return true if the operation is being performed using the system session.
211 : */
212 79560 : bool dsdb_audit_is_system_session(const struct ldb_module *module)
213 : {
214 79560 : struct security_token *user_token = NULL;
215 :
216 : /*
217 : * acl_user_token does not alter module and security_token_is_system
218 : * does not alter the security token so it's safe to discard the const.
219 : */
220 79560 : user_token = acl_user_token(discard_const(module));
221 79560 : if (user_token == NULL) {
222 0 : return false;
223 : }
224 79560 : return security_token_is_system(user_token);;
225 :
226 : }
227 :
228 : /*
229 : * @brief get the session identifier GUID
230 : *
231 : * Get the GUID that uniquely identifies the current authenticated session.
232 : *
233 : * @param module the ldb_module.
234 : *
235 : * @return the unique session GUID
236 : */
237 273055 : const struct GUID *dsdb_audit_get_unique_session_token(
238 : const struct ldb_module *module)
239 : {
240 273055 : struct ldb_context *ldb = ldb_module_get_ctx(discard_const(module));
241 229347 : struct auth_session_info *session_info
242 43708 : = (struct auth_session_info *)ldb_get_opaque(
243 : ldb,
244 : DSDB_SESSION_INFO);
245 273055 : if(!session_info) {
246 0 : return NULL;
247 : }
248 273055 : return &session_info->unique_session_token;
249 : }
250 :
251 : /*
252 : * @brief get the actual user session identifier
253 : *
254 : * Get the GUID that uniquely identifies the current authenticated session.
255 : * This is the session of the connected user, as it may differ from the
256 : * session the operation is being performed as, i.e. for operations performed
257 : * under the system session.
258 : *
259 : * @param context the ldb_context.
260 : *
261 : * @return the unique session GUID
262 : */
263 2518 : const struct GUID *dsdb_audit_get_actual_unique_session_token(
264 : struct ldb_context *ldb)
265 : {
266 2492 : struct auth_session_info *session_info
267 26 : = (struct auth_session_info *)ldb_get_opaque(
268 : ldb,
269 : DSDB_NETWORK_SESSION_INFO);
270 2518 : if(!session_info) {
271 8 : return NULL;
272 : }
273 2510 : return &session_info->unique_session_token;
274 : }
275 :
276 : /*
277 : * @brief Get a printable string value for the remote host address.
278 : *
279 : * Get a printable string representation of the remote host, for display in the
280 : * the audit logs.
281 : *
282 : * @param ldb the ldb context.
283 : * @param mem_ctx the talloc memory context that will own the returned string.
284 : *
285 : * @return A string representation of the remote host address or "Unknown"
286 : *
287 : */
288 0 : char *dsdb_audit_get_remote_host(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
289 : {
290 : const struct tsocket_address *remote_address;
291 0 : char* remote_host = NULL;
292 :
293 0 : remote_address = dsdb_audit_get_remote_address(ldb);
294 0 : if (remote_address == NULL) {
295 0 : remote_host = talloc_asprintf(mem_ctx, "Unknown");
296 0 : return remote_host;
297 : }
298 :
299 0 : remote_host = tsocket_address_string(remote_address, mem_ctx);
300 0 : return remote_host;
301 : }
302 :
303 : /*
304 : * @brief get a printable representation of the primary DN.
305 : *
306 : * Get a printable representation of the primary DN. The primary DN is the
307 : * DN of the object being added, deleted, modified or renamed.
308 : *
309 : * @param the ldb_request.
310 : *
311 : * @return a printable and linearized DN
312 : */
313 287028 : const char* dsdb_audit_get_primary_dn(const struct ldb_request *request)
314 : {
315 287028 : struct ldb_dn *dn = NULL;
316 287028 : switch (request->operation) {
317 151503 : case LDB_ADD:
318 151503 : if (request->op.add.message != NULL) {
319 151503 : dn = request->op.add.message->dn;
320 : }
321 151503 : break;
322 106828 : case LDB_MODIFY:
323 106828 : if (request->op.mod.message != NULL) {
324 106828 : dn = request->op.mod.message->dn;
325 : }
326 106828 : break;
327 28697 : case LDB_DELETE:
328 28697 : dn = request->op.del.dn;
329 28697 : break;
330 0 : case LDB_RENAME:
331 0 : dn = request->op.rename.olddn;
332 0 : break;
333 0 : default:
334 0 : dn = NULL;
335 0 : break;
336 : }
337 287028 : if (dn == NULL) {
338 0 : return NULL;
339 : }
340 287028 : return ldb_dn_get_linearized(dn);
341 : }
342 :
343 : /*
344 : * @brief Get the ldb_message from a request.
345 : *
346 : * Get the ldb_message for the request, returns NULL is there is no
347 : * associated ldb_message
348 : *
349 : * @param The request
350 : *
351 : * @return the message associated with this request, or NULL
352 : */
353 1703231 : const struct ldb_message *dsdb_audit_get_message(
354 : const struct ldb_request *request)
355 : {
356 1703231 : switch (request->operation) {
357 673907 : case LDB_ADD:
358 673907 : return request->op.add.message;
359 927128 : case LDB_MODIFY:
360 927128 : return request->op.mod.message;
361 102196 : default:
362 102196 : return NULL;
363 : }
364 : }
365 :
366 : /*
367 : * @brief get the secondary dn, i.e. the target dn for a rename.
368 : *
369 : * Get the secondary dn, i.e. the target for a rename. This is only applicable
370 : * got a rename operation, for the non rename operations this function returns
371 : * NULL.
372 : *
373 : * @param request the ldb_request.
374 : *
375 : * @return the secondary dn in a printable and linearized form.
376 : */
377 0 : const char *dsdb_audit_get_secondary_dn(const struct ldb_request *request)
378 : {
379 0 : switch (request->operation) {
380 0 : case LDB_RENAME:
381 0 : return ldb_dn_get_linearized(request->op.rename.newdn);
382 0 : default:
383 0 : return NULL;
384 : }
385 : }
386 :
387 : /*
388 : * @brief Map the request operation to a description.
389 : *
390 : * Get a description of the operation for logging
391 : *
392 : * @param request the ldb_request
393 : *
394 : * @return a string describing the operation, or "Unknown" if the operation
395 : * is not known.
396 : */
397 236185 : const char *dsdb_audit_get_operation_name(const struct ldb_request *request)
398 : {
399 236185 : switch (request->operation) {
400 0 : case LDB_SEARCH:
401 0 : return "Search";
402 114186 : case LDB_ADD:
403 114186 : return "Add";
404 93302 : case LDB_MODIFY:
405 93302 : return "Modify";
406 28697 : case LDB_DELETE:
407 28697 : return "Delete";
408 0 : case LDB_RENAME:
409 0 : return "Rename";
410 0 : case LDB_EXTENDED:
411 0 : return "Extended";
412 0 : case LDB_REQ_REGISTER_CONTROL:
413 0 : return "Register Control";
414 0 : case LDB_REQ_REGISTER_PARTITION:
415 0 : return "Register Partition";
416 0 : default:
417 0 : return "Unknown";
418 : }
419 : }
420 :
421 : /*
422 : * @brief get a description of a modify action for logging.
423 : *
424 : * Get a brief description of the modification action suitable for logging.
425 : *
426 : * @param flags the ldb_attributes flags.
427 : *
428 : * @return a brief description, or "unknown".
429 : */
430 154387 : const char *dsdb_audit_get_modification_action(unsigned int flags)
431 : {
432 154387 : switch (LDB_FLAG_MOD_TYPE(flags)) {
433 47148 : case LDB_FLAG_MOD_ADD:
434 47148 : return "add";
435 43900 : case LDB_FLAG_MOD_DELETE:
436 43900 : return "delete";
437 63339 : case LDB_FLAG_MOD_REPLACE:
438 63339 : return "replace";
439 0 : default:
440 0 : return "unknown";
441 : }
442 : }
443 :
444 : /*
445 : * @brief Add an ldb_value to a json object array
446 : *
447 : * Convert the current ldb_value to a JSON object and append it to array.
448 : * {
449 : * "value":"xxxxxxxx",
450 : * "base64":true
451 : * "truncated":true
452 : * }
453 : *
454 : * value is the JSON string representation of the ldb_val,
455 : * will be null if the value is zero length. The value will be
456 : * truncated if it is more than MAX_LENGTH bytes long. It will also
457 : * be base64 encoded if it contains any non printable characters.
458 : *
459 : * base64 Indicates that the value is base64 encoded, will be absent if the
460 : * value is not encoded.
461 : *
462 : * truncated Indicates that the length of the value exceeded MAX_LENGTH and was
463 : * truncated. Note that vales are truncated and then base64 encoded.
464 : * so an encoded value can be longer than MAX_LENGTH.
465 : *
466 : * @param array the JSON array to append the value to.
467 : * @param lv the ldb_val to convert and append to the array.
468 : *
469 : */
470 1714181 : static int dsdb_audit_add_ldb_value(struct json_object *array,
471 : const struct ldb_val lv)
472 : {
473 : bool base64;
474 : int len;
475 1714181 : struct json_object value = json_empty_object;
476 1714181 : int rc = 0;
477 :
478 1714181 : json_assert_is_array(array);
479 1714181 : if (json_is_invalid(array)) {
480 0 : return -1;
481 : }
482 :
483 1714181 : if (lv.length == 0 || lv.data == NULL) {
484 0 : rc = json_add_object(array, NULL, NULL);
485 0 : if (rc != 0) {
486 0 : goto failure;
487 : }
488 0 : return 0;
489 : }
490 :
491 1714181 : base64 = ldb_should_b64_encode(NULL, &lv);
492 1714181 : len = min(lv.length, MAX_LENGTH);
493 1714181 : value = json_new_object();
494 1714181 : if (json_is_invalid(&value)) {
495 0 : goto failure;
496 : }
497 :
498 1714181 : if (lv.length > MAX_LENGTH) {
499 4198 : rc = json_add_bool(&value, "truncated", true);
500 4198 : if (rc != 0) {
501 0 : goto failure;
502 : }
503 : }
504 1714181 : if (base64) {
505 277020 : TALLOC_CTX *ctx = talloc_new(NULL);
506 277020 : char *encoded = ldb_base64_encode(
507 : ctx,
508 277020 : (char*) lv.data,
509 : len);
510 :
511 277020 : if (ctx == NULL) {
512 0 : goto failure;
513 : }
514 :
515 277020 : rc = json_add_bool(&value, "base64", true);
516 277020 : if (rc != 0) {
517 0 : TALLOC_FREE(ctx);
518 0 : goto failure;
519 : }
520 277020 : rc = json_add_string(&value, "value", encoded);
521 277020 : if (rc != 0) {
522 0 : TALLOC_FREE(ctx);
523 0 : goto failure;
524 : }
525 277020 : TALLOC_FREE(ctx);
526 : } else {
527 1437161 : rc = json_add_stringn(&value, "value", (char *)lv.data, len);
528 1437161 : if (rc != 0) {
529 0 : goto failure;
530 : }
531 : }
532 : /*
533 : * As array is a JSON array the element name is NULL
534 : */
535 1714181 : rc = json_add_object(array, NULL, &value);
536 1714181 : if (rc != 0) {
537 0 : goto failure;
538 : }
539 1714181 : return 0;
540 0 : failure:
541 : /*
542 : * In the event of a failure value will not have been added to array
543 : * so it needs to be freed to prevent a leak.
544 : */
545 0 : json_free(&value);
546 0 : DBG_ERR("unable to add ldb value to JSON audit message");
547 0 : return -1;
548 : }
549 :
550 : /*
551 : * @brief Build a JSON object containing the attributes in an ldb_message.
552 : *
553 : * Build a JSON object containing all the attributes in an ldb_message.
554 : * The attributes are keyed by attribute name, the values of "secret attributes"
555 : * are supressed.
556 : *
557 : * {
558 : * "password":{
559 : * "redacted":true,
560 : * "action":"delete"
561 : * },
562 : * "name":{
563 : * "values": [
564 : * {
565 : * "value":"xxxxxxxx",
566 : * "base64":true
567 : * "truncated":true
568 : * },
569 : * ],
570 : * "action":"add",
571 : * }
572 : * }
573 : *
574 : * values is an array of json objects generated by add_ldb_value.
575 : * redacted indicates that the attribute is secret.
576 : * action is only set for modification operations.
577 : *
578 : * @param operation the ldb operation being performed
579 : * @param message the ldb_message to process.
580 : *
581 : * @return A populated json object.
582 : *
583 : */
584 207488 : struct json_object dsdb_audit_attributes_json(
585 : enum ldb_request_type operation,
586 : const struct ldb_message* message)
587 : {
588 :
589 : unsigned int i, j;
590 207488 : struct json_object attributes = json_new_object();
591 :
592 207488 : if (json_is_invalid(&attributes)) {
593 0 : goto failure;
594 : }
595 2559593 : for (i=0;i<message->num_elements;i++) {
596 1229455 : struct json_object actions = json_empty_object;
597 1229455 : struct json_object attribute = json_empty_object;
598 1229455 : struct json_object action = json_empty_object;
599 1229455 : const char *name = message->elements[i].name;
600 1229455 : int rc = 0;
601 :
602 1229455 : action = json_new_object();
603 1229455 : if (json_is_invalid(&action)) {
604 0 : goto failure;
605 : }
606 :
607 : /*
608 : * If this is a modify operation tag the attribute with
609 : * the modification action.
610 : */
611 1229455 : if (operation == LDB_MODIFY) {
612 154387 : const char *act = NULL;
613 154387 : const int flags = message->elements[i].flags;
614 154387 : act = dsdb_audit_get_modification_action(flags);
615 154387 : rc = json_add_string(&action, "action", act);
616 154387 : if (rc != 0) {
617 0 : json_free(&action);
618 0 : goto failure;
619 : }
620 : }
621 1229455 : if (operation == LDB_ADD) {
622 1075068 : rc = json_add_string(&action, "action", "add");
623 1075068 : if (rc != 0) {
624 0 : json_free(&action);
625 0 : goto failure;
626 : }
627 : }
628 :
629 : /*
630 : * If the attribute is a secret attribute, tag it as redacted
631 : * and don't include the values
632 : */
633 1229455 : if (dsdb_audit_redact_attribute(name)) {
634 8696 : rc = json_add_bool(&action, "redacted", true);
635 8696 : if (rc != 0) {
636 0 : json_free(&action);
637 0 : goto failure;
638 : }
639 : } else {
640 : struct json_object values;
641 : /*
642 : * Add the values for the action
643 : */
644 1220759 : values = json_new_array();
645 1220759 : if (json_is_invalid(&values)) {
646 0 : json_free(&action);
647 0 : goto failure;
648 : }
649 :
650 2934940 : for (j=0;j<message->elements[i].num_values;j++) {
651 1714181 : rc = dsdb_audit_add_ldb_value(
652 1714181 : &values, message->elements[i].values[j]);
653 1714181 : if (rc != 0) {
654 0 : json_free(&values);
655 0 : json_free(&action);
656 0 : goto failure;
657 : }
658 : }
659 1220759 : rc = json_add_object(&action, "values", &values);
660 1220759 : if (rc != 0) {
661 0 : json_free(&values);
662 0 : json_free(&action);
663 0 : goto failure;
664 : }
665 : }
666 1229455 : attribute = json_get_object(&attributes, name);
667 1229455 : if (json_is_invalid(&attribute)) {
668 0 : json_free(&action);
669 0 : goto failure;
670 : }
671 1229455 : actions = json_get_array(&attribute, "actions");
672 1229455 : if (json_is_invalid(&actions)) {
673 0 : json_free(&action);
674 0 : goto failure;
675 : }
676 1229455 : rc = json_add_object(&actions, NULL, &action);
677 1229455 : if (rc != 0) {
678 0 : json_free(&action);
679 0 : goto failure;
680 : }
681 1229455 : rc = json_add_object(&attribute, "actions", &actions);
682 1229455 : if (rc != 0) {
683 0 : json_free(&actions);
684 0 : goto failure;
685 : }
686 1229455 : rc = json_add_object(&attributes, name, &attribute);
687 1229455 : if (rc != 0) {
688 0 : json_free(&attribute);
689 0 : goto failure;
690 : }
691 : }
692 207488 : return attributes;
693 0 : failure:
694 0 : json_free(&attributes);
695 0 : DBG_ERR("Unable to create ldb attributes JSON audit message\n");
696 0 : return attributes;
697 : }
698 :
699 : /*
700 : * @brief Generate a human readable string, detailing attributes in a message
701 : *
702 : * For modify operations each attribute is prefixed with the action.
703 : * Normal values are enclosed in []
704 : * Base64 values are enclosed in {}
705 : * Truncated values are indicated by three trailing dots "..."
706 : *
707 : * @param[in] ldb the ldb_context
708 : * @param[out] buffer the attributes will be appended to the buffer.
709 : * assumed to have been allocated via talloc.
710 : * @param[in] operation the operation type
711 : * @param[in] message the message to process
712 : *
713 : * @return a pointer to buffer
714 : *
715 : */
716 0 : char *dsdb_audit_log_attributes(
717 : struct ldb_context *ldb,
718 : char *buffer,
719 : enum ldb_request_type operation,
720 : const struct ldb_message *message)
721 : {
722 : size_t i, j;
723 0 : for (i=0;i<message->num_elements;i++) {
724 0 : if (i > 0) {
725 0 : buffer = talloc_asprintf_append_buffer(buffer, " ");
726 : }
727 :
728 0 : if (message->elements[i].name == NULL) {
729 0 : ldb_debug(
730 : ldb,
731 : LDB_DEBUG_ERROR,
732 : "Error: Invalid element name (NULL) at "
733 : "position %zu", i);
734 0 : return NULL;
735 : }
736 :
737 0 : if (operation == LDB_MODIFY) {
738 0 : const char *action =NULL;
739 0 : action = dsdb_audit_get_modification_action(
740 0 : message->elements[i].flags);
741 0 : buffer = talloc_asprintf_append_buffer(
742 : buffer,
743 : "%s: %s ",
744 : action,
745 0 : message->elements[i].name);
746 : } else {
747 0 : buffer = talloc_asprintf_append_buffer(
748 : buffer,
749 : "%s ",
750 0 : message->elements[i].name);
751 : }
752 :
753 0 : if (dsdb_audit_redact_attribute(message->elements[i].name)) {
754 : /*
755 : * Do not log the value of any secret or password
756 : * attributes
757 : */
758 0 : buffer = talloc_asprintf_append_buffer(
759 : buffer,
760 : "[REDACTED SECRET ATTRIBUTE]");
761 0 : continue;
762 : }
763 :
764 0 : for (j=0;j<message->elements[i].num_values;j++) {
765 : struct ldb_val v;
766 0 : bool use_b64_encode = false;
767 : size_t length;
768 0 : if (j > 0) {
769 0 : buffer = talloc_asprintf_append_buffer(
770 : buffer,
771 : " ");
772 : }
773 :
774 0 : v = message->elements[i].values[j];
775 0 : length = MIN(MAX_LENGTH, v.length);
776 0 : use_b64_encode = ldb_should_b64_encode(ldb, &v);
777 0 : if (use_b64_encode) {
778 0 : const char *encoded = ldb_base64_encode(
779 : buffer,
780 0 : (char *)v.data,
781 : length);
782 0 : buffer = talloc_asprintf_append_buffer(
783 : buffer,
784 : "{%s%s}",
785 : encoded,
786 0 : (v.length > MAX_LENGTH ? "..." : ""));
787 : } else {
788 0 : buffer = talloc_asprintf_append_buffer(
789 : buffer,
790 : "[%*.*s%s]",
791 : (int)length,
792 : (int)length,
793 0 : (char *)v.data,
794 0 : (v.length > MAX_LENGTH ? "..." : ""));
795 : }
796 : }
797 : }
798 0 : return buffer;
799 : }
800 :
801 : /*
802 : * @brief generate a human readable log entry detailing an ldb operation.
803 : *
804 : * Generate a human readable log entry detailing an ldb operation.
805 : *
806 : * @param[in] mem_ctx the talloc context owning the returned string.
807 : * @param[in] module the ldb module
808 : * @param[in] request the request
809 : * @param[in] reply the result of the operation
810 : *
811 : * @return the log entry.
812 : *
813 : */
814 0 : char *dsdb_audit_operation_human_readable(
815 : TALLOC_CTX *mem_ctx,
816 : struct ldb_module *module,
817 : const struct ldb_request *request,
818 : const struct ldb_reply *reply)
819 : {
820 0 : struct ldb_context *ldb = NULL;
821 0 : const char *remote_host = NULL;
822 0 : const struct tsocket_address *remote = NULL;
823 0 : const struct dom_sid *sid = NULL;
824 : struct dom_sid_buf user_sid;
825 0 : const char *timestamp = NULL;
826 0 : const char *op_name = NULL;
827 0 : char *log_entry = NULL;
828 0 : const char *dn = NULL;
829 0 : const char *new_dn = NULL;
830 0 : const struct ldb_message *message = NULL;
831 :
832 0 : TALLOC_CTX *ctx = talloc_new(NULL);
833 :
834 0 : ldb = ldb_module_get_ctx(module);
835 :
836 0 : remote_host = dsdb_audit_get_remote_host(ldb, ctx);
837 0 : remote = dsdb_audit_get_remote_address(ldb);
838 0 : if (remote != NULL && dsdb_audit_is_system_session(module)) {
839 0 : sid = dsdb_audit_get_actual_sid(ldb);
840 : } else {
841 0 : sid = dsdb_audit_get_user_sid(module);
842 : }
843 0 : timestamp = audit_get_timestamp(ctx);
844 0 : op_name = dsdb_audit_get_operation_name(request);
845 0 : dn = dsdb_audit_get_primary_dn(request);
846 0 : new_dn = dsdb_audit_get_secondary_dn(request);
847 :
848 0 : message = dsdb_audit_get_message(request);
849 :
850 0 : log_entry = talloc_asprintf(
851 : mem_ctx,
852 : "[%s] at [%s] status [%s] "
853 : "remote host [%s] SID [%s] DN [%s]",
854 : op_name,
855 : timestamp,
856 0 : ldb_strerror(reply->error),
857 : remote_host,
858 : dom_sid_str_buf(sid, &user_sid),
859 : dn);
860 0 : if (new_dn != NULL) {
861 0 : log_entry = talloc_asprintf_append_buffer(
862 : log_entry,
863 : " New DN [%s]",
864 : new_dn);
865 : }
866 0 : if (message != NULL) {
867 0 : log_entry = talloc_asprintf_append_buffer(log_entry,
868 : " attributes [");
869 0 : log_entry = dsdb_audit_log_attributes(ldb,
870 : log_entry,
871 0 : request->operation,
872 : message);
873 0 : log_entry = talloc_asprintf_append_buffer(log_entry, "]");
874 : }
875 0 : TALLOC_FREE(ctx);
876 0 : return log_entry;
877 : }
|