summaryrefslogtreecommitdiffstats
path: root/source4/dsdb/samdb/ldb_modules/tests/test_audit_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/dsdb/samdb/ldb_modules/tests/test_audit_util.c')
-rw-r--r--source4/dsdb/samdb/ldb_modules/tests/test_audit_util.c1261
1 files changed, 1261 insertions, 0 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/tests/test_audit_util.c b/source4/dsdb/samdb/ldb_modules/tests/test_audit_util.c
new file mode 100644
index 0000000..44f7b77
--- /dev/null
+++ b/source4/dsdb/samdb/ldb_modules/tests/test_audit_util.c
@@ -0,0 +1,1261 @@
+/*
+ Unit tests for the dsdb audit logging utility code code in audit_util.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/>.
+*/
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <unistd.h>
+#include <cmocka.h>
+
+#include "../audit_util.c"
+
+#include "lib/ldb/include/ldb_private.h"
+
+static void test_dsdb_audit_add_ldb_value(void **state)
+{
+ struct json_object object;
+ struct json_object array;
+ struct ldb_val val = data_blob_null;
+ struct json_t *el = NULL;
+ struct json_t *atr = NULL;
+ char* base64 = NULL;
+
+ TALLOC_CTX *ctx = talloc_new(NULL);
+ /*
+ * Test a non array object
+ */
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+ dsdb_audit_add_ldb_value(&object, val);
+ assert_true(json_is_invalid(&object));
+ json_free(&object);
+
+ array = json_new_array();
+ assert_false(json_is_invalid(&array));
+ /*
+ * Test a data_blob_null, should encode as a JSON null value.
+ */
+ val = data_blob_null;
+ dsdb_audit_add_ldb_value(&array, val);
+ el = json_array_get(array.root, 0);
+ assert_true(json_is_null(el));
+
+ /*
+ * Test a +ve length but a null data ptr, should encode as a null.
+ */
+ val = data_blob_null;
+ val.length = 1;
+ dsdb_audit_add_ldb_value(&array, val);
+ el = json_array_get(array.root, 1);
+ assert_true(json_is_null(el));
+
+ /*
+ * Test a zero length but a non null data ptr, should encode as a null.
+ */
+ val = data_blob_null;
+ val.data = discard_const("Data on the stack");
+ dsdb_audit_add_ldb_value(&array, val);
+ el = json_array_get(array.root, 2);
+ assert_true(json_is_null(el));
+
+ /*
+ * Test a printable value.
+ * value should not be encoded
+ * truncated and base64 should be missing
+ */
+ val = data_blob_string_const("A value of interest");
+ dsdb_audit_add_ldb_value(&array, val);
+ el = json_array_get(array.root, 3);
+ assert_true(json_is_object(el));
+ atr = json_object_get(el, "value");
+ assert_true(json_is_string(atr));
+ assert_string_equal("A value of interest", json_string_value(atr));
+ assert_null(json_object_get(el, "truncated"));
+ assert_null(json_object_get(el, "base64"));
+
+ /*
+ * Test non printable value, should be base64 encoded.
+ * truncated should be missing and base64 should be set.
+ */
+ val = data_blob_string_const("A value of interest\n");
+ dsdb_audit_add_ldb_value(&array, val);
+ el = json_array_get(array.root, 4);
+ assert_true(json_is_object(el));
+ atr = json_object_get(el, "value");
+ assert_true(json_is_string(atr));
+ assert_string_equal(
+ "QSB2YWx1ZSBvZiBpbnRlcmVzdAo=",
+ json_string_value(atr));
+ atr = json_object_get(el, "base64");
+ assert_true(json_is_boolean(atr));
+ assert_true(json_boolean(atr));
+ assert_null(json_object_get(el, "truncated"));
+
+ /*
+ * test a printable value exactly max bytes long
+ * should not be truncated or encoded.
+ */
+ val = data_blob_null;
+ val.length = MAX_LENGTH;
+ val.data = (unsigned char *)generate_random_str_list(
+ ctx,
+ MAX_LENGTH,
+ "abcdefghijklmnopqrstuvwzyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "1234567890!@#$%^&*()");
+
+ dsdb_audit_add_ldb_value(&array, val);
+
+ el = json_array_get(array.root, 5);
+ assert_true(json_is_object(el));
+ atr = json_object_get(el, "value");
+ assert_true(json_is_string(atr));
+ assert_int_equal(MAX_LENGTH, strlen(json_string_value(atr)));
+ assert_memory_equal(val.data, json_string_value(atr), MAX_LENGTH);
+
+ assert_null(json_object_get(el, "base64"));
+ assert_null(json_object_get(el, "truncated"));
+
+
+ /*
+ * test a printable value exactly max + 1 bytes long
+ * should be truncated and not encoded.
+ */
+ val = data_blob_null;
+ val.length = MAX_LENGTH + 1;
+ val.data = (unsigned char *)generate_random_str_list(
+ ctx,
+ MAX_LENGTH + 1,
+ "abcdefghijklmnopqrstuvwzyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "1234567890!@#$%^&*()");
+
+ dsdb_audit_add_ldb_value(&array, val);
+
+ el = json_array_get(array.root, 6);
+ assert_true(json_is_object(el));
+ atr = json_object_get(el, "value");
+ assert_true(json_is_string(atr));
+ assert_int_equal(MAX_LENGTH, strlen(json_string_value(atr)));
+ assert_memory_equal(val.data, json_string_value(atr), MAX_LENGTH);
+
+ atr = json_object_get(el, "truncated");
+ assert_true(json_is_boolean(atr));
+ assert_true(json_boolean(atr));
+
+ assert_null(json_object_get(el, "base64"));
+
+ TALLOC_FREE(val.data);
+
+ /*
+ * test a non-printable value exactly max bytes long
+ * should not be truncated but should be encoded.
+ */
+ val = data_blob_null;
+ val.length = MAX_LENGTH;
+ val.data = (unsigned char *)generate_random_str_list(
+ ctx,
+ MAX_LENGTH,
+ "abcdefghijklmnopqrstuvwzyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "1234567890!@#$%^&*()");
+
+ val.data[0] = 0x03;
+ dsdb_audit_add_ldb_value(&array, val);
+ base64 = ldb_base64_encode(ctx, (char*) val.data, MAX_LENGTH);
+
+ el = json_array_get(array.root, 7);
+ assert_true(json_is_object(el));
+ atr = json_object_get(el, "value");
+ assert_true(json_is_string(atr));
+ assert_int_equal(strlen(base64), strlen(json_string_value(atr)));
+ assert_string_equal(base64, json_string_value(atr));
+
+ atr = json_object_get(el, "base64");
+ assert_true(json_is_boolean(atr));
+ assert_true(json_boolean(atr));
+
+ assert_null(json_object_get(el, "truncated"));
+ TALLOC_FREE(base64);
+ TALLOC_FREE(val.data);
+
+ /*
+ * test a non-printable value exactly max + 1 bytes long
+ * should be truncated and encoded.
+ */
+ val = data_blob_null;
+ val.length = MAX_LENGTH + 1;
+ val.data = (unsigned char *)generate_random_str_list(
+ ctx,
+ MAX_LENGTH + 1,
+ "abcdefghijklmnopqrstuvwzyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "1234567890!@#$%^&*()");
+
+ val.data[0] = 0x03;
+ dsdb_audit_add_ldb_value(&array, val);
+ /*
+ * The data is truncated before it is base 64 encoded
+ */
+ base64 = ldb_base64_encode(ctx, (char*) val.data, MAX_LENGTH);
+
+ el = json_array_get(array.root, 8);
+ assert_true(json_is_object(el));
+ atr = json_object_get(el, "value");
+ assert_true(json_is_string(atr));
+ assert_int_equal(strlen(base64), strlen(json_string_value(atr)));
+ assert_string_equal(base64, json_string_value(atr));
+
+ atr = json_object_get(el, "base64");
+ assert_true(json_is_boolean(atr));
+ assert_true(json_boolean(atr));
+
+ atr = json_object_get(el, "truncated");
+ assert_true(json_is_boolean(atr));
+ assert_true(json_boolean(atr));
+
+ TALLOC_FREE(base64);
+ TALLOC_FREE(val.data);
+
+ json_free(&array);
+ TALLOC_FREE(ctx);
+}
+
+static void test_dsdb_audit_attributes_json(void **state)
+{
+ struct ldb_message *msg = NULL;
+
+ struct json_object o;
+ json_t *a = NULL;
+ json_t *v = NULL;
+ json_t *x = NULL;
+ json_t *y = NULL;
+
+ TALLOC_CTX *ctx = talloc_new(NULL);
+
+
+ /*
+ * Test an empty message
+ * Should get an empty attributes object
+ */
+ msg = talloc_zero(ctx, struct ldb_message);
+
+ o = dsdb_audit_attributes_json(LDB_ADD, msg);
+ assert_true(json_is_object(o.root));
+ assert_int_equal(0, json_object_size(o.root));
+ json_free(&o);
+
+ o = dsdb_audit_attributes_json(LDB_MODIFY, msg);
+ assert_true(json_is_object(o.root));
+ assert_int_equal(0, json_object_size(o.root));
+ json_free(&o);
+
+ /*
+ * Test a message with a single secret attribute
+ * should only have that object and it should have no value
+ * attribute and redacted should be set.
+ */
+ msg = talloc_zero(ctx, struct ldb_message);
+ ldb_msg_add_string(msg, "clearTextPassword", "secret");
+
+ o = dsdb_audit_attributes_json(LDB_ADD, msg);
+ assert_true(json_is_object(o.root));
+ assert_int_equal(1, json_object_size(o.root));
+
+ a = json_object_get(o.root, "clearTextPassword");
+ assert_int_equal(1, json_object_size(a));
+
+ v = json_object_get(a, "actions");
+ assert_true(json_is_array(v));
+ assert_int_equal(1, json_array_size(v));
+
+ a = json_array_get(v, 0);
+ v = json_object_get(a, "redacted");
+ assert_true(json_is_boolean(v));
+ assert_true(json_boolean(v));
+
+ json_free(&o);
+
+ /*
+ * Test as a modify message, should add an action attribute
+ */
+ o = dsdb_audit_attributes_json(LDB_MODIFY, msg);
+ assert_true(json_is_object(o.root));
+ assert_int_equal(1, json_object_size(o.root));
+
+ a = json_object_get(o.root, "clearTextPassword");
+ assert_true(json_is_object(a));
+ assert_int_equal(1, json_object_size(a));
+
+ v = json_object_get(a, "actions");
+ assert_true(json_is_array(v));
+ assert_int_equal(1, json_array_size(v));
+
+ a = json_array_get(v, 0);
+ v = json_object_get(a, "redacted");
+ assert_true(json_is_boolean(v));
+ assert_true(json_boolean(v));
+
+ v = json_object_get(a, "action");
+ assert_true(json_is_string(v));
+ assert_string_equal("unknown", json_string_value(v));
+
+ json_free(&o);
+ TALLOC_FREE(msg);
+
+ /*
+ * Test a message with a single attribute, single valued attribute
+ */
+ msg = talloc_zero(ctx, struct ldb_message);
+ ldb_msg_add_string(msg, "attribute", "value");
+
+ o = dsdb_audit_attributes_json(LDB_ADD, msg);
+ assert_true(json_is_object(o.root));
+ assert_int_equal(1, json_object_size(o.root));
+
+ a = json_object_get(o.root, "attribute");
+ assert_true(json_is_object(a));
+ assert_int_equal(1, json_object_size(a));
+
+ v = json_object_get(a, "actions");
+ assert_true(json_is_array(v));
+ assert_int_equal(1, json_array_size(v));
+
+ x = json_array_get(v, 0);
+ assert_int_equal(2, json_object_size(x));
+ y = json_object_get(x, "action");
+ assert_string_equal("add", json_string_value(y));
+
+ y = json_object_get(x, "values");
+ assert_true(json_is_array(y));
+ assert_int_equal(1, json_array_size(y));
+
+ x = json_array_get(y, 0);
+ assert_true(json_is_object(x));
+ assert_int_equal(1, json_object_size(x));
+ y = json_object_get(x, "value");
+ assert_string_equal("value", json_string_value(y));
+
+ json_free(&o);
+ TALLOC_FREE(msg);
+
+ /*
+ * Test a message with a single attribute, single valued attribute
+ * And as a modify
+ */
+ msg = talloc_zero(ctx, struct ldb_message);
+ ldb_msg_add_string(msg, "attribute", "value");
+
+ o = dsdb_audit_attributes_json(LDB_MODIFY, msg);
+ assert_true(json_is_object(o.root));
+ assert_int_equal(1, json_object_size(o.root));
+
+ a = json_object_get(o.root, "attribute");
+ assert_true(json_is_object(a));
+ assert_int_equal(1, json_object_size(a));
+
+ v = json_object_get(a, "actions");
+ assert_true(json_is_array(v));
+ assert_int_equal(1, json_array_size(v));
+
+ x = json_array_get(v, 0);
+ assert_int_equal(2, json_object_size(x));
+ y = json_object_get(x, "action");
+ assert_string_equal("unknown", json_string_value(y));
+
+ y = json_object_get(x, "values");
+ assert_true(json_is_array(y));
+ assert_int_equal(1, json_array_size(y));
+
+ x = json_array_get(y, 0);
+ assert_true(json_is_object(x));
+ assert_int_equal(1, json_object_size(x));
+ y = json_object_get(x, "value");
+ assert_string_equal("value", json_string_value(y));
+
+ json_free(&o);
+ TALLOC_FREE(msg);
+
+ /*
+ * Test a message with a multi-valued attribute
+ */
+ msg = talloc_zero(ctx, struct ldb_message);
+ ldb_msg_add_string(msg, "attribute01", "value01");
+ ldb_msg_add_string(msg, "attribute02", "value02");
+ ldb_msg_add_string(msg, "attribute02", "value03");
+
+ o = dsdb_audit_attributes_json(LDB_ADD, msg);
+ assert_true(json_is_object(o.root));
+ assert_int_equal(2, json_object_size(o.root));
+
+ a = json_object_get(o.root, "attribute01");
+ assert_true(json_is_object(a));
+ assert_int_equal(1, json_object_size(a));
+
+ v = json_object_get(a, "actions");
+ assert_true(json_is_array(v));
+ assert_int_equal(1, json_array_size(v));
+
+ x = json_array_get(v, 0);
+ assert_int_equal(2, json_object_size(x));
+ y = json_object_get(x, "action");
+ assert_string_equal("add", json_string_value(y));
+
+ y = json_object_get(x, "values");
+ assert_true(json_is_array(y));
+ assert_int_equal(1, json_array_size(y));
+
+ x = json_array_get(y, 0);
+ assert_true(json_is_object(x));
+ assert_int_equal(1, json_object_size(x));
+ y = json_object_get(x, "value");
+ assert_string_equal("value01", json_string_value(y));
+
+ a = json_object_get(o.root, "attribute02");
+ assert_true(json_is_object(a));
+ assert_int_equal(1, json_object_size(a));
+
+ v = json_object_get(a, "actions");
+ assert_true(json_is_array(v));
+ assert_int_equal(1, json_array_size(v));
+
+ x = json_array_get(v, 0);
+ assert_int_equal(2, json_object_size(x));
+ y = json_object_get(x, "action");
+ assert_string_equal("add", json_string_value(y));
+
+ y = json_object_get(x, "values");
+ assert_true(json_is_array(y));
+ assert_int_equal(2, json_array_size(y));
+
+ x = json_array_get(y, 0);
+ assert_true(json_is_object(x));
+ assert_int_equal(1, json_object_size(x));
+ v = json_object_get(x, "value");
+ assert_string_equal("value02", json_string_value(v));
+
+ x = json_array_get(y, 1);
+ assert_true(json_is_object(x));
+ assert_int_equal(1, json_object_size(x));
+ v = json_object_get(x, "value");
+ assert_string_equal("value03", json_string_value(v));
+
+ json_free(&o);
+ TALLOC_FREE(msg);
+
+ TALLOC_FREE(ctx);
+}
+
+static void test_dsdb_audit_get_remote_address(void **state)
+{
+ struct ldb_context *ldb = NULL;
+ const struct tsocket_address *ts = NULL;
+ struct tsocket_address *in = NULL;
+
+ TALLOC_CTX *ctx = talloc_new(NULL);
+
+ /*
+ * Test a freshly initialized ldb
+ * should return NULL
+ */
+ ldb = ldb_init(ctx, NULL);
+ ts = dsdb_audit_get_remote_address(ldb);
+ assert_null(ts);
+
+ /*
+ * opaque set to null, should return NULL
+ */
+ ldb_set_opaque(ldb, "remoteAddress", NULL);
+ ts = dsdb_audit_get_remote_address(ldb);
+ assert_null(ts);
+
+ /*
+ * Ensure that the value set is returned
+ */
+ tsocket_address_inet_from_strings(ctx, "ip", "127.0.0.1", 0, &in);
+ ldb_set_opaque(ldb, "remoteAddress", in);
+ ts = dsdb_audit_get_remote_address(ldb);
+ assert_non_null(ts);
+ assert_ptr_equal(in, ts);
+
+ TALLOC_FREE(ldb);
+ TALLOC_FREE(ctx);
+
+}
+
+static void test_dsdb_audit_get_ldb_error_string(void **state)
+{
+ struct ldb_context *ldb = NULL;
+ struct ldb_module *module = NULL;
+ const char *s = NULL;
+ const char * const text = "Custom reason";
+
+ TALLOC_CTX *ctx = talloc_new(NULL);
+
+ ldb = ldb_init(ctx, NULL);
+ module = talloc_zero(ctx, struct ldb_module);
+ module->ldb = ldb;
+
+ /*
+ * No ldb error string set should get the default error description for
+ * the status code
+ */
+ s = dsdb_audit_get_ldb_error_string(module, LDB_ERR_OPERATIONS_ERROR);
+ assert_string_equal("Operations error", s);
+
+ /*
+ * Set the error string that should now be returned instead of the
+ * default description.
+ */
+ ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR, text);
+ s = dsdb_audit_get_ldb_error_string(module, LDB_ERR_OPERATIONS_ERROR);
+ /*
+ * Only test the start of the string as ldb_error adds location data.
+ */
+ assert_int_equal(0, strncmp(text, s, strlen(text)));
+
+ TALLOC_FREE(ctx);
+}
+
+static void test_dsdb_audit_get_user_sid(void **state)
+{
+ struct ldb_context *ldb = NULL;
+ struct ldb_module *module = NULL;
+ const struct dom_sid *sid = NULL;
+ struct auth_session_info *sess = NULL;
+ struct security_token *token = NULL;
+ struct dom_sid sids[2];
+ const char * const SID0 = "S-1-5-21-2470180966-3899876309-2637894779";
+ const char * const SID1 = "S-1-5-21-4284042908-2889457889-3672286761";
+ struct dom_sid_buf sid_buf;
+
+
+ TALLOC_CTX *ctx = talloc_new(NULL);
+
+ ldb = ldb_init(ctx, NULL);
+ module = talloc_zero(ctx, struct ldb_module);
+ module->ldb = ldb;
+
+ /*
+ * Freshly initialised structures, will be no session data
+ * so expect NULL
+ */
+ sid = dsdb_audit_get_user_sid(module);
+ assert_null(sid);
+
+ /*
+ * Now add a NULL session info
+ */
+ ldb_set_opaque(ldb, DSDB_SESSION_INFO, sess);
+ sid = dsdb_audit_get_user_sid(module);
+ assert_null(sid);
+
+ /*
+ * Now add a session info with no user sid
+ */
+ sess = talloc_zero(ctx, struct auth_session_info);
+ ldb_set_opaque(ldb, DSDB_SESSION_INFO, sess);
+ sid = dsdb_audit_get_user_sid(module);
+ assert_null(sid);
+
+ /*
+ * Now add an empty security token.
+ */
+ token = talloc_zero(ctx, struct security_token);
+ sess->security_token = token;
+ sid = dsdb_audit_get_user_sid(module);
+ assert_null(sid);
+
+ /*
+ * Add a single SID
+ */
+ string_to_sid(&sids[0], SID0);
+ token->num_sids = 1;
+ token->sids = sids;
+ sid = dsdb_audit_get_user_sid(module);
+ assert_non_null(sid);
+ dom_sid_str_buf(sid, &sid_buf);
+ assert_string_equal(SID0, sid_buf.buf);
+
+ /*
+ * Add a second SID, should still use the first SID
+ */
+ string_to_sid(&sids[1], SID1);
+ token->num_sids = 2;
+ sid = dsdb_audit_get_user_sid(module);
+ assert_non_null(sid);
+ dom_sid_str_buf(sid, &sid_buf);
+ assert_string_equal(SID0, sid_buf.buf);
+
+
+ /*
+ * Now test a null sid in the first position
+ */
+ token->num_sids = 1;
+ token->sids = NULL;
+ sid = dsdb_audit_get_user_sid(module);
+ assert_null(sid);
+
+ TALLOC_FREE(ctx);
+}
+
+static void test_dsdb_audit_get_actual_sid(void **state)
+{
+ struct ldb_context *ldb = NULL;
+ const struct dom_sid *sid = NULL;
+ struct auth_session_info *sess = NULL;
+ struct security_token *token = NULL;
+ struct dom_sid sids[2];
+ const char * const SID0 = "S-1-5-21-2470180966-3899876309-2637894779";
+ const char * const SID1 = "S-1-5-21-4284042908-2889457889-3672286761";
+ struct dom_sid_buf sid_buf;
+
+
+ TALLOC_CTX *ctx = talloc_new(NULL);
+
+ ldb = ldb_init(ctx, NULL);
+
+ /*
+ * Freshly initialised structures, will be no session data
+ * so expect NULL
+ */
+ sid = dsdb_audit_get_actual_sid(ldb);
+ assert_null(sid);
+
+ /*
+ * Now add a NULL session info
+ */
+ ldb_set_opaque(ldb, DSDB_NETWORK_SESSION_INFO, NULL);
+ sid = dsdb_audit_get_actual_sid(ldb);
+ assert_null(sid);
+
+ /*
+ * Now add a session info with no user sid
+ */
+ sess = talloc_zero(ctx, struct auth_session_info);
+ ldb_set_opaque(ldb, DSDB_NETWORK_SESSION_INFO, sess);
+ sid = dsdb_audit_get_actual_sid(ldb);
+ assert_null(sid);
+
+ /*
+ * Now add an empty security token.
+ */
+ token = talloc_zero(ctx, struct security_token);
+ sess->security_token = token;
+ sid = dsdb_audit_get_actual_sid(ldb);
+ assert_null(sid);
+
+ /*
+ * Add a single SID
+ */
+ string_to_sid(&sids[0], SID0);
+ token->num_sids = 1;
+ token->sids = sids;
+ sid = dsdb_audit_get_actual_sid(ldb);
+ assert_non_null(sid);
+ dom_sid_str_buf(sid, &sid_buf);
+ assert_string_equal(SID0, sid_buf.buf);
+
+ /*
+ * Add a second SID, should still use the first SID
+ */
+ string_to_sid(&sids[1], SID1);
+ token->num_sids = 2;
+ sid = dsdb_audit_get_actual_sid(ldb);
+ assert_non_null(sid);
+ dom_sid_str_buf(sid, &sid_buf);
+ assert_string_equal(SID0, sid_buf.buf);
+
+
+ /*
+ * Now test a null sid in the first position
+ */
+ token->num_sids = 1;
+ token->sids = NULL;
+ sid = dsdb_audit_get_actual_sid(ldb);
+ assert_null(sid);
+
+ TALLOC_FREE(ctx);
+}
+
+static void test_dsdb_audit_is_system_session(void **state)
+{
+ struct ldb_context *ldb = NULL;
+ struct ldb_module *module = NULL;
+ const struct dom_sid *sid = NULL;
+ struct auth_session_info *sess = NULL;
+ struct security_token *token = NULL;
+ struct dom_sid sids[2];
+ const char * const SID0 = "S-1-5-21-2470180966-3899876309-2637894779";
+ const char * const SID1 = "S-1-5-21-4284042908-2889457889-3672286761";
+
+
+ TALLOC_CTX *ctx = talloc_new(NULL);
+
+ ldb = ldb_init(ctx, NULL);
+ module = talloc_zero(ctx, struct ldb_module);
+ module->ldb = ldb;
+
+ /*
+ * Freshly initialised structures, will be no session data
+ * so expect NULL
+ */
+ assert_false(dsdb_audit_is_system_session(module));
+
+ /*
+ * Now add a NULL session info
+ */
+ ldb_set_opaque(ldb, DSDB_SESSION_INFO, NULL);
+ assert_false(dsdb_audit_is_system_session(module));
+
+ /*
+ * Now add a session info with no user sid
+ */
+ sess = talloc_zero(ctx, struct auth_session_info);
+ ldb_set_opaque(ldb, DSDB_SESSION_INFO, sess);
+ assert_false(dsdb_audit_is_system_session(module));
+
+ /*
+ * Now add an empty security token.
+ */
+ token = talloc_zero(ctx, struct security_token);
+ sess->security_token = token;
+ assert_false(dsdb_audit_is_system_session(module));
+
+ /*
+ * Add a single SID, non system sid
+ */
+ string_to_sid(&sids[0], SID0);
+ token->num_sids = 1;
+ token->sids = sids;
+ assert_false(dsdb_audit_is_system_session(module));
+
+ /*
+ * Add the system SID to the second position,
+ * this should be ignored.
+ */
+ token->num_sids = 2;
+ sids[1] = global_sid_System;
+ assert_false(dsdb_audit_is_system_session(module));
+
+ /*
+ * Add a single SID, system sid
+ */
+ token->num_sids = 1;
+ sids[0] = global_sid_System;
+ token->sids = sids;
+ assert_true(dsdb_audit_is_system_session(module));
+
+ /*
+ * Add a non system SID to position 2
+ */
+ sids[0] = global_sid_System;
+ string_to_sid(&sids[1], SID1);
+ token->num_sids = 2;
+ token->sids = sids;
+ assert_true(dsdb_audit_is_system_session(module));
+
+ /*
+ * Now test a null sid in the first position
+ */
+ token->num_sids = 1;
+ token->sids = NULL;
+ sid = dsdb_audit_get_user_sid(module);
+ assert_null(sid);
+
+ TALLOC_FREE(ctx);
+}
+
+static void test_dsdb_audit_get_unique_session_token(void **state)
+{
+ struct ldb_context *ldb = NULL;
+ struct ldb_module *module = NULL;
+ struct auth_session_info *sess = NULL;
+ const struct GUID *guid;
+ const char * const GUID_S = "7130cb06-2062-6a1b-409e-3514c26b1773";
+ struct GUID in;
+ char *guid_str;
+ struct GUID_txt_buf guid_buff;
+
+
+ TALLOC_CTX *ctx = talloc_new(NULL);
+
+ ldb = ldb_init(ctx, NULL);
+ module = talloc_zero(ctx, struct ldb_module);
+ module->ldb = ldb;
+
+ /*
+ * Test a freshly initialized ldb
+ * should return NULL
+ */
+ guid = dsdb_audit_get_unique_session_token(module);
+ assert_null(guid);
+
+ /*
+ * Now add a NULL session info
+ */
+ ldb_set_opaque(ldb, DSDB_SESSION_INFO, NULL);
+ guid = dsdb_audit_get_unique_session_token(module);
+ assert_null(guid);
+
+ /*
+ * Now add a session info with no session id
+ * Note if the memory has not been zeroed correctly all bets are
+ * probably off.
+ */
+ sess = talloc_zero(ctx, struct auth_session_info);
+ ldb_set_opaque(ldb, DSDB_SESSION_INFO, sess);
+ guid = dsdb_audit_get_unique_session_token(module);
+ /*
+ * We will get a GUID, but it's contents will be undefined
+ */
+ assert_non_null(guid);
+
+ /*
+ * Now set the session id and confirm that we get it back.
+ */
+ GUID_from_string(GUID_S, &in);
+ sess->unique_session_token = in;
+ guid = dsdb_audit_get_unique_session_token(module);
+ assert_non_null(guid);
+ guid_str = GUID_buf_string(guid, &guid_buff);
+ assert_string_equal(GUID_S, guid_str);
+
+ TALLOC_FREE(ctx);
+
+}
+
+static void test_dsdb_audit_get_actual_unique_session_token(void **state)
+{
+ struct ldb_context *ldb = NULL;
+ struct auth_session_info *sess = NULL;
+ const struct GUID *guid;
+ const char * const GUID_S = "7130cb06-2062-6a1b-409e-3514c26b1773";
+ struct GUID in;
+ char *guid_str;
+ struct GUID_txt_buf guid_buff;
+
+
+ TALLOC_CTX *ctx = talloc_new(NULL);
+
+ ldb = ldb_init(ctx, NULL);
+
+ /*
+ * Test a freshly initialized ldb
+ * should return NULL
+ */
+ guid = dsdb_audit_get_actual_unique_session_token(ldb);
+ assert_null(guid);
+
+ /*
+ * Now add a NULL session info
+ */
+ ldb_set_opaque(ldb, DSDB_NETWORK_SESSION_INFO, NULL);
+ guid = dsdb_audit_get_actual_unique_session_token(ldb);
+ assert_null(guid);
+
+ /*
+ * Now add a session info with no session id
+ * Note if the memory has not been zeroed correctly all bets are
+ * probably off.
+ */
+ sess = talloc_zero(ctx, struct auth_session_info);
+ ldb_set_opaque(ldb, DSDB_NETWORK_SESSION_INFO, sess);
+ guid = dsdb_audit_get_actual_unique_session_token(ldb);
+ /*
+ * We will get a GUID, but it's contents will be undefined
+ */
+ assert_non_null(guid);
+
+ /*
+ * Now set the session id and confirm that we get it back.
+ */
+ GUID_from_string(GUID_S, &in);
+ sess->unique_session_token = in;
+ guid = dsdb_audit_get_actual_unique_session_token(ldb);
+ assert_non_null(guid);
+ guid_str = GUID_buf_string(guid, &guid_buff);
+ assert_string_equal(GUID_S, guid_str);
+
+ TALLOC_FREE(ctx);
+
+}
+
+static void test_dsdb_audit_get_remote_host(void **state)
+{
+ struct ldb_context *ldb = NULL;
+ char *rh = NULL;
+ struct tsocket_address *in = NULL;
+
+ TALLOC_CTX *ctx = talloc_new(NULL);
+
+ ldb = ldb_init(ctx, NULL);
+
+ /*
+ * Test a freshly initialized ldb
+ * should return "Unknown"
+ */
+ rh = dsdb_audit_get_remote_host(ldb, ctx);
+ assert_string_equal("Unknown", rh);
+ TALLOC_FREE(rh);
+
+ /*
+ * opaque set to null, should return NULL
+ */
+ ldb_set_opaque(ldb, "remoteAddress", NULL);
+ rh = dsdb_audit_get_remote_host(ldb, ctx);
+ assert_string_equal("Unknown", rh);
+ TALLOC_FREE(rh);
+
+ /*
+ * Ensure that the value set is returned
+ */
+ tsocket_address_inet_from_strings(ctx, "ip", "127.0.0.1", 42, &in);
+ ldb_set_opaque(ldb, "remoteAddress", in);
+ rh = dsdb_audit_get_remote_host(ldb, ctx);
+ assert_string_equal("ipv4:127.0.0.1:42", rh);
+ TALLOC_FREE(rh);
+
+ TALLOC_FREE(ctx);
+
+}
+
+static void test_dsdb_audit_get_primary_dn(void **state)
+{
+ struct ldb_request *req = NULL;
+ struct ldb_message *msg = NULL;
+ struct ldb_context *ldb = NULL;
+
+ struct ldb_dn *dn = NULL;
+
+ const char * const DN = "dn=CN=USER,CN=Users,DC=SAMBA,DC=ORG";
+ const char *s = NULL;
+
+ TALLOC_CTX *ctx = talloc_new(NULL);
+
+ req = talloc_zero(ctx, struct ldb_request);
+ msg = talloc_zero(ctx, struct ldb_message);
+ ldb = ldb_init(ctx, NULL);
+ dn = ldb_dn_new(ctx, ldb, DN);
+
+ /*
+ * Try an empty request.
+ */
+ s = dsdb_audit_get_primary_dn(req);
+ assert_null(s);
+
+ /*
+ * Now try an add with a null message.
+ */
+ req->operation = LDB_ADD;
+ req->op.add.message = NULL;
+ s = dsdb_audit_get_primary_dn(req);
+ assert_null(s);
+
+ /*
+ * Now try an mod with a null message.
+ */
+ req->operation = LDB_MODIFY;
+ req->op.mod.message = NULL;
+ s = dsdb_audit_get_primary_dn(req);
+ assert_null(s);
+
+ /*
+ * Now try an add with a missing dn
+ */
+ req->operation = LDB_ADD;
+ req->op.add.message = msg;
+ s = dsdb_audit_get_primary_dn(req);
+ assert_null(s);
+
+ /*
+ * Now try a mod with a messing dn
+ */
+ req->operation = LDB_ADD;
+ req->op.mod.message = msg;
+ s = dsdb_audit_get_primary_dn(req);
+ assert_null(s);
+
+ /*
+ * Add a dn to the message
+ */
+ msg->dn = dn;
+
+ /*
+ * Now try an add with a dn
+ */
+ req->operation = LDB_ADD;
+ req->op.add.message = msg;
+ s = dsdb_audit_get_primary_dn(req);
+ assert_non_null(s);
+ assert_string_equal(DN, s);
+
+ /*
+ * Now try a mod with a dn
+ */
+ req->operation = LDB_MODIFY;
+ req->op.mod.message = msg;
+ s = dsdb_audit_get_primary_dn(req);
+ assert_non_null(s);
+ assert_string_equal(DN, s);
+
+ /*
+ * Try a delete without a dn
+ */
+ req->operation = LDB_DELETE;
+ req->op.del.dn = NULL;
+ s = dsdb_audit_get_primary_dn(req);
+ assert_null(s);
+
+ /*
+ * Try a delete with a dn
+ */
+ req->operation = LDB_DELETE;
+ req->op.del.dn = dn;
+ s = dsdb_audit_get_primary_dn(req);
+ assert_non_null(s);
+ assert_string_equal(DN, s);
+
+ /*
+ * Try a rename without a dn
+ */
+ req->operation = LDB_RENAME;
+ req->op.rename.olddn = NULL;
+ s = dsdb_audit_get_primary_dn(req);
+ assert_null(s);
+
+ /*
+ * Try a rename with a dn
+ */
+ req->operation = LDB_RENAME;
+ req->op.rename.olddn = dn;
+ s = dsdb_audit_get_primary_dn(req);
+ assert_non_null(s);
+ assert_string_equal(DN, s);
+
+ /*
+ * Try an extended operation, i.e. one that does not have a DN
+ * associated with it for logging purposes.
+ */
+ req->operation = LDB_EXTENDED;
+ s = dsdb_audit_get_primary_dn(req);
+ assert_null(s);
+
+ TALLOC_FREE(ctx);
+}
+
+static void test_dsdb_audit_get_message(void **state)
+{
+ struct ldb_request *req = NULL;
+ struct ldb_message *msg = NULL;
+ const struct ldb_message *r = NULL;
+
+
+ TALLOC_CTX *ctx = talloc_new(NULL);
+
+ req = talloc_zero(ctx, struct ldb_request);
+ msg = talloc_zero(ctx, struct ldb_message);
+
+ /*
+ * Test an empty message
+ */
+ r = dsdb_audit_get_message(req);
+ assert_null(r);
+
+ /*
+ * Test an add message
+ */
+ req->operation = LDB_ADD;
+ req->op.add.message = msg;
+ r = dsdb_audit_get_message(req);
+ assert_ptr_equal(msg, r);
+
+ /*
+ * Test a modify message
+ */
+ req->operation = LDB_MODIFY;
+ req->op.mod.message = msg;
+ r = dsdb_audit_get_message(req);
+ assert_ptr_equal(msg, r);
+
+ /*
+ * Test a Delete message, i.e. trigger the default case
+ */
+ req->operation = LDB_DELETE;
+ r = dsdb_audit_get_message(req);
+ assert_null(r);
+
+ TALLOC_FREE(ctx);
+}
+
+static void test_dsdb_audit_get_secondary_dn(void **state)
+{
+ struct ldb_request *req = NULL;
+ struct ldb_context *ldb = NULL;
+
+ struct ldb_dn *dn = NULL;
+
+ const char * const DN = "dn=CN=USER,CN=Users,DC=SAMBA,DC=ORG";
+ const char *s = NULL;
+
+ TALLOC_CTX *ctx = talloc_new(NULL);
+
+ req = talloc_zero(ctx, struct ldb_request);
+ ldb = ldb_init(ctx, NULL);
+ dn = ldb_dn_new(ctx, ldb, DN);
+
+ /*
+ * Try an empty request.
+ */
+ s = dsdb_audit_get_secondary_dn(req);
+ assert_null(s);
+
+ /*
+ * Try a rename without a dn
+ */
+ req->operation = LDB_RENAME;
+ req->op.rename.newdn = NULL;
+ s = dsdb_audit_get_secondary_dn(req);
+ assert_null(s);
+
+ /*
+ * Try a rename with a dn
+ */
+ req->operation = LDB_RENAME;
+ req->op.rename.newdn = dn;
+ s = dsdb_audit_get_secondary_dn(req);
+ assert_non_null(s);
+ assert_string_equal(DN, s);
+
+ /*
+ * Try an extended operation, i.e. one that does not have a DN
+ * associated with it for logging purposes.
+ */
+ req->operation = LDB_EXTENDED;
+ s = dsdb_audit_get_primary_dn(req);
+ assert_null(s);
+
+ TALLOC_FREE(ctx);
+}
+
+static void test_dsdb_audit_get_operation_name(void **state)
+{
+ struct ldb_request *req = NULL;
+
+ TALLOC_CTX *ctx = talloc_new(NULL);
+
+ req = talloc_zero(ctx, struct ldb_request);
+
+ req->operation = LDB_SEARCH;
+ assert_string_equal("Search", dsdb_audit_get_operation_name(req));
+
+ req->operation = LDB_ADD;
+ assert_string_equal("Add", dsdb_audit_get_operation_name(req));
+
+ req->operation = LDB_MODIFY;
+ assert_string_equal("Modify", dsdb_audit_get_operation_name(req));
+
+ req->operation = LDB_DELETE;
+ assert_string_equal("Delete", dsdb_audit_get_operation_name(req));
+
+ req->operation = LDB_RENAME;
+ assert_string_equal("Rename", dsdb_audit_get_operation_name(req));
+
+ req->operation = LDB_EXTENDED;
+ assert_string_equal("Extended", dsdb_audit_get_operation_name(req));
+
+ req->operation = LDB_REQ_REGISTER_CONTROL;
+ assert_string_equal(
+ "Register Control",
+ dsdb_audit_get_operation_name(req));
+
+ req->operation = LDB_REQ_REGISTER_PARTITION;
+ assert_string_equal(
+ "Register Partition",
+ dsdb_audit_get_operation_name(req));
+
+ /*
+ * Trigger the default case
+ */
+ req->operation = -1;
+ assert_string_equal("Unknown", dsdb_audit_get_operation_name(req));
+
+ TALLOC_FREE(ctx);
+}
+
+static void test_dsdb_audit_get_modification_action(void **state)
+{
+ assert_string_equal(
+ "add",
+ dsdb_audit_get_modification_action(LDB_FLAG_MOD_ADD));
+ assert_string_equal(
+ "delete",
+ dsdb_audit_get_modification_action(LDB_FLAG_MOD_DELETE));
+ assert_string_equal(
+ "replace",
+ dsdb_audit_get_modification_action(LDB_FLAG_MOD_REPLACE));
+ /*
+ * Trigger the default case
+ */
+ assert_string_equal(
+ "unknown",
+ dsdb_audit_get_modification_action(0));
+}
+
+static void test_dsdb_audit_is_password_attribute(void **state)
+{
+ assert_true(dsdb_audit_is_password_attribute("userPassword"));
+ assert_true(dsdb_audit_is_password_attribute("clearTextPassword"));
+ assert_true(dsdb_audit_is_password_attribute("unicodePwd"));
+ assert_true(dsdb_audit_is_password_attribute("dBCSPwd"));
+
+ assert_false(dsdb_audit_is_password_attribute("xserPassword"));
+}
+
+static void test_dsdb_audit_redact_attribute(void **state)
+{
+ assert_true(dsdb_audit_redact_attribute("userPassword"));
+
+ assert_true(dsdb_audit_redact_attribute("pekList"));
+ assert_true(dsdb_audit_redact_attribute("clearTextPassword"));
+ assert_true(dsdb_audit_redact_attribute("initialAuthIncoming"));
+
+ assert_false(dsdb_audit_redact_attribute("supaskrt"));
+}
+
+int main(void) {
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_dsdb_audit_add_ldb_value),
+ cmocka_unit_test(test_dsdb_audit_attributes_json),
+ cmocka_unit_test(test_dsdb_audit_get_remote_address),
+ cmocka_unit_test(test_dsdb_audit_get_ldb_error_string),
+ cmocka_unit_test(test_dsdb_audit_get_user_sid),
+ cmocka_unit_test(test_dsdb_audit_get_actual_sid),
+ cmocka_unit_test(test_dsdb_audit_is_system_session),
+ cmocka_unit_test(test_dsdb_audit_get_unique_session_token),
+ cmocka_unit_test(test_dsdb_audit_get_actual_unique_session_token),
+ cmocka_unit_test(test_dsdb_audit_get_remote_host),
+ cmocka_unit_test(test_dsdb_audit_get_primary_dn),
+ cmocka_unit_test(test_dsdb_audit_get_message),
+ cmocka_unit_test(test_dsdb_audit_get_secondary_dn),
+ cmocka_unit_test(test_dsdb_audit_get_operation_name),
+ cmocka_unit_test(test_dsdb_audit_get_modification_action),
+ cmocka_unit_test(test_dsdb_audit_is_password_attribute),
+ cmocka_unit_test(test_dsdb_audit_redact_attribute),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}