s4 group_audit: Add Windows Event Id's to Group membership changes
[nivanova/samba-autobuild/.git] / source4 / dsdb / samdb / ldb_modules / tests / test_group_audit.c
1 /*
2    Unit tests for the dsdb group auditing code in group_audit.c
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 #include <stdarg.h>
21 #include <stddef.h>
22 #include <setjmp.h>
23 #include <unistd.h>
24 #include <cmocka.h>
25
26 int ldb_group_audit_log_module_init(const char *version);
27 #include "../group_audit.c"
28
29 #include "lib/ldb/include/ldb_private.h"
30 #include <regex.h>
31
32 /*
33  * Mock version of dsdb_search_one
34  */
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;
42
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)
51 {
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;
56
57         g_basedn = basedn;
58         g_scope = scope;
59         g_attrs = attrs;
60         g_dsdb_flags = dsdb_flags;
61         g_exp_fmt = exp_fmt;
62
63         return g_status;
64 }
65
66 /*
67  * Mock version of audit_log_json
68  */
69
70 #define MAX_EXPECTED_MESSAGES 16
71 static struct json_object messages[MAX_EXPECTED_MESSAGES];
72 static size_t messages_sent = 0;
73
74 void audit_message_send(
75         struct imessaging_context *msg_ctx,
76         const char *server_name,
77         uint32_t message_type,
78         struct json_object *message)
79 {
80         messages[messages_sent].root = json_deep_copy(message->root);
81         messages[messages_sent].valid = message->valid;
82         messages_sent++;
83 }
84
85 #define check_group_change_message(m, u, a, e)                                 \
86         _check_group_change_message(m, u, a, e, __FILE__, __LINE__);
87 /*
88  * declare the internal cmocka cm_print_error so that we can output messages
89  * in sub unit format
90  */
91 void cm_print_error(const char * const format, ...);
92
93 /*
94  * Validate a group change JSON audit message
95  *
96  * It should contain 3 elements.
97  * Have a type of "groupChange"
98  * Have a groupChange element
99  *
100  * The group change element should have 10 elements.
101  *
102  * There should be a user element matching the expected value
103  * There should be an action matching the expected value
104  */
105 static void _check_group_change_message(const int message,
106                                         const char *user,
107                                         const char *action,
108                                         enum event_id_type event_id,
109                                         const char *file,
110                                         const int line)
111 {
112         struct json_object json;
113         json_t *audit = NULL;
114         json_t *v = NULL;
115         const char* value;
116         int int_value;
117         int cmp;
118
119         json = messages[message];
120
121         /*
122          * Validate the root JSON element
123          * check the number of elements
124          */
125         if (json_object_size(json.root) != 3) {
126                 cm_print_error(
127                     "Unexpected number of elements in root %zu != %d\n",
128                     json_object_size(json.root),
129                     3);
130                 _fail(file, line);
131         }
132
133         /*
134          * Check the type element
135          */
136         v = json_object_get(json.root, "type");
137         if (v == NULL) {
138                 cm_print_error( "No \"type\" element\n");
139                 _fail(file, line);
140         }
141
142         value = json_string_value(v);
143         cmp = strcmp("groupChange", value);
144         if (cmp != 0) {
145                 cm_print_error(
146                     "Unexpected type \"%s\" != \"groupChange\"\n",
147                     value);
148                 _fail(file, line);
149         }
150
151
152         audit = json_object_get(json.root, "groupChange");
153         if (audit == NULL) {
154                 cm_print_error("No groupChange element\n");
155                 _fail(file, line);
156         }
157
158         /*
159          * Validate the groupChange element
160          */
161         if (json_object_size(audit) != 11) {
162                 cm_print_error("Unexpected number of elements in groupChange "
163                                "%zu != %d\n",
164                                json_object_size(audit),
165                                11);
166                 _fail(file, line);
167         }
168         /*
169          * Validate the user element
170          */
171         v = json_object_get(audit, "user");
172         if (v == NULL) {
173                 cm_print_error( "No user element\n");
174                 _fail(file, line);
175         }
176
177         value = json_string_value(v);
178         cmp = strcmp(user, value);
179         if (cmp != 0) {
180                 cm_print_error(
181                     "Unexpected user name \"%s\" != \"%s\"\n",
182                     value,
183                     user);
184                 _fail(file, line);
185         }
186         /*
187          * Validate the action element
188          */
189         v = json_object_get(audit, "action");
190         if (v == NULL) {
191                 cm_print_error( "No action element\n");
192                 _fail(file, line);
193         }
194
195         value = json_string_value(v);
196         cmp = strcmp(action, value);
197         if (cmp != 0) {
198                 print_error(
199                     "Unexpected action \"%s\" != \"%s\"\n",
200                     value,
201                     action);
202                 _fail(file, line);
203         }
204
205         /*
206          * Validate the eventId element
207          */
208         v = json_object_get(audit, "eventId");
209         if (v == NULL) {
210                 cm_print_error("No eventId element\n");
211                 _fail(file, line);
212         }
213
214         int_value = json_integer_value(v);
215         if (int_value != event_id) {
216                 cm_print_error("Unexpected eventId \"%d\" != \"%d\"\n",
217                                int_value,
218                                event_id);
219                 _fail(file, line);
220         }
221 }
222
223 #define check_timestamp(b, t)\
224         _check_timestamp(b, t, __FILE__, __LINE__);
225 /*
226  * Test helper to check ISO 8601 timestamps for validity
227  */
228 static void _check_timestamp(
229         time_t before,
230         const char *timestamp,
231         const char *file,
232         const int line)
233 {
234         int rc;
235         int usec, tz;
236         char c[2];
237         struct tm tm;
238         time_t after;
239         time_t actual;
240
241
242         after = time(NULL);
243
244         /*
245          * Convert the ISO 8601 timestamp into a time_t
246          * Note for convenience we ignore the value of the microsecond
247          * part of the time stamp.
248          */
249         rc = sscanf(
250                 timestamp,
251                 "%4d-%2d-%2dT%2d:%2d:%2d.%6d%1c%4d",
252                 &tm.tm_year,
253                 &tm.tm_mon,
254                 &tm.tm_mday,
255                 &tm.tm_hour,
256                 &tm.tm_min,
257                 &tm.tm_sec,
258                 &usec,
259                 c,
260                 &tz);
261         assert_int_equal(9, rc);
262         tm.tm_year = tm.tm_year - 1900;
263         tm.tm_mon = tm.tm_mon - 1;
264         tm.tm_isdst = -1;
265         actual = mktime(&tm);
266
267         /*
268          * The time stamp should be before <= actual <= after
269          */
270         if (difftime(actual, before) < 0) {
271                 char buffer[40];
272                 strftime(buffer,
273                          sizeof(buffer)-1,
274                          "%Y-%m-%dT%T",
275                          localtime(&before));
276                 cm_print_error(
277                     "time stamp \"%s\" is before start time \"%s\"\n",
278                     timestamp,
279                     buffer);
280                 _fail(file, line);
281         }
282         if (difftime(after, actual) < 0) {
283                 char buffer[40];
284                 strftime(buffer,
285                          sizeof(buffer)-1,
286                          "%Y-%m-%dT%T",
287                          localtime(&after));
288                 cm_print_error(
289                     "time stamp \"%s\" is after finish time \"%s\"\n",
290                     timestamp,
291                     buffer);
292                 _fail(file, line);
293         }
294 }
295
296 #define check_version(v, m, n)\
297         _check_version(v, m, n, __FILE__, __LINE__);
298 /*
299  * Test helper to validate a version object.
300  */
301 static void _check_version(
302         struct json_t *version,
303         int major,
304         int minor,
305         const char* file,
306         const int line)
307 {
308         struct json_t *v = NULL;
309         int value;
310
311         if (!json_is_object(version)) {
312                 cm_print_error("version is not a JSON object\n");
313                 _fail(file, line);
314         }
315
316         if (json_object_size(version) != 2) {
317                 cm_print_error(
318                     "Unexpected number of elements in version %zu != %d\n",
319                     json_object_size(version),
320                     2);
321                 _fail(file, line);
322         }
323
324         /*
325          * Validate the major version number element
326          */
327         v = json_object_get(version, "major");
328         if (v == NULL) {
329                 cm_print_error( "No major element\n");
330                 _fail(file, line);
331         }
332
333         value = json_integer_value(v);
334         if (value != major) {
335                 print_error(
336                     "Unexpected major version number \"%d\" != \"%d\"\n",
337                     value,
338                     major);
339                 _fail(file, line);
340         }
341
342         /*
343          * Validate the minor version number element
344          */
345         v = json_object_get(version, "minor");
346         if (v == NULL) {
347                 cm_print_error( "No minor element\n");
348                 _fail(file, line);
349         }
350
351         value = json_integer_value(v);
352         if (value != minor) {
353                 print_error(
354                     "Unexpected minor version number \"%d\" != \"%d\"\n",
355                     value,
356                     minor);
357                 _fail(file, line);
358         }
359 }
360
361 /*
362  * Test helper to insert a transaction_id into a request.
363  */
364 static void add_transaction_id(struct ldb_request *req, const char *id)
365 {
366         struct GUID guid;
367         struct dsdb_control_transaction_identifier *transaction_id = NULL;
368
369         transaction_id = talloc_zero(
370                 req,
371                 struct dsdb_control_transaction_identifier);
372         assert_non_null(transaction_id);
373         GUID_from_string(id, &guid);
374         transaction_id->transaction_guid = guid;
375         ldb_request_add_control(
376                 req,
377                 DSDB_CONTROL_TRANSACTION_IDENTIFIER_OID,
378                 false,
379                 transaction_id);
380 }
381
382 /*
383  * Test helper to add a session id and user SID
384  */
385 static void add_session_data(
386         TALLOC_CTX *ctx,
387         struct ldb_context *ldb,
388         const char *session,
389         const char *user_sid)
390 {
391         struct auth_session_info *sess = NULL;
392         struct security_token *token = NULL;
393         struct dom_sid *sid = NULL;
394         struct GUID session_id;
395         bool ok;
396
397         sess = talloc_zero(ctx, struct auth_session_info);
398         token = talloc_zero(ctx, struct security_token);
399         sid = talloc_zero(ctx, struct dom_sid);
400         ok = string_to_sid(sid, user_sid);
401         assert_true(ok);
402         token->sids = sid;
403         sess->security_token = token;
404         GUID_from_string(session, &session_id);
405         sess->unique_session_token = session_id;
406         ldb_set_opaque(ldb, DSDB_SESSION_INFO, sess);
407 }
408
409 static void test_get_transaction_id(void **state)
410 {
411         struct ldb_request *req = NULL;
412         struct GUID *guid;
413         const char * const ID = "7130cb06-2062-6a1b-409e-3514c26b1773";
414         char *guid_str = NULL;
415         struct GUID_txt_buf guid_buff;
416
417
418         TALLOC_CTX *ctx = talloc_new(NULL);
419
420
421         /*
422          * No transaction id, should return a zero guid
423          */
424         req = talloc_zero(ctx, struct ldb_request);
425         guid = get_transaction_id(req);
426         assert_null(guid);
427         TALLOC_FREE(req);
428
429         /*
430          * And now test with the transaction_id set
431          */
432         req = talloc_zero(ctx, struct ldb_request);
433         assert_non_null(req);
434         add_transaction_id(req, ID);
435
436         guid = get_transaction_id(req);
437         guid_str = GUID_buf_string(guid, &guid_buff);
438         assert_string_equal(ID, guid_str);
439         TALLOC_FREE(req);
440
441         TALLOC_FREE(ctx);
442 }
443
444 static void test_audit_group_hr(void **state)
445 {
446         struct ldb_context *ldb = NULL;
447         struct ldb_module  *module = NULL;
448         struct ldb_request *req = NULL;
449
450         struct tsocket_address *ts = NULL;
451
452         const char *const SID = "S-1-5-21-2470180966-3899876309-2637894779";
453         const char * const SESSION = "7130cb06-2062-6a1b-409e-3514c26b1773";
454
455         struct GUID transaction_id;
456         const char *const TRANSACTION = "7130cb06-2062-6a1b-409e-3514c26b1773";
457
458
459         char *line = NULL;
460         const char *rs = NULL;
461         regex_t regex;
462         int ret;
463
464
465         TALLOC_CTX *ctx = talloc_new(NULL);
466
467         ldb = ldb_init(ctx, NULL);
468
469         GUID_from_string(TRANSACTION, &transaction_id);
470
471         module = talloc_zero(ctx, struct ldb_module);
472         module->ldb = ldb;
473
474         tsocket_address_inet_from_strings(ctx, "ip", "127.0.0.1", 0, &ts);
475         ldb_set_opaque(ldb, "remoteAddress", ts);
476
477         add_session_data(ctx, ldb, SESSION, SID);
478
479         req = talloc_zero(ctx, struct ldb_request);
480         req->operation =  LDB_ADD;
481         add_transaction_id(req, TRANSACTION);
482
483         line = audit_group_human_readable(
484                 ctx,
485                 module,
486                 req,
487                 "the-action",
488                 "the-user-name",
489                 "the-group-name",
490                 LDB_ERR_OPERATIONS_ERROR);
491         assert_non_null(line);
492
493         rs =    "\\[the-action\\] at \\["
494                 "[^]]*"
495                 "\\] status \\[Operations error\\] "
496                 "Remote host \\[ipv4:127.0.0.1:0\\] "
497                 "SID \\[S-1-5-21-2470180966-3899876309-2637894779\\] "
498                 "Group \\[the-group-name\\] "
499                 "User \\[the-user-name\\]";
500
501         ret = regcomp(&regex, rs, 0);
502         assert_int_equal(0, ret);
503
504         ret = regexec(&regex, line, 0, NULL, 0);
505         assert_int_equal(0, ret);
506
507         regfree(&regex);
508         TALLOC_FREE(ctx);
509
510 }
511
512 /*
513  * test get_parsed_dns
514  * For this test we assume Valgrind or Address Sanitizer will detect any over
515  * runs. Also we don't care that the values are DN's only that the value in the
516  * element is copied to the parsed_dns.
517  */
518 static void test_get_parsed_dns(void **state)
519 {
520         struct ldb_message_element *el = NULL;
521         struct parsed_dn *dns = NULL;
522
523         TALLOC_CTX *ctx = talloc_new(NULL);
524
525         el = talloc_zero(ctx, struct ldb_message_element);
526
527         /*
528          * empty element, zero dns
529          */
530         dns = get_parsed_dns(ctx, el);
531         assert_null(dns);
532
533         /*
534          * one entry
535          */
536         el->num_values = 1;
537         el->values = talloc_zero_array(ctx, DATA_BLOB, 1);
538         el->values[0] = data_blob_string_const("The first value");
539
540         dns = get_parsed_dns(ctx, el);
541
542         assert_ptr_equal(el->values[0].data, dns[0].v->data);
543         assert_int_equal(el->values[0].length, dns[0].v->length);
544
545         TALLOC_FREE(dns);
546         TALLOC_FREE(el);
547
548
549         /*
550          * Multiple values
551          */
552         el = talloc_zero(ctx, struct ldb_message_element);
553         el->num_values = 2;
554         el->values = talloc_zero_array(ctx, DATA_BLOB, 2);
555         el->values[0] = data_blob_string_const("The first value");
556         el->values[0] = data_blob_string_const("The second value");
557
558         dns = get_parsed_dns(ctx, el);
559
560         assert_ptr_equal(el->values[0].data, dns[0].v->data);
561         assert_int_equal(el->values[0].length, dns[0].v->length);
562
563         assert_ptr_equal(el->values[1].data, dns[1].v->data);
564         assert_int_equal(el->values[1].length, dns[1].v->length);
565
566         TALLOC_FREE(ctx);
567 }
568
569 static void test_dn_compare(void **state)
570 {
571
572         struct ldb_context *ldb = NULL;
573         struct parsed_dn *a;
574         DATA_BLOB ab;
575
576         struct parsed_dn *b;
577         DATA_BLOB bb;
578
579         int res;
580
581         TALLOC_CTX *ctx = talloc_new(NULL);
582         const struct GUID *ZERO_GUID = talloc_zero(ctx, struct GUID);
583
584         ldb = ldb_init(ctx, NULL);
585         ldb_register_samba_handlers(ldb);
586
587
588         /*
589          * Identical binary DN's
590          */
591         ab = data_blob_string_const(
592                 "<GUID=fbee08fd-6f75-4bd4-af3f-e4f063a6379e>;"
593                 "OU=Domain Controllers,DC=ad,DC=testing,DC=samba,DC=org");
594         a = talloc_zero(ctx, struct parsed_dn);
595         a->v = &ab;
596
597         bb = data_blob_string_const(
598                 "<GUID=fbee08fd-6f75-4bd4-af3f-e4f063a6379e>;"
599                 "OU=Domain Controllers,DC=ad,DC=testing,DC=samba,DC=org");
600         b = talloc_zero(ctx, struct parsed_dn);
601         b->v = &bb;
602
603         res = dn_compare(ctx, ldb, a, b);
604         assert_int_equal(BINARY_EQUAL, res);
605         /*
606          * DN's should not have been parsed
607          */
608         assert_null(a->dsdb_dn);
609         assert_memory_equal(ZERO_GUID, &a->guid, sizeof(struct GUID));
610         assert_null(b->dsdb_dn);
611         assert_memory_equal(ZERO_GUID, &b->guid, sizeof(struct GUID));
612
613         TALLOC_FREE(a);
614         TALLOC_FREE(b);
615
616         /*
617          * differing binary DN's but equal GUID's
618          */
619         ab = data_blob_string_const(
620                 "<GUID=efdc91e5-5a5a-493e-9606-166ed0c2651e>;"
621                 "OU=Domain Controllers,DC=ad,DC=testing,DC=samba,DC=com");
622         a = talloc_zero(ctx, struct parsed_dn);
623         a->v = &ab;
624
625         bb = data_blob_string_const(
626                 "<GUID=efdc91e5-5a5a-493e-9606-166ed0c2651e>;"
627                 "OU=Domain Controllers,DC=ad,DC=testing,DC=samba,DC=org");
628         b = talloc_zero(ctx, struct parsed_dn);
629         b->v = &bb;
630
631         res = dn_compare(ctx, ldb, a, b);
632         assert_int_equal(EQUAL, res);
633         /*
634          * DN's should have been parsed
635          */
636         assert_non_null(a->dsdb_dn);
637         assert_memory_not_equal(ZERO_GUID, &a->guid, sizeof(struct GUID));
638         assert_non_null(b->dsdb_dn);
639         assert_memory_not_equal(ZERO_GUID, &b->guid, sizeof(struct GUID));
640
641         TALLOC_FREE(a);
642         TALLOC_FREE(b);
643
644         /*
645          * differing binary DN's but and second guid greater
646          */
647         ab = data_blob_string_const(
648                 "<GUID=efdc91e5-5a5a-493e-9606-166ed0c2651d>;"
649                 "OU=Domain Controllers,DC=ad,DC=testing,DC=samba,DC=com");
650         a = talloc_zero(ctx, struct parsed_dn);
651         a->v = &ab;
652
653         bb = data_blob_string_const(
654                 "<GUID=efdc91e5-5a5a-493e-9606-166ed0c2651e>;"
655                 "OU=Domain Controllers,DC=ad,DC=testing,DC=samba,DC=org");
656         b = talloc_zero(ctx, struct parsed_dn);
657         b->v = &bb;
658
659         res = dn_compare(ctx, ldb, a, b);
660         assert_int_equal(LESS_THAN, res);
661         /*
662          * DN's should have been parsed
663          */
664         assert_non_null(a->dsdb_dn);
665         assert_memory_not_equal(ZERO_GUID, &a->guid, sizeof(struct GUID));
666         assert_non_null(b->dsdb_dn);
667         assert_memory_not_equal(ZERO_GUID, &b->guid, sizeof(struct GUID));
668
669         TALLOC_FREE(a);
670         TALLOC_FREE(b);
671
672         /*
673          * differing binary DN's but and second guid less
674          */
675         ab = data_blob_string_const(
676                 "<GUID=efdc91e5-5a5a-493e-9606-166ed0c2651d>;"
677                 "OU=Domain Controllers,DC=ad,DC=testing,DC=samba,DC=com");
678         a = talloc_zero(ctx, struct parsed_dn);
679         a->v = &ab;
680
681         bb = data_blob_string_const(
682                 "<GUID=efdc91e5-5a5a-493e-9606-166ed0c2651c>;"
683                 "OU=Domain Controllers,DC=ad,DC=testing,DC=samba,DC=org");
684         b = talloc_zero(ctx, struct parsed_dn);
685         b->v = &bb;
686
687         res = dn_compare(ctx, ldb, a, b);
688         assert_int_equal(GREATER_THAN, res);
689         /*
690          * DN's should have been parsed
691          */
692         assert_non_null(a->dsdb_dn);
693         assert_memory_not_equal(ZERO_GUID, &a->guid, sizeof(struct GUID));
694         assert_non_null(b->dsdb_dn);
695         assert_memory_not_equal(ZERO_GUID, &b->guid, sizeof(struct GUID));
696
697         TALLOC_FREE(a);
698         TALLOC_FREE(b);
699
700         TALLOC_FREE(ctx);
701 }
702
703 static void test_get_primary_group_dn(void **state)
704 {
705
706         struct ldb_context *ldb = NULL;
707         struct ldb_module *module = NULL;
708         const uint32_t RID = 71;
709         struct dom_sid sid;
710         const char *SID = "S-1-5-21-2470180966-3899876309-2637894779";
711         const char *DN = "OU=Things,DC=ad,DC=testing,DC=samba,DC=org";
712         const char *dn;
713
714         TALLOC_CTX *ctx = talloc_new(NULL);
715
716         ldb = ldb_init(ctx, NULL);
717         ldb_register_samba_handlers(ldb);
718
719         module = talloc_zero(ctx, struct ldb_module);
720         module->ldb = ldb;
721
722         /*
723          * Pass an empty dom sid this will cause dom_sid_split_rid to fail;
724          * assign to sid.num_auths to suppress a valgrind warning.
725          */
726         sid.num_auths = 0;
727         dn = get_primary_group_dn(ctx, module, &sid, RID);
728         assert_null(dn);
729
730         /*
731          * A valid dom sid
732          */
733         assert_true(string_to_sid(&sid, SID));
734         g_dn = DN;
735         dn = get_primary_group_dn(ctx, module, &sid, RID);
736         assert_non_null(dn);
737         assert_string_equal(DN, dn);
738         assert_int_equal(LDB_SCOPE_BASE, g_scope);
739         assert_int_equal(0, g_dsdb_flags);
740         assert_null(g_attrs);
741         assert_null(g_exp_fmt);
742         assert_string_equal
743                 ("<SID=S-1-5-21-2470180966-3899876309-71>",
744                 ldb_dn_get_extended_linearized(ctx, g_basedn, 1));
745
746         /*
747          * Test dsdb search failure
748          */
749         g_status = LDB_ERR_NO_SUCH_OBJECT;
750         dn = get_primary_group_dn(ctx, module, &sid, RID);
751         assert_null(dn);
752
753         TALLOC_FREE(ldb);
754         TALLOC_FREE(ctx);
755 }
756
757 static void test_audit_group_json(void **state)
758 {
759         struct ldb_context *ldb = NULL;
760         struct ldb_module  *module = NULL;
761         struct ldb_request *req = NULL;
762
763         struct tsocket_address *ts = NULL;
764
765         const char *const SID = "S-1-5-21-2470180966-3899876309-2637894779";
766         const char * const SESSION = "7130cb06-2062-6a1b-409e-3514c26b1773";
767
768         struct GUID transaction_id;
769         const char *const TRANSACTION = "7130cb06-2062-6a1b-409e-3514c26b1773";
770
771         enum event_id_type event_id = EVT_ID_USER_ADDED_TO_GLOBAL_SEC_GROUP;
772
773         struct json_object json;
774         json_t *audit = NULL;
775         json_t *v = NULL;
776         json_t *o = NULL;
777         time_t before;
778
779
780         TALLOC_CTX *ctx = talloc_new(NULL);
781
782         ldb = ldb_init(ctx, NULL);
783
784         GUID_from_string(TRANSACTION, &transaction_id);
785
786         module = talloc_zero(ctx, struct ldb_module);
787         module->ldb = ldb;
788
789         tsocket_address_inet_from_strings(ctx, "ip", "127.0.0.1", 0, &ts);
790         ldb_set_opaque(ldb, "remoteAddress", ts);
791
792         add_session_data(ctx, ldb, SESSION, SID);
793
794         req = talloc_zero(ctx, struct ldb_request);
795         req->operation =  LDB_ADD;
796         add_transaction_id(req, TRANSACTION);
797
798         before = time(NULL);
799         json = audit_group_json(module,
800                                 req,
801                                 "the-action",
802                                 "the-user-name",
803                                 "the-group-name",
804                                 event_id,
805                                 LDB_ERR_OPERATIONS_ERROR);
806         assert_int_equal(3, json_object_size(json.root));
807
808         v = json_object_get(json.root, "type");
809         assert_non_null(v);
810         assert_string_equal("groupChange", json_string_value(v));
811
812         v = json_object_get(json.root, "timestamp");
813         assert_non_null(v);
814         assert_true(json_is_string(v));
815         check_timestamp(before, json_string_value(v));
816
817         audit = json_object_get(json.root, "groupChange");
818         assert_non_null(audit);
819         assert_true(json_is_object(audit));
820         assert_int_equal(11, json_object_size(audit));
821
822         o = json_object_get(audit, "version");
823         assert_non_null(o);
824         check_version(o, AUDIT_MAJOR, AUDIT_MINOR);
825
826         v = json_object_get(audit, "eventId");
827         assert_non_null(v);
828         assert_true(json_is_integer(v));
829         assert_int_equal(EVT_ID_USER_ADDED_TO_GLOBAL_SEC_GROUP,
830                          json_integer_value(v));
831
832         v = json_object_get(audit, "statusCode");
833         assert_non_null(v);
834         assert_true(json_is_integer(v));
835         assert_int_equal(LDB_ERR_OPERATIONS_ERROR, json_integer_value(v));
836
837         v = json_object_get(audit, "status");
838         assert_non_null(v);
839         assert_true(json_is_string(v));
840         assert_string_equal("Operations error", json_string_value(v));
841
842         v = json_object_get(audit, "user");
843         assert_non_null(v);
844         assert_true(json_is_string(v));
845         assert_string_equal("the-user-name", json_string_value(v));
846
847         v = json_object_get(audit, "group");
848         assert_non_null(v);
849         assert_true(json_is_string(v));
850         assert_string_equal("the-group-name", json_string_value(v));
851
852         v = json_object_get(audit, "action");
853         assert_non_null(v);
854         assert_true(json_is_string(v));
855         assert_string_equal("the-action", json_string_value(v));
856
857         json_free(&json);
858         TALLOC_FREE(ctx);
859 }
860
861 static void setup_ldb(
862         TALLOC_CTX *ctx,
863         struct ldb_context **ldb,
864         struct ldb_module **module,
865         const char *ip,
866         const char *session,
867         const char *sid)
868 {
869         struct tsocket_address *ts = NULL;
870         struct audit_context *context = NULL;
871
872         *ldb = ldb_init(ctx, NULL);
873         ldb_register_samba_handlers(*ldb);
874
875
876         *module = talloc_zero(ctx, struct ldb_module);
877         (*module)->ldb = *ldb;
878
879         context = talloc_zero(*module, struct audit_context);
880         context->send_events = true;
881         context->msg_ctx = (struct imessaging_context *) 0x01;
882
883         ldb_module_set_private(*module, context);
884
885         tsocket_address_inet_from_strings(ctx, "ip", "127.0.0.1", 0, &ts);
886         ldb_set_opaque(*ldb, "remoteAddress", ts);
887
888         add_session_data(ctx, *ldb, session, sid);
889 }
890
891 /*
892  * Test the removal of a user from a group.
893  *
894  * The new element contains one group member
895  * The old element contains two group member
896  *
897  * Expect to see the removed entry logged.
898  *
899  * This test confirms bug 13664
900  * https://bugzilla.samba.org/show_bug.cgi?id=13664
901  */
902 static void test_log_membership_changes_removed(void **state)
903 {
904         struct ldb_context *ldb = NULL;
905         struct ldb_module  *module = NULL;
906         const char * const SID = "S-1-5-21-2470180966-3899876309-2637894779";
907         const char * const SESSION = "7130cb06-2062-6a1b-409e-3514c26b1773";
908         const char * const TRANSACTION = "7130cb06-2062-6a1b-409e-3514c26b1773";
909         const char * const IP = "127.0.0.1";
910         struct ldb_request *req = NULL;
911         struct ldb_message_element *new_el = NULL;
912         struct ldb_message_element *old_el = NULL;
913         uint32_t group_type = GTYPE_SECURITY_GLOBAL_GROUP;
914         int status = 0;
915         TALLOC_CTX *ctx = talloc_new(NULL);
916
917         setup_ldb(ctx, &ldb, &module, IP, SESSION, SID);
918
919         /*
920          * Build the ldb_request
921          */
922         req = talloc_zero(ctx, struct ldb_request);
923         req->operation =  LDB_ADD;
924         add_transaction_id(req, TRANSACTION);
925
926         /*
927          * Populate the new elements, containing one entry.
928          * Indicating that one element has been removed
929          */
930         new_el = talloc_zero(ctx, struct ldb_message_element);
931         new_el->num_values = 1;
932         new_el->values = talloc_zero_array(ctx, DATA_BLOB, 1);
933         new_el->values[0] = data_blob_string_const(
934                 "<GUID=081519b5-a709-44a0-bc95-dd4bfe809bf8>;"
935                 "CN=testuser131953,CN=Users,DC=addom,DC=samba,"
936                 "DC=example,DC=com");
937
938         /*
939          * Populate the old elements, with two elements
940          * The first is the same as the one in new elements.
941          */
942         old_el = talloc_zero(ctx, struct ldb_message_element);
943         old_el->num_values = 2;
944         old_el->values = talloc_zero_array(ctx, DATA_BLOB, 2);
945         old_el->values[0] = data_blob_string_const(
946                 "<GUID=cb8c2777-dcf5-419c-ab57-f645dbdf681b>;"
947                 "cn=grpadttstuser01,cn=users,DC=addom,"
948                 "DC=samba,DC=example,DC=com");
949         old_el->values[1] = data_blob_string_const(
950                 "<GUID=081519b5-a709-44a0-bc95-dd4bfe809bf8>;"
951                 "CN=testuser131953,CN=Users,DC=addom,DC=samba,"
952                 "DC=example,DC=com");
953
954         /*
955          * call log_membership_changes
956          */
957         messages_sent = 0;
958         log_membership_changes(module, req, new_el, old_el, group_type, status);
959
960         /*
961          * Check the results
962          */
963         assert_int_equal(1, messages_sent);
964
965         check_group_change_message(
966             0,
967             "cn=grpadttstuser01,cn=users,DC=addom,DC=samba,DC=example,DC=com",
968             "Removed",
969             EVT_ID_USER_REMOVED_FROM_GLOBAL_SEC_GROUP);
970
971         /*
972          * Clean up
973          */
974         json_free(&messages[0]);
975         TALLOC_FREE(ctx);
976 }
977
978 /* test log_membership_changes
979  *
980  * old contains 2 user dn's
981  * new contains 0 user dn's
982  *
983  * Expect to see both dn's logged as deleted.
984  */
985 static void test_log_membership_changes_remove_all(void **state)
986 {
987         struct ldb_context *ldb = NULL;
988         struct ldb_module  *module = NULL;
989         const char * const SID = "S-1-5-21-2470180966-3899876309-2637894779";
990         const char * const SESSION = "7130cb06-2062-6a1b-409e-3514c26b1773";
991         const char * const TRANSACTION = "7130cb06-2062-6a1b-409e-3514c26b1773";
992         const char * const IP = "127.0.0.1";
993         struct ldb_request *req = NULL;
994         struct ldb_message_element *new_el = NULL;
995         struct ldb_message_element *old_el = NULL;
996         int status = 0;
997         uint32_t group_type = GTYPE_SECURITY_BUILTIN_LOCAL_GROUP;
998         TALLOC_CTX *ctx = talloc_new(NULL);
999
1000         setup_ldb(ctx, &ldb, &module, IP, SESSION, SID);
1001
1002         /*
1003          * Build the ldb_request
1004          */
1005         req = talloc_zero(ctx, struct ldb_request);
1006         req->operation =  LDB_ADD;
1007         add_transaction_id(req, TRANSACTION);
1008
1009         /*
1010          * Populate the new elements, containing no entries.
1011          * Indicating that all elements have been removed
1012          */
1013         new_el = talloc_zero(ctx, struct ldb_message_element);
1014         new_el->num_values = 0;
1015         new_el->values = NULL;
1016
1017         /*
1018          * Populate the old elements, with two elements
1019          */
1020         old_el = talloc_zero(ctx, struct ldb_message_element);
1021         old_el->num_values = 2;
1022         old_el->values = talloc_zero_array(ctx, DATA_BLOB, 2);
1023         old_el->values[0] = data_blob_string_const(
1024                 "<GUID=cb8c2777-dcf5-419c-ab57-f645dbdf681b>;"
1025                 "cn=grpadttstuser01,cn=users,DC=addom,"
1026                 "DC=samba,DC=example,DC=com");
1027         old_el->values[1] = data_blob_string_const(
1028                 "<GUID=081519b5-a709-44a0-bc95-dd4bfe809bf8>;"
1029                 "CN=testuser131953,CN=Users,DC=addom,DC=samba,"
1030                 "DC=example,DC=com");
1031
1032         /*
1033          * call log_membership_changes
1034          */
1035         messages_sent = 0;
1036         log_membership_changes(module, req, new_el, old_el, group_type, status);
1037
1038         /*
1039          * Check the results
1040          */
1041         assert_int_equal(2, messages_sent);
1042
1043         check_group_change_message(
1044             0,
1045             "cn=grpadttstuser01,cn=users,DC=addom,DC=samba,DC=example,DC=com",
1046             "Removed",
1047             EVT_ID_USER_REMOVED_FROM_LOCAL_SEC_GROUP);
1048
1049         check_group_change_message(
1050             1,
1051             "CN=testuser131953,CN=Users,DC=addom,DC=samba,DC=example,DC=com",
1052             "Removed",
1053             EVT_ID_USER_REMOVED_FROM_LOCAL_SEC_GROUP);
1054
1055         /*
1056          * Clean up
1057          */
1058         json_free(&messages[0]);
1059         json_free(&messages[1]);
1060         TALLOC_FREE(ctx);
1061 }
1062
1063 /* test log_membership_changes
1064  *
1065  * Add an entry.
1066  *
1067  * Old entries contains a single user dn
1068  * New entries contains 2 user dn's, one matching the dn in old entries
1069  *
1070  * Should see a single new entry logged.
1071  */
1072 static void test_log_membership_changes_added(void **state)
1073 {
1074         struct ldb_context *ldb = NULL;
1075         struct ldb_module  *module = NULL;
1076         const char * const SID = "S-1-5-21-2470180966-3899876309-2637894779";
1077         const char * const SESSION = "7130cb06-2062-6a1b-409e-3514c26b1773";
1078         const char * const TRANSACTION = "7130cb06-2062-6a1b-409e-3514c26b1773";
1079         const char * const IP = "127.0.0.1";
1080         struct ldb_request *req = NULL;
1081         struct ldb_message_element *new_el = NULL;
1082         struct ldb_message_element *old_el = NULL;
1083         uint32_t group_type = GTYPE_SECURITY_DOMAIN_LOCAL_GROUP;
1084         int status = 0;
1085         TALLOC_CTX *ctx = talloc_new(NULL);
1086
1087         setup_ldb(ctx, &ldb, &module, IP, SESSION, SID);
1088
1089         /*
1090          * Build the ldb_request
1091          */
1092         req = talloc_zero(ctx, struct ldb_request);
1093         req->operation =  LDB_ADD;
1094         add_transaction_id(req, TRANSACTION);
1095
1096         /*
1097          * Populate the old elements adding a single entry.
1098          */
1099         old_el = talloc_zero(ctx, struct ldb_message_element);
1100         old_el->num_values = 1;
1101         old_el->values = talloc_zero_array(ctx, DATA_BLOB, 1);
1102         old_el->values[0] = data_blob_string_const(
1103                 "<GUID=081519b5-a709-44a0-bc95-dd4bfe809bf8>;"
1104                 "CN=testuser131953,CN=Users,DC=addom,DC=samba,"
1105                 "DC=example,DC=com");
1106
1107         /*
1108          * Populate the new elements adding two entries. One matches the entry
1109          * in old elements. We expect to see the other element logged as Added
1110          */
1111         new_el = talloc_zero(ctx, struct ldb_message_element);
1112         new_el->num_values = 2;
1113         new_el->values = talloc_zero_array(ctx, DATA_BLOB, 2);
1114         new_el->values[0] = data_blob_string_const(
1115                 "<GUID=cb8c2777-dcf5-419c-ab57-f645dbdf681b>;"
1116                 "cn=grpadttstuser01,cn=users,DC=addom,"
1117                 "DC=samba,DC=example,DC=com");
1118         new_el->values[1] = data_blob_string_const(
1119                 "<GUID=081519b5-a709-44a0-bc95-dd4bfe809bf8>;"
1120                 "CN=testuser131953,CN=Users,DC=addom,DC=samba,"
1121                 "DC=example,DC=com");
1122
1123         /*
1124          * call log_membership_changes
1125          */
1126         messages_sent = 0;
1127         log_membership_changes(module, req, new_el, old_el, group_type, status);
1128
1129         /*
1130          * Check the results
1131          */
1132         assert_int_equal(1, messages_sent);
1133
1134         check_group_change_message(
1135             0,
1136             "cn=grpadttstuser01,cn=users,DC=addom,DC=samba,DC=example,DC=com",
1137             "Added",
1138             EVT_ID_USER_ADDED_TO_LOCAL_SEC_GROUP);
1139
1140         /*
1141          * Clean up
1142          */
1143         json_free(&messages[0]);
1144         TALLOC_FREE(ctx);
1145 }
1146
1147 /*
1148  * test log_membership_changes.
1149  *
1150  * Old entries is empty
1151  * New entries contains 2 user dn's
1152  *
1153  * Expect to see log messages for two added users
1154  */
1155 static void test_log_membership_changes_add_to_empty(void **state)
1156 {
1157         struct ldb_context *ldb = NULL;
1158         struct ldb_module  *module = NULL;
1159         const char * const SID = "S-1-5-21-2470180966-3899876309-2637894779";
1160         const char * const SESSION = "7130cb06-2062-6a1b-409e-3514c26b1773";
1161         const char * const TRANSACTION = "7130cb06-2062-6a1b-409e-3514c26b1773";
1162         const char * const IP = "127.0.0.1";
1163         struct ldb_request *req = NULL;
1164         struct ldb_message_element *new_el = NULL;
1165         struct ldb_message_element *old_el = NULL;
1166         uint32_t group_type = GTYPE_SECURITY_UNIVERSAL_GROUP;
1167         int status = 0;
1168         TALLOC_CTX *ctx = talloc_new(NULL);
1169
1170         /*
1171          * Set up the ldb and module structures
1172          */
1173         setup_ldb(ctx, &ldb, &module, IP, SESSION, SID);
1174
1175         /*
1176          * Build the request structure
1177          */
1178         req = talloc_zero(ctx, struct ldb_request);
1179         req->operation =  LDB_ADD;
1180         add_transaction_id(req, TRANSACTION);
1181
1182         /*
1183          * Build the element containing the old values
1184          */
1185         old_el = talloc_zero(ctx, struct ldb_message_element);
1186         old_el->num_values = 0;
1187         old_el->values = NULL;
1188
1189         /*
1190          * Build the element containing the new values
1191          */
1192         new_el = talloc_zero(ctx, struct ldb_message_element);
1193         new_el->num_values = 2;
1194         new_el->values = talloc_zero_array(ctx, DATA_BLOB, 2);
1195         new_el->values[0] = data_blob_string_const(
1196                 "<GUID=cb8c2777-dcf5-419c-ab57-f645dbdf681b>;"
1197                 "cn=grpadttstuser01,cn=users,DC=addom,"
1198                 "DC=samba,DC=example,DC=com");
1199         new_el->values[1] = data_blob_string_const(
1200                 "<GUID=081519b5-a709-44a0-bc95-dd4bfe809bf8>;"
1201                 "CN=testuser131953,CN=Users,DC=addom,DC=samba,"
1202                 "DC=example,DC=com");
1203
1204         /*
1205          * Run log membership changes
1206          */
1207         messages_sent = 0;
1208         log_membership_changes(module, req, new_el, old_el, group_type, status);
1209         assert_int_equal(2, messages_sent);
1210
1211         check_group_change_message(
1212             0,
1213             "cn=grpadttstuser01,cn=users,DC=addom,DC=samba,DC=example,DC=com",
1214             "Added",
1215             EVT_ID_USER_ADDED_TO_UNIVERSAL_SEC_GROUP);
1216
1217         check_group_change_message(
1218             1,
1219             "CN=testuser131953,CN=Users,DC=addom,DC=samba,DC=example,DC=com",
1220             "Added",
1221             EVT_ID_USER_ADDED_TO_UNIVERSAL_SEC_GROUP);
1222
1223         json_free(&messages[0]);
1224         json_free(&messages[1]);
1225         TALLOC_FREE(ctx);
1226 }
1227
1228 /* test log_membership_changes
1229  *
1230  * Test Replication Meta Data flag handling.
1231  *
1232  * 4 entries in old and new entries with their RMD_FLAGS set as below:
1233  *    old   new
1234  * 1)  0     0    Not logged
1235  * 2)  1     1    Both deleted, no change not logged
1236  * 3)  0     1    New tagged as deleted, log as deleted
1237  * 4)  1     0    Has been undeleted, log as an add
1238  *
1239  * Should see a single new entry logged.
1240  */
1241 static void test_log_membership_changes_rmd_flags(void **state)
1242 {
1243         struct ldb_context *ldb = NULL;
1244         struct ldb_module  *module = NULL;
1245         const char * const SID = "S-1-5-21-2470180966-3899876309-2637894779";
1246         const char * const SESSION = "7130cb06-2062-6a1b-409e-3514c26b1773";
1247         const char * const TRANSACTION = "7130cb06-2062-6a1b-409e-3514c26b1773";
1248         const char * const IP = "127.0.0.1";
1249         struct ldb_request *req = NULL;
1250         struct ldb_message_element *new_el = NULL;
1251         struct ldb_message_element *old_el = NULL;
1252         uint32_t group_type = GTYPE_SECURITY_GLOBAL_GROUP;
1253         int status = 0;
1254         TALLOC_CTX *ctx = talloc_new(NULL);
1255
1256         setup_ldb(ctx, &ldb, &module, IP, SESSION, SID);
1257
1258         /*
1259          * Build the ldb_request
1260          */
1261         req = talloc_zero(ctx, struct ldb_request);
1262         req->operation =  LDB_ADD;
1263         add_transaction_id(req, TRANSACTION);
1264
1265         /*
1266          * Populate the old elements.
1267          */
1268         old_el = talloc_zero(ctx, struct ldb_message_element);
1269         old_el->num_values = 4;
1270         old_el->values = talloc_zero_array(ctx, DATA_BLOB, 4);
1271         old_el->values[0] = data_blob_string_const(
1272                 "<GUID=cb8c2777-dcf5-419c-ab57-f645dbdf681b>;"
1273                 "<RMD_FLAGS=0>;"
1274                 "cn=grpadttstuser01,cn=users,DC=addom,"
1275                 "DC=samba,DC=example,DC=com");
1276         old_el->values[1] = data_blob_string_const(
1277                 "<GUID=cb8c2777-dcf5-419c-ab57-f645dbdf681c>;"
1278                 "<RMD_FLAGS=1>;"
1279                 "cn=grpadttstuser02,cn=users,DC=addom,"
1280                 "DC=samba,DC=example,DC=com");
1281         old_el->values[2] = data_blob_string_const(
1282                 "<GUID=cb8c2777-dcf5-419c-ab57-f645dbdf681d>;"
1283                 "<RMD_FLAGS=0>;"
1284                 "cn=grpadttstuser03,cn=users,DC=addom,"
1285                 "DC=samba,DC=example,DC=com");
1286         old_el->values[3] = data_blob_string_const(
1287                 "<GUID=cb8c2777-dcf5-419c-ab57-f645dbdf681e>;"
1288                 "<RMD_FLAGS=1>;"
1289                 "cn=grpadttstuser04,cn=users,DC=addom,"
1290                 "DC=samba,DC=example,DC=com");
1291
1292         /*
1293          * Populate the new elements.
1294          */
1295         new_el = talloc_zero(ctx, struct ldb_message_element);
1296         new_el->num_values = 4;
1297         new_el->values = talloc_zero_array(ctx, DATA_BLOB, 4);
1298         new_el->values[0] = data_blob_string_const(
1299                 "<GUID=cb8c2777-dcf5-419c-ab57-f645dbdf681b>;"
1300                 "<RMD_FLAGS=0>;"
1301                 "cn=grpadttstuser01,cn=users,DC=addom,"
1302                 "DC=samba,DC=example,DC=com");
1303         new_el->values[1] = data_blob_string_const(
1304                 "<GUID=cb8c2777-dcf5-419c-ab57-f645dbdf681c>;"
1305                 "<RMD_FLAGS=1>;"
1306                 "cn=grpadttstuser02,cn=users,DC=addom,"
1307                 "DC=samba,DC=example,DC=com");
1308         new_el->values[2] = data_blob_string_const(
1309                 "<GUID=cb8c2777-dcf5-419c-ab57-f645dbdf681d>;"
1310                 "<RMD_FLAGS=1>;"
1311                 "cn=grpadttstuser03,cn=users,DC=addom,"
1312                 "DC=samba,DC=example,DC=com");
1313         new_el->values[3] = data_blob_string_const(
1314                 "<GUID=cb8c2777-dcf5-419c-ab57-f645dbdf681e>;"
1315                 "<RMD_FLAGS=0>;"
1316                 "cn=grpadttstuser04,cn=users,DC=addom,"
1317                 "DC=samba,DC=example,DC=com");
1318
1319         /*
1320          * call log_membership_changes
1321          */
1322         messages_sent = 0;
1323         log_membership_changes(module, req, new_el, old_el, group_type, status);
1324
1325         /*
1326          * Check the results
1327          */
1328         assert_int_equal(2, messages_sent);
1329
1330         check_group_change_message(
1331             0,
1332             "cn=grpadttstuser03,cn=users,DC=addom,DC=samba,DC=example,DC=com",
1333             "Removed",
1334             EVT_ID_USER_REMOVED_FROM_GLOBAL_SEC_GROUP);
1335         check_group_change_message(
1336             1,
1337             "cn=grpadttstuser04,cn=users,DC=addom,DC=samba,DC=example,DC=com",
1338             "Added",
1339             EVT_ID_USER_ADDED_TO_GLOBAL_SEC_GROUP);
1340
1341         /*
1342          * Clean up
1343          */
1344         json_free(&messages[0]);
1345         json_free(&messages[1]);
1346         TALLOC_FREE(ctx);
1347 }
1348
1349 static void test_get_add_member_event(void **state)
1350 {
1351         assert_int_equal(
1352             EVT_ID_USER_ADDED_TO_LOCAL_SEC_GROUP,
1353             get_add_member_event(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP));
1354
1355         assert_int_equal(EVT_ID_USER_ADDED_TO_GLOBAL_SEC_GROUP,
1356                          get_add_member_event(GTYPE_SECURITY_GLOBAL_GROUP));
1357
1358         assert_int_equal(
1359             EVT_ID_USER_ADDED_TO_LOCAL_SEC_GROUP,
1360             get_add_member_event(GTYPE_SECURITY_DOMAIN_LOCAL_GROUP));
1361
1362         assert_int_equal(EVT_ID_USER_ADDED_TO_UNIVERSAL_SEC_GROUP,
1363                          get_add_member_event(GTYPE_SECURITY_UNIVERSAL_GROUP));
1364
1365         assert_int_equal(EVT_ID_USER_ADDED_TO_GLOBAL_GROUP,
1366                          get_add_member_event(GTYPE_DISTRIBUTION_GLOBAL_GROUP));
1367
1368         assert_int_equal(
1369             EVT_ID_USER_ADDED_TO_LOCAL_GROUP,
1370             get_add_member_event(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP));
1371
1372         assert_int_equal(
1373             EVT_ID_USER_ADDED_TO_UNIVERSAL_GROUP,
1374             get_add_member_event(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP));
1375
1376         assert_int_equal(EVT_ID_NONE, get_add_member_event(0));
1377
1378         assert_int_equal(EVT_ID_NONE, get_add_member_event(UINT32_MAX));
1379 }
1380
1381 static void test_get_remove_member_event(void **state)
1382 {
1383         assert_int_equal(
1384             EVT_ID_USER_REMOVED_FROM_LOCAL_SEC_GROUP,
1385             get_remove_member_event(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP));
1386
1387         assert_int_equal(EVT_ID_USER_REMOVED_FROM_GLOBAL_SEC_GROUP,
1388                          get_remove_member_event(GTYPE_SECURITY_GLOBAL_GROUP));
1389
1390         assert_int_equal(
1391             EVT_ID_USER_REMOVED_FROM_LOCAL_SEC_GROUP,
1392             get_remove_member_event(GTYPE_SECURITY_DOMAIN_LOCAL_GROUP));
1393
1394         assert_int_equal(
1395             EVT_ID_USER_REMOVED_FROM_UNIVERSAL_SEC_GROUP,
1396             get_remove_member_event(GTYPE_SECURITY_UNIVERSAL_GROUP));
1397
1398         assert_int_equal(
1399             EVT_ID_USER_REMOVED_FROM_GLOBAL_GROUP,
1400             get_remove_member_event(GTYPE_DISTRIBUTION_GLOBAL_GROUP));
1401
1402         assert_int_equal(
1403             EVT_ID_USER_REMOVED_FROM_LOCAL_GROUP,
1404             get_remove_member_event(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP));
1405
1406         assert_int_equal(
1407             EVT_ID_USER_REMOVED_FROM_UNIVERSAL_GROUP,
1408             get_remove_member_event(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP));
1409
1410         assert_int_equal(EVT_ID_NONE, get_remove_member_event(0));
1411
1412         assert_int_equal(EVT_ID_NONE, get_remove_member_event(UINT32_MAX));
1413 }
1414 /*
1415  * Note: to run under valgrind us:
1416  *       valgrind --suppressions=test_group_audit.valgrind bin/test_group_audit
1417  *       This suppresses the errors generated because the ldb_modules are not
1418  *       de-registered.
1419  *
1420  */
1421 int main(void) {
1422         const struct CMUnitTest tests[] = {
1423             cmocka_unit_test(test_audit_group_json),
1424             cmocka_unit_test(test_get_transaction_id),
1425             cmocka_unit_test(test_audit_group_hr),
1426             cmocka_unit_test(test_get_parsed_dns),
1427             cmocka_unit_test(test_dn_compare),
1428             cmocka_unit_test(test_get_primary_group_dn),
1429             cmocka_unit_test(test_log_membership_changes_removed),
1430             cmocka_unit_test(test_log_membership_changes_remove_all),
1431             cmocka_unit_test(test_log_membership_changes_added),
1432             cmocka_unit_test(test_log_membership_changes_add_to_empty),
1433             cmocka_unit_test(test_log_membership_changes_rmd_flags),
1434             cmocka_unit_test(test_get_add_member_event),
1435             cmocka_unit_test(test_get_remove_member_event),
1436         };
1437
1438         cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
1439         return cmocka_run_group_tests(tests, NULL, NULL);
1440 }