json: Add unit tests for error handling
authorGary Lockyer <gary@catalyst.net.nz>
Thu, 12 Jul 2018 21:15:34 +0000 (09:15 +1200)
committerGary Lockyer <gary@samba.org>
Wed, 25 Jul 2018 04:29:50 +0000 (06:29 +0200)
Add cmocka unit tests to exercise the error handling in the JSON
routines.

Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
Reviewed-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
lib/audit_logging/tests/audit_logging_error_test.c [new file with mode: 0644]
lib/audit_logging/wscript_build
source4/dsdb/samdb/ldb_modules/tests/test_audit_log_errors.c [new file with mode: 0644]
source4/dsdb/samdb/ldb_modules/tests/test_group_audit_errors.c [new file with mode: 0644]
source4/dsdb/samdb/ldb_modules/wscript_build_server
source4/selftest/tests.py

diff --git a/lib/audit_logging/tests/audit_logging_error_test.c b/lib/audit_logging/tests/audit_logging_error_test.c
new file mode 100644 (file)
index 0000000..1c0929a
--- /dev/null
@@ -0,0 +1,869 @@
+/*
+ * Unit tests for the audit_logging library.
+ *
+ *  Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ *
+ */
+
+/*
+ * Unit tests for lib/audit_logging/audit_logging.c
+ *
+ * These tests exercise the error handling code and mock the jannson functions
+ * to trigger errors.
+ *
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "includes.h"
+
+#include "librpc/ndr/libndr.h"
+#include "lib/tsocket/tsocket.h"
+#include "libcli/security/dom_sid.h"
+#include "lib/messaging/messaging.h"
+#include "auth/common_auth.h"
+
+#include "lib/audit_logging/audit_logging.h"
+
+const int JANNASON_FAILURE = -1;
+const int CALL_ORIG = -2;
+
+/*
+ * cmocka wrappers for json_object
+ */
+json_t *__wrap_json_object(void);
+json_t *__real_json_object(void);
+json_t *__wrap_json_object(void)
+{
+
+       bool fail = (bool)mock();
+       if (fail) {
+               return NULL;
+       }
+       return __real_json_object();
+}
+
+/*
+ * cmocka wrappers for json_array
+ */
+json_t *__wrap_json_array(void);
+json_t *__real_json_array(void);
+json_t *__wrap_json_array(void)
+{
+
+       bool fail = (bool)mock();
+       if (fail) {
+               return NULL;
+       }
+       return __real_json_array();
+}
+
+/*
+ * cmoka wrappers for json_integer
+ */
+json_t *__wrap_json_integer(json_int_t value);
+json_t *__real_json_integer(json_int_t value);
+json_t *__wrap_json_integer(json_int_t value)
+{
+
+       bool fail = (bool)mock();
+       if (fail) {
+               return NULL;
+       }
+       return __real_json_integer(value);
+}
+
+/*
+ * cmocka wrappers for json_string
+ */
+json_t *__wrap_json_string(const char *value);
+json_t *__real_json_string(const char *value);
+json_t *__wrap_json_string(const char *value)
+{
+
+       bool fail = (bool)mock();
+       if (fail) {
+               return NULL;
+       }
+       return __real_json_string(value);
+}
+
+/*
+ * cmocka wrappers for json_dumps
+ */
+char *__wrap_json_dumps(const json_t *json, size_t flags);
+char *__real_json_dumps(const json_t *json, size_t flags);
+char *__wrap_json_dumps(const json_t *json, size_t flags)
+{
+
+       bool fail = (bool)mock();
+       if (fail) {
+               return NULL;
+       }
+       return __real_json_dumps(json, flags);
+}
+
+/*
+ * cmocka wrappers for json_object_set_new
+ */
+int __wrap_json_object_set_new(json_t *object, const char *key, json_t *value);
+int __real_json_object_set_new(json_t *object, const char *key, json_t *value);
+int __wrap_json_object_set_new(json_t *object, const char *key, json_t *value)
+{
+       int rc = (int)mock();
+       if (rc != CALL_ORIG) {
+               return rc;
+       }
+       return __real_json_object_set_new(object, key, value);
+}
+
+/*
+ * cmocka wrappers for json_array_append_new
+ */
+int __wrap_json_array_append_new(json_t *object,
+                                const char *key,
+                                json_t *value);
+int __real_json_array_append_new(json_t *object,
+                                const char *key,
+                                json_t *value);
+int __wrap_json_array_append_new(json_t *object, const char *key, json_t *value)
+{
+       int rc = (int)mock();
+       if (rc != CALL_ORIG) {
+               return rc;
+       }
+       return __real_json_array_append_new(object, key, value);
+}
+
+/*
+ * cmocka wrappers for json_array_extend
+ */
+int __wrap_json_array_extend(json_t *array, json_t *other_array);
+int __real_json_array_extend(json_t *array, json_t *other_array);
+int __wrap_json_array_extend(json_t *array, json_t *other_array)
+{
+
+       int rc = (int)mock();
+       if (rc != CALL_ORIG) {
+               return rc;
+       }
+       return __real_json_array_extend(array, other_array);
+}
+
+/*
+ * cmocka wrappers for json_object_update
+ */
+int __wrap_json_object_update(json_t *object, json_t *other_object);
+int __real_json_object_update(json_t *object, json_t *other_object);
+int __wrap_json_object_update(json_t *object, json_t *other_object)
+{
+
+       int rc = (int)mock();
+       if (rc != CALL_ORIG) {
+               return rc;
+       }
+       return __real_json_array_extend(object, other_object);
+}
+
+/*
+ * cmocka wrappers for gettimeofday
+ */
+int __wrap_gettimeofday(struct timeval *tv, struct timezone *tz);
+int __real_gettimeofday(struct timeval *tv, struct timezone *tz);
+int __wrap_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+
+       int rc = (int)mock();
+       if (rc != 0) {
+               return rc;
+       }
+       return __real_gettimeofday(tv, tz);
+}
+
+/*
+ * cmocka wrappers for localtime
+ */
+struct tm *__wrap_localtime(const time_t *timep);
+struct tm *__real_localtime(const time_t *timep);
+struct tm *__wrap_localtime(const time_t *timep)
+{
+       bool fail = (bool)mock();
+       if (fail) {
+               return NULL;
+       }
+       return __real_localtime(timep);
+}
+
+/*
+ * cmocka wrappers for talloc_named_const
+ */
+static const void *REAL_TALLOC = "Here";
+
+void *__wrap_talloc_named_const(const void *context,
+                               size_t size,
+                               const char *name);
+void *__real_talloc_named_const(const void *context,
+                               size_t size,
+                               const char *name);
+void *__wrap_talloc_named_const(const void *context,
+                               size_t size,
+                               const char *name)
+{
+
+       void *ret = (void *)mock();
+
+       if (ret == NULL) {
+               return NULL;
+       }
+       return __real_talloc_named_const(context, size, name);
+}
+
+/*
+ * cmocka wrappers for talloc_strdup
+ */
+char *__wrap_talloc_strdup(const void *t, const char *p);
+char *__real_talloc_strdup(const void *t, const char *p);
+char *__wrap_talloc_strdup(const void *t, const char *p)
+{
+
+       void *ret = (void *)mock();
+
+       if (ret == NULL) {
+               return NULL;
+       }
+       return __real_talloc_strdup(t, p);
+}
+
+char *__wrap_tsocket_address_string(const struct tsocket_address *addr,
+                                   TALLOC_CTX *mem_ctx);
+char *__real_tsocket_address_string(const struct tsocket_address *addr,
+                                   TALLOC_CTX *mem_ctx);
+char *__wrap_tsocket_address_string(const struct tsocket_address *addr,
+                                   TALLOC_CTX *mem_ctx)
+{
+
+       bool fail = (bool)mock();
+       if (fail) {
+               return NULL;
+       }
+       return __real_tsocket_address_string(addr, mem_ctx);
+}
+
+static void test_json_add_int(void **state)
+{
+       struct json_object object;
+       int rc = 0;
+
+       will_return(__wrap_json_object, false);
+       object = json_new_object();
+
+       /*
+        * Test json integer failure
+        */
+       will_return(__wrap_json_integer, true);
+       rc = json_add_int(&object, "name", 2);
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+
+       /*
+        * Test json object set new failure
+        */
+       will_return(__wrap_json_integer, false);
+       will_return(__wrap_json_object_set_new, JANNASON_FAILURE);
+       rc = json_add_int(&object, "name", 2);
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+       json_free(&object);
+}
+
+static void test_json_add_bool(void **state)
+{
+       struct json_object object;
+       int rc = 0;
+
+       will_return(__wrap_json_object, false);
+       object = json_new_object();
+
+       /*
+        * json_boolean does not return an error code.
+        * Test json object set new failure
+        */
+       will_return(__wrap_json_object_set_new, JANNASON_FAILURE);
+       rc = json_add_bool(&object, "name", true);
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+
+       json_free(&object);
+}
+
+static void test_json_add_string(void **state)
+{
+       struct json_object object;
+       int rc = 0;
+
+       will_return(__wrap_json_object, false);
+       object = json_new_object();
+       assert_false(json_is_invalid(&object));
+
+       /*
+        * Test json string failure
+        */
+       will_return(__wrap_json_string, true);
+       rc = json_add_string(&object, "name", "value");
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+
+       /*
+        * Test json object set new failure
+        */
+       will_return(__wrap_json_string, false);
+       will_return(__wrap_json_object_set_new, JANNASON_FAILURE);
+       rc = json_add_string(&object, "name", "value");
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+
+       /*
+        * Test json object set new failure for a NULL string
+        */
+       will_return(__wrap_json_object_set_new, JANNASON_FAILURE);
+       rc = json_add_string(&object, "null", NULL);
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+
+       json_free(&object);
+}
+
+static void test_json_add_object(void **state)
+{
+       struct json_object object;
+       struct json_object value;
+       int rc = 0;
+
+       will_return(__wrap_json_object, false);
+       will_return(__wrap_json_object, false);
+
+       object = json_new_object();
+       value = json_new_object();
+
+       /*
+        * Test json object set new failure
+        */
+       will_return(__wrap_json_object_set_new, JANNASON_FAILURE);
+       rc = json_add_object(&object, "name", &value);
+
+       assert_false(json_is_invalid(&object));
+       assert_false(json_is_invalid(&value));
+       assert_int_equal(JSON_ERROR, rc);
+
+       /*
+        * Test json object set new failure for a NULL value
+        */
+       will_return(__wrap_json_object_set_new, JANNASON_FAILURE);
+       rc = json_add_object(&object, "null", NULL);
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+
+       json_free(&object);
+       json_free(&value);
+}
+
+static void test_json_add_to_array(void **state)
+{
+       struct json_object array;
+       struct json_object value;
+       int rc = 0;
+
+       will_return(__wrap_json_array, false);
+       will_return(__wrap_json_object, false);
+
+       array = json_new_array();
+       value = json_new_object();
+
+       /*
+        * Test json array append new failure
+        */
+       will_return(__wrap_json_array_append_new, JANNASON_FAILURE);
+       rc = json_add_object(&array, "name", &value);
+
+       assert_false(json_is_invalid(&array));
+       assert_false(json_is_invalid(&value));
+       assert_int_equal(JSON_ERROR, rc);
+
+       /*
+        * Test json append new failure with a NULL value
+        */
+       will_return(__wrap_json_array_append_new, JANNASON_FAILURE);
+       rc = json_add_object(&array, "null", NULL);
+
+       assert_false(json_is_invalid(&array));
+       assert_int_equal(JSON_ERROR, rc);
+
+       json_free(&array);
+       json_free(&value);
+}
+
+static void test_json_add_timestamp(void **state)
+{
+       struct json_object object;
+       int rc = 0;
+
+       will_return(__wrap_json_object, false);
+       object = json_new_object();
+
+       /*
+        * Test json string failure
+        */
+       will_return(__wrap_gettimeofday, 0);
+       will_return(__wrap_localtime, false);
+       will_return(__wrap_json_string, true);
+       rc = json_add_timestamp(&object);
+
+       /*
+        * Test json_object_set_new failure
+        */
+       will_return(__wrap_gettimeofday, 0);
+       will_return(__wrap_localtime, false);
+       will_return(__wrap_json_string, false);
+       will_return(__wrap_json_object_set_new, JANNASON_FAILURE);
+       rc = json_add_timestamp(&object);
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+
+       /*
+        * Test gettimeofday failure
+        */
+       will_return(__wrap_gettimeofday, -1);
+       rc = json_add_timestamp(&object);
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+
+       /*
+        * Test local time failure
+        */
+       will_return(__wrap_gettimeofday, 0);
+       will_return(__wrap_localtime, true);
+       rc = json_add_timestamp(&object);
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+
+       json_free(&object);
+}
+
+static void test_json_add_stringn(void **state)
+{
+       struct json_object object;
+       int rc = 0;
+
+       will_return(__wrap_json_object, false);
+       object = json_new_object();
+       assert_false(json_is_invalid(&object));
+
+       /*
+        * Test json string failure
+        */
+       will_return(__wrap_json_string, true);
+       rc = json_add_stringn(&object, "name", "value", 3);
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+
+       /*
+        * Test json object set new failure
+        */
+       will_return(__wrap_json_string, false);
+       will_return(__wrap_json_object_set_new, JANNASON_FAILURE);
+       rc = json_add_stringn(&object, "name", "value", 3);
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+
+       /*
+        * Test json object set new failure for a NULL string
+        */
+       will_return(__wrap_json_object_set_new, JANNASON_FAILURE);
+       rc = json_add_stringn(&object, "null", NULL, 2);
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+
+       /*
+        * Test json object set new failure for a zero string size
+        */
+       will_return(__wrap_json_object_set_new, JANNASON_FAILURE);
+       rc = json_add_stringn(&object, "zero", "no value", 0);
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+       json_free(&object);
+}
+
+static void test_json_add_version(void **state)
+{
+       struct json_object object;
+       int rc = 0;
+
+       /*
+        * Fail creating the version object
+        */
+       will_return(__wrap_json_object, false);
+       object = json_new_object();
+
+       will_return(__wrap_json_object, true);
+       rc = json_add_version(&object, 1, 11);
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+
+       json_free(&object);
+
+       /*
+        * Fail adding the major version
+        */
+       will_return(__wrap_json_object, false);
+       object = json_new_object();
+
+       will_return(__wrap_json_object, false);
+       will_return(__wrap_json_integer, false);
+       will_return(__wrap_json_object_set_new, JANNASON_FAILURE);
+       rc = json_add_version(&object, 2, 12);
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+
+       json_free(&object);
+
+       /*
+        * Fail adding the minor version
+        */
+       will_return(__wrap_json_object, false);
+       object = json_new_object();
+
+       will_return(__wrap_json_object, false);
+       will_return(__wrap_json_integer, false);
+       will_return(__wrap_json_object_set_new, CALL_ORIG);
+       will_return(__wrap_json_integer, false);
+       will_return(__wrap_json_object_set_new, JANNASON_FAILURE);
+       rc = json_add_version(&object, 3, 13);
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+
+       json_free(&object);
+
+       /*
+        * Fail adding the version object
+        */
+       will_return(__wrap_json_object, false);
+       object = json_new_object();
+
+       will_return(__wrap_json_object, false);
+       will_return(__wrap_json_integer, false);
+       will_return(__wrap_json_object_set_new, CALL_ORIG);
+       will_return(__wrap_json_integer, false);
+       will_return(__wrap_json_object_set_new, JANNASON_FAILURE);
+       rc = json_add_version(&object, 4, 14);
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+
+       json_free(&object);
+}
+
+static void test_json_add_address(void **state)
+{
+       struct json_object object;
+       int rc = 0;
+       struct tsocket_address *ip = NULL;
+
+       TALLOC_CTX *ctx = NULL;
+
+       will_return(__wrap_talloc_named_const, REAL_TALLOC);
+       ctx = talloc_new(NULL);
+
+       /*
+        * Add a null address
+        */
+       will_return(__wrap_json_object, false);
+       object = json_new_object();
+
+       will_return(__wrap_json_object_set_new, JANNASON_FAILURE);
+       rc = json_add_address(&object, "name", NULL);
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+
+       /*
+        * Add a non null address, json_object_set_new failure
+        */
+       rc = tsocket_address_inet_from_strings(ctx, "ip", "127.0.0.1", 21, &ip);
+       assert_int_equal(0, rc);
+
+       will_return(__wrap_talloc_named_const, REAL_TALLOC);
+       will_return(__wrap_tsocket_address_string, false);
+       will_return(__wrap_json_string, false);
+       will_return(__wrap_json_object_set_new, JANNASON_FAILURE);
+       rc = json_add_address(&object, "name", ip);
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+
+       /*
+        * Add a non null address, with a talloc failure
+        */
+       rc = tsocket_address_inet_from_strings(ctx, "ip", "127.0.0.1", 21, &ip);
+       assert_int_equal(0, rc);
+
+       will_return(__wrap_talloc_named_const, NULL);
+       rc = json_add_address(&object, "name", ip);
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+
+       /*
+        * Add a non null address, tsocket_address_string failure
+        */
+       rc = tsocket_address_inet_from_strings(ctx, "ip", "127.0.0.1", 21, &ip);
+       assert_int_equal(0, rc);
+
+       will_return(__wrap_talloc_named_const, REAL_TALLOC);
+       will_return(__wrap_tsocket_address_string, true);
+       rc = json_add_address(&object, "name", ip);
+
+       assert_false(json_is_invalid(&object));
+       assert_int_equal(JSON_ERROR, rc);
+
+       TALLOC_FREE(ctx);
+       json_free(&object);
+}
+
+static void test_json_add_sid(void **state)
+{
+       struct json_object object;
+       const char *SID = "S-1-5-21-2470180966-3899876309-2637894779";
+       struct dom_sid sid;
+       int rc;
+
+       /*
+        * Add a null SID
+        */
+       will_return(__wrap_json_object, false);
+       object = json_new_object();
+
+       will_return(__wrap_json_object_set_new, JANNASON_FAILURE);
+       rc = json_add_sid(&object, "null", NULL);
+       assert_int_equal(JSON_ERROR, rc);
+
+       /*
+        * Add a non null SID
+        */
+       assert_true(string_to_sid(&sid, SID));
+       will_return(__wrap_json_string, false);
+       will_return(__wrap_json_object_set_new, JANNASON_FAILURE);
+       rc = json_add_sid(&object, "sid", &sid);
+       assert_int_equal(JSON_ERROR, rc);
+
+       json_free(&object);
+}
+
+static void test_json_add_guid(void **state)
+{
+       struct json_object object;
+       const char *GUID = "3ab88633-1e57-4c1a-856c-d1bc4b15bbb1";
+       struct GUID guid;
+       NTSTATUS status;
+       int rc;
+
+       /*
+        * Add a null GUID
+        */
+       will_return(__wrap_json_object, false);
+       object = json_new_object();
+
+       will_return(__wrap_json_object_set_new, JANNASON_FAILURE);
+       rc = json_add_guid(&object, "null", NULL);
+       assert_int_equal(JSON_ERROR, rc);
+
+       /*
+        * Add a non null GUID
+        */
+       status = GUID_from_string(GUID, &guid);
+       assert_true(NT_STATUS_IS_OK(status));
+       will_return(__wrap_json_string, false);
+       will_return(__wrap_json_object_set_new, JANNASON_FAILURE);
+       rc = json_add_guid(&object, "guid", &guid);
+       assert_int_equal(JSON_ERROR, rc);
+
+       json_free(&object);
+}
+
+static void test_json_to_string(void **state)
+{
+       struct json_object object;
+       char *s = NULL;
+       TALLOC_CTX *ctx = NULL;
+
+       will_return(__wrap_talloc_named_const, REAL_TALLOC);
+       ctx = talloc_new(NULL);
+
+       will_return(__wrap_json_object, false);
+       object = json_new_object();
+
+       /*
+        * json_dumps failure
+        */
+       will_return(__wrap_json_dumps, true);
+       s = json_to_string(ctx, &object);
+       assert_null(s);
+
+       /*
+        * talloc failure
+        */
+       will_return(__wrap_json_dumps, false);
+       will_return(__wrap_talloc_strdup, NULL);
+       s = json_to_string(ctx, &object);
+       assert_null(s);
+       TALLOC_FREE(ctx);
+       json_free(&object);
+}
+
+static void test_json_get_array(void **state)
+{
+       struct json_object object;
+       struct json_object stored_array;
+       struct json_object array;
+
+       int rc;
+
+       will_return(__wrap_json_object, false);
+       object = json_new_object();
+       assert_false(json_is_invalid(&object));
+
+       will_return(__wrap_json_array, false);
+       stored_array = json_new_array();
+       assert_false(json_is_invalid(&stored_array));
+
+       will_return(__wrap_json_object_set_new, CALL_ORIG);
+       rc = json_add_object(&object, "array", &stored_array);
+       assert_int_equal(0, rc);
+
+       /*
+        * json array failure
+        */
+       will_return(__wrap_json_array, true);
+       array = json_get_array(&object, "array");
+       assert_true(json_is_invalid(&array));
+
+       /*
+        * json array extend failure
+        */
+       will_return(__wrap_json_array, false);
+       will_return(__wrap_json_array_extend, true);
+       array = json_get_array(&object, "array");
+       assert_true(json_is_invalid(&array));
+
+       json_free(&stored_array);
+       json_free(&object);
+}
+
+static void test_json_get_object(void **state)
+{
+       struct json_object object;
+       struct json_object stored;
+       struct json_object retreived;
+
+       int rc;
+
+       will_return(__wrap_json_object, false);
+       object = json_new_object();
+       assert_false(json_is_invalid(&object));
+
+       will_return(__wrap_json_object, false);
+       stored = json_new_object();
+       assert_false(json_is_invalid(&stored));
+
+       will_return(__wrap_json_object_set_new, CALL_ORIG);
+       rc = json_add_object(&object, "stored", &stored);
+       assert_int_equal(0, rc);
+
+       /*
+        * json object update failure
+        */
+       will_return(__wrap_json_object, false);
+       will_return(__wrap_json_object_update, true);
+       retreived = json_get_object(&object, "stored");
+       assert_true(json_is_invalid(&retreived));
+
+       json_free(&object);
+}
+
+int main(int argc, const char **argv)
+{
+       const struct CMUnitTest tests[] = {
+           cmocka_unit_test(test_json_add_int),
+           cmocka_unit_test(test_json_add_bool),
+           cmocka_unit_test(test_json_add_string),
+           cmocka_unit_test(test_json_add_object),
+           cmocka_unit_test(test_json_add_to_array),
+           cmocka_unit_test(test_json_add_timestamp),
+           cmocka_unit_test(test_json_add_stringn),
+           cmocka_unit_test(test_json_add_version),
+           cmocka_unit_test(test_json_add_address),
+           cmocka_unit_test(test_json_add_sid),
+           cmocka_unit_test(test_json_add_guid),
+           cmocka_unit_test(test_json_to_string),
+           cmocka_unit_test(test_json_get_array),
+           cmocka_unit_test(test_json_get_object),
+       };
+
+       cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+       return cmocka_run_group_tests(tests, NULL, NULL);
+}
index 24ac8bb47897ec25638569eb7b6d5da6f74d1aa5..4811e056b72cd1acb5c2d28086c5c87c802536fa 100644 (file)
@@ -23,3 +23,34 @@ if bld.AD_DC_BUILD_IS_ENABLED() and bld.CONFIG_GET('ENABLE_SELFTEST'):
         ''',
         install=False
     )
+
+if bld.AD_DC_BUILD_IS_ENABLED() and bld.CONFIG_GET('ENABLE_SELFTEST'):
+    bld.SAMBA_BINARY(
+        'audit_logging_error_test',
+        source='tests/audit_logging_error_test.c',
+        deps='''
+             audit_logging
+             jansson
+             cmocka
+             talloc
+             samba-util
+             LIBTSOCKET
+        ''',
+        install=False,
+        ldflags='''
+            -Wl,--wrap,json_object_set_new
+            -Wl,--wrap,json_object_update
+            -Wl,--wrap,json_array_append_new
+            -Wl,--wrap,json_array_extend
+            -Wl,--wrap,json_object
+            -Wl,--wrap,json_string
+            -Wl,--wrap,json_integer
+            -Wl,--wrap,json_array
+            -Wl,--wrap,json_dumps
+            -Wl,--wrap,gettimeofday
+            -Wl,--wrap,localtime
+            -Wl,--wrap,talloc_named_const
+            -Wl,--wrap,talloc_strdup
+            -Wl,--wrap,tsocket_address_string
+        '''
+    )
diff --git a/source4/dsdb/samdb/ldb_modules/tests/test_audit_log_errors.c b/source4/dsdb/samdb/ldb_modules/tests/test_audit_log_errors.c
new file mode 100644 (file)
index 0000000..2931768
--- /dev/null
@@ -0,0 +1,639 @@
+/*
+   Unit tests for the dsdb audit logging code code in audit_log.c
+
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * These tests exercise the error handling code
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <unistd.h>
+#include <cmocka.h>
+
+int ldb_audit_log_module_init(const char *version);
+#include "../audit_log.c"
+#include "lib/ldb/include/ldb_private.h"
+
+/*
+ * cmocka wrappers for json_new_object
+ */
+struct json_object __wrap_json_new_object(void);
+struct json_object __real_json_new_object(void);
+struct json_object __wrap_json_new_object(void)
+{
+
+       bool use_real = (bool)mock();
+       if (!use_real) {
+               return json_empty_object;
+       }
+       return __real_json_new_object();
+}
+
+/*
+ * cmocka wrappers for json_add_version
+ */
+int __wrap_json_add_version(struct json_object *object, int major, int minor);
+int __real_json_add_version(struct json_object *object, int major, int minor);
+int __wrap_json_add_version(struct json_object *object, int major, int minor)
+{
+
+       int ret = (int)mock();
+       if (ret) {
+               return ret;
+       }
+       return __real_json_add_version(object, major, minor);
+}
+
+/*
+ * cmocka wrappers for json_add_version
+ */
+int __wrap_json_add_timestamp(struct json_object *object);
+int __real_json_add_timestamp(struct json_object *object);
+int __wrap_json_add_timestamp(struct json_object *object)
+{
+
+       int ret = (int)mock();
+       if (ret) {
+               return ret;
+       }
+       return __real_json_add_timestamp(object);
+}
+/*
+ * unit test of operation_json, that ensures that all the expected
+ * attributes and objects are in the json object.
+ */
+static void test_operation_json(void **state)
+{
+       struct ldb_context *ldb = NULL;
+       struct ldb_module  *module = NULL;
+       struct ldb_request *req = NULL;
+       struct ldb_reply *reply = NULL;
+       struct audit_private *audit_private = NULL;
+
+       struct tsocket_address *ts = NULL;
+
+       struct auth_session_info *sess = NULL;
+       struct security_token *token = NULL;
+       struct dom_sid sid;
+       const char *const SID = "S-1-5-21-2470180966-3899876309-2637894779";
+       const char * const SESSION = "7130cb06-2062-6a1b-409e-3514c26b1773";
+       struct GUID session_id;
+
+       struct GUID transaction_id;
+       const char *const TRANSACTION = "7130cb06-2062-6a1b-409e-3514c26b1773";
+
+       struct ldb_dn *dn = NULL;
+       const char *const DN = "dn=CN=USER,CN=Users,DC=SAMBA,DC=ORG";
+
+       struct ldb_message *msg = NULL;
+
+       struct json_object json;
+
+
+       /*
+        * Test setup
+        */
+       TALLOC_CTX *ctx = talloc_new(NULL);
+
+       ldb = ldb_init(ctx, NULL);
+
+       audit_private = talloc_zero(ctx, struct audit_private);
+       GUID_from_string(TRANSACTION, &transaction_id);
+       audit_private->transaction_guid = transaction_id;
+
+       module = talloc_zero(ctx, struct ldb_module);
+       module->ldb = ldb;
+       ldb_module_set_private(module, audit_private);
+
+       tsocket_address_inet_from_strings(ctx, "ip", "127.0.0.1", 0, &ts);
+       ldb_set_opaque(ldb, "remoteAddress", ts);
+
+       sess = talloc_zero(ctx, struct auth_session_info);
+       token = talloc_zero(ctx, struct security_token);
+       string_to_sid(&sid, SID);
+       token->num_sids = 1;
+       token->sids = &sid;
+       sess->security_token = token;
+       GUID_from_string(SESSION, &session_id);
+       sess->unique_session_token = session_id;
+       ldb_set_opaque(ldb, DSDB_SESSION_INFO, sess);
+
+       msg = talloc_zero(ctx, struct ldb_message);
+       dn = ldb_dn_new(ctx, ldb, DN);
+       msg->dn = dn;
+       ldb_msg_add_string(msg, "attribute", "the-value");
+
+       req = talloc_zero(ctx, struct ldb_request);
+       req->operation =  LDB_ADD;
+       req->op.add.message = msg;
+
+       reply = talloc_zero(ctx, struct ldb_reply);
+       reply->error = LDB_ERR_OPERATIONS_ERROR;
+
+       /*
+        * Fail on the creation of the audit json object
+        */
+
+       will_return(__wrap_json_new_object, false);
+
+       json = operation_json(module, req, reply);
+       assert_true(json_is_invalid(&json));
+
+       /*
+        * Fail adding the version object .
+        */
+
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, JSON_ERROR);
+
+       json = operation_json(module, req, reply);
+       assert_true(json_is_invalid(&json));
+
+       /*
+        * Fail on creation of the wrapper.
+        */
+
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, 0);
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_new_object, false);
+
+       json = operation_json(module, req, reply);
+       assert_true(json_is_invalid(&json));
+
+       /*
+        * Fail adding the timestamp to the wrapper object.
+        */
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, 0);
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_timestamp, JSON_ERROR);
+
+       json = operation_json(module, req, reply);
+       assert_true(json_is_invalid(&json));
+
+       /*
+        * Now test the happy path
+        */
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, 0);
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_timestamp, 0);
+
+       json = operation_json(module, req, reply);
+       assert_false(json_is_invalid(&json));
+       json_free(&json);
+
+       TALLOC_FREE(ctx);
+
+}
+
+/*
+ * minimal unit test of password_change_json, that ensures that all the expected
+ * attributes and objects are in the json object.
+ */
+static void test_password_change_json(void **state)
+{
+       struct ldb_context *ldb = NULL;
+       struct ldb_module  *module = NULL;
+       struct ldb_request *req = NULL;
+       struct ldb_reply *reply = NULL;
+       struct audit_private *audit_private = NULL;
+
+       struct tsocket_address *ts = NULL;
+
+       struct auth_session_info *sess = NULL;
+       struct security_token *token = NULL;
+       struct dom_sid sid;
+       const char *const SID = "S-1-5-21-2470180966-3899876309-2637894779";
+       const char * const SESSION = "7130cb06-2062-6a1b-409e-3514c26b1773";
+       struct GUID session_id;
+
+       struct GUID transaction_id;
+       const char *const TRANSACTION = "7130cb06-2062-6a1b-409e-3514c26b1773";
+
+       struct ldb_dn *dn = NULL;
+       const char *const DN = "dn=CN=USER,CN=Users,DC=SAMBA,DC=ORG";
+
+       struct ldb_message *msg = NULL;
+
+       struct json_object json;
+
+       TALLOC_CTX *ctx = talloc_new(NULL);
+
+       ldb = ldb_init(ctx, NULL);
+
+       audit_private = talloc_zero(ctx, struct audit_private);
+       GUID_from_string(TRANSACTION, &transaction_id);
+       audit_private->transaction_guid = transaction_id;
+
+       module = talloc_zero(ctx, struct ldb_module);
+       module->ldb = ldb;
+       ldb_module_set_private(module, audit_private);
+
+       tsocket_address_inet_from_strings(ctx, "ip", "127.0.0.1", 0, &ts);
+       ldb_set_opaque(ldb, "remoteAddress", ts);
+
+       sess = talloc_zero(ctx, struct auth_session_info);
+       token = talloc_zero(ctx, struct security_token);
+       string_to_sid(&sid, SID);
+       token->num_sids = 1;
+       token->sids = &sid;
+       sess->security_token = token;
+       GUID_from_string(SESSION, &session_id);
+       sess->unique_session_token = session_id;
+       ldb_set_opaque(ldb, DSDB_SESSION_INFO, sess);
+
+       msg = talloc_zero(ctx, struct ldb_message);
+       dn = ldb_dn_new(ctx, ldb, DN);
+       msg->dn = dn;
+       ldb_msg_add_string(msg, "planTextPassword", "super-secret");
+
+       req = talloc_zero(ctx, struct ldb_request);
+       req->operation =  LDB_ADD;
+       req->op.add.message = msg;
+       reply = talloc_zero(ctx, struct ldb_reply);
+       reply->error = LDB_SUCCESS;
+
+
+       /*
+        * Fail on the creation of the audit json object
+        */
+
+       will_return(__wrap_json_new_object, false);
+       json = password_change_json(module, req, reply);
+
+       assert_true(json_is_invalid(&json));
+
+       /*
+        * Fail adding the version object .
+        */
+
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, JSON_ERROR);
+
+       json = password_change_json(module, req, reply);
+       assert_true(json_is_invalid(&json));
+
+       /*
+        * Fail on creation of the wrapper.
+        */
+
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, 0);
+       will_return(__wrap_json_new_object, false);
+
+       json = password_change_json(module, req, reply);
+       assert_true(json_is_invalid(&json));
+
+       /*
+        * Fail on creation of the time stamp.
+        */
+
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, 0);
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_timestamp, JSON_ERROR);
+
+       json = password_change_json(module, req, reply);
+       assert_true(json_is_invalid(&json));
+
+       /*
+        * Now test the happy path
+        */
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, 0);
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_timestamp, 0);
+
+       json = password_change_json(module, req, reply);
+       assert_false(json_is_invalid(&json));
+       json_free(&json);
+
+       TALLOC_FREE(ctx);
+}
+
+
+/*
+ * minimal unit test of transaction_json, that ensures that all the expected
+ * attributes and objects are in the json object.
+ */
+static void test_transaction_json(void **state)
+{
+
+       struct GUID guid;
+       const char * const GUID = "7130cb06-2062-6a1b-409e-3514c26b1773";
+
+       struct json_object json;
+
+       GUID_from_string(GUID, &guid);
+
+
+       /*
+        * Fail on the creation of the audit json object
+        */
+
+       will_return(__wrap_json_new_object, false);
+
+       json = transaction_json("delete", &guid, 10000099);
+       assert_true(json_is_invalid(&json));
+
+       /*
+        * Fail adding the version object .
+        */
+
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, JSON_ERROR);
+
+       json = transaction_json("delete", &guid, 10000099);
+       assert_true(json_is_invalid(&json));
+
+       /*
+        * Fail on creation of the wrapper.
+        */
+
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, 0);
+       will_return(__wrap_json_new_object, false);
+
+       json = transaction_json("delete", &guid, 10000099);
+       assert_true(json_is_invalid(&json));
+
+       /*
+        * Fail on creation of the time stamp.
+        */
+
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, 0);
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_timestamp, JSON_ERROR);
+
+       json = transaction_json("delete", &guid, 10000099);
+       assert_true(json_is_invalid(&json));
+
+       /*
+        * Now test the happy path
+        */
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, 0);
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_timestamp, 0);
+
+       json = transaction_json("delete", &guid, 10000099);
+       assert_false(json_is_invalid(&json));
+       json_free(&json);
+}
+
+/*
+ * minimal unit test of commit_failure_json, that ensures that all the
+ * expected attributes and objects are in the json object.
+ */
+static void test_commit_failure_json(void **state)
+{
+
+       struct GUID guid;
+       const char * const GUID = "7130cb06-2062-6a1b-409e-3514c26b1773";
+
+       struct json_object json;
+
+       GUID_from_string(GUID, &guid);
+
+
+       /*
+        * Fail on the creation of the audit json object
+        */
+
+       will_return(__wrap_json_new_object, false);
+
+       json = commit_failure_json(
+               "prepare",
+               987876,
+               LDB_ERR_OPERATIONS_ERROR,
+               "because",
+               &guid);
+       assert_true(json_is_invalid(&json));
+
+       /*
+        * Fail adding the version object .
+        */
+
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, JSON_ERROR);
+
+       json = commit_failure_json(
+               "prepare",
+               987876,
+               LDB_ERR_OPERATIONS_ERROR,
+               "because",
+               &guid);
+       assert_true(json_is_invalid(&json));
+
+       /*
+        * Fail on creation of the wrapper.
+        */
+
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, 0);
+       will_return(__wrap_json_new_object, false);
+
+       json = commit_failure_json(
+               "prepare",
+               987876,
+               LDB_ERR_OPERATIONS_ERROR,
+               "because",
+               &guid);
+       assert_true(json_is_invalid(&json));
+
+       /*
+        * Fail on creation of the time stamp.
+        */
+
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, 0);
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_timestamp, JSON_ERROR);
+
+       json = commit_failure_json(
+               "prepare",
+               987876,
+               LDB_ERR_OPERATIONS_ERROR,
+               "because",
+               &guid);
+       assert_true(json_is_invalid(&json));
+
+       /*
+        * Now test the happy path
+        */
+
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, 0);
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_timestamp, 0);
+
+       json = commit_failure_json(
+               "prepare",
+               987876,
+               LDB_ERR_OPERATIONS_ERROR,
+               "because",
+               &guid);
+       assert_false(json_is_invalid(&json));
+       json_free(&json);
+}
+
+/*
+ * unit test of replicated_update_json, that ensures that all the expected
+ * attributes and objects are in the json object.
+ */
+static void test_replicated_update_json(void **state)
+{
+       struct ldb_context *ldb = NULL;
+       struct ldb_module  *module = NULL;
+       struct ldb_request *req = NULL;
+       struct ldb_reply *reply = NULL;
+       struct audit_private *audit_private = NULL;
+       struct dsdb_extended_replicated_objects *ro = NULL;
+       struct repsFromTo1 *source_dsa = NULL;
+
+       struct GUID transaction_id;
+       const char *const TRANSACTION = "7130cb06-2062-6a1b-409e-3514c26b1773";
+
+       struct ldb_dn *dn = NULL;
+       const char *const DN = "dn=CN=USER,CN=Users,DC=SAMBA,DC=ORG";
+
+       struct GUID source_dsa_obj_guid;
+       const char *const SOURCE_DSA = "7130cb06-2062-6a1b-409e-3514c26b1793";
+
+       struct GUID invocation_id;
+       const char *const INVOCATION_ID =
+               "7130cb06-2062-6a1b-409e-3514c26b1893";
+       struct json_object json;
+
+       TALLOC_CTX *ctx = talloc_new(NULL);
+
+       ldb = ldb_init(ctx, NULL);
+
+       audit_private = talloc_zero(ctx, struct audit_private);
+       GUID_from_string(TRANSACTION, &transaction_id);
+       audit_private->transaction_guid = transaction_id;
+
+       module = talloc_zero(ctx, struct ldb_module);
+       module->ldb = ldb;
+       ldb_module_set_private(module, audit_private);
+
+       dn = ldb_dn_new(ctx, ldb, DN);
+       GUID_from_string(SOURCE_DSA, &source_dsa_obj_guid);
+       GUID_from_string(INVOCATION_ID, &invocation_id);
+       source_dsa = talloc_zero(ctx, struct repsFromTo1);
+       source_dsa->source_dsa_obj_guid = source_dsa_obj_guid;
+       source_dsa->source_dsa_invocation_id = invocation_id;
+
+       ro = talloc_zero(ctx, struct dsdb_extended_replicated_objects);
+       ro->source_dsa = source_dsa;
+       ro->num_objects = 808;
+       ro->linked_attributes_count = 2910;
+       ro->partition_dn = dn;
+       ro->error = WERR_NOT_SUPPORTED;
+
+
+       req = talloc_zero(ctx, struct ldb_request);
+       req->op.extended.data = ro;
+       req->operation = LDB_EXTENDED;
+
+       reply = talloc_zero(ctx, struct ldb_reply);
+       reply->error = LDB_ERR_NO_SUCH_OBJECT;
+
+
+       /*
+        * Fail on the creation of the audit json object
+        */
+
+       will_return(__wrap_json_new_object, false);
+
+       json = replicated_update_json(module, req, reply);
+       assert_true(json_is_invalid(&json));
+
+       /*
+        * Fail adding the version object .
+        */
+
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, JSON_ERROR);
+
+       json = replicated_update_json(module, req, reply);
+       assert_true(json_is_invalid(&json));
+
+       /*
+        * Fail on creation of the wrapper.
+        */
+
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, 0);
+       will_return(__wrap_json_new_object, false);
+
+       json = replicated_update_json(module, req, reply);
+       assert_true(json_is_invalid(&json));
+
+       /*
+        * Fail on creation of the time stamp.
+        */
+
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, 0);
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_timestamp, JSON_ERROR);
+
+       json = replicated_update_json(module, req, reply);
+       assert_true(json_is_invalid(&json));
+
+       /*
+        * Now test the happy path.
+        */
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, 0);
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_timestamp, 0);
+
+       json = replicated_update_json(module, req, reply);
+       assert_false(json_is_invalid(&json));
+       json_free(&json);
+
+       TALLOC_FREE(ctx);
+}
+
+int main(void) {
+       const struct CMUnitTest tests[] = {
+               cmocka_unit_test(test_operation_json),
+               cmocka_unit_test(test_password_change_json),
+               cmocka_unit_test(test_transaction_json),
+               cmocka_unit_test(test_commit_failure_json),
+               cmocka_unit_test(test_replicated_update_json),
+       };
+
+       cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+       return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/source4/dsdb/samdb/ldb_modules/tests/test_group_audit_errors.c b/source4/dsdb/samdb/ldb_modules/tests/test_group_audit_errors.c
new file mode 100644 (file)
index 0000000..3c8829e
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+   Unit tests for the dsdb group auditing code in group_audit.c
+
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * These tests exercise the error handling routines.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <unistd.h>
+#include <cmocka.h>
+
+int ldb_group_audit_log_module_init(const char *version);
+#include "../group_audit.c"
+
+#include "lib/ldb/include/ldb_private.h"
+
+/*
+ * cmocka wrappers for json_new_object
+ */
+struct json_object __wrap_json_new_object(void);
+struct json_object __real_json_new_object(void);
+struct json_object __wrap_json_new_object(void)
+{
+
+       bool use_real = (bool)mock();
+       if (!use_real) {
+               return json_empty_object;
+       }
+       return __real_json_new_object();
+}
+
+/*
+ * cmocka wrappers for json_add_version
+ */
+int __wrap_json_add_version(struct json_object *object, int major, int minor);
+int __real_json_add_version(struct json_object *object, int major, int minor);
+int __wrap_json_add_version(struct json_object *object, int major, int minor)
+{
+
+       int ret = (int)mock();
+       if (ret) {
+               return ret;
+       }
+       return __real_json_add_version(object, major, minor);
+}
+
+/*
+ * cmocka wrappers for json_add_version
+ */
+int __wrap_json_add_timestamp(struct json_object *object);
+int __real_json_add_timestamp(struct json_object *object);
+int __wrap_json_add_timestamp(struct json_object *object)
+{
+
+       int ret = (int)mock();
+       if (ret) {
+               return ret;
+       }
+       return __real_json_add_timestamp(object);
+}
+
+/*
+ * Test helper to add a session id and user SID
+ */
+static void add_session_data(
+       TALLOC_CTX *ctx,
+       struct ldb_context *ldb,
+       const char *session,
+       const char *user_sid)
+{
+       struct auth_session_info *sess = NULL;
+       struct security_token *token = NULL;
+       struct dom_sid *sid = NULL;
+       struct GUID session_id;
+       bool ok;
+
+       sess = talloc_zero(ctx, struct auth_session_info);
+       token = talloc_zero(ctx, struct security_token);
+       sid = talloc_zero(ctx, struct dom_sid);
+       ok = string_to_sid(sid, user_sid);
+       assert_true(ok);
+       token->sids = sid;
+       sess->security_token = token;
+       GUID_from_string(session, &session_id);
+       sess->unique_session_token = session_id;
+       ldb_set_opaque(ldb, DSDB_SESSION_INFO, sess);
+}
+
+/*
+ * Test helper to insert a transaction_id into a request.
+ */
+static void add_transaction_id(struct ldb_request *req, const char *id)
+{
+       struct GUID guid;
+       struct dsdb_control_transaction_identifier *transaction_id = NULL;
+
+       transaction_id = talloc_zero(
+               req,
+               struct dsdb_control_transaction_identifier);
+       assert_non_null(transaction_id);
+       GUID_from_string(id, &guid);
+       transaction_id->transaction_guid = guid;
+       ldb_request_add_control(
+               req,
+               DSDB_CONTROL_TRANSACTION_IDENTIFIER_OID,
+               false,
+               transaction_id);
+}
+
+static void test_audit_group_json(void **state)
+{
+       struct ldb_context *ldb = NULL;
+       struct ldb_module  *module = NULL;
+       struct ldb_request *req = NULL;
+
+       struct tsocket_address *ts = NULL;
+
+       const char *const SID = "S-1-5-21-2470180966-3899876309-2637894779";
+       const char * const SESSION = "7130cb06-2062-6a1b-409e-3514c26b1773";
+
+       struct GUID transaction_id;
+       const char *const TRANSACTION = "7130cb06-2062-6a1b-409e-3514c26b1773";
+
+
+       struct json_object json;
+
+       TALLOC_CTX *ctx = talloc_new(NULL);
+
+       ldb = ldb_init(ctx, NULL);
+
+       GUID_from_string(TRANSACTION, &transaction_id);
+
+       module = talloc_zero(ctx, struct ldb_module);
+       module->ldb = ldb;
+
+       tsocket_address_inet_from_strings(ctx, "ip", "127.0.0.1", 0, &ts);
+       ldb_set_opaque(ldb, "remoteAddress", ts);
+
+       add_session_data(ctx, ldb, SESSION, SID);
+
+       req = talloc_zero(ctx, struct ldb_request);
+       req->operation =  LDB_ADD;
+       add_transaction_id(req, TRANSACTION);
+
+       /*
+        * Fail on the creation of the audit json object
+        */
+
+       will_return(__wrap_json_new_object, false);
+
+       json = audit_group_json(
+               module,
+               req,
+               "the-action",
+               "the-user-name",
+               "the-group-name",
+               LDB_ERR_OPERATIONS_ERROR);
+       assert_true(json_is_invalid(&json));
+
+       /*
+        * Fail adding the version object .
+        */
+
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, JSON_ERROR);
+
+       json = audit_group_json(
+               module,
+               req,
+               "the-action",
+               "the-user-name",
+               "the-group-name",
+               LDB_ERR_OPERATIONS_ERROR);
+       assert_true(json_is_invalid(&json));
+
+       /*
+        * Fail on creation of the wrapper.
+        */
+
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, 0);
+       will_return(__wrap_json_new_object, false);
+
+       json = audit_group_json(
+               module,
+               req,
+               "the-action",
+               "the-user-name",
+               "the-group-name",
+               LDB_ERR_OPERATIONS_ERROR);
+       assert_true(json_is_invalid(&json));
+
+       /*
+        * Fail adding the timestamp to the wrapper object.
+        */
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, 0);
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_timestamp, JSON_ERROR);
+
+       json = audit_group_json(
+               module,
+               req,
+               "the-action",
+               "the-user-name",
+               "the-group-name",
+               LDB_ERR_OPERATIONS_ERROR);
+       assert_true(json_is_invalid(&json));
+
+
+       /*
+        * Now test the happy path
+        */
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_version, 0);
+       will_return(__wrap_json_new_object, true);
+       will_return(__wrap_json_add_timestamp, 0);
+
+       json = audit_group_json(
+               module,
+               req,
+               "the-action",
+               "the-user-name",
+               "the-group-name",
+               LDB_ERR_OPERATIONS_ERROR);
+       assert_false(json_is_invalid(&json));
+
+       json_free(&json);
+       TALLOC_FREE(ctx);
+
+}
+
+/*
+ * Note: to run under valgrind us:
+ *       valgrind --suppressions=test_group_audit.valgrind bin/test_group_audit
+ *       This suppresses the errors generated because the ldb_modules are not
+ *       de-registered.
+ *
+ */
+int main(void) {
+       const struct CMUnitTest tests[] = {
+               cmocka_unit_test(test_audit_group_json),
+       };
+
+       cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+       return cmocka_run_group_tests(tests, NULL, NULL);
+}
index 39c9477db80fce6cce0dbfa160a688d97c9929fc..a0bb0d478e9d67d29cc9ef60a5d9d6e66adfe265 100644 (file)
@@ -37,6 +37,25 @@ bld.SAMBA_BINARY('test_audit_log',
                  ''',
                  install=False)
 
