dsdb group audit tests: check_version improve diagnostics
[Samba.git] / source4 / dsdb / samdb / ldb_modules / tests / test_group_audit.c
blobce7e485b9b0989806bf942dc5f7c321185a31fc2
1 /*
2 Unit tests for the dsdb group auditing code in group_audit.c
4 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <stdarg.h>
21 #include <stddef.h>
22 #include <setjmp.h>
23 #include <unistd.h>
24 #include <cmocka.h>
26 int ldb_group_audit_log_module_init(const char *version);
27 #include "../group_audit.c"
29 #include "lib/ldb/include/ldb_private.h"
30 #include <regex.h>
33 * Mock version of dsdb_search_one
35 struct ldb_dn *g_basedn = NULL;
36 enum ldb_scope g_scope;
37 const char * const *g_attrs = NULL;
38 uint32_t g_dsdb_flags;
39 const char *g_exp_fmt;
40 const char *g_dn = NULL;
41 int g_status = LDB_SUCCESS;
43 int dsdb_search_one(struct ldb_context *ldb,
44 TALLOC_CTX *mem_ctx,
45 struct ldb_message **msg,
46 struct ldb_dn *basedn,
47 enum ldb_scope scope,
48 const char * const *attrs,
49 uint32_t dsdb_flags,
50 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
52 struct ldb_dn *dn = ldb_dn_new(mem_ctx, ldb, g_dn);
53 struct ldb_message *m = talloc_zero(mem_ctx, struct ldb_message);
54 m->dn = dn;
55 *msg = m;
57 g_basedn = basedn;
58 g_scope = scope;
59 g_attrs = attrs;
60 g_dsdb_flags = dsdb_flags;
61 g_exp_fmt = exp_fmt;
63 return g_status;
67 * Mocking for audit_log_hr to capture the called parameters
69 const char *audit_log_hr_prefix = NULL;
70 const char *audit_log_hr_message = NULL;
71 int audit_log_hr_debug_class = 0;
72 int audit_log_hr_debug_level = 0;
74 static void audit_log_hr_init(void)
76 audit_log_hr_prefix = NULL;
77 audit_log_hr_message = NULL;
78 audit_log_hr_debug_class = 0;
79 audit_log_hr_debug_level = 0;
82 void audit_log_human_text(
83 const char *prefix,
84 const char *message,
85 int debug_class,
86 int debug_level)
88 audit_log_hr_prefix = prefix;
89 audit_log_hr_message = message;
90 audit_log_hr_debug_class = debug_class;
91 audit_log_hr_debug_level = debug_level;
94 #define MAX_EXPECTED_MESSAGES 16
95 static struct json_object messages[MAX_EXPECTED_MESSAGES];
96 static size_t messages_sent = 0;
98 void audit_message_send(
99 struct imessaging_context *msg_ctx,
100 const char *server_name,
101 uint32_t message_type,
102 struct json_object *message)
104 messages[messages_sent].root = json_deep_copy(message->root);
105 messages[messages_sent].error = message->error;
106 messages_sent++;
109 #define check_group_change_message(m, u, a)\
110 _check_group_change_message(m, u, a, __FILE__, __LINE__);
112 * declare the internal cmocka cm_print_error so that we can output messages
113 * in sub unit format
115 void cm_print_error(const char * const format, ...);
118 * Validate a group change JSON audit message
120 * It should contain 3 elements.
121 * Have a type of "groupChange"
122 * Have a groupChange element
124 * The group change element should have 10 elements.
126 * There should be a user element matching the expected value
127 * There should be an action matching the expected value
129 static void _check_group_change_message(
130 const int message,
131 const char *user,
132 const char *action,
133 const char *file,
134 const int line)
136 struct json_object json;
137 json_t *audit = NULL;
138 json_t *v = NULL;
139 const char* value;
140 json = messages[message];
143 * Validate the root JSON element
144 * check the number of elements
146 if (json_object_size(json.root) != 3) {
147 cm_print_error(
148 "Unexpected number of elements in root %zu != %d\n",
149 json_object_size(json.root),
151 _fail(file, line);
155 * Check the type element
157 v = json_object_get(json.root, "type");
158 if (v == NULL) {
159 cm_print_error( "No \"type\" element\n");
160 _fail(file, line);
163 value = json_string_value(v);
164 if (strncmp("groupChange", value, strlen("groupChange") != 0)) {
165 cm_print_error(
166 "Unexpected type \"%s\" != \"groupChange\"\n",
167 value);
168 _fail(file, line);
172 audit = json_object_get(json.root, "groupChange");
173 if (audit == NULL) {
174 cm_print_error("No groupChange element\n");
175 _fail(file, line);
179 * Validate the groupChange element
181 if (json_object_size(audit) != 10) {
182 cm_print_error(
183 "Unexpected number of elements in groupChange "
184 "%zu != %d\n",
185 json_object_size(audit),
186 10);
187 _fail(file, line);
190 * Validate the user element
192 v = json_object_get(audit, "user");
193 if (v == NULL) {
194 cm_print_error( "No user element\n");
195 _fail(file, line);
198 value = json_string_value(v);
199 if (strncmp(user, value, strlen(user) != 0)) {
200 cm_print_error(
201 "Unexpected user name \"%s\" != \"%s\"\n",
202 value,
203 user);
204 _fail(file, line);
208 * Validate the action element
210 v = json_object_get(audit, "action");
211 if (v == NULL) {
212 cm_print_error( "No action element\n");
213 _fail(file, line);
216 value = json_string_value(v);
217 if (strncmp(action, value, strlen(action) != 0)) {
218 print_error(
219 "Unexpected action \"%s\" != \"%s\"\n",
220 value,
221 action);
222 _fail(file, line);
226 #define check_timestamp(b, t)\
227 _check_timestamp(b, t, __FILE__, __LINE__);
229 * Test helper to check ISO 8601 timestamps for validity
231 static void _check_timestamp(
232 time_t before,
233 const char *timestamp,
234 const char *file,
235 const int line)
237 int rc;
238 int usec, tz;
239 char c[2];
240 struct tm tm;
241 time_t after;
242 time_t actual;
245 after = time(NULL);
248 * Convert the ISO 8601 timestamp into a time_t
249 * Note for convenience we ignore the value of the microsecond
250 * part of the time stamp.
252 rc = sscanf(
253 timestamp,
254 "%4d-%2d-%2dT%2d:%2d:%2d.%6d%1c%4d",
255 &tm.tm_year,
256 &tm.tm_mon,
257 &tm.tm_mday,
258 &tm.tm_hour,
259 &tm.tm_min,
260 &tm.tm_sec,
261 &usec,
263 &tz);
264 assert_int_equal(9, rc);
265 tm.tm_year = tm.tm_year - 1900;
266 tm.tm_mon = tm.tm_mon - 1;
267 tm.tm_isdst = -1;
268 actual = mktime(&tm);
271 * The time stamp should be before <= actual <= after
273 if (difftime(actual, before) < 0) {
274 char buffer[40];
275 strftime(buffer,
276 sizeof(buffer)-1,
277 "%Y-%m-%dT%T",
278 localtime(&before));
279 cm_print_error(
280 "time stamp \"%s\" is before start time \"%s\"\n",
281 timestamp,
282 buffer);
283 _fail(file, line);
285 if (difftime(after, actual) < 0) {
286 char buffer[40];
287 strftime(buffer,
288 sizeof(buffer)-1,
289 "%Y-%m-%dT%T",
290 localtime(&after));
291 cm_print_error(
292 "time stamp \"%s\" is after finish time \"%s\"\n",
293 timestamp,
294 buffer);
295 _fail(file, line);
299 #define check_version(v, m, n)\
300 _check_version(v, m, n, __FILE__, __LINE__);
302 * Test helper to validate a version object.
304 static void _check_version(
305 struct json_t *version,
306 int major,
307 int minor,
308 const char* file,
309 const int line)
311 struct json_t *v = NULL;
312 int value;
314 if (!json_is_object(version)) {
315 cm_print_error("version is not a JSON object\n");
316 _fail(file, line);
319 if (json_object_size(version) != 2) {
320 cm_print_error(
321 "Unexpected number of elements in version %zu != %d\n",
322 json_object_size(version),
324 _fail(file, line);
328 * Validate the major version number element
330 v = json_object_get(version, "major");
331 if (v == NULL) {
332 cm_print_error( "No major element\n");
333 _fail(file, line);
336 value = json_integer_value(v);
337 if (value != major) {
338 print_error(
339 "Unexpected major version number \"%d\" != \"%d\"\n",
340 value,
341 major);
342 _fail(file, line);
346 * Validate the minor version number element
348 v = json_object_get(version, "minor");
349 if (v == NULL) {
350 cm_print_error( "No minor element\n");
351 _fail(file, line);
354 value = json_integer_value(v);
355 if (value != minor) {
356 print_error(
357 "Unexpected minor version number \"%d\" != \"%d\"\n",
358 value,
359 minor);
360 _fail(file, line);
365 * Test helper to insert a transaction_id into a request.
367 static void add_transaction_id(struct ldb_request *req, const char *id)
369 struct GUID guid;
370 struct dsdb_control_transaction_identifier *transaction_id = NULL;
372 transaction_id = talloc_zero(
373 req,
374 struct dsdb_control_transaction_identifier);
375 assert_non_null(transaction_id);
376 GUID_from_string(id, &guid);
377 transaction_id->transaction_guid = guid;
378 ldb_request_add_control(
379 req,
380 DSDB_CONTROL_TRANSACTION_IDENTIFIER_OID,
381 false,
382 transaction_id);
386 * Test helper to add a session id and user SID
388 static void add_session_data(
389 TALLOC_CTX *ctx,
390 struct ldb_context *ldb,
391 const char *session,
392 const char *user_sid)
394 struct auth_session_info *sess = NULL;
395 struct security_token *token = NULL;
396 struct dom_sid *sid = NULL;
397 struct GUID session_id;
398 bool ok;
400 sess = talloc_zero(ctx, struct auth_session_info);
401 token = talloc_zero(ctx, struct security_token);
402 sid = talloc_zero(ctx, struct dom_sid);
403 ok = string_to_sid(sid, user_sid);
404 assert_true(ok);
405 token->sids = sid;
406 sess->security_token = token;
407 GUID_from_string(session, &session_id);
408 sess->unique_session_token = session_id;
409 ldb_set_opaque(ldb, DSDB_SESSION_INFO, sess);
412 static void test_get_transaction_id(void **state)
414 struct ldb_request *req = NULL;
415 struct GUID *guid;
416 const char * const ID = "7130cb06-2062-6a1b-409e-3514c26b1773";
417 char *guid_str = NULL;
418 struct GUID_txt_buf guid_buff;
421 TALLOC_CTX *ctx = talloc_new(NULL);
425 * No transaction id, should return a zero guid
427 req = talloc_zero(ctx, struct ldb_request);
428 guid = get_transaction_id(req);
429 assert_null(guid);
430 TALLOC_FREE(req);
433 * And now test with the transaction_id set
435 req = talloc_zero(ctx, struct ldb_request);
436 assert_non_null(req);
437 add_transaction_id(req, ID);
439 guid = get_transaction_id(req);
440 guid_str = GUID_buf_string(guid, &guid_buff);
441 assert_string_equal(ID, guid_str);
442 TALLOC_FREE(req);
444 TALLOC_FREE(ctx);
447 static void test_audit_group_hr(void **state)
449 struct ldb_context *ldb = NULL;
450 struct ldb_module *module = NULL;
451 struct ldb_request *req = NULL;
453 struct tsocket_address *ts = NULL;
455 const char *const SID = "S-1-5-21-2470180966-3899876309-2637894779";
456 const char * const SESSION = "7130cb06-2062-6a1b-409e-3514c26b1773";
458 struct GUID transaction_id;
459 const char *const TRANSACTION = "7130cb06-2062-6a1b-409e-3514c26b1773";
462 char *line = NULL;
463 const char *rs = NULL;
464 regex_t regex;
465 int ret;
468 TALLOC_CTX *ctx = talloc_new(NULL);
470 ldb = ldb_init(ctx, NULL);
472 GUID_from_string(TRANSACTION, &transaction_id);
474 module = talloc_zero(ctx, struct ldb_module);
475 module->ldb = ldb;
477 tsocket_address_inet_from_strings(ctx, "ip", "127.0.0.1", 0, &ts);
478 ldb_set_opaque(ldb, "remoteAddress", ts);
480 add_session_data(ctx, ldb, SESSION, SID);
482 req = talloc_zero(ctx, struct ldb_request);
483 req->operation = LDB_ADD;
484 add_transaction_id(req, TRANSACTION);
486 line = audit_group_human_readable(
487 ctx,
488 module,
489 req,
490 "the-action",
491 "the-user-name",
492 "the-group-name",
493 LDB_ERR_OPERATIONS_ERROR);
494 assert_non_null(line);
496 rs = "\\[the-action\\] at \\["
497 "[^]]*"
498 "\\] status \\[Operations error\\] "
499 "Remote host \\[ipv4:127.0.0.1:0\\] "
500 "SID \\[S-1-5-21-2470180966-3899876309-2637894779\\] "
501 "Group \\[the-group-name\\] "
502 "User \\[the-user-name\\]";
504 ret = regcomp(&regex, rs, 0);
505 assert_int_equal(0, ret);
507 ret = regexec(&regex, line, 0, NULL, 0);
508 assert_int_equal(0, ret);
510 regfree(&regex);
511 TALLOC_FREE(ctx);
516 * test get_parsed_dns
517 * For this test we assume Valgrind or Address Sanitizer will detect any over
518 * runs. Also we don't care that the values are DN's only that the value in the
519 * element is copied to the parsed_dns.
521 static void test_get_parsed_dns(void **state)
523 struct ldb_message_element *el = NULL;
524 struct parsed_dn *dns = NULL;
526 TALLOC_CTX *ctx = talloc_new(NULL);
528 el = talloc_zero(ctx, struct ldb_message_element);
531 * empty element, zero dns
533 dns = get_parsed_dns(ctx, el);
534 assert_null(dns);
537 * one entry
539 el->num_values = 1;
540 el->values = talloc_zero_array(ctx, DATA_BLOB, 1);
541 el->values[0] = data_blob_string_const("The first value");
543 dns = get_parsed_dns(ctx, el);
545 assert_ptr_equal(el->values[0].data, dns[0].v->data);
546 assert_int_equal(el->values[0].length, dns[0].v->length);
548 TALLOC_FREE(dns);
549 TALLOC_FREE(el);
553 * Multiple values
555 el = talloc_zero(ctx, struct ldb_message_element);
556 el->num_values = 2;
557 el->values = talloc_zero_array(ctx, DATA_BLOB, 2);
558 el->values[0] = data_blob_string_const("The first value");
559 el->values[0] = data_blob_string_const("The second value");
561 dns = get_parsed_dns(ctx, el);
563 assert_ptr_equal(el->values[0].data, dns[0].v->data);
564 assert_int_equal(el->values[0].length, dns[0].v->length);
566 assert_ptr_equal(el->values[1].data, dns[1].v->data);
567 assert_int_equal(el->values[1].length, dns[1].v->length);
569 TALLOC_FREE(ctx);
572 static void test_dn_compare(void **state)
575 struct ldb_context *ldb = NULL;
576 struct parsed_dn *a;
577 DATA_BLOB ab;
579 struct parsed_dn *b;
580 DATA_BLOB bb;
582 int res;
584 TALLOC_CTX *ctx = talloc_new(NULL);
585 const struct GUID *ZERO_GUID = talloc_zero(ctx, struct GUID);
587 ldb = ldb_init(ctx, NULL);
588 ldb_register_samba_handlers(ldb);
592 * Identical binary DN's
594 ab = data_blob_string_const(
595 "<GUID=fbee08fd-6f75-4bd4-af3f-e4f063a6379e>;"
596 "OU=Domain Controllers,DC=ad,DC=testing,DC=samba,DC=org");
597 a = talloc_zero(ctx, struct parsed_dn);
598 a->v = &ab;
600 bb = data_blob_string_const(
601 "<GUID=fbee08fd-6f75-4bd4-af3f-e4f063a6379e>;"
602 "OU=Domain Controllers,DC=ad,DC=testing,DC=samba,DC=org");
603 b = talloc_zero(ctx, struct parsed_dn);
604 b->v = &bb;
606 res = dn_compare(ctx, ldb, a, b);
607 assert_int_equal(BINARY_EQUAL, res);
609 * DN's should not have been parsed
611 assert_null(a->dsdb_dn);
612 assert_memory_equal(ZERO_GUID, &a->guid, sizeof(struct GUID));
613 assert_null(b->dsdb_dn);
614 assert_memory_equal(ZERO_GUID, &b->guid, sizeof(struct GUID));
616 TALLOC_FREE(a);
617 TALLOC_FREE(b);
620 * differing binary DN's but equal GUID's
622 ab = data_blob_string_const(
623 "<GUID=efdc91e5-5a5a-493e-9606-166ed0c2651e>;"
624 "OU=Domain Controllers,DC=ad,DC=testing,DC=samba,DC=com");
625 a = talloc_zero(ctx, struct parsed_dn);
626 a->v = &ab;
628 bb = data_blob_string_const(
629 "<GUID=efdc91e5-5a5a-493e-9606-166ed0c2651e>;"
630 "OU=Domain Controllers,DC=ad,DC=testing,DC=samba,DC=org");
631 b = talloc_zero(ctx, struct parsed_dn);
632 b->v = &bb;
634 res = dn_compare(ctx, ldb, a, b);
635 assert_int_equal(EQUAL, res);
637 * DN's should have been parsed
639 assert_non_null(a->dsdb_dn);
640 assert_memory_not_equal(ZERO_GUID, &a->guid, sizeof(struct GUID));
641 assert_non_null(b->dsdb_dn);
642 assert_memory_not_equal(ZERO_GUID, &b->guid, sizeof(struct GUID));
644 TALLOC_FREE(a);
645 TALLOC_FREE(b);
648 * differing binary DN's but and second guid greater
650 ab = data_blob_string_const(
651 "<GUID=efdc91e5-5a5a-493e-9606-166ed0c2651d>;"
652 "OU=Domain Controllers,DC=ad,DC=testing,DC=samba,DC=com");
653 a = talloc_zero(ctx, struct parsed_dn);
654 a->v = &ab;
656 bb = data_blob_string_const(
657 "<GUID=efdc91e5-5a5a-493e-9606-166ed0c2651e>;"
658 "OU=Domain Controllers,DC=ad,DC=testing,DC=samba,DC=org");
659 b = talloc_zero(ctx, struct parsed_dn);
660 b->v = &bb;
662 res = dn_compare(ctx, ldb, a, b);
663 assert_int_equal(LESS_THAN, res);
665 * DN's should have been parsed
667 assert_non_null(a->dsdb_dn);
668 assert_memory_not_equal(ZERO_GUID, &a->guid, sizeof(struct GUID));
669 assert_non_null(b->dsdb_dn);
670 assert_memory_not_equal(ZERO_GUID, &b->guid, sizeof(struct GUID));
672 TALLOC_FREE(a);
673 TALLOC_FREE(b);
676 * differing binary DN's but and second guid less
678 ab = data_blob_string_const(
679 "<GUID=efdc91e5-5a5a-493e-9606-166ed0c2651d>;"
680 "OU=Domain Controllers,DC=ad,DC=testing,DC=samba,DC=com");
681 a = talloc_zero(ctx, struct parsed_dn);
682 a->v = &ab;
684 bb = data_blob_string_const(
685 "<GUID=efdc91e5-5a5a-493e-9606-166ed0c2651c>;"
686 "OU=Domain Controllers,DC=ad,DC=testing,DC=samba,DC=org");
687 b = talloc_zero(ctx, struct parsed_dn);
688 b->v = &bb;
690 res = dn_compare(ctx, ldb, a, b);
691 assert_int_equal(GREATER_THAN, res);
693 * DN's should have been parsed
695 assert_non_null(a->dsdb_dn);
696 assert_memory_not_equal(ZERO_GUID, &a->guid, sizeof(struct GUID));
697 assert_non_null(b->dsdb_dn);
698 assert_memory_not_equal(ZERO_GUID, &b->guid, sizeof(struct GUID));
700 TALLOC_FREE(a);
701 TALLOC_FREE(b);
703 TALLOC_FREE(ctx);
706 static void test_get_primary_group_dn(void **state)
709 struct ldb_context *ldb = NULL;
710 struct ldb_module *module = NULL;
711 const uint32_t RID = 71;
712 struct dom_sid sid;
713 const char *SID = "S-1-5-21-2470180966-3899876309-2637894779";
714 const char *DN = "OU=Things,DC=ad,DC=testing,DC=samba,DC=org";
715 const char *dn;
717 TALLOC_CTX *ctx = talloc_new(NULL);
719 ldb = ldb_init(ctx, NULL);
720 ldb_register_samba_handlers(ldb);
722 module = talloc_zero(ctx, struct ldb_module);
723 module->ldb = ldb;
726 * Pass an empty dom sid this will cause dom_sid_split_rid to fail;
727 * assign to sid.num_auths to suppress a valgrind warning.
729 sid.num_auths = 0;
730 dn = get_primary_group_dn(ctx, module, &sid, RID);
731 assert_null(dn);
734 * A valid dom sid
736 assert_true(string_to_sid(&sid, SID));
737 g_dn = DN;
738 dn = get_primary_group_dn(ctx, module, &sid, RID);
739 assert_non_null(dn);
740 assert_string_equal(DN, dn);
741 assert_int_equal(LDB_SCOPE_BASE, g_scope);
742 assert_int_equal(0, g_dsdb_flags);
743 assert_null(g_attrs);
744 assert_null(g_exp_fmt);
745 assert_string_equal
746 ("<SID=S-1-5-21-2470180966-3899876309-71>",
747 ldb_dn_get_extended_linearized(ctx, g_basedn, 1));
750 * Test dsdb search failure
752 g_status = LDB_ERR_NO_SUCH_OBJECT;
753 dn = get_primary_group_dn(ctx, module, &sid, RID);
754 assert_null(dn);
756 TALLOC_FREE(ldb);
757 TALLOC_FREE(ctx);
761 * Mocking for audit_log_json to capture the called parameters
763 const char *audit_log_json_prefix = NULL;
764 struct json_object *audit_log_json_message = NULL;
765 int audit_log_json_debug_class = 0;
766 int audit_log_json_debug_level = 0;
768 static void audit_log_json_init(void)
770 audit_log_json_prefix = NULL;
771 audit_log_json_message = NULL;
772 audit_log_json_debug_class = 0;
773 audit_log_json_debug_level = 0;
776 void audit_log_json(
777 const char* prefix,
778 struct json_object* message,
779 int debug_class,
780 int debug_level)
782 audit_log_json_prefix = prefix;
783 audit_log_json_message = message;
784 audit_log_json_debug_class = debug_class;
785 audit_log_json_debug_level = debug_level;
789 * Mocking for audit_message_send to capture the called parameters
791 struct imessaging_context *audit_message_send_msg_ctx = NULL;
792 const char *audit_message_send_server_name = NULL;
793 uint32_t audit_message_send_message_type = 0;
794 struct json_object *audit_message_send_message = NULL;
796 static void audit_message_send_init(void) {
797 audit_message_send_msg_ctx = NULL;
798 audit_message_send_server_name = NULL;
799 audit_message_send_message_type = 0;
800 audit_message_send_message = NULL;
803 static void test_audit_group_json(void **state)
805 struct ldb_context *ldb = NULL;
806 struct ldb_module *module = NULL;
807 struct ldb_request *req = NULL;
809 struct tsocket_address *ts = NULL;
811 const char *const SID = "S-1-5-21-2470180966-3899876309-2637894779";
812 const char * const SESSION = "7130cb06-2062-6a1b-409e-3514c26b1773";
814 struct GUID transaction_id;
815 const char *const TRANSACTION = "7130cb06-2062-6a1b-409e-3514c26b1773";
818 struct json_object json;
819 json_t *audit = NULL;
820 json_t *v = NULL;
821 json_t *o = NULL;
822 time_t before;
825 TALLOC_CTX *ctx = talloc_new(NULL);
827 ldb = ldb_init(ctx, NULL);
829 GUID_from_string(TRANSACTION, &transaction_id);
831 module = talloc_zero(ctx, struct ldb_module);
832 module->ldb = ldb;
834 tsocket_address_inet_from_strings(ctx, "ip", "127.0.0.1", 0, &ts);
835 ldb_set_opaque(ldb, "remoteAddress", ts);
837 add_session_data(ctx, ldb, SESSION, SID);
839 req = talloc_zero(ctx, struct ldb_request);
840 req->operation = LDB_ADD;
841 add_transaction_id(req, TRANSACTION);
843 before = time(NULL);
844 json = audit_group_json(
845 module,
846 req,
847 "the-action",
848 "the-user-name",
849 "the-group-name",
850 LDB_ERR_OPERATIONS_ERROR);
851 assert_int_equal(3, json_object_size(json.root));
853 v = json_object_get(json.root, "type");
854 assert_non_null(v);
855 assert_string_equal("groupChange", json_string_value(v));
857 v = json_object_get(json.root, "timestamp");
858 assert_non_null(v);
859 assert_true(json_is_string(v));
860 check_timestamp(before, json_string_value(v));
862 audit = json_object_get(json.root, "groupChange");
863 assert_non_null(audit);
864 assert_true(json_is_object(audit));
865 assert_int_equal(10, json_object_size(audit));
867 o = json_object_get(audit, "version");
868 assert_non_null(o);
869 check_version(o, AUDIT_MAJOR, AUDIT_MINOR);
871 v = json_object_get(audit, "statusCode");
872 assert_non_null(v);
873 assert_true(json_is_integer(v));
874 assert_int_equal(LDB_ERR_OPERATIONS_ERROR, json_integer_value(v));
876 v = json_object_get(audit, "status");
877 assert_non_null(v);
878 assert_true(json_is_string(v));
879 assert_string_equal("Operations error", json_string_value(v));
881 v = json_object_get(audit, "user");
882 assert_non_null(v);
883 assert_true(json_is_string(v));
884 assert_string_equal("the-user-name", json_string_value(v));
886 v = json_object_get(audit, "group");
887 assert_non_null(v);
888 assert_true(json_is_string(v));
889 assert_string_equal("the-group-name", json_string_value(v));
891 v = json_object_get(audit, "action");
892 assert_non_null(v);
893 assert_true(json_is_string(v));
894 assert_string_equal("the-action", json_string_value(v));
896 json_free(&json);
897 TALLOC_FREE(ctx);
900 static void setup_ldb(
901 TALLOC_CTX *ctx,
902 struct ldb_context **ldb,
903 struct ldb_module **module,
904 const char *ip,
905 const char *session,
906 const char *sid)
908 struct tsocket_address *ts = NULL;
909 struct audit_context *context = NULL;
911 *ldb = ldb_init(ctx, NULL);
912 ldb_register_samba_handlers(*ldb);
915 *module = talloc_zero(ctx, struct ldb_module);
916 (*module)->ldb = *ldb;
918 context = talloc_zero(*module, struct audit_context);
919 context->send_events = true;
920 context->msg_ctx = (struct imessaging_context *) 0x01;
922 ldb_module_set_private(*module, context);
924 tsocket_address_inet_from_strings(ctx, "ip", "127.0.0.1", 0, &ts);
925 ldb_set_opaque(*ldb, "remoteAddress", ts);
927 add_session_data(ctx, *ldb, session, sid);
931 * Test the removal of a user from a group.
933 * The new element contains one group member
934 * The old element contains two group member
936 * Expect to see the removed entry logged.
938 * This test confirms bug 13664
939 * https://bugzilla.samba.org/show_bug.cgi?id=13664
941 static void test_log_membership_changes_removed(void **state)
943 struct ldb_context *ldb = NULL;
944 struct ldb_module *module = NULL;
945 const char * const SID = "S-1-5-21-2470180966-3899876309-2637894779";
946 const char * const SESSION = "7130cb06-2062-6a1b-409e-3514c26b1773";
947 const char * const TRANSACTION = "7130cb06-2062-6a1b-409e-3514c26b1773";
948 const char * const IP = "127.0.0.1";
949 struct ldb_request *req = NULL;
950 struct ldb_message_element *new_el = NULL;
951 struct ldb_message_element *old_el = NULL;
952 int status = 0;
953 TALLOC_CTX *ctx = talloc_new(NULL);
955 setup_ldb(ctx, &ldb, &module, IP, SESSION, SID);
958 * Build the ldb_request
960 req = talloc_zero(ctx, struct ldb_request);
961 req->operation = LDB_ADD;
962 add_transaction_id(req, TRANSACTION);
965 * Populate the new elements, containing one entry.
966 * Indicating that one element has been removed
968 new_el = talloc_zero(ctx, struct ldb_message_element);
969 new_el->num_values = 1;
970 new_el->values = talloc_zero_array(ctx, DATA_BLOB, 1);
971 new_el->values[0] = data_blob_string_const(
972 "<GUID=081519b5-a709-44a0-bc95-dd4bfe809bf8>;"
973 "CN=testuser131953,CN=Users,DC=addom,DC=samba,"
974 "DC=example,DC=com");
977 * Populate the old elements, with two elements
978 * The first is the same as the one in new elements.
980 old_el = talloc_zero(ctx, struct ldb_message_element);
981 old_el->num_values = 2;
982 old_el->values = talloc_zero_array(ctx, DATA_BLOB, 2);
983 old_el->values[0] = data_blob_string_const(
984 "<GUID=cb8c2777-dcf5-419c-ab57-f645dbdf681b>;"
985 "cn=grpadttstuser01,cn=users,DC=addom,"
986 "DC=samba,DC=example,DC=com");
987 old_el->values[1] = data_blob_string_const(
988 "<GUID=081519b5-a709-44a0-bc95-dd4bfe809bf8>;"
989 "CN=testuser131953,CN=Users,DC=addom,DC=samba,"
990 "DC=example,DC=com");
993 * call log_membership_changes
995 messages_sent = 0;
996 log_membership_changes(module, req, new_el, old_el, status);
999 * Check the results
1001 assert_int_equal(1, messages_sent);
1003 check_group_change_message(
1005 "cn=grpadttstuser01,cn=users,DC=addom,DC=samba,DC=example,DC=com",
1006 "Removed");
1009 * Clean up
1011 json_free(&messages[0]);
1012 TALLOC_FREE(ctx);
1015 static void test_place_holder(void **state)
1017 audit_log_json_init();
1018 audit_log_hr_init();
1019 audit_message_send_init();
1023 * Note: to run under valgrind us:
1024 * valgrind --suppressions=test_group_audit.valgrind bin/test_group_audit
1025 * This suppresses the errors generated because the ldb_modules are not
1026 * de-registered.
1029 int main(void) {
1030 const struct CMUnitTest tests[] = {
1031 cmocka_unit_test(test_audit_group_json),
1032 cmocka_unit_test(test_place_holder),
1033 cmocka_unit_test(test_get_transaction_id),
1034 cmocka_unit_test(test_audit_group_hr),
1035 cmocka_unit_test(test_get_parsed_dns),
1036 cmocka_unit_test(test_dn_compare),
1037 cmocka_unit_test(test_get_primary_group_dn),
1038 cmocka_unit_test(test_log_membership_changes_removed),
1041 cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
1042 return cmocka_run_group_tests(tests, NULL, NULL);