+bld.SAMBA_BINARY('test_audit_log_errors',
+                 source='tests/test_audit_log_errors.c',
+                 deps='''
+                 talloc
+                 samba-util
+                 samdb-common
+                 samdb
+                 cmocka
+                 audit_logging
+                 DSDB_MODULE_HELPERS
+                 DSDB_MODULE_HELPERS_AUDIT
+                 ''',
+                 ldflags='''
+                     -Wl,--wrap,json_new_object
+                     -Wl,--wrap,json_add_version
+                     -Wl,--wrap,json_add_timestamp
+                 ''',
+                 install=False)
+
 bld.SAMBA_BINARY('test_group_audit',
                  source='tests/test_group_audit.c',
                  deps='''
@@ -51,6 +70,25 @@ bld.SAMBA_BINARY('test_group_audit',
                  ''',
                  install=False)
 
+bld.SAMBA_BINARY('test_group_audit_errors',
+                 source='tests/test_group_audit_errors.c',
+                 deps='''
+                 talloc
+                 samba-util
+                 samdb-common
+                 samdb
+                 cmocka
+                 audit_logging
+                 DSDB_MODULE_HELPERS
+                 DSDB_MODULE_HELPERS_AUDIT
+                 ''',
+                 ldflags='''
+                     -Wl,--wrap,json_new_object
+                     -Wl,--wrap,json_add_version
+                     -Wl,--wrap,json_add_timestamp
+                 ''',
+                 install=False)
+
 bld.SAMBA_MODULE('ldb_samba_dsdb',
        source='samba_dsdb.c',
        subsystem='ldb',
index 978a520005523a1e8a9cd4820b1c0754a3d2c44b..4b77b7e8675075d13033918900401daa79004327 100755 (executable)
@@ -1114,7 +1114,7 @@ for env in ["ad_dc_ntvfs", "ad_dc", "fl2000dc", "fl2003dc", "fl2008r2dc",
             'renamedc', 'labdc']:
     plantestsuite("samba4.blackbox.dbcheck(%s)" % env, env + ":local" , ["PYTHON=%s" % python, os.path.join(bbdir, "dbcheck.sh"), '$PREFIX/provision', configuration])
 
-# cmocka tests not requiring a specific encironment
+# cmocka tests not requiring a specific environment
 #
 plantestsuite("samba4.dsdb.samdb.ldb_modules.unique_object_sids" , "none",
               [os.path.join(bindir(), "test_unique_object_sids")])
@@ -1122,7 +1122,15 @@ plantestsuite("samba4.dsdb.samdb.ldb_modules.encrypted_secrets", "none",
                   [os.path.join(bindir(), "test_encrypted_secrets")])
 plantestsuite("lib.audit_logging.audit_logging", "none",
                   [os.path.join(bindir(), "audit_logging_test")])
+plantestsuite("lib.audit_logging.audit_logging.errors", "none",
+                  [os.path.join(bindir(), "audit_logging_error_test")])
 plantestsuite("samba4.dsdb.samdb.ldb_modules.audit_util", "none",
                   [os.path.join(bindir(), "test_audit_util")])
 plantestsuite("samba4.dsdb.samdb.ldb_modules.audit_log", "none",
                   [os.path.join(bindir(), "test_audit_log")])
+plantestsuite("samba4.dsdb.samdb.ldb_modules.audit_log.errors", "none",
+                  [os.path.join(bindir(), "test_audit_log_errors")])
+plantestsuite("samba4.dsdb.samdb.ldb_modules.group_audit", "none",
+                  [os.path.join(bindir(), "test_group_audit")])
+plantestsuite("samba4.dsdb.samdb.ldb_modules.group_audit.errors", "none",
+                  [os.path.join(bindir(), "test_group_audit_errors")])