summaryrefslogtreecommitdiffstats
path: root/src/tests
diff options
context:
space:
mode:
Diffstat (limited to 'src/tests')
-rw-r--r--src/tests/auth-tests.c343
-rw-r--r--src/tests/check_and_open-tests.c218
-rw-r--r--src/tests/common.c109
-rw-r--r--src/tests/common.h21
-rw-r--r--src/tests/fail_over-tests.c304
-rw-r--r--src/tests/files-tests.c323
-rw-r--r--src/tests/find_uid-tests.c125
-rw-r--r--src/tests/ipa_ldap_opt-tests.c59
-rw-r--r--src/tests/ipa_timerules-tests.c580
-rw-r--r--src/tests/krb5_utils-tests.c307
-rw-r--r--src/tests/python-test.py445
-rw-r--r--src/tests/refcount-tests.c232
-rw-r--r--src/tests/resolv-tests.c598
-rw-r--r--src/tests/stress-tests.c328
-rw-r--r--src/tests/strtonum-tests.c455
-rw-r--r--src/tests/sysdb-tests.c3330
16 files changed, 7777 insertions, 0 deletions
diff --git a/src/tests/auth-tests.c b/src/tests/auth-tests.c
new file mode 100644
index 000000000..71215bcd2
--- /dev/null
+++ b/src/tests/auth-tests.c
@@ -0,0 +1,343 @@
+/*
+ SSSD
+
+ Test for local authentication utilities
+
+ Authors:
+ Sumit Bose <sbose@redhat.com>
+
+ Copyright (C) 2010 Red Hat
+
+ 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 <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <string.h>
+#include <popt.h>
+#include <talloc.h>
+#include <tevent.h>
+
+#include <check.h>
+
+#include "util/util.h"
+#include "confdb/confdb.h"
+#include "db/sysdb.h"
+
+#define TESTS_PATH "tests_auth"
+#define TEST_CONF_FILE "tests_conf.ldb"
+
+struct sysdb_test_ctx {
+ struct sysdb_ctx *sysdb;
+ struct confdb_ctx *confdb;
+ struct tevent_context *ev;
+ struct sss_domain_info *domain;
+};
+
+static int setup_sysdb_tests(struct sysdb_test_ctx **ctx)
+{
+ struct sysdb_test_ctx *test_ctx;
+ char *conf_db;
+ int ret;
+
+ const char *val[2];
+ val[1] = NULL;
+
+ /* Create tests directory if it doesn't exist */
+ /* (relative to current dir) */
+ ret = mkdir(TESTS_PATH, 0775);
+ if (ret == -1 && errno != EEXIST) {
+ fail("Could not create %s directory", TESTS_PATH);
+ return EFAULT;
+ }
+
+ test_ctx = talloc_zero(NULL, struct sysdb_test_ctx);
+ if (test_ctx == NULL) {
+ fail("Could not allocate memory for test context");
+ return ENOMEM;
+ }
+
+ /* Create an event context
+ * It will not be used except in confdb_init and sysdb_init
+ */
+ test_ctx->ev = tevent_context_init(test_ctx);
+ if (test_ctx->ev == NULL) {
+ fail("Could not create event context");
+ talloc_free(test_ctx);
+ return EIO;
+ }
+
+ conf_db = talloc_asprintf(test_ctx, "%s/%s", TESTS_PATH, TEST_CONF_FILE);
+ if (conf_db == NULL) {
+ fail("Out of memory, aborting!");
+ talloc_free(test_ctx);
+ return ENOMEM;
+ }
+ DEBUG(3, ("CONFDB: %s\n", conf_db));
+
+ /* Connect to the conf db */
+ ret = confdb_init(test_ctx, &test_ctx->confdb, conf_db);
+ if (ret != EOK) {
+ fail("Could not initialize connection to the confdb");
+ talloc_free(test_ctx);
+ return ret;
+ }
+
+ val[0] = "LOCAL";
+ ret = confdb_add_param(test_ctx->confdb, true,
+ "config/sssd", "domains", val);
+ if (ret != EOK) {
+ fail("Could not initialize domains placeholder");
+ talloc_free(test_ctx);
+ return ret;
+ }
+
+ val[0] = "local";
+ ret = confdb_add_param(test_ctx->confdb, true,
+ "config/domain/LOCAL", "id_provider", val);
+ if (ret != EOK) {
+ fail("Could not initialize provider");
+ talloc_free(test_ctx);
+ return ret;
+ }
+
+ val[0] = "TRUE";
+ ret = confdb_add_param(test_ctx->confdb, true,
+ "config/domain/LOCAL", "enumerate", val);
+ if (ret != EOK) {
+ fail("Could not initialize LOCAL domain");
+ talloc_free(test_ctx);
+ return ret;
+ }
+
+ val[0] = "TRUE";
+ ret = confdb_add_param(test_ctx->confdb, true,
+ "config/domain/LOCAL", "cache_credentials", val);
+ if (ret != EOK) {
+ fail("Could not initialize LOCAL domain");
+ talloc_free(test_ctx);
+ return ret;
+ }
+
+ ret = confdb_get_domain(test_ctx->confdb, "local", &test_ctx->domain);
+ if (ret != EOK) {
+ fail("Could not retrieve LOCAL domain");
+ talloc_free(test_ctx);
+ return ret;
+ }
+
+ ret = sysdb_domain_init(test_ctx, test_ctx->ev,
+ test_ctx->domain, TESTS_PATH, &test_ctx->sysdb);
+ if (ret != EOK) {
+ fail("Could not initialize connection to the sysdb (%d)", ret);
+ talloc_free(test_ctx);
+ return ret;
+ }
+
+ *ctx = test_ctx;
+ return EOK;
+}
+
+static void do_failed_login_test(uint32_t failed_login_attempts,
+ time_t last_failed_login,
+ int offline_failed_login_attempts,
+ int offline_failed_login_delay,
+ int expected_result,
+ int expected_counter,
+ time_t expected_delay)
+{
+ struct sysdb_test_ctx *test_ctx;
+ int ret;
+ const char *val[2];
+ val[1] = NULL;
+ struct ldb_message *ldb_msg;
+ uint32_t returned_failed_login_attempts;
+ time_t delayed_until;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ fail_unless(ret == EOK, "Could not set up the test");
+
+ val[0] = talloc_asprintf(test_ctx, "%u", offline_failed_login_attempts);
+ fail_unless(val[0] != NULL, "talloc_sprintf failed");
+ ret = confdb_add_param(test_ctx->confdb, true,
+ "config/pam", CONFDB_PAM_FAILED_LOGIN_ATTEMPTS, val);
+ fail_unless(ret == EOK, "Could not set offline_failed_login_attempts");
+
+ val[0] = talloc_asprintf(test_ctx, "%u", offline_failed_login_delay);
+ ret = confdb_add_param(test_ctx->confdb, true,
+ "config/pam", CONFDB_PAM_FAILED_LOGIN_DELAY, val);
+ fail_unless(ret == EOK, "Could not set offline_failed_login_delay");
+
+ ldb_msg = ldb_msg_new(test_ctx);
+ fail_unless(ldb_msg != NULL, "ldb_msg_new failed");
+
+ ret = ldb_msg_add_fmt(ldb_msg, SYSDB_FAILED_LOGIN_ATTEMPTS, "%u",
+ failed_login_attempts);
+ fail_unless(ret == EOK, "ldb_msg_add_string failed");
+
+ ret = ldb_msg_add_fmt(ldb_msg, SYSDB_LAST_FAILED_LOGIN, "%lld",
+ (long long) last_failed_login);
+ fail_unless(ret == EOK, "ldb_msg_add_string failed");
+
+ ret = check_failed_login_attempts(test_ctx, test_ctx->confdb, ldb_msg,
+ &returned_failed_login_attempts,
+ &delayed_until);
+ fail_unless(ret == expected_result,
+ "check_failed_login_attempts returned wrong error code, "
+ "expected [%d], got [%d]", expected_result, ret);
+
+ fail_unless(returned_failed_login_attempts == expected_counter,
+ "check_failed_login_attempts returned wrong number of failed "
+ "login attempts, expected [%d], got [%d]",
+ expected_counter, failed_login_attempts);
+
+ fail_unless(delayed_until == expected_delay,
+ "check_failed_login_attempts wrong delay, "
+ "expected [%d], got [%d]",
+ expected_delay, delayed_until);
+
+ talloc_free(test_ctx);
+}
+
+START_TEST(test_failed_login_attempts)
+{
+ time_t now;
+
+ /* if offline_failed_login_attempts == 0 a login is never denied */
+ do_failed_login_test(0, 0, 0, 5, EOK, 0, -1);
+ do_failed_login_test(0, time(NULL), 0, 5, EOK, 0, -1);
+ do_failed_login_test(2, 0, 0, 5, EOK, 2, -1);
+ do_failed_login_test(2, time(NULL), 0, 5, EOK, 2, -1);
+
+ do_failed_login_test(0, 0, 0, 0, EOK, 0, -1);
+ do_failed_login_test(0, time(NULL), 0, 0, EOK, 0, -1);
+ do_failed_login_test(2, 0, 0, 0, EOK, 2, -1);
+ do_failed_login_test(2, time(NULL), 0, 0, EOK, 2, -1);
+
+ /* if offline_failed_login_attempts != 0 and
+ * offline_failed_login_delay == 0 a login is denied if the number of
+ * failed attempts >= offline_failed_login_attempts */
+ do_failed_login_test(0, 0, 2, 0, EOK, 0, -1);
+ do_failed_login_test(0, time(NULL), 2, 0, EOK, 0, -1);
+ do_failed_login_test(2, 0, 2, 0, EACCES, 2, -1);
+ do_failed_login_test(2, time(NULL), 2, 0, EACCES, 2, -1);
+
+ /* if offline_failed_login_attempts != 0 and
+ * offline_failed_login_delay != 0 a login is denied only if the number of
+ * failed attempts >= offline_failed_login_attempts AND the last failed
+ * login attempt is not longer than offline_failed_login_delay ago */
+ do_failed_login_test(0, 0, 2, 5, EOK, 0, -1);
+ do_failed_login_test(0, time(NULL), 2, 5, EOK, 0, -1);
+ do_failed_login_test(2, 0, 2, 5, EOK, 0, -1);
+ now = time(NULL);
+ do_failed_login_test(2, now, 2, 5, EACCES, 2, (now + 5 * 60));
+
+}
+END_TEST
+
+Suite *auth_suite (void)
+{
+ Suite *s = suite_create ("auth");
+
+ TCase *tc_auth = tcase_create ("auth");
+
+ tcase_add_test (tc_auth, test_failed_login_attempts);
+ tcase_set_timeout(tc_auth, 60);
+
+ suite_add_tcase (s, tc_auth);
+
+ return s;
+}
+
+static int clean_db_dir(void)
+{
+ int ret;
+
+ ret = unlink(TESTS_PATH"/"TEST_CONF_FILE);
+ if (ret != EOK && errno != ENOENT) {
+ fprintf(stderr, "Could not delete the test config ldb file (%d) (%s)\n",
+ errno, strerror(errno));
+ return ret;
+ }
+
+ ret = unlink(TESTS_PATH"/"LOCAL_SYSDB_FILE);
+ if (ret != EOK && errno != ENOENT) {
+ fprintf(stderr, "Could not delete the test config ldb file (%d) (%s)\n",
+ errno, strerror(errno));
+ return ret;
+ }
+
+ ret = rmdir(TESTS_PATH);
+ if (ret != EOK && errno != ENOENT) {
+ fprintf(stderr, "Could not delete the test directory (%d) (%s)\n",
+ errno, strerror(errno));
+ return ret;
+ }
+
+ return EOK;
+}
+
+int main(int argc, const char *argv[])
+{
+ int ret;
+ int opt;
+ int failure_count;
+ poptContext pc;
+ Suite *s = auth_suite ();
+ SRunner *sr = srunner_create (s);
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ SSSD_MAIN_OPTS
+ { NULL }
+ };
+
+ pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch(opt) {
+ default:
+ fprintf(stderr, "\nInvalid option %s: %s\n\n",
+ poptBadOption(pc, 0), poptStrerror(opt));
+ poptPrintUsage(pc, stderr, 0);
+ return 1;
+ }
+ }
+ poptFreeContext(pc);
+
+ ret = clean_db_dir();
+ if (ret != EOK) {
+ fprintf(stderr, "Could not delete the db directory (%d) (%s)\n",
+ errno, strerror(errno));
+ return EXIT_FAILURE;
+ }
+
+ srunner_run_all(sr, CK_ENV);
+ failure_count = srunner_ntests_failed (sr);
+ srunner_free (sr);
+ if (failure_count == 0) {
+ ret = clean_db_dir();
+ if (ret != EOK) {
+ fprintf(stderr, "Could not delete the db directory (%d) (%s)\n",
+ errno, strerror(errno));
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+ }
+ return EXIT_FAILURE;
+}
diff --git a/src/tests/check_and_open-tests.c b/src/tests/check_and_open-tests.c
new file mode 100644
index 000000000..b0d638b55
--- /dev/null
+++ b/src/tests/check_and_open-tests.c
@@ -0,0 +1,218 @@
+/*
+ SSSD
+
+ Utilities tests check_and_open
+
+ Authors:
+ Sumit Bose <sbose@redhat.com>
+
+ Copyright (C) 2009 Red Hat
+
+ 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 <stdlib.h>
+#include <check.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "util/util.h"
+
+#define SUFFIX ".symlink"
+
+#define FILENAME_TEMPLATE "check_and_open-tests-XXXXXX"
+char *filename;
+uid_t uid;
+gid_t gid;
+mode_t mode;
+int fd;
+
+void setup_check_and_open(void)
+{
+ int ret;
+
+ filename = strdup(FILENAME_TEMPLATE);
+ fail_unless(filename != NULL, "strdup failed");
+ ret = mkstemp(filename);
+ fail_unless(ret != -1, "mkstemp failed [%d][%s]", errno, strerror(errno));
+ close(ret);
+
+ uid = getuid();
+ gid = getgid();
+ mode = (S_IRUSR | S_IWUSR);
+ fd = -1;
+}
+
+void teardown_check_and_open(void)
+{
+ int ret;
+
+ if (fd != -1) {
+ ret = close(fd);
+ fail_unless(ret == 0, "close failed [%d][%s]", errno, strerror(errno));
+ }
+
+ fail_unless(filename != NULL, "unknown filename");
+ ret = unlink(filename);
+ free(filename);
+ fail_unless(ret == 0, "unlink failed [%d][%s]", errno, strerror(errno));
+}
+
+START_TEST(test_wrong_filename)
+{
+ int ret;
+
+ ret = check_and_open_readonly("/bla/bla/bla", &fd, uid, gid, mode);
+ fail_unless(ret == ENOENT,
+ "check_and_open_readonly succeeded on non-existing file");
+ fail_unless(fd == -1, "check_and_open_readonly file descriptor not -1");
+}
+END_TEST
+
+START_TEST(test_symlink)
+{
+ int ret;
+ char *newpath;
+ size_t newpath_length;
+
+ newpath_length = strlen(filename) + strlen(SUFFIX) + 1;
+ newpath = malloc((newpath_length) * sizeof(char));
+ fail_unless(newpath != NULL, "malloc failed");
+
+ ret = snprintf(newpath, newpath_length, "%s%s", filename, SUFFIX);
+ fail_unless(ret == newpath_length - 1,
+ "snprintf failed: expected [%d] got [%d]", newpath_length -1,
+ ret);
+
+ ret = symlink(filename, newpath);
+ fail_unless(ret == 0, "symlink failed [%d][%s]", ret, strerror(ret));
+
+ ret = check_and_open_readonly(newpath, &fd, uid, gid, mode);
+ unlink(newpath);
+ fail_unless(ret == EINVAL,
+ "check_and_open_readonly succeeded on symlink");
+ fail_unless(fd == -1, "check_and_open_readonly file descriptor not -1");
+}
+END_TEST
+
+START_TEST(test_not_regular_file)
+{
+ int ret;
+
+ ret = check_and_open_readonly("/dev/null", &fd, uid, gid, mode);
+ fail_unless(ret == EINVAL,
+ "check_and_open_readonly succeeded on non-regular file");
+ fail_unless(fd == -1, "check_and_open_readonly file descriptor not -1");
+}
+END_TEST
+
+START_TEST(test_wrong_uid)
+{
+ int ret;
+
+ ret = check_and_open_readonly(filename, &fd, uid+1, gid, mode);
+ fail_unless(ret == EINVAL,
+ "check_and_open_readonly succeeded with wrong uid");
+ fail_unless(fd == -1, "check_and_open_readonly file descriptor not -1");
+}
+END_TEST
+
+START_TEST(test_wrong_gid)
+{
+ int ret;
+
+ ret = check_and_open_readonly(filename, &fd, uid, gid+1, mode);
+ fail_unless(ret == EINVAL,
+ "check_and_open_readonly succeeded with wrong gid");
+ fail_unless(fd == -1, "check_and_open_readonly file descriptor not -1");
+}
+END_TEST
+
+START_TEST(test_wrong_permission)
+{
+ int ret;
+
+ ret = check_and_open_readonly(filename, &fd, uid, gid, (mode|S_IWOTH));
+ fail_unless(ret == EINVAL,
+ "check_and_open_readonly succeeded with wrong mode");
+ fail_unless(fd == -1, "check_and_open_readonly file descriptor not -1");
+}
+END_TEST
+
+START_TEST(test_ok)
+{
+ int ret;
+
+ ret = check_and_open_readonly(filename, &fd, uid, gid, mode);
+ fail_unless(ret == EOK,
+ "check_and_open_readonly failed");
+ fail_unless(fd >= 0,
+ "check_and_open_readonly returned illegal file descriptor");
+}
+END_TEST
+
+START_TEST(test_write)
+{
+ int ret;
+ ssize_t size;
+ errno_t my_errno;
+
+ ret = check_and_open_readonly(filename, &fd, uid, gid, mode);
+ fail_unless(ret == EOK,
+ "check_and_open_readonly failed");
+ fail_unless(fd >= 0,
+ "check_and_open_readonly returned illegal file descriptor");
+
+ size = write(fd, "abc", 3);
+ my_errno = errno;
+ fail_unless(size == -1, "check_and_open_readonly file is not readonly");
+ fail_unless(my_errno == EBADF,
+ "write failed for other reason than readonly");
+}
+END_TEST
+
+Suite *check_and_open_suite (void)
+{
+ Suite *s = suite_create ("check_and_open");
+
+ TCase *tc_check_and_open_readonly = tcase_create ("check_and_open_readonly");
+ tcase_add_checked_fixture (tc_check_and_open_readonly,
+ setup_check_and_open,
+ teardown_check_and_open);
+ tcase_add_test (tc_check_and_open_readonly, test_wrong_filename);
+ tcase_add_test (tc_check_and_open_readonly, test_not_regular_file);
+ tcase_add_test (tc_check_and_open_readonly, test_symlink);
+ tcase_add_test (tc_check_and_open_readonly, test_wrong_uid);
+ tcase_add_test (tc_check_and_open_readonly, test_wrong_gid);
+ tcase_add_test (tc_check_and_open_readonly, test_wrong_permission);
+ tcase_add_test (tc_check_and_open_readonly, test_ok);
+ tcase_add_test (tc_check_and_open_readonly, test_write);
+ suite_add_tcase (s, tc_check_and_open_readonly);
+
+ return s;
+}
+
+int main(void)
+{
+ int number_failed;
+ Suite *s = check_and_open_suite ();
+ SRunner *sr = srunner_create (s);
+ /* If CK_VERBOSITY is set, use that, otherwise it defaults to CK_NORMAL */
+ srunner_run_all(sr, CK_ENV);
+ number_failed = srunner_ntests_failed (sr);
+ srunner_free (sr);
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
diff --git a/src/tests/common.c b/src/tests/common.c
new file mode 100644
index 000000000..50dc61b16
--- /dev/null
+++ b/src/tests/common.c
@@ -0,0 +1,109 @@
+/*
+ SSSD
+
+ Common utilities for check-based tests using talloc.
+
+ Authors:
+ Martin Nagy <mnagy@redhat.com>
+
+ Copyright (C) Red Hat, Inc 2009
+
+ 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 <check.h>
+#include <stdio.h>
+
+#include "tests/common.h"
+#include "util/dlinklist.h"
+#include "util/util.h"
+
+TALLOC_CTX *global_talloc_context = NULL;
+
+struct size_snapshot {
+ struct size_snapshot *prev;
+ struct size_snapshot *next;
+
+ TALLOC_CTX *ctx;
+ size_t bytes_allocated;
+};
+
+static struct size_snapshot *snapshot_stack;
+
+void
+_check_leaks(TALLOC_CTX *ctx, size_t bytes, const char *location)
+{
+ size_t bytes_allocated;
+
+ bytes_allocated = talloc_total_size(ctx);
+ if (bytes_allocated != bytes) {
+ fprintf(stderr, "Leak report for %s:\n", location);
+ talloc_report_full(ctx, stderr);
+ fail("%s: memory leaks detected, %d bytes still allocated",
+ location, bytes_allocated - bytes);
+ }
+}
+
+void
+check_leaks_push(TALLOC_CTX *ctx)
+{
+ struct size_snapshot *snapshot;
+
+ snapshot = talloc(NULL, struct size_snapshot);
+ snapshot->ctx = ctx;
+ snapshot->bytes_allocated = talloc_total_size(ctx);
+ DLIST_ADD(snapshot_stack, snapshot);
+}
+
+void
+_check_leaks_pop(TALLOC_CTX *ctx, const char *location)
+{
+ struct size_snapshot *snapshot;
+ TALLOC_CTX *old_ctx;
+ size_t bytes_allocated;
+
+ if (snapshot_stack == NULL) {
+ fail("%s: trying to pop an empty stack");
+ }
+
+ snapshot = snapshot_stack;
+ DLIST_REMOVE(snapshot_stack, snapshot);
+
+ old_ctx = snapshot->ctx;
+ bytes_allocated = snapshot->bytes_allocated;
+
+ fail_if(old_ctx != ctx, "Bad push/pop order");
+
+ talloc_zfree(snapshot);
+ _check_leaks(old_ctx, bytes_allocated, location);
+}
+
+void
+leak_check_setup(void)
+{
+ talloc_enable_null_tracking();
+ global_talloc_context = talloc_new(NULL);
+ fail_unless(global_talloc_context != NULL, "talloc_new failed");
+ check_leaks_push(global_talloc_context);
+}
+
+void
+leak_check_teardown(void)
+{
+ check_leaks_pop(global_talloc_context);
+ if (snapshot_stack != NULL) {
+ fail("Exiting with a non-empty stack");
+ }
+ check_leaks(global_talloc_context, 0);
+}
diff --git a/src/tests/common.h b/src/tests/common.h
new file mode 100644
index 000000000..0e954d7db
--- /dev/null
+++ b/src/tests/common.h
@@ -0,0 +1,21 @@
+#ifndef __TESTS_COMMON_H__
+#define __TESTS_COMMON_H__
+
+#include <talloc.h>
+
+extern TALLOC_CTX *global_talloc_context;
+
+#define check_leaks(ctx, bytes) _check_leaks((ctx), (bytes), __location__)
+void _check_leaks(TALLOC_CTX *ctx,
+ size_t bytes,
+ const char *location);
+
+void check_leaks_push(TALLOC_CTX *ctx);
+
+#define check_leaks_pop(ctx) _check_leaks_pop((ctx), __location__)
+void _check_leaks_pop(TALLOC_CTX *ctx, const char *location);
+
+void leak_check_setup(void);
+void leak_check_teardown(void);
+
+#endif /* !__TESTS_COMMON_H__ */
diff --git a/src/tests/fail_over-tests.c b/src/tests/fail_over-tests.c
new file mode 100644
index 000000000..e794f03b5
--- /dev/null
+++ b/src/tests/fail_over-tests.c
@@ -0,0 +1,304 @@
+/*
+ SSSD
+
+ Fail over tests.
+
+ Authors:
+ Martin Nagy <mnagy@redhat.com>
+
+ Copyright (C) Red Hat, Inc 2009
+
+ 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 <arpa/inet.h>
+
+#include <check.h>
+#include <popt.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <talloc.h>
+#include <tevent.h>
+
+#include "resolv/async_resolv.h"
+#include "tests/common.h"
+#include "util/util.h"
+
+/* Interface under test */
+#include "providers/fail_over.h"
+
+int use_net_test;
+
+struct test_ctx {
+ struct tevent_context *ev;
+ struct resolv_ctx *resolv;
+ struct fo_ctx *fo_ctx;
+ int tasks;
+};
+
+struct task {
+ struct test_ctx *test_ctx;
+ const char *location;
+ int recv;
+ int port;
+ int new_server_status;
+ int new_port_status;
+};
+
+static struct test_ctx *
+setup_test(void)
+{
+ struct test_ctx *ctx;
+ int ret;
+
+ ctx = talloc_zero(global_talloc_context, struct test_ctx);
+ fail_if(ctx == NULL, "Could not allocate memory for test context");
+
+ ctx->ev = tevent_context_init(ctx);
+ if (ctx->ev == NULL) {
+ talloc_free(ctx);
+ fail("Could not init tevent context");
+ }
+
+ ret = resolv_init(ctx, ctx->ev, 5, &ctx->resolv);
+ if (ret != EOK) {
+ talloc_free(ctx);
+ fail("Could not init resolv context");
+ }
+
+ ctx->fo_ctx = fo_context_init(ctx, 5 * 60);
+ if (ctx->fo_ctx == NULL) {
+ talloc_free(ctx);
+ fail("Could not init fail over context");
+ }
+
+ return ctx;
+}
+
+static void
+test_loop(struct test_ctx *data)
+{
+ while (data->tasks != 0)
+ tevent_loop_once(data->ev);
+}
+
+START_TEST(test_fo_new_service)
+{
+ int i;
+ int ret;
+ struct test_ctx *ctx;
+ struct fo_service *service;
+ struct fo_service *services[10];
+
+ ctx = setup_test();
+ check_leaks_push(ctx);
+
+ for (i = 0; i < 10; i++) {
+ char buf[16];
+ sprintf(buf, "service_%d", i);
+
+ check_leaks_push(ctx);
+ ret = fo_new_service(ctx->fo_ctx, buf, &services[i]);
+ fail_if(ret != EOK);
+ }
+
+ ret = fo_new_service(ctx->fo_ctx, "service_3", &service);
+ fail_if(ret != EEXIST);
+
+ for (i = 9; i >= 0; i--) {
+ char buf[16];
+ sprintf(buf, "service_%d", i);
+
+ ret = fo_get_service(ctx->fo_ctx, buf, &service);
+ fail_if(ret != EOK);
+ fail_if(service != services[i]);
+ talloc_free(service);
+ check_leaks_pop(ctx);
+
+ ret = fo_get_service(ctx->fo_ctx, buf, &service);
+ fail_if(ret != ENOENT);
+ }
+
+ check_leaks_pop(ctx);
+ talloc_free(ctx);
+}
+END_TEST
+
+static void
+test_resolve_service_callback(struct tevent_req *req)
+{
+ uint64_t recv_status;
+ int port;
+ struct task *task;
+ struct fo_server *server = NULL;
+ struct hostent *he;
+ int i;
+
+ task = tevent_req_callback_data(req, struct task);
+
+ task->test_ctx->tasks--;
+
+ recv_status = fo_resolve_service_recv(req, &server);
+ talloc_free(req);
+ fail_if(recv_status != task->recv, "%s: Expected return of %d, got %d",
+ task->location, task->recv, recv_status);
+ if (recv_status != EOK)
+ return;
+ fail_if(server == NULL);
+ port = fo_get_server_port(server);
+ fail_if(port != task->port, "%s: Expected port %d, got %d", task->location,
+ task->port, port);
+
+ if (task->new_port_status >= 0)
+ fo_set_port_status(server, task->new_port_status);
+ if (task->new_server_status >= 0)
+ fo_set_server_status(server, task->new_server_status);
+
+ he = fo_get_server_hostent(server);
+ fail_if(he == NULL, "%s: fo_get_server_hostent() returned NULL");
+ for (i = 0; he->h_addr_list[i]; i++) {
+ char buf[256];
+
+ inet_ntop(he->h_addrtype, he->h_addr_list[i], buf, sizeof(buf));
+ fail_if(strcmp(buf, "127.0.0.1") != 0 && strcmp(buf, "::1") != 0);
+ }
+
+}
+
+#define get_request(a, b, c, d, e, f) \
+ _get_request(a, b, c, d, e, f, __location__)
+
+static void
+_get_request(struct test_ctx *test_ctx, struct fo_service *service,
+ int expected_recv, int expected_port, int new_port_status,
+ int new_server_status, const char *location)
+{
+ struct tevent_req *req;
+ struct task *task;
+
+ task = talloc(test_ctx, struct task);
+ fail_if(task == NULL);
+
+ task->test_ctx = test_ctx;
+ task->recv = expected_recv;
+ task->port = expected_port;
+ task->new_port_status = new_port_status;
+ task->new_server_status = new_server_status;
+ task->location = location;
+ test_ctx->tasks++;
+
+ req = fo_resolve_service_send(test_ctx, test_ctx->ev, test_ctx->resolv, service);
+ fail_if(req == NULL, "%s: fo_resolve_service_send() failed", location);
+
+ tevent_req_set_callback(req, test_resolve_service_callback, task);
+ test_loop(test_ctx);
+}
+
+START_TEST(test_fo_resolve_service)
+{
+ struct test_ctx *ctx;
+ struct fo_service *service[2];
+
+ ctx = setup_test();
+ fail_if(ctx == NULL);
+
+ /* Add service. */
+ fail_if(fo_new_service(ctx->fo_ctx, "http", &service[0]) != EOK);
+
+ fail_if(fo_new_service(ctx->fo_ctx, "ldap", &service[1]) != EOK);
+
+ /* Add servers. */
+ fail_if(fo_add_server(service[0], "localhost", 20, NULL) != EOK);
+ fail_if(fo_add_server(service[0], "127.0.0.1", 80, NULL) != EOK);
+
+ fail_if(fo_add_server(service[1], "localhost", 30, NULL) != EOK);
+ fail_if(fo_add_server(service[1], "127.0.0.1", 389, NULL) != EOK);
+ fail_if(fo_add_server(service[1], "127.0.0.1", 389, NULL) != EEXIST);
+
+ /* Make requests. */
+ get_request(ctx, service[0], EOK, 20, PORT_WORKING, -1);
+ get_request(ctx, service[0], EOK, 20, -1, SERVER_NOT_WORKING);
+ get_request(ctx, service[0], EOK, 80, PORT_WORKING, -1);
+ get_request(ctx, service[0], EOK, 80, PORT_NOT_WORKING, -1);
+ get_request(ctx, service[0], ENOENT, 0, -1, -1);
+
+ get_request(ctx, service[1], EOK, 389, PORT_WORKING, -1);
+ get_request(ctx, service[1], EOK, 389, -1, SERVER_NOT_WORKING);
+ get_request(ctx, service[1], ENOENT, 0, -1, -1);
+
+ talloc_free(ctx);
+}
+END_TEST
+
+Suite *
+create_suite(void)
+{
+ Suite *s = suite_create("fail_over");
+
+ TCase *tc = tcase_create("FAIL_OVER Tests");
+
+ tcase_add_checked_fixture(tc, leak_check_setup, leak_check_teardown);
+ /* Do some testing */
+ tcase_add_test(tc, test_fo_new_service);
+ tcase_add_test(tc, test_fo_resolve_service);
+ if (use_net_test) {
+ }
+ /* Add all test cases to the test suite */
+ suite_add_tcase(s, tc);
+
+ return s;
+}
+
+int
+main(int argc, const char *argv[])
+{
+ int opt;
+ poptContext pc;
+ int failure_count;
+ Suite *suite;
+ SRunner *sr;
+ int debug = 0;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ { "debug-level", 'd', POPT_ARG_INT, &debug, 0, "Set debug level", NULL },
+ { "use-net-test", 'n', POPT_ARG_NONE, 0, 'n', "Run tests that need an active internet connection", NULL },
+ POPT_TABLEEND
+ };
+
+ pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch(opt) {
+ case 'n':
+ use_net_test = 1;
+ break;
+
+ default:
+ fprintf(stderr, "\nInvalid option %s: %s\n\n",
+ poptBadOption(pc, 0), poptStrerror(opt));
+ poptPrintUsage(pc, stderr, 0);
+ return 1;
+ }
+ }
+ poptFreeContext(pc);
+ debug_level = debug;
+
+ suite = create_suite();
+ sr = srunner_create(suite);
+ /* If CK_VERBOSITY is set, use that, otherwise it defaults to CK_NORMAL */
+ srunner_run_all(sr, CK_ENV);
+ failure_count = srunner_ntests_failed(sr);
+ srunner_free(sr);
+ return (failure_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+}
diff --git a/src/tests/files-tests.c b/src/tests/files-tests.c
new file mode 100644
index 000000000..90b971779
--- /dev/null
+++ b/src/tests/files-tests.c
@@ -0,0 +1,323 @@
+/*
+ * Authors:
+ * Jakub Hrozek <jhrozek@redhat.com>
+ *
+ * Copyright (C) 2008 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * 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; version 3 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdlib.h>
+#include <check.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <errno.h>
+#include <talloc.h>
+#include <popt.h>
+
+#include "config.h"
+#include "tools/tools_util.h"
+#include "util/util.h"
+
+static char tpl_dir[] = "file-tests-dir-XXXXXX";
+static char *dir_path;
+static char *dst_path;
+static uid_t uid;
+static gid_t gid;
+static TALLOC_CTX *test_ctx = NULL;
+
+static void setup_files_test(void)
+{
+ /* create a temporary directory that we fill with stuff later on */
+ test_ctx = talloc_new(NULL);
+ dir_path = mkdtemp(talloc_strdup(test_ctx, tpl_dir));
+ dst_path = mkdtemp(talloc_strdup(test_ctx, tpl_dir));
+
+ uid = getuid();
+ gid = getgid();
+}
+
+static void teardown_files_test(void)
+{
+ char *cmd = NULL;
+
+ /* OK this is crude but since the functions to remove tree are under test.. */
+ if (dir_path && test_ctx) {
+ cmd = talloc_asprintf(test_ctx, "/bin/rm -rf %s\n", dir_path);
+ system(cmd);
+ }
+ if (dst_path && test_ctx) {
+ cmd = talloc_asprintf(test_ctx, "/bin/rm -rf %s\n", dst_path);
+ system(cmd);
+ }
+
+ /* clean up */
+ talloc_zfree(test_ctx);
+}
+
+static int create_simple_file(const char *name, const char *content)
+{
+ int fd;
+ ssize_t size;
+ int ret;
+
+ fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0700);
+ fail_if(fd == -1, "Cannot create simple file\n");
+
+ size = write(fd, "abc", 3);
+ fail_if(size == -1, "Cannot write to file\n");
+
+ ret = fsync(fd);
+ fail_if(ret == -1, "Cannot sync file\n");
+
+ ret = close(fd);
+ fail_if(ret == -1, "Cannot close file\n");
+
+ return ret;
+}
+
+START_TEST(test_remove_tree)
+{
+ int ret;
+ char origpath[PATH_MAX+1];
+
+ errno = 0;
+ getcwd(origpath, PATH_MAX);
+ fail_unless(errno == 0, "Cannot getcwd\n");
+
+ DEBUG(5, ("About to delete %s\n", dir_path));
+
+ /* create a file */
+ ret = chdir(dir_path);
+ fail_if(ret == -1, "Cannot chdir1\n");
+
+ ret = create_simple_file("bar", "bar");
+ fail_if(ret == -1, "Cannot create file1\n");
+
+ /* create a subdir and file inside it */
+ ret = mkdir("subdir", 0700);
+ fail_if(ret == -1, "Cannot create subdir\n");
+
+ ret = chdir("subdir");
+ fail_if(ret == -1, "Cannot chdir\n");
+
+ ret = create_simple_file("foo", "foo");
+ fail_if(ret == -1, "Cannot create file\n");
+
+ /* create another subdir, empty this time */
+ ret = mkdir("subdir2", 0700);
+ fail_if(ret == -1, "Cannot create subdir\n");
+
+ ret = chdir(origpath);
+ fail_if(ret == -1, "Cannot chdir2\n");
+
+ /* go back */
+ ret = chdir(origpath);
+ fail_if(ret == -1, "Cannot chdir\n");
+
+ /* and finally wipe it out.. */
+ ret = remove_tree(dir_path);
+ fail_unless(ret == EOK, "remove_tree failed\n");
+
+ /* check if really gone */
+ ret = access(dir_path, F_OK);
+ fail_unless(ret == -1, "directory still there after remove_tree\n");
+}
+END_TEST
+
+START_TEST(test_simple_copy)
+{
+ int ret;
+ char origpath[PATH_MAX+1];
+ char *tmp;
+ int fd = -1;
+
+ errno = 0;
+ getcwd(origpath, PATH_MAX);
+ fail_unless(errno == 0, "Cannot getcwd\n");
+
+ /* create a file */
+ ret = chdir(dir_path);
+ fail_if(ret == -1, "Cannot chdir1\n");
+
+ ret = create_simple_file("bar", "bar");
+ fail_if(ret == -1, "Cannot create file1\n");
+
+ /* create a subdir and file inside it */
+ ret = mkdir("subdir", 0700);
+ fail_if(ret == -1, "Cannot create subdir\n");
+
+ ret = chdir("subdir");
+ fail_if(ret == -1, "Cannot chdir\n");
+
+ ret = create_simple_file("foo", "foo");
+ fail_if(ret == -1, "Cannot create file\n");
+
+ /* go back */
+ ret = chdir(origpath);
+ fail_if(ret == -1, "Cannot chdir\n");
+
+ /* and finally copy.. */
+ DEBUG(5, ("Will copy from '%s' to '%s'\n", dir_path, dst_path));
+ ret = copy_tree(dir_path, dst_path, uid, gid);
+ fail_unless(ret == EOK, "copy_tree failed\n");
+
+ /* check if really copied */
+ ret = access(dst_path, F_OK);
+ fail_unless(ret == 0, "destination directory not there\n");
+
+ tmp = talloc_asprintf(test_ctx, "%s/bar", dst_path);
+ ret = check_and_open_readonly(tmp, &fd, uid, gid, 0700);
+ fail_unless(ret == EOK, "Cannot open %s\n");
+ close(fd);
+ talloc_free(tmp);
+}
+END_TEST
+
+START_TEST(test_copy_symlink)
+{
+ int ret;
+ char origpath[PATH_MAX+1];
+ char *tmp;
+ struct stat statbuf;
+
+ errno = 0;
+ getcwd(origpath, PATH_MAX);
+ fail_unless(errno == 0, "Cannot getcwd\n");
+
+ /* create a subdir */
+ ret = chdir(dir_path);
+ fail_if(ret == -1, "Cannot chdir\n");
+
+ ret = create_simple_file("footarget", "foo");
+ fail_if(ret == -1, "Cannot create file\n");
+
+ ret = symlink("footarget", "foolink");
+ fail_if(ret == -1, "Cannot create symlink\n");
+
+ /* go back */
+ ret = chdir(origpath);
+ fail_if(ret == -1, "Cannot chdir\n");
+
+ /* and finally copy.. */
+ DEBUG(5, ("Will copy from '%s' to '%s'\n", dir_path, dst_path));
+ ret = copy_tree(dir_path, dst_path, uid, gid);
+ fail_unless(ret == EOK, "copy_tree failed\n");
+
+ /* check if really copied */
+ ret = access(dst_path, F_OK);
+ fail_unless(ret == 0, "destination directory not there\n");
+
+ tmp = talloc_asprintf(test_ctx, "%s/foolink", dst_path);
+ ret = lstat(tmp, &statbuf);
+ fail_unless(ret == 0, "cannot stat the symlink %s\n", tmp);
+ fail_unless(S_ISLNK(statbuf.st_mode), "%s not a symlink?\n", tmp);
+ talloc_free(tmp);
+}
+END_TEST
+
+START_TEST(test_copy_node)
+{
+ int ret;
+ char origpath[PATH_MAX+1];
+ char *tmp;
+ struct stat statbuf;
+
+ errno = 0;
+ getcwd(origpath, PATH_MAX);
+ fail_unless(errno == 0, "Cannot getcwd\n");
+
+ /* create a node */
+ ret = chdir(dir_path);
+ fail_if(ret == -1, "Cannot chdir\n");
+
+ ret = mknod("testnode", S_IFIFO | S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH, 0);
+ fail_unless(ret == 0, "cannot stat /dev/null: %s", strerror(errno));
+
+ /* go back */
+ ret = chdir(origpath);
+ fail_if(ret == -1, "Cannot chdir\n");
+
+ /* and finally copy.. */
+ DEBUG(5, ("Will copy from '%s' to '%s'\n", dir_path, dst_path));
+ ret = copy_tree(dir_path, dst_path, uid, gid);
+ fail_unless(ret == EOK, "copy_tree failed\n");
+
+ /* check if really copied */
+ ret = access(dst_path, F_OK);
+ fail_unless(ret == 0, "destination directory not there\n");
+
+ tmp = talloc_asprintf(test_ctx, "%s/testnode", dst_path);
+ ret = lstat(tmp, &statbuf);
+ fail_unless(ret == 0, "cannot stat the node %s\n", tmp);
+ fail_unless(S_ISFIFO(statbuf.st_mode), "%s not a char device??\n", tmp);
+ talloc_free(tmp);
+}
+END_TEST
+
+static Suite *files_suite(void)
+{
+ Suite *s = suite_create("files_suite");
+
+ TCase *tc_files = tcase_create("files");
+ tcase_add_checked_fixture(tc_files,
+ setup_files_test,
+ teardown_files_test);
+
+ tcase_add_test(tc_files, test_remove_tree);
+ tcase_add_test(tc_files, test_simple_copy);
+ tcase_add_test(tc_files, test_copy_symlink);
+ tcase_add_test(tc_files, test_copy_node);
+ suite_add_tcase(s, tc_files);
+
+ return s;
+}
+
+int main(int argc, char *argv[])
+{
+ int number_failed;
+ int opt;
+ poptContext pc;
+ int debug = 0;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ { "debug-level", 'd', POPT_ARG_INT, &debug, 0, "Set debug level", NULL },
+ POPT_TABLEEND
+ };
+
+ pc = poptGetContext(argv[0], argc, (const char **) argv, long_options, 0);
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ fprintf(stderr, "\nInvalid option %s: %s\n\n",
+ poptBadOption(pc, 0), poptStrerror(opt));
+ poptPrintUsage(pc, stderr, 0);
+ return 1;
+ }
+ poptFreeContext(pc);
+ debug_level = debug;
+
+ Suite *s = files_suite();
+ SRunner *sr = srunner_create(s);
+ /* If CK_VERBOSITY is set, use that, otherwise it defaults to CK_NORMAL */
+ srunner_run_all(sr, CK_ENV);
+ number_failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
diff --git a/src/tests/find_uid-tests.c b/src/tests/find_uid-tests.c
new file mode 100644
index 000000000..9eafadd45
--- /dev/null
+++ b/src/tests/find_uid-tests.c
@@ -0,0 +1,125 @@
+/*
+ SSSD
+
+ find_uid - Utilities tests
+
+ Authors:
+ Sumit Bose <sbose@redhat.com>
+
+ Copyright (C) 2009 Red Hat
+
+ 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 <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <check.h>
+
+#include "util/find_uid.h"
+
+
+START_TEST(test_check_if_uid_is_active_success)
+{
+ uid_t uid;
+ bool result;
+ int ret;
+
+ uid = getuid();
+
+ ret = check_if_uid_is_active(uid, &result);
+ fail_unless(ret == EOK, "check_if_uid_is_active failed.");
+ fail_unless(result, "check_if_uid_is_active did not found my uid [%d]",
+ uid);
+}
+END_TEST
+
+START_TEST(test_check_if_uid_is_active_fail)
+{
+ uid_t uid;
+ bool result;
+ int ret;
+
+ uid = (uid_t) -4;
+
+ ret = check_if_uid_is_active(uid, &result);
+ fail_unless(ret == EOK, "check_if_uid_is_active failed.");
+ fail_unless(!result, "check_if_uid_is_active found (hopefully not active) "
+ "uid [%d]", uid);
+}
+END_TEST
+
+START_TEST(test_get_uid_table)
+{
+ uid_t uid;
+ int ret;
+ TALLOC_CTX *tmp_ctx;
+ hash_table_t *table;
+ hash_key_t key;
+ hash_value_t value;
+
+ tmp_ctx = talloc_new(NULL);
+ fail_unless(tmp_ctx != NULL, "talloc_new failed.");
+
+ ret = get_uid_table(tmp_ctx, &table);
+ fail_unless(ret == EOK, "get_uid_table failed.");
+
+ uid = getuid();
+ key.type = HASH_KEY_ULONG;
+ key.ul = (unsigned long) uid;
+
+ ret = hash_lookup(table, &key, &value);
+
+ fail_unless(ret == HASH_SUCCESS, "Cannot find my uid [%d] in the table", uid);
+
+ uid = (uid_t) -4;
+ key.type = HASH_KEY_ULONG;
+ key.ul = (unsigned long) uid;
+
+ ret = hash_lookup(table, &key, &value);
+
+ fail_unless(ret == HASH_ERROR_KEY_NOT_FOUND, "Found (hopefully not active) "
+ "uid [%d] in the table", uid);
+
+ talloc_free(tmp_ctx);
+}
+END_TEST
+
+Suite *find_uid_suite (void)
+{
+ Suite *s = suite_create ("find_uid");
+
+ TCase *tc_find_uid = tcase_create ("find_uid");
+
+ tcase_add_test (tc_find_uid, test_check_if_uid_is_active_success);
+ tcase_add_test (tc_find_uid, test_check_if_uid_is_active_fail);
+ tcase_add_test (tc_find_uid, test_get_uid_table);
+ suite_add_tcase (s, tc_find_uid);
+
+ return s;
+}
+
+int main(void)
+{
+ debug_level = 255;
+ int number_failed;
+ Suite *s = find_uid_suite ();
+ SRunner *sr = srunner_create (s);
+ /* If CK_VERBOSITY is set, use that, otherwise it defaults to CK_NORMAL */
+ srunner_run_all(sr, CK_ENV);
+ number_failed = srunner_ntests_failed (sr);
+ srunner_free (sr);
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/src/tests/ipa_ldap_opt-tests.c b/src/tests/ipa_ldap_opt-tests.c
new file mode 100644
index 000000000..215f94a4d
--- /dev/null
+++ b/src/tests/ipa_ldap_opt-tests.c
@@ -0,0 +1,59 @@
+/*
+ SSSD
+
+ Tests if IPA and LDAP backend options are in sync
+
+ Authors:
+ Jakub Hrozek <jhrozek@redhat.com>
+
+ Copyright (C) 2010 Red Hat
+
+ 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 <check.h>
+#include <stdlib.h>
+
+#include "providers/ipa/ipa_common.h"
+#include "providers/ldap/sdap.h"
+
+START_TEST(test_check_num_opts)
+{
+ fail_if(IPA_OPTS_BASIC_TEST != SDAP_OPTS_BASIC);
+}
+END_TEST
+
+Suite *ipa_ldap_opt_suite (void)
+{
+ Suite *s = suite_create ("ipa_ldap_opt");
+
+ TCase *tc_ipa_ldap_opt = tcase_create ("ipa_ldap_opt");
+
+ tcase_add_test (tc_ipa_ldap_opt, test_check_num_opts);
+ suite_add_tcase (s, tc_ipa_ldap_opt);
+
+ return s;
+}
+
+int main(void)
+{
+ int number_failed;
+ Suite *s = ipa_ldap_opt_suite ();
+ SRunner *sr = srunner_create (s);
+ /* If CK_VERBOSITY is set, use that, otherwise it defaults to CK_NORMAL */
+ srunner_run_all(sr, CK_ENV);
+ number_failed = srunner_ntests_failed (sr);
+ srunner_free (sr);
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/src/tests/ipa_timerules-tests.c b/src/tests/ipa_timerules-tests.c
new file mode 100644
index 000000000..0a7be90be
--- /dev/null
+++ b/src/tests/ipa_timerules-tests.c
@@ -0,0 +1,580 @@
+/*
+ Timelib
+
+ test_timelib.c
+
+ Copyright (C) Jakub Hrozek <jhrozek@redhat.com> 2009
+
+ 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/>.
+*/
+
+#define _XOPEN_SOURCE /* strptime */
+
+#include <check.h>
+#include <popt.h>
+#include <time.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include "providers/ipa/ipa_timerules.h"
+#include "util/util.h"
+#include "tests/common.h"
+
+#define CHECK_TIME_RULE_LEAK(ctx, tctx, str, now, result) do { \
+ check_leaks_push(ctx); \
+ ret = check_time_rule(ctx, tctx, str, now, result); \
+ check_leaks_pop(ctx); \
+} while (0)
+
+static TALLOC_CTX *ctx;
+
+static void usage(poptContext pc, const char *error)
+{
+ poptPrintUsage(pc, stderr, 0);
+ if (error) fprintf(stderr, "%s", error);
+}
+
+int str2time_t(const char *fmt, const char *str, time_t *out)
+{
+ char *err;
+ struct tm stm;
+ memset(&stm, 0, sizeof(struct tm));
+
+ err = strptime(str, fmt, &stm);
+ if(!err || err[0] != '\0')
+ return EINVAL;
+
+ DEBUG(9, ("after strptime: %s", asctime(&stm)));
+ stm.tm_isdst = -1;
+ *out = mktime(&stm);
+ DEBUG(9, ("after mktime: %s", ctime(out)));
+ return (*out == -1) ? EINVAL : EOK;
+}
+
+/* Fixtures - open the time library before every test, close it afterwards */
+void setup(void)
+{
+ leak_check_setup();
+
+ ctx = talloc_new(NULL);
+ fail_if(ctx == NULL);
+}
+
+void teardown(void)
+{
+ leak_check_teardown();
+}
+
+/* Test that timelib detects a time rule inside the absolute range */
+START_TEST(test_timelib_absolute_in_range)
+{
+ time_t now;
+ int ret;
+ bool result;
+ static struct time_rules_ctx *tctx = NULL;
+
+
+ ret = init_time_rules_parser(ctx, &tctx);
+ fail_if(ret != EOK);
+
+ fail_unless(str2time_t("%F", "2000-1-1", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "absolute 199412161032.5 ~ 200512161032,5", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule");
+ fail_unless(result == true, "Range check error");
+
+ talloc_free(tctx);
+}
+END_TEST
+
+/* Test that timelib detects a time rule outside the absolute range */
+START_TEST(test_timelib_absolute_out_of_range)
+{
+ time_t now;
+ int ret;
+ bool result;
+ static struct time_rules_ctx *tctx = NULL;
+
+ ret = init_time_rules_parser(ctx, &tctx);
+ fail_if(ret != EOK);
+
+ fail_unless(str2time_t("%F", "2007-1-1", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "absolute 199412161032.5 ~ 200512161032,5", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule");
+ fail_unless(result == false, "Range check error");
+
+ talloc_free(tctx);
+}
+END_TEST
+
+/* Test that absolute timeranges work OK with only minimal data supplied */
+START_TEST(test_timelib_absolute_minimal)
+{
+ time_t now;
+ int ret;
+ bool result;
+ static struct time_rules_ctx *tctx = NULL;
+
+ ret = init_time_rules_parser(ctx, &tctx);
+ fail_if(ret != EOK);
+
+ fail_unless(str2time_t("%F", "2000-1-1", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "absolute 19941216 ~ 20051216", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule");
+ fail_unless(result == true, "Range check error");
+
+ talloc_free(tctx);
+}
+END_TEST
+
+/* Test a time value "right off the edge" of the time specifier */
+START_TEST(test_timelib_absolute_one_off)
+{
+ time_t now;
+ int ret;
+ bool result;
+ static struct time_rules_ctx *tctx = NULL;
+
+ ret = init_time_rules_parser(ctx, &tctx);
+ fail_if(ret != EOK);
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M-%S", "1994-12-16-10-32-29", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "absolute 19941216103230 ~ 19941216103231", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule");
+ fail_unless(result == false, "Range check error");
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M-%S", "1994-12-16-10-32-32", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "absolute 19941216103230 ~ 19941216103231", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule");
+ fail_unless(result == false, "Range check error");
+
+ talloc_free(tctx);
+}
+END_TEST
+
+
+/* Test a time value "right on the edge" of the time specifier */
+START_TEST(test_timelib_absolute_one_on)
+{
+ time_t now;
+ int ret;
+ bool result;
+ static struct time_rules_ctx *tctx = NULL;
+
+ ret = init_time_rules_parser(ctx, &tctx);
+ fail_if(ret != EOK);
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M-%S", "1994-12-16-10-32-30", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "absolute 19941216103230 ~ 19941216103231", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule");
+ fail_unless(result == true, "Range check error");
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M-%S", "1994-12-16-10-32-31", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "absolute 19941216103230 ~ 19941216103231", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule");
+ fail_unless(result == true, "Range check error");
+
+ talloc_free(tctx);
+}
+END_TEST
+
+START_TEST(test_timelib_periodic_daily_in)
+{
+ time_t now;
+ int ret;
+ bool result;
+ static struct time_rules_ctx *tctx = NULL;
+
+ ret = init_time_rules_parser(ctx, &tctx);
+ fail_if(ret != EOK);
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-03-30-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic daily 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule");
+ fail_unless(result == true, "Range check error");
+
+ /* test edges */
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-03-30-09-30", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic daily 0930 ~ 1830", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule (edge1)");
+ fail_unless(result == true, "Range check error");
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-03-30-18-30", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic daily 0930 ~ 1830", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule (edge2)");
+ fail_unless(result == true, "Range check error");
+
+ /* test wrap around */
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-03-30-16-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic daily 1500 ~ 0600", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule (edge1)");
+ fail_unless(result == true, "Range check error1");
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-03-30-15-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic daily 1500 ~ 0600", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule (edge1)");
+ fail_unless(result == true, "Range check error1");
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-03-30-06-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic daily 1500 ~ 0600", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule (edge1)");
+ fail_unless(result == true, "Range check error1");
+
+ talloc_free(tctx);
+}
+END_TEST
+
+START_TEST(test_timelib_periodic_daily_out)
+{
+ time_t now;
+ int ret;
+ bool result;
+ static struct time_rules_ctx *tctx = NULL;
+
+ ret = init_time_rules_parser(ctx, &tctx);
+ fail_if(ret != EOK);
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-03-30-21-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic daily 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule");
+ fail_unless(result == false, "Range check error");
+
+ /* test one-off errors */
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-03-30-09-29", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic daily 0930 ~ 1830", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule (one-off 1)");
+ fail_unless(result == false, "Range check error");
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-03-30-18-31", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic daily 0930 ~ 1830", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule (one-off 2)");
+ fail_unless(result == false, "Range check error");
+
+ /* test wrap around */
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-03-30-10-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic daily 1500 ~ 0600", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule (edge1)");
+ fail_unless(result == false, "Range check error");
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-03-30-14-59", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic daily 1500 ~ 0600", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule (edge1)");
+ fail_unless(result == false, "Range check error1");
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-03-30-06-01", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic daily 1500 ~ 0600", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule (edge1)");
+ fail_unless(result == false, "Range check error2");
+
+ talloc_free(tctx);
+}
+END_TEST
+
+START_TEST(test_timelib_periodic_weekly_in)
+{
+ time_t now;
+ int ret;
+ bool result;
+ static struct time_rules_ctx *tctx = NULL;
+
+ ret = init_time_rules_parser(ctx, &tctx);
+ fail_if(ret != EOK);
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-04-02-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic weekly day Mon-Fri 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule");
+ fail_unless(result == true, "Range check error1");
+
+ /* test edges - monday */
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-06-22-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic weekly day Mon-Fri 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule");
+ fail_unless(result == true, "Range check error2");
+
+ /* test edges - friday */
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-06-26-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic weekly day Mon-Fri 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule");
+ fail_unless(result == true, "Range check error3");
+
+ /* test wrap around */
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-11-03-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic weekly day Fri-Tue 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule");
+ fail_unless(result == true, "Range check error2");
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-11-06-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic weekly day Fri-Tue 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule");
+ fail_unless(result == true, "Range check error3");
+
+ talloc_free(tctx);
+}
+END_TEST
+
+START_TEST(test_timelib_periodic_weekly_out)
+{
+ time_t now;
+ int ret;
+ bool result;
+ static struct time_rules_ctx *tctx = NULL;
+
+ ret = init_time_rules_parser(ctx, &tctx);
+ fail_if(ret != EOK);
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-04-04-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic weekly day Mon-Fri 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule");
+ fail_unless(result == false, "Range check error");
+
+ /* test one-off error - monday */
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-06-22-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic weekly day Tue-Thu 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule");
+ fail_unless(result == false, "Range check error");
+
+ /* test one-off error - friday */
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-06-26-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic weekly day Tue-Thu 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule");
+ fail_unless(result == false, "Range check error");
+
+ /* test wrap around */
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-11-04-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic weekly day Fri-Tue 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule");
+ fail_unless(result == false, "Range check error2");
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-11-05-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic weekly day Fri-Tue 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule");
+ fail_unless(result == false, "Range check error3");
+
+ talloc_free(tctx);
+}
+END_TEST
+
+START_TEST(test_timelib_periodic_monthly_in)
+{
+ time_t now;
+ int ret;
+ bool result;
+ static struct time_rules_ctx *tctx = NULL;
+
+ ret = init_time_rules_parser(ctx, &tctx);
+ fail_if(ret != EOK);
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-04-07-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic monthly week 1,2 day Mon,Tue 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule1 (ret = %d: %s)", ret, strerror(ret));
+ fail_unless(result == true, "Range check error");
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-04-05-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic monthly day 1-5,10,15,20-25 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule2 (ret = %d: %s)", ret, strerror(ret));
+ fail_unless(result == true, "Range check error");
+
+ /* edges - week in */
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-06-13-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic monthly week 1,2 day Sat 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule (week edge 1)");
+ fail_unless(result == true, "Range check error");
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-06-29-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic monthly week 5 day Mon,Tue 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule (week edge 2)");
+ fail_unless(result == true, "Range check error");
+
+ /* edges - day in */
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-04-01-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic monthly day 1-10 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule (day edge 1)");
+ fail_unless(result == true, "Range check error");
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-04-10-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic monthly day 1-10 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule (day edge 2)");
+ fail_unless(result == true, "Range check error");
+
+ talloc_free(tctx);
+}
+END_TEST
+
+START_TEST(test_timelib_periodic_monthly_out)
+{
+ time_t now;
+ int ret;
+ bool result;
+ static struct time_rules_ctx *tctx = NULL;
+
+ ret = init_time_rules_parser(ctx, &tctx);
+ fail_if(ret != EOK);
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-06-03-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic monthly week 1,2 day Mon,Tue 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule (ret = %d)", ret);
+ fail_unless(result == false, "Range check error");
+
+ /* one-off error - week out */
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-06-15-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic monthly week 1 day Sun-Sat 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule (week edge 1)");
+ fail_unless(result == false, "Range check error");
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-06-28-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic monthly week 5 day Mon,Tue 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule (week edge 2)");
+ fail_unless(result == false, "Range check error");
+
+ /* one-off error - day out */
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-04-01-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic monthly day 2-10 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule (day edge 1)");
+ fail_unless(result == false, "Range check error");
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-04-11-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic monthly day 1-10 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule (day edge 2)");
+ fail_unless(result == false, "Range check error");
+
+ talloc_free(tctx);
+}
+END_TEST
+
+START_TEST(test_timelib_periodic_yearly_in)
+{
+ time_t now;
+ int ret;
+ bool result;
+ static struct time_rules_ctx *tctx = NULL;
+
+ ret = init_time_rules_parser(ctx, &tctx);
+ fail_if(ret != EOK);
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-08-03-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic yearly month 1,7-8 day 1-10 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule (ret = %d)", ret);
+ fail_unless(result == true, "Range check error1");
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-01-01-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic yearly month 1,7-8 day 1-10 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule (ret = %d)", ret);
+ fail_unless(result == true, "Range check error2");
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-01-01-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic yearly week 1 day 1-7 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule (ret = %d)", ret);
+ fail_unless(result == true, "Range check error3");
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-07-10-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic yearly month 1,7-8 day 1-10 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule (ret = %d)", ret);
+ fail_unless(result == true, "Range check error4");
+
+ talloc_free(tctx);
+}
+END_TEST
+
+START_TEST(test_timelib_periodic_yearly_out)
+{
+ time_t now;
+ int ret;
+ bool result;
+ static struct time_rules_ctx *tctx = NULL;
+
+ ret = init_time_rules_parser(ctx, &tctx);
+ fail_if(ret != EOK);
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-06-13-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic yearly month 7-8 day 1-10 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule1 (ret = %d)", ret);
+ fail_unless(result == false, "Range check error");
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-09-13-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic yearly month 7-8 day 1-10 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule2 (ret = %d)", ret);
+ fail_unless(result == false, "Range check error");
+
+ fail_unless(str2time_t("%Y-%m-%d-%H-%M", "2009-01-11-12-00", &now) == 0, "Cannot parse time spec");
+ CHECK_TIME_RULE_LEAK(ctx, tctx, "periodic yearly month 1,7-8 day 1-10 0900 ~ 1800", now, &result);
+ fail_unless(ret == EOK, "Fail to check the time rule3 (ret = %d)", ret);
+ fail_unless(result == false, "Range check error");
+
+ talloc_free(tctx);
+}
+END_TEST
+
+Suite *create_timelib_suite(void)
+{
+ Suite *s = suite_create("timelib");
+
+ TCase *tc_timelib = tcase_create("Timelib Tests");
+
+
+ /* Add setup() and teardown() methods */
+ tcase_add_checked_fixture(tc_timelib, setup, teardown);
+
+ /* Do some testing */
+ tcase_add_test(tc_timelib, test_timelib_absolute_in_range);
+ tcase_add_test(tc_timelib, test_timelib_absolute_out_of_range);
+ tcase_add_test(tc_timelib, test_timelib_absolute_minimal);
+ tcase_add_test(tc_timelib, test_timelib_absolute_one_off);
+ tcase_add_test(tc_timelib, test_timelib_absolute_one_on);
+
+ tcase_add_test(tc_timelib, test_timelib_periodic_daily_in);
+ tcase_add_test(tc_timelib, test_timelib_periodic_daily_out);
+ tcase_add_test(tc_timelib, test_timelib_periodic_weekly_in);
+ tcase_add_test(tc_timelib, test_timelib_periodic_weekly_out);
+ tcase_add_test(tc_timelib, test_timelib_periodic_monthly_in);
+ tcase_add_test(tc_timelib, test_timelib_periodic_monthly_out);
+ tcase_add_test(tc_timelib, test_timelib_periodic_yearly_in);
+ tcase_add_test(tc_timelib, test_timelib_periodic_yearly_out);
+
+ /* Add all test cases to the test suite */
+ suite_add_tcase(s, tc_timelib);
+
+ return s;
+}
+
+int main(int argc, const char *argv[])
+{
+ int ret;
+ poptContext pc;
+ int failure_count;
+ Suite *timelib_suite;
+ SRunner *sr;
+ int debug = 0;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ { "debug-level", 'd', POPT_ARG_INT, &debug, 0, "Set debug level", NULL },
+ POPT_TABLEEND
+ };
+
+ pc = poptGetContext(NULL, argc, (const char **) argv, long_options, 0);
+ if((ret = poptGetNextOpt(pc)) < -1) {
+ usage(pc, poptStrerror(ret));
+ return EXIT_FAILURE;
+ }
+ debug_level = debug;
+
+ timelib_suite = create_timelib_suite();
+ sr = srunner_create(timelib_suite);
+ /* If CK_VERBOSITY is set, use that, otherwise it defaults to CK_NORMAL */
+ srunner_run_all(sr, CK_ENV);
+ failure_count = srunner_ntests_failed(sr);
+ srunner_free(sr);
+ return (failure_count==0 ? EXIT_SUCCESS : EXIT_FAILURE);
+}
+
diff --git a/src/tests/krb5_utils-tests.c b/src/tests/krb5_utils-tests.c
new file mode 100644
index 000000000..8676f3bfa
--- /dev/null
+++ b/src/tests/krb5_utils-tests.c
@@ -0,0 +1,307 @@
+/*
+ SSSD
+
+ Kerberos 5 Backend Module -- Utilities tests
+
+ Authors:
+ Sumit Bose <sbose@redhat.com>
+
+ Copyright (C) 2009 Red Hat
+
+ 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 <stdlib.h>
+#include <check.h>
+
+#include "providers/krb5/krb5_utils.h"
+#include "providers/krb5/krb5_auth.h"
+
+#define BASE "/abc/def"
+
+#define USERNAME "testuser"
+#define UID "12345"
+#define PRINCIPLE_NAME "testuser@EXAMPLE.COM"
+#define REALM "REALM.ORG"
+#define HOME_DIRECTORY "/home/testuser"
+#define CCACHE_DIR "/var/tmp"
+#define PID "4321"
+
+extern struct dp_option default_krb5_opts[];
+
+TALLOC_CTX *tmp_ctx = NULL;
+struct krb5child_req *kr;
+
+void setup_talloc_context(void)
+{
+ int ret;
+ int i;
+
+ struct pam_data *pd;
+ struct krb5_ctx *krb5_ctx;
+ fail_unless(tmp_ctx == NULL, "Talloc context already initialized.");
+ tmp_ctx = talloc_new(NULL);
+ fail_unless(tmp_ctx != NULL, "Cannot create talloc context.");
+
+ kr = talloc_zero(tmp_ctx, struct krb5child_req);
+ fail_unless(kr != NULL, "Cannot create krb5child_req structure.");
+
+ pd = talloc_zero(tmp_ctx, struct pam_data);
+ fail_unless(pd != NULL, "Cannot create pam_data structure.");
+
+ krb5_ctx = talloc_zero(tmp_ctx, struct krb5_ctx);
+ fail_unless(pd != NULL, "Cannot create krb5_ctx structure.");
+
+ pd->user = discard_const(USERNAME);
+ pd->pw_uid = atoi(UID);
+ pd->upn = PRINCIPLE_NAME;
+ pd->cli_pid = atoi(PID);
+
+ krb5_ctx->opts = talloc_zero_array(tmp_ctx, struct dp_option, KRB5_OPTS);
+ fail_unless(krb5_ctx->opts != NULL, "Cannot created options.");
+ for (i = 0; i < KRB5_OPTS; i++) {
+ krb5_ctx->opts[i].opt_name = default_krb5_opts[i].opt_name;
+ krb5_ctx->opts[i].type = default_krb5_opts[i].type;
+ krb5_ctx->opts[i].def_val = default_krb5_opts[i].def_val;
+ }
+ ret = dp_opt_set_string(krb5_ctx->opts, KRB5_REALM, REALM);
+ fail_unless(ret == EOK, "Failed to set Realm");
+ ret = dp_opt_set_string(krb5_ctx->opts, KRB5_CCACHEDIR, CCACHE_DIR);
+ fail_unless(ret == EOK, "Failed to set Ccache dir");
+
+ kr->homedir = HOME_DIRECTORY;
+
+ kr->pd = pd;
+ kr->krb5_ctx = krb5_ctx;
+
+}
+
+void free_talloc_context(void)
+{
+ int ret;
+ fail_unless(tmp_ctx != NULL, "Talloc context already freed.");
+ ret = talloc_free(tmp_ctx);
+ tmp_ctx = NULL;
+ fail_unless(ret == 0, "Connot free talloc context.");
+}
+
+START_TEST(test_multiple_substitutions)
+{
+ const char *test_template = BASE"_%u_%U_%u";
+ const char *expected = BASE"_"USERNAME"_"UID"_"USERNAME;
+ char *result;
+
+ result = expand_ccname_template(tmp_ctx, kr, test_template);
+
+ fail_unless(result != NULL, "Cannot expand template [%s].", test_template);
+ fail_unless(strcmp(result, expected) == 0,
+ "Expansion failed, result [%s], expected [%s].",
+ result, expected);
+}
+END_TEST
+
+START_TEST(test_username)
+{
+ const char *test_template = BASE"_%u";
+ const char *expected = BASE"_"USERNAME;
+ char *result;
+
+ result = expand_ccname_template(tmp_ctx, kr, test_template);
+
+ fail_unless(result != NULL, "Cannot expand template [%s].", test_template);
+ fail_unless(strcmp(result, expected) == 0,
+ "Expansion failed, result [%s], expected [%s].",
+ result, expected);
+}
+END_TEST
+
+START_TEST(test_uid)
+{
+ const char *test_template = BASE"_%U";
+ const char *expected = BASE"_"UID;
+ char *result;
+
+ result = expand_ccname_template(tmp_ctx, kr, test_template);
+
+ fail_unless(result != NULL, "Cannot expand template [%s].", test_template);
+ fail_unless(strcmp(result, expected) == 0,
+ "Expansion failed, result [%s], expected [%s].",
+ result, expected);
+}
+END_TEST
+
+START_TEST(test_upn)
+{
+ const char *test_template = BASE"_%p";
+ const char *expected = BASE"_"PRINCIPLE_NAME;
+ char *result;
+
+ result = expand_ccname_template(tmp_ctx, kr, test_template);
+
+ fail_unless(result != NULL, "Cannot expand template [%s].", test_template);
+ fail_unless(strcmp(result, expected) == 0,
+ "Expansion failed, result [%s], expected [%s].",
+ result, expected);
+}
+END_TEST
+
+START_TEST(test_realm)
+{
+ const char *test_template = BASE"_%r";
+ const char *expected = BASE"_"REALM;
+ char *result;
+
+ result = expand_ccname_template(tmp_ctx, kr, test_template);
+
+ fail_unless(result != NULL, "Cannot expand template [%s].", test_template);
+ fail_unless(strcmp(result, expected) == 0,
+ "Expansion failed, result [%s], expected [%s].",
+ result, expected);
+}
+END_TEST
+
+START_TEST(test_home)
+{
+ const char *test_template = BASE"_%h";
+ const char *expected = BASE"_"HOME_DIRECTORY;
+ char *result;
+
+ result = expand_ccname_template(tmp_ctx, kr, test_template);
+
+ fail_unless(result != NULL, "Cannot expand template [%s].", test_template);
+ fail_unless(strcmp(result, expected) == 0,
+ "Expansion failed, result [%s], expected [%s].",
+ result, expected);
+}
+END_TEST
+
+START_TEST(test_ccache_dir)
+{
+ const char *test_template = BASE"_%d";
+ const char *expected = BASE"_"CCACHE_DIR;
+ char *result;
+
+ result = expand_ccname_template(tmp_ctx, kr, test_template);
+
+ fail_unless(result != NULL, "Cannot expand template [%s].", test_template);
+ fail_unless(strcmp(result, expected) == 0,
+ "Expansion failed, result [%s], expected [%s].",
+ result, expected);
+}
+END_TEST
+
+START_TEST(test_pid)
+{
+ const char *test_template = BASE"_%P";
+ const char *expected = BASE"_"PID;
+ char *result;
+
+ result = expand_ccname_template(tmp_ctx, kr, test_template);
+
+ fail_unless(result != NULL, "Cannot expand template [%s].", test_template);
+ fail_unless(strcmp(result, expected) == 0,
+ "Expansion failed, result [%s], expected [%s].",
+ result, expected);
+}
+END_TEST
+
+START_TEST(test_percent)
+{
+ const char *test_template = BASE"_%%";
+ const char *expected = BASE"_%";
+ char *result;
+
+ result = expand_ccname_template(tmp_ctx, kr, test_template);
+
+ fail_unless(result != NULL, "Cannot expand template [%s].", test_template);
+ fail_unless(strcmp(result, expected) == 0,
+ "Expansion failed, result [%s], expected [%s].",
+ result, expected);
+}
+END_TEST
+
+START_TEST(test_unknow_template)
+{
+ const char *test_template = BASE"_%X";
+ char *result;
+
+ result = expand_ccname_template(tmp_ctx, kr, test_template);
+
+ fail_unless(result == NULL, "Unknown template [%s] should fail.",
+ test_template);
+}
+END_TEST
+
+START_TEST(test_NULL)
+{
+ char *test_template = NULL;
+ char *result;
+
+ result = expand_ccname_template(tmp_ctx, kr, test_template);
+
+ fail_unless(result == NULL, "Expected NULL as a result for an empty input.",
+ test_template);
+}
+END_TEST
+
+START_TEST(test_no_substitution)
+{
+ const char *test_template = BASE;
+ char *result;
+
+ result = expand_ccname_template(tmp_ctx, kr, test_template);
+
+ fail_unless(result != NULL, "Cannot expand template [%s].", test_template);
+ fail_unless(strcmp(result, test_template) == 0,
+ "Expansion failed, result [%s], expected [%s].",
+ result, test_template);
+}
+END_TEST
+
+Suite *krb5_utils_suite (void)
+{
+ Suite *s = suite_create ("krb5_utils");
+
+ TCase *tc_ccname_template = tcase_create ("ccname_template");
+ tcase_add_checked_fixture (tc_ccname_template, setup_talloc_context,
+ free_talloc_context);
+ tcase_add_test (tc_ccname_template, test_no_substitution);
+ tcase_add_test (tc_ccname_template, test_NULL);
+ tcase_add_test (tc_ccname_template, test_unknow_template);
+ tcase_add_test (tc_ccname_template, test_username);
+ tcase_add_test (tc_ccname_template, test_uid);
+ tcase_add_test (tc_ccname_template, test_upn);
+ tcase_add_test (tc_ccname_template, test_realm);
+ tcase_add_test (tc_ccname_template, test_home);
+ tcase_add_test (tc_ccname_template, test_ccache_dir);
+ tcase_add_test (tc_ccname_template, test_pid);
+ tcase_add_test (tc_ccname_template, test_percent);
+ tcase_add_test (tc_ccname_template, test_multiple_substitutions);
+ suite_add_tcase (s, tc_ccname_template);
+
+ return s;
+}
+
+int main(void)
+{
+ int number_failed;
+ Suite *s = krb5_utils_suite ();
+ SRunner *sr = srunner_create (s);
+ /* If CK_VERBOSITY is set, use that, otherwise it defaults to CK_NORMAL */
+ srunner_run_all(sr, CK_ENV);
+ number_failed = srunner_ntests_failed (sr);
+ srunner_free (sr);
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
diff --git a/src/tests/python-test.py b/src/tests/python-test.py
new file mode 100644
index 000000000..e1eaab2d1
--- /dev/null
+++ b/src/tests/python-test.py
@@ -0,0 +1,445 @@
+#!/usr/bin/python
+#coding=utf-8
+
+# Authors:
+# Jakub Hrozek <jhrozek@redhat.com>
+#
+# Copyright (C) 2009 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# 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; version 2 only
+#
+# 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+import os
+import tempfile
+import shutil
+import unittest
+import commands
+import errno
+
+# module under test
+import pysss
+
+class LocalTest(unittest.TestCase):
+ local_path = "/var/lib/sss/db/sssd.ldb"
+
+ def setUp(self):
+ self.local = pysss.local()
+
+ def _run_and_check(self, runme):
+ (status, output) = commands.getstatusoutput(runme)
+ self.failUnlessEqual(status, 0, output)
+
+ def _get_object_info(self, name, subtree, domain):
+ search_dn = "dn=name=%s,cn=%s,cn=%s,cn=sysdb" % (name, subtree, domain)
+ (status, output) = commands.getstatusoutput("ldbsearch -H %s %s" % (self.local_path,search_dn))
+
+ if status: return {}
+
+ kw = {}
+ for key, value in [ l.split(':') for l in output.split('\n') if ":" in l ]:
+ kw[key] = value.strip()
+
+ del kw['asq']
+ return kw
+
+ def get_user_info(self, name, domain="LOCAL"):
+ return self._get_object_info(name, "users", domain)
+
+ def get_group_info(self, name, domain="LOCAL"):
+ return self._get_object_info(name, "groups", domain)
+
+ def _validate_object(self, kw, name, **kwargs):
+ if kw == {}: self.fail("Could not get %s info" % name)
+ for key in kwargs.keys():
+ self.assert_(str(kwargs[key]) == str(kw[key]), "%s %s != %s %s" % (key, kwargs[key], key, kw[key]))
+
+ def validate_user(self, username, **kwargs):
+ return self._validate_object(self.get_user_info(username), "user", **kwargs)
+
+ def validate_group(self, groupname, **kwargs):
+ return self._validate_object(self.get_group_info(groupname), "group", **kwargs)
+
+ def _validate_no_object(self, kw, name):
+ if kw != {}:
+ self.fail("Got %s info" % name)
+
+ def validate_no_user(self, username):
+ return self._validate_no_object(self.get_user_info(username), "user")
+
+ def validate_no_group(self, groupname):
+ return self._validate_no_object(self.get_group_info(groupname), "group")
+
+ def _get_object_membership(self, name, subtree, domain):
+ search_dn = "dn=name=%s,cn=%s,cn=%s,cn=sysdb" % (name, subtree, domain)
+ (status, output) = commands.getstatusoutput("ldbsearch -H %s %s" % (self.local_path,search_dn))
+
+ if status:
+ return []
+
+ members = [ value.strip() for key, value in [ l.split(':') for l in output.split('\n') if ":" in l ] if key == "memberof" ]
+ return members
+
+ def _assertMembership(self, name, group_list, subtree, domain):
+ members = self._get_object_membership(name, subtree, domain)
+ for group in group_list:
+ group_dn = "name=%s,cn=groups,cn=%s,cn=sysdb" % (group, domain)
+ if group_dn in members:
+ members.remove(group_dn)
+ else:
+ self.fail("Cannot find required group %s" % group_dn)
+
+ if len(members) > 0:
+ self.fail("More groups than selected")
+
+ def assertUserMembership(self, name, group_list, domain="LOCAL"):
+ return self._assertMembership(name, group_list, "users", domain)
+
+ def assertGroupMembership(self, name, group_list, domain="LOCAL"):
+ return self._assertMembership(name, group_list, "groups", domain)
+
+ def get_user_membership(self, name, domain="LOCAL"):
+ return self._get_object_membership(name, "users", domain)
+
+ def get_group_membership(self, name, domain="LOCAL"):
+ return self._get_object_membership(name, "groups", domain)
+
+ def add_group(self, groupname):
+ self._run_and_check("sss_groupadd %s" % (groupname))
+
+ def remove_group(self, groupname):
+ self._run_and_check("sss_groupdel %s" % (groupname))
+
+ def add_user(self, username):
+ self._run_and_check("sss_useradd %s" % (username))
+
+ def add_user_not_home(self, username):
+ self._run_and_check("sss_useradd -M %s" % (username))
+
+ def remove_user(self, username):
+ self._run_and_check("sss_userdel %s" % (username))
+
+ def remove_user_not_home(self, username):
+ self._run_and_check("sss_userdel -R %s" % (username))
+
+class SanityTest(unittest.TestCase):
+ def testInstantiate(self):
+ "Test that the local backed binding can be instantiated"
+ local = pysss.local()
+ self.assert_(local.__class__, "<type 'sss.local'>")
+
+class UseraddTest(LocalTest):
+ def tearDown(self):
+ if self.username:
+ self.remove_user(self.username)
+
+ def testUseradd(self):
+ "Test adding a local user"
+ self.username = "testUseradd"
+ self.local.useradd(self.username)
+ self.validate_user(self.username)
+ # check home directory was created with default name
+ self.assertEquals(os.access("/home/%s" % self.username, os.F_OK), True)
+
+ def testUseraddWithParams(self):
+ "Test adding a local user with modified parameters"
+ self.username = "testUseraddWithParams"
+ self.local.useradd(self.username,
+ gecos="foo bar",
+ homedir="/home/foobar",
+ shell="/bin/zsh")
+ self.validate_user(self.username,
+ gecos="foo bar",
+ homeDirectory="/home/foobar",
+ loginShell="/bin/zsh")
+ # check home directory was created with nondefault name
+ self.assertEquals(os.access("/home/foobar", os.F_OK), True)
+
+ def testUseraddNoHomedir(self):
+ "Test adding a local user without creating his home dir"
+ self.username = "testUseraddNoHomedir"
+ self.local.useradd(self.username, create_home = False)
+ self.validate_user(self.username)
+ # check home directory was not created
+ self.assertEquals(os.access("/home/%s" % self.username, os.F_OK), False)
+ self.local.userdel(self.username, remove = False)
+ self.username = None # fool tearDown into not removing the user
+
+ def testUseraddAlternateSkeldir(self):
+ "Test adding a local user and init his homedir from a custom location"
+ self.username = "testUseraddAlternateSkeldir"
+
+ skeldir = tempfile.mkdtemp()
+ fd, path = tempfile.mkstemp(dir=skeldir)
+ fdo = os.fdopen(fd)
+ fdo.flush()
+ fdo.close
+ self.assertEquals(os.access(path, os.F_OK), True)
+ filename = os.path.basename(path)
+
+ try:
+ self.local.useradd(self.username, skel = skeldir)
+ self.validate_user(self.username)
+ self.assertEquals(os.access("/home/%s/%s"%(self.username,filename), os.F_OK), True)
+ finally:
+ shutil.rmtree(skeldir)
+
+ def testUseraddToGroups(self):
+ "Test adding a local user with group membership"
+ self.username = "testUseraddToGroups"
+ self.add_group("gr1")
+ self.add_group("gr2")
+ try:
+ self.local.useradd(self.username,
+ groups=["gr1","gr2"])
+ self.assertUserMembership(self.username,
+ ["gr1","gr2"])
+ finally:
+ self.remove_group("gr1")
+ self.remove_group("gr2")
+
+ def testUseraddWithUID(self):
+ "Test adding a local user with a custom UID"
+ self.username = "testUseraddWithUID"
+ self.local.useradd(self.username,
+ uid=1024)
+ self.validate_user(self.username,
+ uidNumber=1024)
+
+class UseraddTestNegative(LocalTest):
+ def testUseraddNoParams(self):
+ "Test that local.useradd() requires the username parameter"
+ self.assertRaises(TypeError, self.local.useradd)
+
+ def testUseraddUserAlreadyExists(self):
+ "Test adding a local with a duplicite name"
+ self.username = "testUseraddUserAlreadyExists"
+ self.local.useradd(self.username)
+ try:
+ self.local.useradd(self.username)
+ except IOError, e:
+ self.assertEquals(e.errno, errno.EEXIST)
+ else:
+ self.fail("Was expecting exception")
+ finally:
+ self.remove_user(self.username)
+
+ def testUseraddUIDAlreadyExists(self):
+ "Test adding a local with a duplicite user ID"
+ self.username = "testUseraddUIDAlreadyExists1"
+ self.local.useradd(self.username, uid=1025)
+ try:
+ self.local.useradd("testUseraddUIDAlreadyExists2", uid=1025)
+ except IOError, e:
+ self.assertEquals(e.errno, errno.EEXIST)
+ else:
+ self.fail("Was expecting exception")
+ finally:
+ self.remove_user(self.username)
+
+class UserdelTest(LocalTest):
+ def testUserdel(self):
+ self.add_user("testUserdel")
+ self.assertEquals(os.access("/home/testUserdel", os.F_OK), True)
+ self.validate_user("testUserdel")
+ self.local.userdel("testUserdel")
+ self.validate_no_user("testUserdel")
+ self.assertEquals(os.access("/home/testUserdel", os.F_OK), False)
+
+ def testUserdelNotHomedir(self):
+ self.add_user("testUserdel")
+ self.assertEquals(os.access("/home/testUserdel", os.F_OK), True)
+ self.validate_user("testUserdel")
+ self.local.userdel("testUserdel", remove=False)
+ self.validate_no_user("testUserdel")
+ self.assertEquals(os.access("/home/testUserdel", os.F_OK), True)
+ shutil.rmtree("/home/testUserdel")
+ os.remove("/var/mail/testUserdel")
+
+ def testUserdelNegative(self):
+ self.validate_no_user("testUserdelNegative")
+ try:
+ self.local.userdel("testUserdelNegative")
+ except IOError, e:
+ self.assertEquals(e.errno, errno.ENOENT)
+ else:
+ fail("Was expecting exception")
+
+class UsermodTest(LocalTest):
+ def setUp(self):
+ self.local = pysss.local()
+ self.username = "UsermodTest"
+ self.add_user_not_home(self.username)
+
+ def tearDown(self):
+ self.remove_user_not_home(self.username)
+
+ def testUsermod(self):
+ "Test modifying user attributes"
+ self.local.usermod(self.username,
+ gecos="foo bar",
+ homedir="/home/foobar",
+ shell="/bin/zsh")
+ self.validate_user(self.username,
+ gecos="foo bar",
+ homeDirectory="/home/foobar",
+ loginShell="/bin/zsh")
+
+ def testUsermodUID(self):
+ "Test modifying UID"
+ self.local.usermod(self.username,
+ uid=1024)
+ self.validate_user(self.username,
+ uidNumber=1024)
+
+ def testUsermodGroupMembership(self):
+ "Test adding to and removing from groups"
+ self.add_group("gr1")
+ self.add_group("gr2")
+
+ try:
+ self.local.usermod(self.username,
+ addgroups=["gr1","gr2"])
+ self.assertUserMembership(self.username,
+ ["gr1","gr2"])
+ self.local.usermod(self.username,
+ rmgroups=["gr2"])
+ self.assertUserMembership(self.username,
+ ["gr1"])
+ self.local.usermod(self.username,
+ rmgroups=["gr1"])
+ self.assertUserMembership(self.username,
+ [])
+ finally:
+ self.remove_group("gr1")
+ self.remove_group("gr2")
+
+ def testUsermodLockUnlock(self):
+ "Test locking and unlocking user"
+ self.local.usermod(self.username,
+ lock=self.local.lock)
+ self.validate_user(self.username,
+ disabled="true")
+ self.local.usermod(self.username,
+ lock=self.local.unlock)
+ self.validate_user(self.username,
+ disabled="false")
+
+class GroupaddTest(LocalTest):
+ def tearDown(self):
+ if self.groupname:
+ self.remove_group(self.groupname)
+
+ def testGroupadd(self):
+ "Test adding a local group"
+ self.groupname = "testGroupadd"
+ self.local.groupadd(self.groupname)
+ self.validate_group(self.groupname)
+
+ def testGroupaddWithGID(self):
+ "Test adding a local group with a custom GID"
+ self.groupname = "testUseraddWithGID"
+ self.local.groupadd(self.groupname,
+ gid=1024)
+ self.validate_group(self.groupname,
+ gidNumber=1024)
+
+class GroupaddTestNegative(LocalTest):
+ def testGroupaddNoParams(self):
+ "Test that local.groupadd() requires the groupname parameter"
+ self.assertRaises(TypeError, self.local.groupadd)
+
+ def testGroupaddUserAlreadyExists(self):
+ "Test adding a local with a duplicite name"
+ self.groupname = "testGroupaddUserAlreadyExists"
+ self.local.groupadd(self.groupname)
+ try:
+ self.local.groupadd(self.groupname)
+ except IOError, e:
+ self.assertEquals(e.errno, errno.EEXIST)
+ else:
+ self.fail("Was expecting exception")
+ finally:
+ self.remove_group(self.groupname)
+
+ def testGroupaddGIDAlreadyExists(self):
+ "Test adding a local with a duplicite group ID"
+ self.groupname = "testGroupaddGIDAlreadyExists1"
+ self.local.groupadd(self.groupname, gid=1025)
+ try:
+ self.local.groupadd("testGroupaddGIDAlreadyExists2", gid=1025)
+ except IOError, e:
+ self.assertEquals(e.errno, errno.EEXIST)
+ else:
+ self.fail("Was expecting exception")
+ finally:
+ self.remove_group(self.groupname)
+
+class GroupdelTest(LocalTest):
+ def testGroupdel(self):
+ self.add_group("testGroupdel")
+ self.validate_group("testGroupdel")
+ self.local.groupdel("testGroupdel")
+ self.validate_no_group("testGroupdel")
+
+ def testGroupdelNegative(self):
+ self.validate_no_group("testGroupdelNegative")
+ try:
+ self.local.groupdel("testGroupdelNegative")
+ except IOError, e:
+ self.assertEquals(e.errno, errno.ENOENT)
+ else:
+ fail("Was expecting exception")
+
+
+class GroupmodTest(LocalTest):
+ def setUp(self):
+ self.local = pysss.local()
+ self.groupname = "GroupmodTest"
+ self.add_group(self.groupname)
+
+ def tearDown(self):
+ self.remove_group(self.groupname)
+
+ def testGroupmodGID(self):
+ "Test modifying UID"
+ self.local.groupmod(self.groupname,
+ gid=1024)
+ self.validate_group(self.groupname,
+ gidNumber=1024)
+
+ def testGroupmodGroupMembership(self):
+ "Test adding to groups"
+ self.add_group("gr1")
+ self.add_group("gr2")
+ try:
+ self.local.groupmod(self.groupname,
+ addgroups=["gr1","gr2"])
+ self.assertGroupMembership(self.groupname,
+ ["gr1","gr2"])
+ self.local.groupmod(self.groupname,
+ rmgroups=["gr2"])
+ self.assertGroupMembership(self.groupname,
+ ["gr1"])
+ self.local.groupmod(self.groupname,
+ rmgroups=["gr1"])
+ self.assertGroupMembership(self.groupname,
+ [])
+ finally:
+ self.remove_group("gr1")
+ self.remove_group("gr2")
+
+# -------------- run the test suite -------------- #
+if __name__ == "__main__":
+ unittest.main()
+
diff --git a/src/tests/refcount-tests.c b/src/tests/refcount-tests.c
new file mode 100644
index 000000000..db2a256ee
--- /dev/null
+++ b/src/tests/refcount-tests.c
@@ -0,0 +1,232 @@
+/*
+ SSSD
+
+ Reference counting tests.
+
+ Authors:
+ Martin Nagy <mnagy@redhat.com>
+
+ Copyright (C) Red Hat, Inc 2009
+
+ 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 <stdlib.h>
+#include <check.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <popt.h>
+
+#include "tests/common.h"
+#include "util/util.h"
+
+/* Interface under test */
+#include "util/refcount.h"
+
+/* Fail the test if object 'obj' does not have 'num' references. */
+#define REF_ASSERT(obj, num) \
+ fail_unless(((obj)->DO_NOT_TOUCH_THIS_MEMBER_refcount == (num)), \
+ "Reference count of " #obj " should be %d but is %d", \
+ (num), (obj)->DO_NOT_TOUCH_THIS_MEMBER_refcount)
+
+#define FILLER_SIZE 32
+
+struct foo {
+ REFCOUNT_COMMON;
+ char a[FILLER_SIZE];
+ char b[FILLER_SIZE];
+};
+
+struct bar {
+ char a[FILLER_SIZE];
+ REFCOUNT_COMMON;
+ char b[FILLER_SIZE];
+};
+
+struct baz {
+ char a[FILLER_SIZE];
+ char b[FILLER_SIZE];
+ REFCOUNT_COMMON;
+};
+
+#define SET_FILLER(target) do { \
+ memset((target)->a, 'a', FILLER_SIZE); \
+ memset((target)->b, 'b', FILLER_SIZE); \
+} while (0)
+
+#define CHECK_FILLER(target) do { \
+ int _counter; \
+ for (_counter = 0; _counter < FILLER_SIZE; _counter++) { \
+ fail_unless((target)->a[_counter] == 'a', "Corrupted memory in " \
+ #target "->a[%d] of size %d", _counter, FILLER_SIZE); \
+ fail_unless((target)->b[_counter] == 'b', "Corrupted memory in " \
+ #target "->b[%d] of size %d", _counter, FILLER_SIZE); \
+ } \
+} while (0)
+
+struct container {
+ struct foo *foo;
+ struct bar *bar;
+ struct baz *baz;
+};
+
+static struct container *global;
+
+START_TEST(test_refcount_basic)
+{
+ struct container *containers;
+ int i;
+
+ /* First allocate our global storage place. */
+ global = talloc(NULL, struct container);
+ fail_if(global == NULL);
+
+ /* Allocate foo. */
+ global->foo = rc_alloc(global, struct foo);
+ fail_if(global->foo == NULL);
+ SET_FILLER(global->foo);
+ REF_ASSERT(global->foo, 1);
+
+ /* Allocate bar. */
+ global->bar = rc_alloc(global, struct bar);
+ fail_if(global->bar == NULL);
+ SET_FILLER(global->bar);
+ REF_ASSERT(global->bar, 1);
+
+ /* Allocate baz. */
+ global->baz = rc_alloc(global, struct baz);
+ fail_if(global->baz == NULL);
+ SET_FILLER(global->baz);
+ REF_ASSERT(global->baz, 1);
+
+ /* Try multiple attaches. */
+ containers = talloc_array(NULL, struct container, 100);
+ fail_if(containers == NULL);
+ for (i = 0; i < 100; i++) {
+ containers[i].foo = rc_reference(containers, struct foo, global->foo);
+ containers[i].bar = rc_reference(containers, struct bar, global->bar);
+ containers[i].baz = rc_reference(containers, struct baz, global->baz);
+ REF_ASSERT(containers[i].foo, i + 2);
+ REF_ASSERT(global->foo, i + 2);
+ REF_ASSERT(containers[i].bar, i + 2);
+ REF_ASSERT(global->bar, i + 2);
+ REF_ASSERT(containers[i].baz, i + 2);
+ REF_ASSERT(global->baz, i + 2);
+ }
+ talloc_free(containers);
+
+ CHECK_FILLER(global->foo);
+ CHECK_FILLER(global->bar);
+ CHECK_FILLER(global->baz);
+
+ REF_ASSERT(global->foo, 1);
+ REF_ASSERT(global->bar, 1);
+ REF_ASSERT(global->baz, 1);
+
+ talloc_free(global);
+}
+END_TEST
+
+START_TEST(test_refcount_swap)
+{
+ void *tmp_ctx;
+ struct container *container1;
+ struct container *container2;
+
+ tmp_ctx = talloc_new(NULL);
+
+ check_leaks_push(tmp_ctx);
+
+ container1 = talloc(tmp_ctx, struct container);
+ container2 = talloc(tmp_ctx, struct container);
+
+ /* Allocate. */
+ container1->foo = rc_alloc(container1, struct foo);
+ fail_if(container1->foo == NULL);
+ SET_FILLER(container1->foo);
+
+ /* Reference. */
+ container2->foo = rc_reference(container2, struct foo, container1->foo);
+ fail_if(container2->foo == NULL);
+
+ /* Make sure everything is as it should be. */
+ fail_unless(container1->foo == container2->foo);
+ REF_ASSERT(container1->foo, 2);
+
+ /* Free in reverse order. */
+ talloc_free(container1);
+ REF_ASSERT(container2->foo, 1);
+ CHECK_FILLER(container2->foo);
+ talloc_free(container2);
+
+ check_leaks_pop(tmp_ctx);
+ talloc_free(tmp_ctx);
+}
+END_TEST
+
+Suite *create_suite(void)
+{
+ Suite *s = suite_create("refcount");
+
+ TCase *tc = tcase_create("REFCOUNT Tests");
+
+ /* Do some testing */
+ tcase_add_checked_fixture(tc, leak_check_setup, leak_check_teardown);
+ tcase_add_test(tc, test_refcount_basic);
+ tcase_add_test(tc, test_refcount_swap);
+
+ /* Add all test cases to the test suite */
+ suite_add_tcase(s, tc);
+
+ return s;
+}
+
+int main(int argc, const char *argv[])
+{
+ int opt;
+ poptContext pc;
+ int failure_count;
+ Suite *suite;
+ SRunner *sr;
+ int debug = 0;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ { "debug-level", 'd', POPT_ARG_INT, &debug, 0, "Set debug level", NULL },
+ POPT_TABLEEND
+ };
+
+ pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch(opt) {
+ default:
+ fprintf(stderr, "\nInvalid option %s: %s\n\n",
+ poptBadOption(pc, 0), poptStrerror(opt));
+ poptPrintUsage(pc, stderr, 0);
+ return 1;
+ }
+ }
+ poptFreeContext(pc);
+ debug_level = debug;
+
+ suite = create_suite();
+ sr = srunner_create(suite);
+ srunner_set_fork_status(sr, CK_FORK);
+ /* If CK_VERBOSITY is set, use that, otherwise it defaults to CK_NORMAL */
+ srunner_run_all(sr, CK_ENV);
+ failure_count = srunner_ntests_failed(sr);
+ srunner_free(sr);
+ return (failure_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+}
+
diff --git a/src/tests/resolv-tests.c b/src/tests/resolv-tests.c
new file mode 100644
index 000000000..04b9e2e76
--- /dev/null
+++ b/src/tests/resolv-tests.c
@@ -0,0 +1,598 @@
+/*
+ SSSD
+
+ Async resolver tests
+
+ Authors:
+ Martin Nagy <mnagy@redhat.com>
+ Jakub Hrozek <jhrozek@redhat.com>
+
+ Copyright (C) Red Hat, Inc 2009
+
+ 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 <stdlib.h>
+#include <check.h>
+#include <string.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <popt.h>
+#include <arpa/inet.h>
+
+#include "tests/common.h"
+#include "util/util.h"
+
+/* Interface under test */
+#include "resolv/async_resolv.h"
+
+static int use_net_test;
+static char *txt_host;
+static char *srv_host;
+
+struct resolv_test_ctx {
+ struct tevent_context *ev;
+ struct resolv_ctx *resolv;
+
+ enum {
+ TESTING_HOSTNAME,
+ TESTING_TXT,
+ TESTING_SRV,
+ } tested_function;
+
+ int error;
+ bool done;
+};
+
+static int setup_resolv_test(struct resolv_test_ctx **ctx)
+{
+ struct resolv_test_ctx *test_ctx;
+ int ret;
+
+ test_ctx = talloc_zero(global_talloc_context, struct resolv_test_ctx);
+ if (test_ctx == NULL) {
+ fail("Could not allocate memory for test context");
+ return ENOMEM;
+ }
+
+ test_ctx->ev = tevent_context_init(test_ctx);
+ if (test_ctx->ev == NULL) {
+ fail("Could not init tevent context");
+ talloc_free(test_ctx);
+ return EFAULT;
+ }
+
+ ret = resolv_init(test_ctx, test_ctx->ev, 5, &test_ctx->resolv);
+ if (ret != EOK) {
+ fail("Could not init resolv context");
+ talloc_free(test_ctx);
+ return ret;
+ }
+
+ *ctx = test_ctx;
+ return EOK;
+}
+
+static int test_loop(struct resolv_test_ctx *data)
+{
+ while (!data->done)
+ tevent_loop_once(data->ev);
+
+ return data->error;
+}
+
+START_TEST(test_copy_hostent)
+{
+ void *ctx;
+ struct hostent *new_he;
+
+ char name[] = "foo.example.com";
+ char alias_1[] = "bar.example.com";
+ char alias_2[] = "baz.example.com";
+ char *aliases[] = { alias_1, alias_2, NULL };
+ char addr_1[] = { 1, 2, 3, 4 };
+ char addr_2[] = { 4, 3, 2, 1 };
+ char *addr_list[] = { addr_1, addr_2, NULL };
+ struct hostent he = {
+ name, aliases, 123 /* Whatever. */,
+ sizeof(addr_1), addr_list
+ };
+
+ ctx = talloc_new(global_talloc_context);
+ fail_if(ctx == NULL);
+
+ check_leaks_push(ctx);
+ new_he = resolv_copy_hostent(ctx, &he);
+ fail_if(new_he == NULL);
+ fail_if(strcmp(new_he->h_name, name));
+ fail_if(strcmp(new_he->h_aliases[0], alias_1));
+ fail_if(strcmp(new_he->h_aliases[1], alias_2));
+ fail_if(new_he->h_aliases[2] != NULL);
+ fail_if(new_he->h_addrtype != 123);
+ fail_if(new_he->h_length != sizeof(addr_1));
+ fail_if(memcmp(new_he->h_addr_list[0], addr_1, sizeof(addr_1)));
+ fail_if(memcmp(new_he->h_addr_list[1], addr_2, sizeof(addr_1)));
+ fail_if(new_he->h_addr_list[2] != NULL);
+
+ talloc_free(new_he);
+ check_leaks_pop(ctx);
+}
+END_TEST
+
+static void test_localhost(struct tevent_req *req)
+{
+ int recv_status;
+ int status;
+ struct hostent *hostent;
+ int i;
+ struct resolv_test_ctx *test_ctx = tevent_req_callback_data(req,
+ struct resolv_test_ctx);
+
+ test_ctx->done = true;
+
+ recv_status = resolv_gethostbyname_recv(req, test_ctx,
+ &status, NULL, &hostent);
+ talloc_zfree(req);
+ if (recv_status != EOK) {
+ DEBUG(2, ("resolv_gethostbyname_recv failed: %d\n", recv_status));
+ test_ctx->error = recv_status;
+ return;
+ }
+ DEBUG(7, ("resolv_gethostbyname_recv status: %d\n", status));
+
+ test_ctx->error = ENOENT;
+ for (i = 0; hostent->h_addr_list[i]; i++) {
+ char addr_buf[256];
+ inet_ntop(hostent->h_addrtype, hostent->h_addr_list[i], addr_buf, sizeof(addr_buf));
+
+ /* test that localhost resolves to 127.0.0.1 or ::1 */
+ if (strcmp(addr_buf, "127.0.0.1") == 0 || strcmp(addr_buf, "::1") == 0) {
+ test_ctx->error = EOK;
+ }
+ }
+ talloc_free(hostent);
+}
+
+START_TEST(test_resolv_localhost)
+{
+ struct resolv_test_ctx *test_ctx;
+ int ret = EOK;
+ struct tevent_req *req;
+ const char *hostname = "localhost.localdomain";
+
+ ret = setup_resolv_test(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up test");
+ return;
+ }
+
+ check_leaks_push(test_ctx);
+ req = resolv_gethostbyname_send(test_ctx, test_ctx->ev, test_ctx->resolv, hostname);
+ DEBUG(7, ("Sent resolv_gethostbyname\n"));
+ if (req == NULL) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_localhost, test_ctx);
+ ret = test_loop(test_ctx);
+ }
+
+ check_leaks_pop(test_ctx);
+ fail_unless(ret == EOK);
+
+ talloc_zfree(test_ctx);
+}
+END_TEST
+
+static void test_negative(struct tevent_req *req)
+{
+ int recv_status;
+ int status;
+ struct hostent *hostent;
+ struct resolv_test_ctx *test_ctx;
+
+ test_ctx = tevent_req_callback_data(req, struct resolv_test_ctx);
+ test_ctx->done = true;
+
+ recv_status = resolv_gethostbyname_recv(req, test_ctx,
+ &status, NULL, &hostent);
+ talloc_zfree(req);
+ if (recv_status == EOK) {
+ DEBUG(7, ("resolv_gethostbyname_recv succeeded in a negative test"));
+ return;
+ }
+
+ test_ctx->error = status;
+ DEBUG(2, ("resolv_gethostbyname_recv status: %d: %s\n", status, resolv_strerror(status)));
+}
+
+START_TEST(test_resolv_negative)
+{
+ int ret = EOK;
+ struct tevent_req *req;
+ const char *hostname = "sssd.foo";
+ struct resolv_test_ctx *test_ctx;
+
+ ret = setup_resolv_test(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up test");
+ return;
+ }
+
+ check_leaks_push(test_ctx);
+ req = resolv_gethostbyname_send(test_ctx, test_ctx->ev, test_ctx->resolv, hostname);
+ DEBUG(7, ("Sent resolv_gethostbyname\n"));
+ if (req == NULL) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_negative, test_ctx);
+ ret = test_loop(test_ctx);
+ }
+
+ check_leaks_pop(test_ctx);
+
+ fail_unless(ret != EOK);
+ fail_unless(test_ctx->error == ARES_ENOTFOUND);
+ talloc_zfree(test_ctx);
+}
+END_TEST
+
+static void test_internet(struct tevent_req *req)
+{
+ int recv_status;
+ int status;
+ struct resolv_test_ctx *test_ctx;
+ void *tmp_ctx;
+ struct hostent *hostent = NULL;
+ struct ares_txt_reply *txt_replies = NULL, *txtptr;
+ struct ares_srv_reply *srv_replies = NULL, *srvptr;
+
+ test_ctx = tevent_req_callback_data(req, struct resolv_test_ctx);
+
+ test_ctx->done = true;
+
+ tmp_ctx = talloc_new(test_ctx);
+ check_leaks_push(tmp_ctx);
+
+ switch (test_ctx->tested_function) {
+ case TESTING_HOSTNAME:
+ recv_status = resolv_gethostbyname_recv(req, tmp_ctx,
+ &status, NULL, &hostent);
+ test_ctx->error = (hostent->h_length == 0) ? ENOENT : EOK;
+ break;
+ case TESTING_TXT:
+ recv_status = resolv_gettxt_recv(tmp_ctx, req, &status, NULL,
+ &txt_replies);
+ test_ctx->error = (txt_replies == NULL) ? ENOENT : EOK;
+ for (txtptr = txt_replies; txtptr != NULL; txtptr = txtptr->next) {
+ DEBUG(2, ("TXT Record: %s\n", txtptr->txt));
+ }
+ break;
+ case TESTING_SRV:
+ recv_status = resolv_getsrv_recv(tmp_ctx, req, &status, NULL,
+ &srv_replies);
+ test_ctx->error = (srv_replies == NULL) ? ENOENT : EOK;
+ for (srvptr = srv_replies; srvptr != NULL; srvptr = srvptr->next) {
+ DEBUG(2, ("SRV Record: %d %d %d %s\n", srvptr->weight,
+ srvptr->priority, srvptr->port,
+ srvptr->host));
+ }
+ break;
+ }
+ talloc_zfree(req);
+ fail_if(recv_status != EOK, "The recv function failed: %d", recv_status);
+ DEBUG(7, ("recv status: %d\n", status));
+
+ if (hostent != NULL) {
+ talloc_free(hostent);
+ } else if (txt_replies != NULL) {
+ talloc_free(txt_replies);
+ } else if (srv_replies != NULL) {
+ talloc_free(srv_replies);
+ }
+ check_leaks_pop(tmp_ctx);
+}
+
+START_TEST(test_resolv_internet)
+{
+ int ret = EOK;
+ struct tevent_req *req;
+ const char *hostname = "redhat.com";
+ struct resolv_test_ctx *test_ctx;
+
+ ret = setup_resolv_test(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up test");
+ return;
+ }
+ test_ctx->tested_function = TESTING_HOSTNAME;
+
+ check_leaks_push(test_ctx);
+ req = resolv_gethostbyname_send(test_ctx, test_ctx->ev, test_ctx->resolv, hostname);
+ DEBUG(7, ("Sent resolv_gethostbyname\n"));
+ if (req == NULL) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_internet, test_ctx);
+ ret = test_loop(test_ctx);
+ }
+
+ fail_unless(ret == EOK);
+ check_leaks_pop(test_ctx);
+ talloc_zfree(test_ctx);
+}
+END_TEST
+
+START_TEST(test_resolv_internet_txt)
+{
+ int ret;
+ struct tevent_req *req;
+ struct resolv_test_ctx *test_ctx;
+
+ ret = setup_resolv_test(&test_ctx);
+ fail_if(ret != EOK, "Could not set up test");
+ test_ctx->tested_function = TESTING_TXT;
+
+ check_leaks_push(test_ctx);
+
+ req = resolv_gettxt_send(test_ctx, test_ctx->ev, test_ctx->resolv, txt_host);
+ fail_if(req == NULL, "Function resolv_gettxt_send failed");
+
+ tevent_req_set_callback(req, test_internet, test_ctx);
+ ret = test_loop(test_ctx);
+ fail_unless(ret == EOK);
+
+ check_leaks_pop(test_ctx);
+
+ talloc_zfree(test_ctx);
+}
+END_TEST
+
+START_TEST(test_resolv_internet_srv)
+{
+ int ret;
+ struct tevent_req *req;
+ struct resolv_test_ctx *test_ctx;
+
+ ret = setup_resolv_test(&test_ctx);
+ fail_if(ret != EOK, "Could not set up test");
+ test_ctx->tested_function = TESTING_SRV;
+
+ check_leaks_push(test_ctx);
+
+ req = resolv_getsrv_send(test_ctx, test_ctx->ev, test_ctx->resolv, srv_host);
+ fail_if(req == NULL, "Function resolv_getsrv_send failed");
+
+ tevent_req_set_callback(req, test_internet, test_ctx);
+ ret = test_loop(test_ctx);
+ fail_unless(ret == EOK);
+
+ check_leaks_pop(test_ctx);
+
+ talloc_zfree(test_ctx);
+}
+END_TEST
+
+static void resolv_free_context(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval t, void *ptr)
+{
+ struct resolv_ctx *rctx = talloc_get_type(ptr, struct resolv_ctx);
+ DEBUG(7, ("freeing the context\n"));
+
+ talloc_free(rctx);
+}
+
+static void resolv_free_done(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval t, void *ptr)
+{
+ struct resolv_test_ctx *tctx = talloc_get_type(ptr, struct resolv_test_ctx);
+ DEBUG(7, ("marking test as done\n"));
+
+ tctx->error = EOK;
+ tctx->done = true;
+}
+
+START_TEST(test_resolv_free_context)
+{
+ int ret = EOK;
+ struct tevent_req *req;
+ const char *hostname = "redhat.com";
+ struct resolv_test_ctx *test_ctx;
+ struct tevent_timer *free_timer, *terminate_timer;
+ struct timeval free_tv, terminate_tv;
+
+ ret = setup_resolv_test(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up test");
+ return;
+ }
+
+ req = resolv_gethostbyname_send(test_ctx, test_ctx->ev, test_ctx->resolv, hostname);
+ DEBUG(7, ("Sent resolv_gethostbyname\n"));
+ if (req == NULL) {
+ fail("Error calling resolv_gethostbyname_send");
+ goto done;
+ }
+
+ gettimeofday(&free_tv, NULL);
+ free_tv.tv_sec += 1;
+ free_tv.tv_usec = 0;
+ terminate_tv.tv_sec = free_tv.tv_sec + 1;
+ terminate_tv.tv_usec = 0;
+
+ free_timer = tevent_add_timer(test_ctx->ev, test_ctx, free_tv, resolv_free_context, test_ctx->resolv);
+ if (free_timer == NULL) {
+ fail("Error calling tevent_add_timer");
+ goto done;
+ }
+
+ terminate_timer = tevent_add_timer(test_ctx->ev, test_ctx, terminate_tv, resolv_free_done, test_ctx);
+ if (terminate_timer == NULL) {
+ fail("Error calling tevent_add_timer");
+ goto done;
+ }
+
+ ret = test_loop(test_ctx);
+ fail_unless(ret == EOK);
+
+done:
+ talloc_zfree(test_ctx);
+}
+END_TEST
+
+static void resolv_free_req(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval t, void *ptr)
+{
+ struct tevent_req *req = talloc_get_type(ptr, struct tevent_req);
+ DEBUG(7, ("freeing the request\n"));
+
+ talloc_free(req);
+}
+
+START_TEST(test_resolv_free_req)
+{
+ int ret = EOK;
+ struct tevent_req *req;
+ const char *hostname = "redhat.com";
+ struct resolv_test_ctx *test_ctx;
+ struct tevent_timer *free_timer, *terminate_timer;
+ struct timeval free_tv, terminate_tv;
+
+ ret = setup_resolv_test(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up test");
+ return;
+ }
+
+ check_leaks_push(test_ctx);
+ req = resolv_gethostbyname_send(test_ctx, test_ctx->ev, test_ctx->resolv, hostname);
+ DEBUG(7, ("Sent resolv_gethostbyname\n"));
+ if (req == NULL) {
+ fail("Error calling resolv_gethostbyname_send");
+ goto done;
+ }
+
+ gettimeofday(&free_tv, NULL);
+ free_tv.tv_sec += 1;
+ free_tv.tv_usec = 0;
+ terminate_tv.tv_sec = free_tv.tv_sec + 1;
+ terminate_tv.tv_usec = 0;
+
+ free_timer = tevent_add_timer(test_ctx->ev, test_ctx, free_tv, resolv_free_req, req);
+ if (free_timer == NULL) {
+ fail("Error calling tevent_add_timer");
+ goto done;
+ }
+
+ terminate_timer = tevent_add_timer(test_ctx->ev, test_ctx, terminate_tv, resolv_free_done, test_ctx);
+ if (terminate_timer == NULL) {
+ fail("Error calling tevent_add_timer");
+ goto done;
+ }
+
+ ret = test_loop(test_ctx);
+ check_leaks_pop(test_ctx);
+ fail_unless(ret == EOK);
+
+done:
+ talloc_zfree(test_ctx);
+}
+END_TEST
+
+Suite *create_resolv_suite(void)
+{
+ Suite *s = suite_create("resolv");
+
+ TCase *tc_resolv = tcase_create("RESOLV Tests");
+
+ tcase_add_checked_fixture(tc_resolv, leak_check_setup, leak_check_teardown);
+ /* Do some testing */
+ tcase_add_test(tc_resolv, test_copy_hostent);
+ tcase_add_test(tc_resolv, test_resolv_localhost);
+ tcase_add_test(tc_resolv, test_resolv_negative);
+ if (use_net_test) {
+ tcase_add_test(tc_resolv, test_resolv_internet);
+ if (txt_host != NULL) {
+ tcase_add_test(tc_resolv, test_resolv_internet_txt);
+ }
+ if (srv_host != NULL) {
+ tcase_add_test(tc_resolv, test_resolv_internet_srv);
+ }
+ }
+ tcase_add_test(tc_resolv, test_resolv_free_context);
+ tcase_add_test(tc_resolv, test_resolv_free_req);
+
+ /* Add all test cases to the test suite */
+ suite_add_tcase(s, tc_resolv);
+
+ return s;
+}
+
+int main(int argc, const char *argv[])
+{
+ int opt;
+ poptContext pc;
+ int failure_count;
+ Suite *resolv_suite;
+ SRunner *sr;
+ int debug = 0;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ { "debug-level", 'd', POPT_ARG_INT, &debug, 0, "Set debug level", NULL },
+ { "use-net-test", 'n', POPT_ARG_NONE, 0, 'n', "Run tests that need an active internet connection", NULL },
+ { "txt-host", 't', POPT_ARG_STRING, 0, 't', "Specify the host used for TXT record testing", NULL },
+ { "srv-host", 's', POPT_ARG_STRING, 0, 's', "Specify the host used for SRV record testing", NULL },
+ POPT_TABLEEND
+ };
+
+ pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch(opt) {
+ case 'n':
+ use_net_test = 1;
+ break;
+ case 't':
+ txt_host = poptGetOptArg(pc);
+ break;
+ case 's':
+ srv_host = poptGetOptArg(pc);
+ break;
+ default:
+ fprintf(stderr, "\nInvalid option %s: %s\n\n",
+ poptBadOption(pc, 0), poptStrerror(opt));
+ poptPrintUsage(pc, stderr, 0);
+ return 1;
+ }
+ }
+ poptFreeContext(pc);
+ debug_level = debug;
+
+ resolv_suite = create_resolv_suite();
+ sr = srunner_create(resolv_suite);
+ /* If CK_VERBOSITY is set, use that, otherwise it defaults to CK_NORMAL */
+ srunner_run_all(sr, CK_ENV);
+ failure_count = srunner_ntests_failed(sr);
+ srunner_free(sr);
+ return (failure_count==0 ? EXIT_SUCCESS : EXIT_FAILURE);
+}
+
diff --git a/src/tests/stress-tests.c b/src/tests/stress-tests.c
new file mode 100644
index 000000000..945053185
--- /dev/null
+++ b/src/tests/stress-tests.c
@@ -0,0 +1,328 @@
+/*
+ SSSD
+
+ Stress tests
+
+ Copyright (C) Jakub Hrozek <jhrozek@redhat.com> 2009
+
+ 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 <signal.h>
+#include <stdlib.h>
+#include <talloc.h>
+#include <popt.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <pwd.h>
+#include <grp.h>
+#include <errno.h>
+
+#include "util/util.h"
+
+#define DEFAULT_START 10
+#define DEFAULT_STOP 20
+
+#define NAME_SIZE 255
+#define CHUNK 64
+
+
+/* How many tests failed */
+int failure_count;
+
+/* Be chatty */
+int verbose;
+
+/*
+ * Look up one user. If the user is not found using getpwnam, the success
+ * or failure depends on enoent_fail being set.
+ */
+int test_lookup_user(const char *name, int enoent_fail)
+{
+ struct passwd *pwd = NULL;
+ int ret = 0;
+ int error;
+
+ errno = 0;
+ pwd = getpwnam(name);
+ error = errno;
+ if (pwd == NULL) {
+ if (errno == 0 || errno == ENOENT) {
+ ret = (enoent_fail == 1) ? ENOENT : 0;
+ }
+ }
+
+ if (ret != 0 && verbose) {
+ fprintf(stderr,
+ "getpwnam failed (name: %s): errno = %d, error = %s\n",
+ name, ret, strerror(ret));
+ }
+
+ return ret;
+}
+
+/*
+ * Look up one group. If the user is not found using getgrnam, the success
+ * or failure depends on enoent_fail being set.
+ */
+int test_lookup_group(const char *name, int enoent_fail)
+{
+ struct group *grp = NULL;
+ int ret = 0;
+
+ errno = 0;
+ grp = getgrnam(name);
+ if (grp == NULL) {
+ if (errno == 0 || errno == ENOENT) {
+ ret = enoent_fail ? ENOENT : 0;
+ }
+ }
+
+ if (ret != 0 && verbose) {
+ fprintf(stderr,
+ "getgrnam failed (name %s): errno = %d, error = %s\n",
+ name, ret, strerror(ret));
+ }
+
+ return ret;
+}
+
+int run_one_testcase(const char *name, int group, int enoent_fail)
+{
+ if (group) {
+ return test_lookup_group(name, enoent_fail);
+ } else {
+ return test_lookup_user(name, enoent_fail);
+ }
+}
+
+/*
+ * Beware, has side-effects: changes global variable failure_count
+ */
+void child_handler(int signum)
+{
+ int status, ret;
+
+ while ((ret = wait(&status)) > 0) {
+ if (ret == -1) {
+ perror("wait");
+ exit(EXIT_FAILURE);
+ }
+
+ if (WIFEXITED(status)) {
+ ret = WEXITSTATUS(status);
+ if (ret) {
+ if (verbose) {
+ fprintf(stderr,
+ "A child exited with error code %d\n",
+ WEXITSTATUS(status));
+ }
+ ++failure_count;
+ }
+ } else ++failure_count;
+ }
+}
+
+int generate_names(TALLOC_CTX *mem_ctx, const char *prefix,
+ int start, int stop, char ***_out)
+{
+ char **out;
+ int num_names = stop-start+1;
+ int idx = 0;
+
+ out = talloc_array(mem_ctx, char *, num_names+1);
+ if (out == NULL) {
+ return ENOMEM;
+ }
+
+ for (idx = 0; idx < num_names; ++idx) {
+ out[idx] = talloc_asprintf(mem_ctx, "%s%d", prefix, idx);
+ if (out[idx] == NULL) {
+ return ENOMEM;
+ }
+ }
+ out[idx] = NULL;
+
+ *_out = out;
+ return EOK;
+}
+
+int read_names(TALLOC_CTX *mem_ctx, FILE *stream, char ***_out)
+{
+ char one_name[NAME_SIZE];
+ int n = 0;
+ int array_size = CHUNK;
+ int ret;
+ char **out;
+
+ out = talloc_array(mem_ctx, char *, CHUNK+1);
+ if (out == NULL) {
+ return ENOMEM;
+ }
+ while (fgets(one_name, NAME_SIZE, stream)) {
+ out[n] = talloc_strdup(mem_ctx, one_name);
+ if (out[n] == NULL) {
+ return ENOMEM;
+ }
+ if ((n++ % CHUNK) == 0) {
+ array_size += CHUNK;
+ out = talloc_realloc(mem_ctx, out, char *, array_size);
+ if (out == NULL) {
+ return ENOMEM;
+ }
+ }
+ }
+
+ if ((ret = ferror(stream))) {
+ return ret;
+ }
+ out[n] = NULL;
+
+ *_out = out;
+ return EOK;
+}
+
+int main(int argc, const char *argv[])
+{
+ int opt;
+ poptContext pc;
+ int pc_start=DEFAULT_START;
+ int pc_stop=DEFAULT_STOP;
+ int pc_enoent_fail=0;
+ int pc_groups=0;
+ int pc_verbosity = 0;
+ char *pc_prefix = NULL;
+ TALLOC_CTX *ctx = NULL;
+ char **names = NULL;
+
+ int status, idx, ret;
+ pid_t pid;
+ struct sigaction action, old_action;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ { "groups", 'g', POPT_ARG_NONE, &pc_groups, 0,
+ "Lookup in groups instead of users" },
+ { "prefix", '\0', POPT_ARG_STRING, &pc_prefix, 0,
+ "The username prefix", NULL },
+ { "start", '\0', POPT_ARG_INT | POPT_ARGFLAG_SHOW_DEFAULT,
+ &pc_start, 0,
+ "Start value to append to prefix", NULL },
+ { "stop", '\0', POPT_ARG_INT | POPT_ARGFLAG_SHOW_DEFAULT,
+ &pc_stop, 0,
+ "End value to append to prefix", NULL },
+ { "enoent-fail", '\0', POPT_ARG_NONE, &pc_enoent_fail, 0,
+ "Fail on not getting the requested NSS data (default: No)",
+ NULL },
+ { "verbose", 'v', POPT_ARG_NONE, 0, 'v',
+ "Be verbose" },
+ POPT_TABLEEND
+ };
+
+ /* parse the params */
+ pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 'v':
+ pc_verbosity = 1;
+ break;
+
+ default:
+ fprintf(stderr, "\nInvalid option %s: %s\n\n",
+ poptBadOption(pc, 0), poptStrerror(opt));
+ poptPrintUsage(pc, stderr, 0);
+ return 1;
+ }
+ }
+ poptFreeContext(pc);
+
+ verbose = pc_verbosity;
+
+ if (pc_prefix) {
+ ret = generate_names(ctx, pc_prefix, pc_start, pc_stop, &names);
+ if (ret != EOK) {
+ if (verbose) {
+ errno = ret;
+ perror("generate_names");
+ }
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ ret = read_names(ctx, stdin, &names);
+ if (ret != EOK) {
+ if (verbose) {
+ errno = ret;
+ perror("read_names");
+ }
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /* Reap the children in a handler asynchronously so we can
+ * somehow protect against too many processes */
+ action.sa_handler = child_handler;
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGCHLD);
+ action.sa_flags = SA_NOCLDSTOP;
+
+ sigaction(SIGCHLD, &action, &old_action);
+
+ /* Fire up the child processes */
+ idx = 0;
+ for (idx=0; names[idx]; idx++) {
+ pid = fork();
+ if (pid == -1) {
+ /* Try again in hope that some child has exited */
+ if (errno == EAGAIN) {
+ continue;
+ }
+ perror("fork");
+ exit(EXIT_FAILURE);
+ } else if ( pid == 0 ) {
+ /* child */
+ ret = run_one_testcase(names[idx], pc_groups, pc_enoent_fail);
+ exit(ret);
+ }
+ }
+
+ /* Process the rest of the children here in main */
+ sigaction(SIGCHLD, &old_action, NULL);
+ while ((ret = wait(&status)) > 0) {
+ if (ret == -1) {
+ perror("wait");
+ exit(EXIT_FAILURE);
+ }
+
+ if (WIFEXITED(status)) {
+ ret = WEXITSTATUS(status);
+ if (ret) {
+ if (verbose) {
+ fprintf(stderr,
+ "A child exited with error code %d\n",
+ WEXITSTATUS(status));
+ }
+ ++failure_count;
+ }
+ } else ++failure_count;
+ }
+
+ if (pc_verbosity) {
+ fprintf(stderr,
+ "Total tests run: %d\nPassed: %d\nFailed: %d\n",
+ idx,
+ idx - failure_count,
+ failure_count);
+ }
+ return (failure_count==0 ? EXIT_SUCCESS : EXIT_FAILURE);
+}
diff --git a/src/tests/strtonum-tests.c b/src/tests/strtonum-tests.c
new file mode 100644
index 000000000..7b9cf522c
--- /dev/null
+++ b/src/tests/strtonum-tests.c
@@ -0,0 +1,455 @@
+/*
+ SSSD
+
+ InfoPipe
+
+ Copyright (C) Stephen Gallagher <sgallagh@redhat.com> 2009
+
+ 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 <stdlib.h>
+#include <check.h>
+#include <errno.h>
+#include <popt.h>
+#include "util/util.h"
+#include "util/strtonum.h"
+
+/********************
+ * Utility routines *
+ ********************/
+#define EXPECT_UNSET_ERRNO(error) \
+ do { \
+ fail_unless(error == 0, "errno unexpectedly set to %d[%s]", \
+ error, strerror(error)); \
+ } while(0)
+
+#define CHECK_RESULT(expected, actual) \
+ do { \
+ fail_unless(result == expected, "Expected %ld, got %ld", \
+ expected, result); \
+ } while(0)
+
+#define CHECK_ERRNO(expected, actual) \
+ do { \
+ fail_unless(error == ERANGE, "Expected errno %d[%s], got %d[%s]", \
+ ERANGE, strerror(ERANGE), \
+ error, strerror(ERANGE)); \
+ } while(0)
+
+#define CHECK_ENDPTR(expected, actual) \
+ do { \
+ fail_unless(actual == expected, "Expected endptr %p, got %p", \
+ expected, actual); \
+ } while(0)
+
+#define CHECK_ZERO_ENDPTR(endptr) \
+ do { \
+ fail_unless(endptr && *endptr == '\0', "Invalid endptr"); \
+ } while(0);
+
+/******************
+ * strtoint tests *
+ ******************/
+
+/* Base-10 */
+START_TEST (test_strtoint32_pos_integer_base_10)
+{
+ int32_t result;
+ const char *input = "123";
+ int32_t expected = 123;
+ char *endptr;
+ errno_t error;
+
+ result = strtoint32(input, &endptr, 10);
+ error = errno;
+
+ EXPECT_UNSET_ERRNO(error);
+ CHECK_ZERO_ENDPTR(endptr);
+ CHECK_RESULT(expected, result);
+}
+END_TEST
+
+START_TEST (test_strtoint32_neg_integer_base_10)
+{
+ int32_t result;
+ const char *input = "-123";
+ int32_t expected = -123;
+ char *endptr;
+ errno_t error;
+
+ result = strtoint32(input, &endptr, 10);
+ error = errno;
+
+ EXPECT_UNSET_ERRNO(error);
+ CHECK_ZERO_ENDPTR(endptr);
+ CHECK_RESULT(expected, result);
+}
+END_TEST
+
+START_TEST (test_strtoint32_pos_integer_intmax_base_10)
+{
+ int32_t result;
+ const char *input = "2147483647";
+ int32_t expected = INT32_MAX;
+ char *endptr;
+ errno_t error;
+
+ result = strtoint32(input, &endptr, 10);
+ error = errno;
+
+ EXPECT_UNSET_ERRNO(error);
+ CHECK_ZERO_ENDPTR(endptr);
+ CHECK_RESULT(expected, result);
+}
+END_TEST
+
+START_TEST (test_strtoint32_neg_integer_intmin_base_10)
+{
+ int32_t result;
+ const char *input = "-2147483648";
+ int32_t expected = INT32_MIN;
+ char *endptr;
+ errno_t error;
+
+ result = strtoint32(input, &endptr, 10);
+ error = errno;
+
+ EXPECT_UNSET_ERRNO(error);
+ CHECK_ZERO_ENDPTR(endptr);
+ CHECK_RESULT(expected, result);
+}
+END_TEST
+
+START_TEST (test_strtoint32_pos_integer_overflow_base_10)
+{
+ int32_t result;
+ const char *input = "8589934592";
+ int32_t expected = INT32_MAX;
+ char *endptr;
+ errno_t error;
+
+ result = strtoint32(input, &endptr, 10);
+ error = errno;
+
+ CHECK_ERRNO(ERANGE, error);
+ CHECK_ZERO_ENDPTR(endptr);
+ CHECK_RESULT(expected, actual);
+}
+END_TEST
+
+START_TEST (test_strtoint32_pos_integer_underflow_base_10)
+{
+ int32_t result;
+ const char *input = "-8589934592";
+ int32_t expected = INT32_MIN;
+ char *endptr;
+ errno_t error;
+
+ result = strtoint32(input, &endptr, 10);
+ error = errno;
+
+ CHECK_ERRNO(ERANGE, error);
+ CHECK_ZERO_ENDPTR(endptr);
+ CHECK_RESULT(expected, actual);
+}
+END_TEST
+
+START_TEST (test_strtoint32_mixed_alphanumeric_base_10)
+{
+ int32_t result;
+ const char *input = "12b13";
+ int32_t expected = 12;
+ char *endptr;
+ const char *expected_endptr = input+2;
+ errno_t error;
+
+ result = strtoint32(input, &endptr, 10);
+ error = errno;
+
+ EXPECT_UNSET_ERRNO(error);
+ CHECK_ENDPTR(expected_endptr, endptr);
+ CHECK_RESULT(expected, result);
+}
+END_TEST
+
+START_TEST (test_strtoint32_alphaonly_base_10)
+{
+ int32_t result;
+ const char *input = "alpha";
+ int32_t expected = 0;
+ char *endptr;
+ const char *expected_endptr = input;
+ errno_t error;
+
+ result = strtoint32(input, &endptr, 10);
+ error = errno;
+
+ EXPECT_UNSET_ERRNO(error);
+ CHECK_ENDPTR(expected_endptr, endptr);
+ CHECK_RESULT(expected, result);
+}
+END_TEST
+
+START_TEST (test_strtoint32_alphastart_base_10)
+{
+ int32_t result;
+ const char *input = "alpha12345";
+ int32_t expected = 0;
+ char *endptr;
+ const char *expected_endptr = input;
+ errno_t error;
+
+ result = strtoint32(input, &endptr, 10);
+ error = errno;
+
+ EXPECT_UNSET_ERRNO(error);
+ CHECK_ENDPTR(expected_endptr, endptr);
+ CHECK_RESULT(expected, result);
+}
+END_TEST
+
+START_TEST (test_strtoint32_emptystring_base_10)
+{
+ int32_t result;
+ const char *input = "";
+ int32_t expected = 0;
+ char *endptr;
+ const char *expected_endptr = input;
+ errno_t error;
+
+ result = strtoint32(input, &endptr, 10);
+ error = errno;
+
+ EXPECT_UNSET_ERRNO(error);
+ CHECK_ENDPTR(expected_endptr, endptr);
+ CHECK_RESULT(expected, result);
+}
+END_TEST
+
+/*******************
+ * strtouint tests *
+ *******************/
+
+/* Base-10 */
+START_TEST (test_strtouint32_pos_integer_base_10)
+{
+ uint32_t result;
+ const char *input = "123";
+ uint32_t expected = 123;
+ char *endptr;
+ errno_t error;
+
+ result = strtouint32(input, &endptr, 10);
+ error = errno;
+
+ EXPECT_UNSET_ERRNO(error);
+ CHECK_ZERO_ENDPTR(endptr);
+ CHECK_RESULT(expected, result);
+}
+END_TEST
+
+START_TEST (test_strtouint32_neg_integer_base_10)
+{
+ uint32_t result;
+ const char *input = "-123";
+ uint32_t expected = -123;
+ char *endptr;
+ errno_t error;
+
+ result = strtouint32(input, &endptr, 10);
+ error = errno;
+
+ EXPECT_UNSET_ERRNO(error);
+ CHECK_ZERO_ENDPTR(endptr);
+ CHECK_RESULT(expected, result);
+}
+END_TEST
+
+START_TEST (test_strtouint32_pos_integer_uintmax_base_10)
+{
+ uint32_t result;
+ const char *input = "4294967295";
+ uint32_t expected = UINT32_MAX;
+ char *endptr;
+ errno_t error;
+
+ result = strtouint32(input, &endptr, 10);
+ error = errno;
+
+ EXPECT_UNSET_ERRNO(error);
+ CHECK_ZERO_ENDPTR(endptr);
+ CHECK_RESULT(expected, result);
+}
+END_TEST
+
+
+START_TEST (test_strtouint32_pos_integer_overflow_base_10)
+{
+ uint32_t result;
+ const char *input = "8589934592";
+ uint32_t expected = UINT32_MAX;
+ char *endptr;
+ errno_t error;
+
+ result = strtouint32(input, &endptr, 10);
+ error = errno;
+
+ CHECK_ERRNO(ERANGE, error);
+ CHECK_ZERO_ENDPTR(endptr);
+ CHECK_RESULT(expected, actual);
+}
+END_TEST
+
+START_TEST (test_strtouint32_mixed_alphanumeric_base_10)
+{
+ uint32_t result;
+ const char *input = "12b13";
+ uint32_t expected = 12;
+ char *endptr;
+ const char *expected_endptr = input+2;
+ errno_t error;
+
+ result = strtouint32(input, &endptr, 10);
+ error = errno;
+
+ EXPECT_UNSET_ERRNO(error);
+ CHECK_ENDPTR(expected_endptr, endptr);
+ CHECK_RESULT(expected, result);
+}
+END_TEST
+
+START_TEST (test_strtouint32_alphaonly_base_10)
+{
+ uint32_t result;
+ const char *input = "alpha";
+ uint32_t expected = 0;
+ char *endptr;
+ const char *expected_endptr = input;
+ errno_t error;
+
+ result = strtouint32(input, &endptr, 10);
+ error = errno;
+
+ EXPECT_UNSET_ERRNO(error);
+ CHECK_ENDPTR(expected_endptr, endptr);
+ CHECK_RESULT(expected, result);
+}
+END_TEST
+
+START_TEST (test_strtouint32_alphastart_base_10)
+{
+ uint32_t result;
+ const char *input = "alpha12345";
+ uint32_t expected = 0;
+ char *endptr;
+ const char *expected_endptr = input;
+ errno_t error;
+
+ result = strtouint32(input, &endptr, 10);
+ error = errno;
+
+ EXPECT_UNSET_ERRNO(error);
+ CHECK_ENDPTR(expected_endptr, endptr);
+ CHECK_RESULT(expected, result);
+}
+END_TEST
+
+START_TEST (test_strtouint32_emptystring_base_10)
+{
+ uint32_t result;
+ const char *input = "";
+ uint32_t expected = 0;
+ char *endptr;
+ const char *expected_endptr = input;
+ errno_t error;
+
+ result = strtouint32(input, &endptr, 10);
+ error = errno;
+
+ EXPECT_UNSET_ERRNO(error);
+ CHECK_ENDPTR(expected_endptr, endptr);
+ CHECK_RESULT(expected, result);
+}
+END_TEST
+
+
+
+Suite *create_strtonum_suite(void)
+{
+ Suite *s = suite_create("strtonum");
+
+ TCase *tc_strtoint32 = tcase_create("strtoint32 Tests");
+ tcase_add_test(tc_strtoint32, test_strtoint32_pos_integer_base_10);
+ tcase_add_test(tc_strtoint32, test_strtoint32_neg_integer_base_10);
+ tcase_add_test(tc_strtoint32, test_strtoint32_pos_integer_intmax_base_10);
+ tcase_add_test(tc_strtoint32, test_strtoint32_neg_integer_intmin_base_10);
+ tcase_add_test(tc_strtoint32, test_strtoint32_pos_integer_overflow_base_10);
+ tcase_add_test(tc_strtoint32, test_strtoint32_pos_integer_underflow_base_10);
+ tcase_add_test(tc_strtoint32, test_strtoint32_mixed_alphanumeric_base_10);
+ tcase_add_test(tc_strtoint32, test_strtoint32_alphaonly_base_10);
+ tcase_add_test(tc_strtoint32, test_strtoint32_alphastart_base_10);
+ tcase_add_test(tc_strtoint32, test_strtoint32_emptystring_base_10);
+
+ TCase *tc_strtouint32 = tcase_create("strtouint32 Tests");
+ tcase_add_test(tc_strtouint32, test_strtouint32_pos_integer_base_10);
+ tcase_add_test(tc_strtouint32, test_strtouint32_neg_integer_base_10);
+ tcase_add_test(tc_strtouint32, test_strtouint32_pos_integer_uintmax_base_10);
+ tcase_add_test(tc_strtouint32, test_strtouint32_pos_integer_overflow_base_10);
+ tcase_add_test(tc_strtouint32, test_strtouint32_mixed_alphanumeric_base_10);
+ tcase_add_test(tc_strtouint32, test_strtouint32_alphaonly_base_10);
+ tcase_add_test(tc_strtouint32, test_strtouint32_alphastart_base_10);
+ tcase_add_test(tc_strtouint32, test_strtouint32_emptystring_base_10);
+
+ /* Add all test cases to the suite */
+ suite_add_tcase(s, tc_strtoint32);
+ suite_add_tcase(s, tc_strtouint32);
+
+ return s;
+}
+
+
+int main(int argc, const char *argv[]) {
+ int opt;
+ poptContext pc;
+ int failure_count;
+ Suite *strtonum_suite;
+ SRunner *sr;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ SSSD_MAIN_OPTS
+ { NULL }
+ };
+
+ pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch(opt) {
+ default:
+ fprintf(stderr, "\nInvalid option %s: %s\n\n",
+ poptBadOption(pc, 0), poptStrerror(opt));
+ poptPrintUsage(pc, stderr, 0);
+ return 1;
+ }
+ }
+ poptFreeContext(pc);
+
+ strtonum_suite = create_strtonum_suite();
+ sr = srunner_create(strtonum_suite);
+ /* If CK_VERBOSITY is set, use that, otherwise it defaults to CK_NORMAL */
+ srunner_run_all(sr, CK_ENV);
+ failure_count = srunner_ntests_failed(sr);
+ srunner_free(sr);
+ return (failure_count==0 ? EXIT_SUCCESS : EXIT_FAILURE);
+}
diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
new file mode 100644
index 000000000..8b486b691
--- /dev/null
+++ b/src/tests/sysdb-tests.c
@@ -0,0 +1,3330 @@
+/*
+ SSSD
+
+ System Database
+
+ Copyright (C) Stephen Gallagher <sgallagh@redhat.com> 2009
+
+ 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 <stdlib.h>
+#include <check.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <popt.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "util/util.h"
+#include "confdb/confdb_setup.h"
+#include "db/sysdb_private.h"
+
+#define TESTS_PATH "tests_sysdb"
+#define TEST_CONF_FILE "tests_conf.ldb"
+
+#define TEST_ATTR_NAME "test_attr_name"
+#define TEST_ATTR_VALUE "test_attr_value"
+#define TEST_ATTR_UPDATE_VALUE "test_attr_update_value"
+#define TEST_ATTR_ADD_NAME "test_attr_add_name"
+#define TEST_ATTR_ADD_VALUE "test_attr_add_value"
+#define CUSTOM_TEST_CONTAINER "custom_test_container"
+#define CUSTOM_TEST_OBJECT "custom_test_object"
+
+#define ASQ_TEST_USER "testuser27010"
+#define ASQ_TEST_USER_UID 27010
+
+#define MBO_USER_BASE 27500
+#define MBO_GROUP_BASE 28500
+
+struct sysdb_test_ctx {
+ struct sysdb_ctx *sysdb;
+ struct confdb_ctx *confdb;
+ struct tevent_context *ev;
+ struct sss_domain_info *domain;
+};
+
+static int setup_sysdb_tests(struct sysdb_test_ctx **ctx)
+{
+ struct sysdb_test_ctx *test_ctx;
+ char *conf_db;
+ int ret;
+
+ const char *val[2];
+ val[1] = NULL;
+
+ /* Create tests directory if it doesn't exist */
+ /* (relative to current dir) */
+ ret = mkdir(TESTS_PATH, 0775);
+ if (ret == -1 && errno != EEXIST) {
+ fail("Could not create %s directory", TESTS_PATH);
+ return EFAULT;
+ }
+
+ test_ctx = talloc_zero(NULL, struct sysdb_test_ctx);
+ if (test_ctx == NULL) {
+ fail("Could not allocate memory for test context");
+ return ENOMEM;
+ }
+
+ /* Create an event context
+ * It will not be used except in confdb_init and sysdb_init
+ */
+ test_ctx->ev = tevent_context_init(test_ctx);
+ if (test_ctx->ev == NULL) {
+ fail("Could not create event context");
+ talloc_free(test_ctx);
+ return EIO;
+ }
+
+ conf_db = talloc_asprintf(test_ctx, "%s/%s", TESTS_PATH, TEST_CONF_FILE);
+ if (conf_db == NULL) {
+ fail("Out of memory, aborting!");
+ talloc_free(test_ctx);
+ return ENOMEM;
+ }
+ DEBUG(3, ("CONFDB: %s\n", conf_db));
+
+ /* Connect to the conf db */
+ ret = confdb_init(test_ctx, &test_ctx->confdb, conf_db);
+ if (ret != EOK) {
+ fail("Could not initialize connection to the confdb");
+ talloc_free(test_ctx);
+ return ret;
+ }
+
+ val[0] = "LOCAL";
+ ret = confdb_add_param(test_ctx->confdb, true,
+ "config/sssd", "domains", val);
+ if (ret != EOK) {
+ fail("Could not initialize domains placeholder");
+ talloc_free(test_ctx);
+ return ret;
+ }
+
+ val[0] = "local";
+ ret = confdb_add_param(test_ctx->confdb, true,
+ "config/domain/LOCAL", "id_provider", val);
+ if (ret != EOK) {
+ fail("Could not initialize provider");
+ talloc_free(test_ctx);
+ return ret;
+ }
+
+ val[0] = "TRUE";
+ ret = confdb_add_param(test_ctx->confdb, true,
+ "config/domain/LOCAL", "enumerate", val);
+ if (ret != EOK) {
+ fail("Could not initialize LOCAL domain");
+ talloc_free(test_ctx);
+ return ret;
+ }
+
+ val[0] = "TRUE";
+ ret = confdb_add_param(test_ctx->confdb, true,
+ "config/domain/LOCAL", "cache_credentials", val);
+ if (ret != EOK) {
+ fail("Could not initialize LOCAL domain");
+ talloc_free(test_ctx);
+ return ret;
+ }
+
+ ret = confdb_get_domain(test_ctx->confdb, "local", &test_ctx->domain);
+ if (ret != EOK) {
+ fail("Could not retrieve LOCAL domain");
+ talloc_free(test_ctx);
+ return ret;
+ }
+
+ ret = sysdb_domain_init(test_ctx, test_ctx->ev,
+ test_ctx->domain, TESTS_PATH, &test_ctx->sysdb);
+ if (ret != EOK) {
+ fail("Could not initialize connection to the sysdb (%d)", ret);
+ talloc_free(test_ctx);
+ return ret;
+ }
+
+ *ctx = test_ctx;
+ return EOK;
+}
+
+struct test_data {
+ struct tevent_context *ev;
+ struct sysdb_handle *handle;
+ struct sysdb_test_ctx *ctx;
+
+ const char *username;
+ const char *groupname;
+ uid_t uid;
+ gid_t gid;
+ const char *shell;
+
+ bool finished;
+ int error;
+
+ struct sysdb_attrs *attrs;
+ const char *attrval; /* testing sysdb_get_user_attr */
+ const char **attrlist;
+ struct ldb_message *msg;
+
+ size_t msgs_count;
+ struct ldb_message **msgs;
+};
+
+static int test_loop(struct test_data *data)
+{
+ while (!data->finished)
+ tevent_loop_once(data->ctx->ev);
+
+ return data->error;
+}
+
+static void test_req_done(struct tevent_req *req)
+{
+ struct test_data *data = tevent_req_callback_data(req, struct test_data);
+
+ data->error = sysdb_transaction_commit_recv(req);
+ data->finished = true;
+}
+
+static void test_return(struct test_data *data, int error)
+{
+ struct tevent_req *req;
+
+ if (error != EOK) {
+ goto fail;
+ }
+
+ req = sysdb_transaction_commit_send(data, data->ev, data->handle);
+ if (!req) {
+ error = ENOMEM;
+ goto fail;
+ }
+ tevent_req_set_callback(req, test_req_done, data);
+
+ return;
+
+fail:
+ /* free transaction */
+ talloc_zfree(data->handle);
+
+ data->error = error;
+ data->finished = true;
+}
+
+static void test_add_user_done(struct tevent_req *subreq);
+
+static void test_add_user(struct tevent_req *subreq)
+{
+ struct test_data *data = tevent_req_callback_data(subreq,
+ struct test_data);
+ char *homedir;
+ char *gecos;
+ int ret;
+
+ ret = sysdb_transaction_recv(subreq, data, &data->handle);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ return test_return(data, ret);
+ }
+
+ homedir = talloc_asprintf(data, "/home/testuser%d", data->uid);
+ gecos = talloc_asprintf(data, "Test User %d", data->uid);
+
+ subreq = sysdb_add_user_send(data, data->ev, data->handle,
+ data->ctx->domain, data->username,
+ data->uid, 0,
+ gecos, homedir, "/bin/bash",
+ NULL, 0);
+ if (!subreq) {
+ return test_return(data, ENOMEM);
+ }
+ tevent_req_set_callback(subreq, test_add_user_done, data);
+}
+
+static void test_add_user_done(struct tevent_req *subreq)
+{
+ struct test_data *data = tevent_req_callback_data(subreq, struct test_data);
+ int ret;
+
+ ret = sysdb_add_user_recv(subreq);
+ talloc_zfree(subreq);
+
+ return test_return(data, ret);
+}
+
+static void test_store_user_done(struct tevent_req *subreq);
+
+static void test_store_user(struct tevent_req *req)
+{
+ struct test_data *data = tevent_req_callback_data(req, struct test_data);
+ struct tevent_req *subreq;
+ char *homedir;
+ char *gecos;
+ int ret;
+
+ ret = sysdb_transaction_recv(req, data, &data->handle);
+ if (ret != EOK) {
+ return test_return(data, ret);
+ }
+
+ homedir = talloc_asprintf(data, "/home/testuser%d", data->uid);
+ gecos = talloc_asprintf(data, "Test User %d", data->uid);
+
+ subreq = sysdb_store_user_send(data, data->ev, data->handle,
+ data->ctx->domain, data->username, "x",
+ data->uid, 0,
+ gecos, homedir,
+ data->shell ? data->shell : "/bin/bash",
+ NULL, -1);
+ if (!subreq) {
+ test_return(data, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, test_store_user_done, data);
+}
+
+static void test_store_user_done(struct tevent_req *subreq)
+{
+ struct test_data *data = tevent_req_callback_data(subreq, struct test_data);
+ int ret;
+
+ ret = sysdb_store_user_recv(subreq);
+ talloc_zfree(subreq);
+
+ return test_return(data, ret);
+}
+
+static void test_remove_user_done(struct tevent_req *subreq);
+
+static void test_remove_user(struct tevent_req *req)
+{
+ struct test_data *data = tevent_req_callback_data(req, struct test_data);
+ struct ldb_dn *user_dn;
+ struct tevent_req *subreq;
+ int ret;
+
+ ret = sysdb_transaction_recv(req, data, &data->handle);
+ if (ret != EOK) {
+ return test_return(data, ret);
+ }
+
+ user_dn = sysdb_user_dn(data->ctx->sysdb, data, "LOCAL", data->username);
+ if (!user_dn) return test_return(data, ENOMEM);
+
+ subreq = sysdb_delete_entry_send(data, data->ev, data->handle, user_dn, true);
+ if (!subreq) return test_return(data, ENOMEM);
+
+ tevent_req_set_callback(subreq, test_remove_user_done, data);
+}
+
+static void test_remove_user_done(struct tevent_req *subreq)
+{
+ struct test_data *data = tevent_req_callback_data(subreq,
+ struct test_data);
+ int ret;
+
+ ret = sysdb_delete_entry_recv(subreq);
+ talloc_zfree(subreq);
+
+ return test_return(data, ret);
+}
+
+static void test_remove_user_by_uid_done(struct tevent_req *subreq);
+
+static void test_remove_user_by_uid(struct tevent_req *req)
+{
+ struct test_data *data = tevent_req_callback_data(req, struct test_data);
+ struct tevent_req *subreq;
+ int ret;
+
+ ret = sysdb_transaction_recv(req, data, &data->handle);
+ if (ret != EOK) {
+ return test_return(data, ret);
+ }
+
+ subreq = sysdb_delete_user_send(data, data->ev,
+ NULL, data->handle,
+ data->ctx->domain,
+ NULL, data->uid);
+ if (!subreq) return test_return(data, ENOMEM);
+
+ tevent_req_set_callback(subreq, test_remove_user_by_uid_done, data);
+}
+
+static void test_remove_user_by_uid_done(struct tevent_req *subreq)
+{
+ struct test_data *data = tevent_req_callback_data(subreq,
+ struct test_data);
+ int ret;
+
+ ret = sysdb_delete_user_recv(subreq);
+ if (ret == ENOENT) ret = EOK;
+ talloc_zfree(subreq);
+
+ return test_return(data, ret);
+}
+
+static void test_remove_nonexistent_group_done(struct tevent_req *subreq);
+
+static void test_remove_nonexistent_group(struct tevent_req *req)
+{
+ struct test_data *data = tevent_req_callback_data(req, struct test_data);
+ struct tevent_req *subreq;
+ int ret;
+
+ ret = sysdb_transaction_recv(req, data, &data->handle);
+ if (ret != EOK) {
+ return test_return(data, ret);
+ }
+
+ subreq = sysdb_delete_group_send(data, data->ev,
+ NULL, data->handle,
+ data->ctx->domain,
+ NULL, data->uid);
+ if (!subreq) return test_return(data, ENOMEM);
+
+ tevent_req_set_callback(subreq, test_remove_nonexistent_group_done, data);
+}
+
+static void test_remove_nonexistent_group_done(struct tevent_req *subreq)
+{
+ struct test_data *data = tevent_req_callback_data(subreq,
+ struct test_data);
+ int ret;
+
+ ret = sysdb_delete_group_recv(subreq);
+ talloc_zfree(subreq);
+
+ return test_return(data, ret);
+}
+
+static void test_remove_nonexistent_user_done(struct tevent_req *subreq);
+
+static void test_remove_nonexistent_user(struct tevent_req *req)
+{
+ struct test_data *data = tevent_req_callback_data(req, struct test_data);
+ struct tevent_req *subreq;
+ int ret;
+
+ ret = sysdb_transaction_recv(req, data, &data->handle);
+ if (ret != EOK) {
+ return test_return(data, ret);
+ }
+
+ subreq = sysdb_delete_user_send(data, data->ev,
+ NULL, data->handle,
+ data->ctx->domain,
+ NULL, data->uid);
+ if (!subreq) return test_return(data, ENOMEM);
+
+ tevent_req_set_callback(subreq, test_remove_nonexistent_user_done, data);
+}
+
+static void test_remove_nonexistent_user_done(struct tevent_req *subreq)
+{
+ struct test_data *data = tevent_req_callback_data(subreq,
+ struct test_data);
+ int ret;
+
+ ret = sysdb_delete_user_recv(subreq);
+ talloc_zfree(subreq);
+
+ return test_return(data, ret);
+}
+
+static void test_add_group_done(struct tevent_req *subreq);
+
+static void test_add_group(struct tevent_req *req)
+{
+ struct test_data *data = tevent_req_callback_data(req,
+ struct test_data);
+ struct tevent_req *subreq;
+ int ret;
+
+ ret = sysdb_transaction_recv(req, data, &data->handle);
+ if (ret != EOK) {
+ return test_return(data, ret);
+ }
+
+ subreq = sysdb_add_group_send(data, data->ev, data->handle,
+ data->ctx->domain, data->groupname,
+ data->gid, NULL, 0);
+ if (!subreq) {
+ test_return(data, ret);
+ }
+ tevent_req_set_callback(subreq, test_add_group_done, data);
+}
+
+static void test_add_group_done(struct tevent_req *subreq)
+{
+ struct test_data *data = tevent_req_callback_data(subreq, struct test_data);
+ int ret;
+
+ ret = sysdb_add_group_recv(subreq);
+ talloc_zfree(subreq);
+
+ return test_return(data, ret);
+}
+
+static void test_store_group_done(struct tevent_req *subreq);
+
+static void test_store_group(struct tevent_req *req)
+{
+ struct test_data *data = tevent_req_callback_data(req, struct test_data);
+ struct tevent_req *subreq;
+ int ret;
+
+ ret = sysdb_transaction_recv(req, data, &data->handle);
+ if (ret != EOK) {
+ return test_return(data, ret);
+ }
+
+ subreq = sysdb_store_group_send(data, data->ev, data->handle,
+ data->ctx->domain, data->groupname,
+ data->gid, NULL, -1);
+ if (!subreq) {
+ test_return(data, ret);
+ }
+ tevent_req_set_callback(subreq, test_store_group_done, data);
+}
+
+static void test_store_group_done(struct tevent_req *subreq)
+{
+ struct test_data *data = tevent_req_callback_data(subreq, struct test_data);
+ int ret;
+
+ ret = sysdb_store_group_recv(subreq);
+ talloc_zfree(subreq);
+
+ return test_return(data, ret);
+}
+
+static void test_remove_group_done(struct tevent_req *subreq);
+
+static void test_remove_group(struct tevent_req *req)
+{
+ struct test_data *data = tevent_req_callback_data(req, struct test_data);
+ struct tevent_req *subreq;
+ struct ldb_dn *group_dn;
+ int ret;
+
+ ret = sysdb_transaction_recv(req, data, &data->handle);
+ if (ret != EOK) {
+ return test_return(data, ret);
+ }
+
+ group_dn = sysdb_group_dn(data->ctx->sysdb, data, "LOCAL", data->groupname);
+ if (!group_dn) return test_return(data, ENOMEM);
+
+ subreq = sysdb_delete_entry_send(data, data->ev, data->handle, group_dn, true);
+ if (!subreq) return test_return(data, ENOMEM);
+
+ tevent_req_set_callback(subreq, test_remove_group_done, data);
+}
+
+static void test_remove_group_done(struct tevent_req *subreq)
+{
+ struct test_data *data = tevent_req_callback_data(subreq,
+ struct test_data);
+ int ret;
+
+ ret = sysdb_delete_entry_recv(subreq);
+ talloc_zfree(subreq);
+
+ return test_return(data, ret);
+}
+
+static void test_remove_group_by_gid_done(struct tevent_req *subreq);
+static void test_remove_group_by_gid(struct tevent_req *req)
+{
+ struct test_data *data = tevent_req_callback_data(req, struct test_data);
+ struct tevent_req *subreq;
+ int ret;
+
+ ret = sysdb_transaction_recv(req, data, &data->handle);
+ if (ret != EOK) {
+ return test_return(data, ret);
+ }
+
+ subreq = sysdb_delete_group_send(data, data->ev,
+ NULL, data->handle,
+ data->ctx->domain,
+ NULL, data->gid);
+ if (!subreq) return test_return(data, ENOMEM);
+
+ tevent_req_set_callback(subreq, test_remove_group_by_gid_done, data);
+}
+
+static void test_remove_group_by_gid_done(struct tevent_req *subreq)
+{
+ struct test_data *data = tevent_req_callback_data(subreq,
+ struct test_data);
+ int ret;
+
+ ret = sysdb_delete_group_recv(subreq);
+ if (ret == ENOENT) ret = EOK;
+ talloc_zfree(subreq);
+
+ return test_return(data, ret);
+}
+
+static void test_getpwent(void *pvt, int error, struct ldb_result *res)
+{
+ struct test_data *data = talloc_get_type(pvt, struct test_data);
+ data->finished = true;
+
+ if (error != EOK) {
+ data->error = error;
+ return;
+ }
+
+ switch (res->count) {
+ case 0:
+ data->error = ENOENT;
+ break;
+
+ case 1:
+ data->uid = ldb_msg_find_attr_as_uint(res->msgs[0], SYSDB_UIDNUM, 0);
+ break;
+
+ default:
+ data->error = EFAULT;
+ break;
+ }
+}
+
+static void test_getgrent(void *pvt, int error, struct ldb_result *res)
+{
+ struct test_data *data = talloc_get_type(pvt, struct test_data);
+ data->finished = true;
+
+ if (error != EOK) {
+ data->error = error;
+ return;
+ }
+
+ switch (res->count) {
+ case 0:
+ data->error = ENOENT;
+ break;
+
+ case 1:
+ data->gid = ldb_msg_find_attr_as_uint(res->msgs[0], SYSDB_GIDNUM, 0);
+ break;
+
+ default:
+ data->error = EFAULT;
+ break;
+ }
+}
+
+static void test_getgrgid(void *pvt, int error, struct ldb_result *res)
+{
+ struct test_data *data = talloc_get_type(pvt, struct test_data);
+ data->finished = true;
+
+ if (error != EOK) {
+ data->error = error;
+ return;
+ }
+
+ switch (res->count) {
+ case 0:
+ data->error = ENOENT;
+ break;
+
+ case 1:
+ data->groupname = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, 0);
+ break;
+
+ default:
+ data->error = EFAULT;
+ break;
+ }
+}
+
+static void test_getpwuid(void *pvt, int error, struct ldb_result *res)
+{
+ struct test_data *data = talloc_get_type(pvt, struct test_data);
+ data->finished = true;
+
+ if (error != EOK) {
+ data->error = error;
+ return;
+ }
+
+ switch (res->count) {
+ case 0:
+ data->error = ENOENT;
+ break;
+
+ case 1:
+ data->username = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, 0);
+ break;
+
+ default:
+ data->error = EFAULT;
+ break;
+ }
+}
+
+static void test_enumgrent(void *pvt, int error, struct ldb_result *res)
+{
+ struct test_data *data = talloc_get_type(pvt, struct test_data);
+ const int expected = 20; /* 10 groups + 10 users (we're MPG) */
+
+ data->finished = true;
+
+ if (error != EOK) {
+ data->error = error;
+ return;
+ }
+
+ if (res->count != expected) {
+ data->error = EINVAL;
+ return;
+ }
+
+ data->error = EOK;
+}
+
+static void test_enumpwent(void *pvt, int error, struct ldb_result *res)
+{
+ struct test_data *data = talloc_get_type(pvt, struct test_data);
+ const int expected = 10;
+
+ data->finished = true;
+
+ if (error != EOK) {
+ data->error = error;
+ return;
+ }
+
+ if (res->count != expected) {
+ data->error = EINVAL;
+ return;
+ }
+
+ data->error = EOK;
+}
+
+static void test_set_user_attr_done(struct tevent_req *subreq);
+static void test_set_user_attr(struct tevent_req *req)
+{
+ struct test_data *data = tevent_req_callback_data(req, struct test_data);
+ struct tevent_req *subreq;
+ int ret;
+
+ ret = sysdb_transaction_recv(req, data, &data->handle);
+ if (ret != EOK) {
+ return test_return(data, ret);
+ }
+
+ subreq = sysdb_set_user_attr_send(data, data->ev, data->handle,
+ data->ctx->domain, data->username,
+ data->attrs, SYSDB_MOD_REP);
+ if (!subreq) return test_return(data, ENOMEM);
+
+ tevent_req_set_callback(subreq, test_set_user_attr_done, data);
+}
+
+static void test_set_user_attr_done(struct tevent_req *subreq)
+{
+ struct test_data *data = tevent_req_callback_data(subreq,
+ struct test_data);
+ int ret;
+
+ ret = sysdb_set_user_attr_recv(subreq);
+ talloc_zfree(subreq);
+
+ return test_return(data, ret);
+}
+
+static void test_get_user_attr(void *pvt, int error, struct ldb_result *res)
+{
+ struct test_data *data = talloc_get_type(pvt, struct test_data);
+ data->finished = true;
+
+ if (error != EOK) {
+ data->error = error;
+ return;
+ }
+
+ switch (res->count) {
+ case 0:
+ data->error = ENOENT;
+ break;
+
+ case 1:
+ data->attrval = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_SHELL, 0);
+ break;
+
+ default:
+ data->error = EFAULT;
+ break;
+ }
+}
+
+static void test_add_group_member_done(struct tevent_req *subreq);
+
+static void test_add_group_member(struct tevent_req *req)
+{
+ struct test_data *data = tevent_req_callback_data(req, struct test_data);
+ struct tevent_req *subreq;
+ const char *username;
+ int ret;
+
+ ret = sysdb_transaction_recv(req, data, &data->handle);
+ if (ret != EOK) {
+ return test_return(data, ret);
+ }
+
+ username = talloc_asprintf(data, "testuser%d", data->uid);
+ if (username == NULL) {
+ test_return(data, ENOMEM);
+ }
+
+ subreq = sysdb_add_group_member_send(data, data->ev,
+ data->handle, data->ctx->domain,
+ data->groupname, username);
+ if (!subreq) {
+ test_return(data, ENOMEM);
+ }
+
+ tevent_req_set_callback(subreq, test_add_group_member_done, data);
+}
+
+static void test_add_group_member_done(struct tevent_req *subreq)
+{
+ struct test_data *data = tevent_req_callback_data(subreq,
+ struct test_data);
+ int ret = sysdb_add_group_member_recv(subreq);
+
+ test_return(data, ret);
+}
+
+static void test_remove_group_member_done(struct tevent_req *subreq);
+
+static void test_remove_group_member(struct tevent_req *req)
+{
+ struct test_data *data = tevent_req_callback_data(req, struct test_data);
+ struct tevent_req *subreq;
+ const char *username;
+ int ret;
+
+ ret = sysdb_transaction_recv(req, data, &data->handle);
+ if (ret != EOK) {
+ return test_return(data, ret);
+ }
+
+ username = talloc_asprintf(data, "testuser%d", data->uid);
+ if (username == NULL) {
+ test_return(data, ENOMEM);
+ }
+
+ subreq = sysdb_remove_group_member_send(data, data->ev,
+ data->handle, data->ctx->domain,
+ data->groupname, username);
+ if (!subreq) {
+ test_return(data, ENOMEM);
+ }
+
+ tevent_req_set_callback(subreq, test_remove_group_member_done, data);
+}
+
+static void test_remove_group_member_done(struct tevent_req *subreq)
+{
+ struct test_data *data = tevent_req_callback_data(subreq,
+ struct test_data);
+ int ret = sysdb_remove_group_member_recv(subreq);
+
+ test_return(data, ret);
+}
+
+static void test_store_custom_done(struct tevent_req *subreq);
+
+static void test_store_custom(struct tevent_req *subreq)
+{
+ struct test_data *data = tevent_req_callback_data(subreq,
+ struct test_data);
+ int ret;
+ char *object_name;
+
+ ret = sysdb_transaction_recv(subreq, data, &data->handle);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ return test_return(data, ret);
+ }
+
+ object_name = talloc_asprintf(data, "%s_%d", CUSTOM_TEST_OBJECT, data->uid);
+ if (!object_name) {
+ return test_return(data, ENOMEM);
+ }
+
+ subreq = sysdb_store_custom_send(data, data->ev, data->handle,
+ data->ctx->domain, object_name,
+ CUSTOM_TEST_CONTAINER, data->attrs);
+ if (!subreq) {
+ return test_return(data, ENOMEM);
+ }
+ tevent_req_set_callback(subreq, test_store_custom_done, data);
+}
+
+static void test_store_custom_done(struct tevent_req *subreq)
+{
+ struct test_data *data = tevent_req_callback_data(subreq, struct test_data);
+ int ret;
+
+ ret = sysdb_store_custom_recv(subreq);
+ talloc_zfree(subreq);
+
+ return test_return(data, ret);
+}
+
+static void test_search_done(struct tevent_req *req)
+{
+ struct test_data *data = tevent_req_callback_data(req, struct test_data);
+
+ data->finished = true;
+ return;
+}
+
+static void test_delete_custom_done(struct tevent_req *subreq);
+
+static void test_delete_custom(struct tevent_req *subreq)
+{
+ struct test_data *data = tevent_req_callback_data(subreq,
+ struct test_data);
+ int ret;
+
+ ret = sysdb_transaction_recv(subreq, data, &data->handle);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ return test_return(data, ret);
+ }
+
+
+ subreq = sysdb_delete_custom_send(data, data->ev, data->handle,
+ data->ctx->domain, CUSTOM_TEST_OBJECT,
+ CUSTOM_TEST_CONTAINER);
+ if (!subreq) {
+ return test_return(data, ENOMEM);
+ }
+ tevent_req_set_callback(subreq, test_delete_custom_done, data);
+}
+
+static void test_delete_custom_done(struct tevent_req *subreq)
+{
+ struct test_data *data = tevent_req_callback_data(subreq, struct test_data);
+ int ret;
+
+ ret = sysdb_delete_custom_recv(subreq);
+ talloc_zfree(subreq);
+
+ return test_return(data, ret);
+}
+
+static void test_search_all_users_done(struct tevent_req *subreq);
+static void test_search_all_users(struct tevent_req *subreq)
+{
+ struct test_data *data = tevent_req_callback_data(subreq,
+ struct test_data);
+ struct ldb_dn *base_dn;
+ int ret;
+
+ ret = sysdb_transaction_recv(subreq, data, &data->handle);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ return test_return(data, ret);
+ }
+
+ base_dn = ldb_dn_new_fmt(data, data->ctx->sysdb->ldb, SYSDB_TMPL_USER_BASE,
+ "LOCAL");
+ if (base_dn == NULL) {
+ return test_return(data, ENOMEM);
+ }
+
+ subreq = sysdb_search_entry_send(data, data->ev, data->handle,
+ base_dn, LDB_SCOPE_SUBTREE,
+ "objectClass=user", data->attrlist);
+ if (!subreq) {
+ return test_return(data, ENOMEM);
+ }
+ tevent_req_set_callback(subreq, test_search_all_users_done, data);
+}
+
+static void test_search_all_users_done(struct tevent_req *subreq)
+{
+ struct test_data *data = tevent_req_callback_data(subreq, struct test_data);
+ int ret;
+
+ ret = sysdb_search_entry_recv(subreq, data, &data->msgs_count, &data->msgs);
+ talloc_zfree(subreq);
+
+ test_return(data, ret);
+ return;
+}
+
+static void test_delete_recursive_done(struct tevent_req *subreq);
+
+static void test_delete_recursive(struct tevent_req *subreq)
+{
+ struct test_data *data = tevent_req_callback_data(subreq,
+ struct test_data);
+ int ret;
+ struct ldb_dn *dn;
+
+ ret = sysdb_transaction_recv(subreq, data, &data->handle);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ return test_return(data, ret);
+ }
+
+ dn = ldb_dn_new_fmt(data, data->handle->ctx->ldb, SYSDB_DOM_BASE,
+ "LOCAL");
+ if (!dn) {
+ return test_return(data, ENOMEM);
+ }
+
+ subreq = sysdb_delete_recursive_send(data, data->ev, data->handle, dn,
+ false);
+ if (!subreq) {
+ return test_return(data, ENOMEM);
+ }
+ tevent_req_set_callback(subreq, test_delete_recursive_done, data);
+}
+
+static void test_delete_recursive_done(struct tevent_req *subreq)
+{
+ struct test_data *data = tevent_req_callback_data(subreq, struct test_data);
+ int ret;
+
+ ret = sysdb_delete_recursive_recv(subreq);
+ talloc_zfree(subreq);
+ fail_unless(ret == EOK, "sysdb_delete_recursive_recv returned [%d]", ret);
+ return test_return(data, ret);
+}
+
+static void test_memberof_store_group_done(struct tevent_req *subreq);
+static void test_memberof_store_group(struct tevent_req *req)
+{
+ struct test_data *data = tevent_req_callback_data(req, struct test_data);
+ struct tevent_req *subreq;
+ int ret;
+ struct sysdb_attrs *attrs = NULL;
+ char *member;
+ int i;
+
+ ret = sysdb_transaction_recv(req, data, &data->handle);
+ if (ret != EOK) {
+ return test_return(data, ret);
+ }
+
+ attrs = sysdb_new_attrs(data);
+ if (!attrs) {
+ return test_return(data, ENOMEM);
+ }
+ for (i = 0; data->attrlist && data->attrlist[i]; i++) {
+ member = sysdb_group_strdn(data, data->ctx->domain->name,
+ data->attrlist[i]);
+ if (!member) {
+ return test_return(data, ENOMEM);
+ }
+ ret = sysdb_attrs_steal_string(attrs, SYSDB_MEMBER, member);
+ if (ret != EOK) {
+ return test_return(data, ret);
+ }
+ }
+
+ subreq = sysdb_store_group_send(data, data->ev, data->handle,
+ data->ctx->domain, data->groupname,
+ data->gid, attrs, -1);
+ if (!subreq) {
+ test_return(data, ret);
+ }
+ tevent_req_set_callback(subreq, test_memberof_store_group_done, data);
+}
+
+static void test_memberof_store_group_done(struct tevent_req *subreq)
+{
+ struct test_data *data = tevent_req_callback_data(subreq, struct test_data);
+ int ret;
+
+ ret = sysdb_store_group_recv(subreq);
+ talloc_zfree(subreq);
+
+ return test_return(data, ret);
+}
+
+START_TEST (test_sysdb_store_user)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->uid = _i;
+ data->gid = _i;
+ data->username = talloc_asprintf(data, "testuser%d", _i);
+
+ req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!req) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_store_user, data);
+
+ ret = test_loop(data);
+ }
+
+ fail_if(ret != EOK, "Could not store user %s", data->username);
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_store_user_existing)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->uid = _i;
+ data->gid = _i;
+ data->username = talloc_asprintf(data, "testuser%d", _i);
+ data->shell = talloc_asprintf(data, "/bin/ksh");
+
+ req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!req) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_store_user, data);
+
+ ret = test_loop(data);
+ }
+
+ fail_if(ret != EOK, "Could not store user %s", data->username);
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_store_group)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->gid = _i;
+ data->groupname = talloc_asprintf(data, "testgroup%d", _i);
+
+ req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!req) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_store_group, data);
+
+ ret = test_loop(data);
+ }
+
+ fail_if(ret != EOK, "Could not store POSIX group #%d", _i);
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_remove_local_user)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->username = talloc_asprintf(data, "testuser%d", _i);
+
+ req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!req) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_remove_user, data);
+
+ ret = test_loop(data);
+ }
+
+ fail_if(ret != EOK, "Could not remove user %s", data->username);
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_remove_local_user_by_uid)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->uid = _i;
+
+ req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!req) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_remove_user_by_uid, data);
+
+ ret = test_loop(data);
+ }
+
+ fail_if(ret != EOK, "Could not remove user with uid %d", _i);
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_remove_local_group)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->groupname = talloc_asprintf(data, "testgroup%d", _i);
+
+ req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!req) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_remove_group, data);
+
+ ret = test_loop(data);
+ }
+
+ fail_if(ret != EOK, "Could not remove group %s", data->groupname);
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_remove_local_group_by_gid)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->gid = _i;
+
+ req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!req) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_remove_group_by_gid, data);
+
+ ret = test_loop(data);
+ }
+
+ fail_if(ret != EOK, "Could not remove group with gid %d", _i);
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_add_user)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *subreq;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->uid = _i;
+ data->gid = _i;
+ data->username = talloc_asprintf(data, "testuser%d", _i);
+
+ subreq = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!subreq) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(subreq, test_add_user, data);
+
+ ret = test_loop(data);
+ }
+
+ fail_if(ret != EOK, "Could not add user %s", data->username);
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_add_group)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *subreq;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->uid = _i;
+ data->gid = _i;
+ data->groupname = talloc_asprintf(data, "testgroup%d", _i);
+
+ subreq = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!subreq) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(subreq, test_add_group, data);
+
+ ret = test_loop(data);
+ }
+
+ fail_if(ret != EOK, "Could not add group %s", data->groupname);
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_getpwnam)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct test_data *data_uc;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->username = talloc_asprintf(data, "testuser%d", _i);
+
+ ret = sysdb_getpwnam(test_ctx,
+ test_ctx->sysdb,
+ data->ctx->domain,
+ data->username,
+ test_getpwent,
+ data);
+ if (ret == EOK) {
+ ret = test_loop(data);
+ }
+
+ if (ret) {
+ fail("sysdb_getpwnam failed for username %s (%d: %s)",
+ data->username, ret, strerror(ret));
+ goto done;
+ }
+ fail_unless(data->uid == _i,
+ "Did not find the expected UID");
+
+ /* Search for the user with the wrong case */
+ data_uc = talloc_zero(test_ctx, struct test_data);
+ data_uc->ctx = test_ctx;
+ data_uc->username = talloc_asprintf(data_uc, "TESTUSER%d", _i);
+
+ ret = sysdb_getpwnam(test_ctx,
+ test_ctx->sysdb,
+ data_uc->ctx->domain,
+ data_uc->username,
+ test_getpwent,
+ data_uc);
+ if (ret == EOK) {
+ ret = test_loop(data_uc);
+ }
+
+ fail_unless(ret == ENOENT,
+ "The upper-case username search should fail. ");
+
+done:
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_getgrnam)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct test_data *data_uc;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->groupname = talloc_asprintf(data, "testgroup%d", _i);
+
+ ret = sysdb_getgrnam(test_ctx,
+ test_ctx->sysdb,
+ data->ctx->domain,
+ data->groupname,
+ test_getgrent,
+ data);
+ if (ret == EOK) {
+ ret = test_loop(data);
+ }
+
+ if (ret) {
+ fail("sysdb_getgrnam failed for groupname %s (%d: %s)",
+ data->groupname, ret, strerror(ret));
+ goto done;
+ }
+ fail_unless(data->gid == _i,
+ "Did not find the expected GID (found %d expected %d)",
+ data->gid, _i);
+
+ /* Search for the group with the wrong case */
+ data_uc = talloc_zero(test_ctx, struct test_data);
+ data_uc->ctx = test_ctx;
+ data_uc->groupname = talloc_asprintf(data_uc, "TESTGROUP%d", _i);
+
+ ret = sysdb_getgrnam(test_ctx,
+ test_ctx->sysdb,
+ data_uc->ctx->domain,
+ data_uc->groupname,
+ test_getgrent,
+ data_uc);
+ if (ret == EOK) {
+ ret = test_loop(data_uc);
+ }
+
+ fail_unless(ret == ENOENT,
+ "The upper-case groupname search should fail. ");
+done:
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_getgrgid)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ int ret;
+ const char *groupname = NULL;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ groupname = talloc_asprintf(test_ctx, "testgroup%d", _i);
+ if (groupname == NULL) {
+ fail("Cannot allocate memory");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->gid = _i;
+
+ ret = sysdb_getgrgid(test_ctx,
+ test_ctx->sysdb,
+ data->ctx->domain,
+ data->gid,
+ test_getgrgid,
+ data);
+ if (ret == EOK) {
+ ret = test_loop(data);
+ }
+
+ if (ret) {
+ fail("sysdb_getgrgid failed for gid %d (%d: %s)",
+ data->gid, ret, strerror(ret));
+ goto done;
+ }
+ fail_unless(strcmp(data->groupname, groupname) == 0,
+ "Did not find the expected groupname (found %s expected %s)",
+ data->groupname, groupname);
+done:
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_getpwuid)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ int ret;
+ const char *username = NULL;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ username = talloc_asprintf(test_ctx, "testuser%d", _i);
+ if (username == NULL) {
+ fail("Cannot allocate memory");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->uid = _i;
+
+ ret = sysdb_getpwuid(test_ctx,
+ test_ctx->sysdb,
+ data->ctx->domain,
+ data->uid,
+ test_getpwuid,
+ data);
+ if (ret == EOK) {
+ ret = test_loop(data);
+ }
+
+ if (ret) {
+ fail("sysdb_getpwuid failed for uid %d (%d: %s)",
+ data->uid, ret, strerror(ret));
+ goto done;
+ }
+
+ fail_unless(strcmp(data->username, username) == 0,
+ "Did not find the expected username (found %s expected %s)",
+ data->username, username);
+done:
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_enumgrent)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+
+ ret = sysdb_enumgrent(test_ctx,
+ test_ctx->sysdb,
+ data->ctx->domain,
+ test_enumgrent,
+ data);
+ if (ret == EOK) {
+ ret = test_loop(data);
+ }
+
+ fail_unless(ret == EOK,
+ "sysdb_enumgrent failed (%d: %s)",
+ ret, strerror(ret));
+
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_enumpwent)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+
+ ret = sysdb_enumpwent(test_ctx,
+ test_ctx->sysdb,
+ data->ctx->domain,
+ NULL,
+ test_enumpwent,
+ data);
+ if (ret == EOK) {
+ ret = test_loop(data);
+ }
+
+ fail_unless(ret == EOK,
+ "sysdb_enumpwent failed (%d: %s)",
+ ret, strerror(ret));
+
+ talloc_free(test_ctx);
+}
+END_TEST
+
+
+START_TEST (test_sysdb_set_user_attr)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->username = talloc_asprintf(data, "testuser%d", _i);
+
+ data->attrs = sysdb_new_attrs(test_ctx);
+ if (ret != EOK) {
+ fail("Could not create the changeset");
+ return;
+ }
+
+ ret = sysdb_attrs_add_string(data->attrs,
+ SYSDB_SHELL,
+ "/bin/ksh");
+ if (ret != EOK) {
+ fail("Could not create the changeset");
+ return;
+ }
+
+ req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!req) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_set_user_attr, data);
+
+ ret = test_loop(data);
+ }
+
+ fail_if(ret != EOK, "Could not modify user %s", data->username);
+
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_get_user_attr)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ int ret;
+ const char *attrs[] = { SYSDB_SHELL, NULL };
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->username = talloc_asprintf(data, "testuser%d", _i);
+
+ ret = sysdb_get_user_attr(data,
+ data->ctx->sysdb,
+ data->ctx->domain,
+ data->username,
+ attrs,
+ test_get_user_attr,
+ data);
+ if (ret == EOK) {
+ ret = test_loop(data);
+ }
+
+ if (ret) {
+ fail("Could not get attributes for user %s", data->username);
+ goto done;
+ }
+ fail_if(strcmp(data->attrval, "/bin/ksh"),
+ "Got bad attribute value for user %s",
+ data->username);
+done:
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_add_group_member)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->groupname = talloc_asprintf(data, "testgroup%d", _i);
+ data->uid = _i - 1000; /* the UID of user to add */
+
+ req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!req) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_add_group_member, data);
+
+ ret = test_loop(data);
+ }
+
+ fail_if(ret != EOK, "Could not modify group %s", data->groupname);
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_remove_group_member)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->groupname = talloc_asprintf(data, "testgroup%d", _i);
+ data->uid = _i - 1000; /* the UID of user to add */
+
+ req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!req) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_remove_group_member, data);
+
+ ret = test_loop(data);
+ }
+
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_remove_nonexistent_user)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->uid = 12345;
+
+ req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!req) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_remove_nonexistent_user, data);
+
+ ret = test_loop(data);
+ }
+
+ fail_if(ret != ENOENT, "Unexpected return code %d, expected ENOENT", ret);
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_remove_nonexistent_group)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->uid = 12345;
+
+ req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!req) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_remove_nonexistent_group, data);
+
+ ret = test_loop(data);
+ }
+
+ fail_if(ret != ENOENT, "Unexpected return code %d, expected ENOENT", ret);
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_store_custom)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *subreq;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->uid = _i;
+ data->attrs = sysdb_new_attrs(test_ctx);
+ if (ret != EOK) {
+ fail("Could not create attribute list");
+ return;
+ }
+
+ ret = sysdb_attrs_add_string(data->attrs,
+ TEST_ATTR_NAME,
+ TEST_ATTR_VALUE);
+ if (ret != EOK) {
+ fail("Could not add attribute");
+ return;
+ }
+
+ subreq = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!subreq) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(subreq, test_store_custom, data);
+
+ ret = test_loop(data);
+ }
+
+ fail_if(ret != EOK, "Could not add custom object");
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_search_custom_by_name)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *subreq;
+ int ret;
+ char *object_name;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ fail_unless(data != NULL, "talloc_zero failed");
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->attrlist = talloc_array(test_ctx, const char *, 2);
+ fail_unless(data->attrlist != NULL, "talloc_array failed");
+ data->attrlist[0] = TEST_ATTR_NAME;
+ data->attrlist[1] = NULL;
+
+ object_name = talloc_asprintf(data, "%s_%d", CUSTOM_TEST_OBJECT, 29010);
+ fail_unless(object_name != NULL, "talloc_asprintf failed");
+
+ subreq = sysdb_search_custom_by_name_send(data, data->ev,
+ data->ctx->sysdb, NULL,
+ data->ctx->domain,
+ object_name,
+ CUSTOM_TEST_CONTAINER,
+ data->attrlist);
+ if (!subreq) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(subreq, test_search_done, data);
+
+ ret = test_loop(data);
+
+ ret = sysdb_search_custom_recv(subreq, data, &data->msgs_count,
+ &data->msgs);
+ talloc_zfree(subreq);
+ fail_unless(ret == EOK, "sysdb_search_custom_by_name_send failed");
+
+ fail_unless(data->msgs_count == 1,
+ "Wrong number of objects, exptected [1] got [%d]",
+ data->msgs_count);
+ fail_unless(data->msgs[0]->num_elements == 1,
+ "Wrong number of results, expected [1] got [%d]",
+ data->msgs[0]->num_elements);
+ fail_unless(strcmp(data->msgs[0]->elements[0].name, TEST_ATTR_NAME) == 0,
+ "Wrong attribute name");
+ fail_unless(data->msgs[0]->elements[0].num_values == 1,
+ "Wrong number of attribute values");
+ fail_unless(strncmp((const char *)data->msgs[0]->elements[0].values[0].data,
+ TEST_ATTR_VALUE,
+ data->msgs[0]->elements[0].values[0].length) == 0,
+ "Wrong attribute value");
+ }
+
+ fail_if(ret != EOK, "Could not search custom object");
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_update_custom)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *subreq;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->uid = 29010;
+ data->attrs = sysdb_new_attrs(test_ctx);
+ if (ret != EOK) {
+ fail("Could not create attribute list");
+ return;
+ }
+
+ ret = sysdb_attrs_add_string(data->attrs,
+ TEST_ATTR_NAME,
+ TEST_ATTR_UPDATE_VALUE);
+ if (ret != EOK) {
+ fail("Could not add attribute");
+ return;
+ }
+
+ ret = sysdb_attrs_add_string(data->attrs,
+ TEST_ATTR_ADD_NAME,
+ TEST_ATTR_ADD_VALUE);
+ if (ret != EOK) {
+ fail("Could not add attribute");
+ return;
+ }
+
+ subreq = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!subreq) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(subreq, test_store_custom, data);
+
+ ret = test_loop(data);
+ }
+
+ fail_if(ret != EOK, "Could not add custom object");
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_search_custom_update)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *subreq;
+ int ret;
+ char *object_name;
+ struct ldb_message_element *el;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ fail_unless(data != NULL, "talloc_zero failed");
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->attrlist = talloc_array(test_ctx, const char *, 3);
+ fail_unless(data->attrlist != NULL, "talloc_array failed");
+ data->attrlist[0] = TEST_ATTR_NAME;
+ data->attrlist[1] = TEST_ATTR_ADD_NAME;
+ data->attrlist[2] = NULL;
+
+ object_name = talloc_asprintf(data, "%s_%d", CUSTOM_TEST_OBJECT, 29010);
+ fail_unless(object_name != NULL, "talloc_asprintf failed");
+
+ subreq = sysdb_search_custom_by_name_send(data, data->ev,
+ data->ctx->sysdb, NULL,
+ data->ctx->domain,
+ object_name,
+ CUSTOM_TEST_CONTAINER,
+ data->attrlist);
+ if (!subreq) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(subreq, test_search_done, data);
+
+ ret = test_loop(data);
+
+ ret = sysdb_search_custom_recv(subreq, data, &data->msgs_count,
+ &data->msgs);
+ talloc_zfree(subreq);
+ fail_unless(ret == EOK, "sysdb_search_custom_by_name_send failed");
+
+ fail_unless(data->msgs_count == 1,
+ "Wrong number of objects, exptected [1] got [%d]",
+ data->msgs_count);
+ fail_unless(data->msgs[0]->num_elements == 2,
+ "Wrong number of results, expected [2] got [%d]",
+ data->msgs[0]->num_elements);
+
+ el = ldb_msg_find_element(data->msgs[0], TEST_ATTR_NAME);
+ fail_unless(el != NULL, "Attribute [%s] not found", TEST_ATTR_NAME);
+ fail_unless(el->num_values == 1, "Wrong number ([%d] instead of 1) "
+ "of attribute values for [%s]", el->num_values, TEST_ATTR_NAME);
+ fail_unless(strncmp((const char *) el->values[0].data, TEST_ATTR_UPDATE_VALUE,
+ el->values[0].length) == 0,
+ "Wrong attribute value");
+
+ el = ldb_msg_find_element(data->msgs[0], TEST_ATTR_ADD_NAME);
+ fail_unless(el != NULL, "Attribute [%s] not found", TEST_ATTR_ADD_NAME);
+ fail_unless(el->num_values == 1, "Wrong number ([%d] instead of 1) "
+ "of attribute values for [%s]", el->num_values, TEST_ATTR_ADD_NAME);
+ fail_unless(strncmp((const char *) el->values[0].data, TEST_ATTR_ADD_VALUE,
+ el->values[0].length) == 0,
+ "Wrong attribute value");
+
+ }
+
+ fail_if(ret != EOK, "Could not search custom object");
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_search_custom)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *subreq;
+ int ret;
+ const char *filter = "(distinguishedName=*)";
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ fail_unless(data != NULL, "talloc_zero failed");
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->attrlist = talloc_array(test_ctx, const char *, 3);
+ fail_unless(data->attrlist != NULL, "talloc_array failed");
+ data->attrlist[0] = TEST_ATTR_NAME;
+ data->attrlist[1] = TEST_ATTR_ADD_NAME;
+ data->attrlist[2] = NULL;
+
+ subreq = sysdb_search_custom_send(data, data->ev,
+ data->ctx->sysdb, NULL,
+ data->ctx->domain,
+ filter,
+ CUSTOM_TEST_CONTAINER,
+ data->attrlist);
+ if (!subreq) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(subreq, test_search_done, data);
+
+ ret = test_loop(data);
+
+ ret = sysdb_search_custom_recv(subreq, data, &data->msgs_count,
+ &data->msgs);
+ talloc_zfree(subreq);
+ fail_unless(ret == EOK, "sysdb_search_custom_send failed");
+
+ fail_unless(data->msgs_count == 10,
+ "Wrong number of objects, exptected [10] got [%d]",
+ data->msgs_count);
+ }
+
+ fail_if(ret != EOK, "Could not search custom object");
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_delete_custom)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *subreq;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+
+ subreq = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!subreq) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(subreq, test_delete_custom, data);
+
+ ret = test_loop(data);
+ }
+
+ fail_if(ret != EOK, "Could not delete custom object");
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_cache_password)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ fail_unless(ret == EOK, "Could not set up the test");
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->username = talloc_asprintf(data, "testuser%d", _i);
+
+ req = sysdb_cache_password_send(data, test_ctx->ev, test_ctx->sysdb, NULL,
+ test_ctx->domain, data->username,
+ data->username);
+ fail_unless(req != NULL, "sysdb_cache_password_send failed [%d].", ret);
+
+ tevent_req_set_callback(req, test_search_done, data);
+
+ ret = test_loop(data);
+ fail_unless(ret == EOK, "test_loop failed [%d].", ret);
+
+ ret = sysdb_cache_password_recv(req);
+ fail_unless(ret == EOK, "sysdb_cache_password request failed [%d].", ret);
+
+ talloc_free(test_ctx);
+}
+END_TEST
+
+static void cached_authentication_without_expiration(const char *username,
+ const char *password,
+ int expected_result)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+ time_t expire_date;
+ time_t delayed_until;
+ const char *val[2];
+ val[1] = NULL;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ fail_unless(ret == EOK, "Could not set up the test");
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->username = username;
+
+ val[0] = "0";
+ ret = confdb_add_param(test_ctx->confdb, true, CONFDB_PAM_CONF_ENTRY,
+ CONFDB_PAM_CRED_TIMEOUT, val);
+ if (ret != EOK) {
+ fail("Could not initialize provider");
+ talloc_free(test_ctx);
+ return;
+ }
+
+ req = sysdb_cache_auth_send(data, test_ctx->ev, test_ctx->sysdb,
+ test_ctx->domain, data->username,
+ (const uint8_t *) password, strlen(password),
+ test_ctx->confdb);
+ fail_unless(req != NULL, "sysdb_cache_password_send failed.");
+
+ tevent_req_set_callback(req, test_search_done, data);
+
+ ret = test_loop(data);
+ fail_unless(ret == EOK, "test_loop failed.");
+
+ ret = sysdb_cache_auth_recv(req, &expire_date, &delayed_until);
+ fail_unless(ret == expected_result, "sysdb_cache_auth request does not "
+ "return expected result [%d].",
+ expected_result);
+
+ fail_unless(expire_date == 0, "Wrong expire date, expected [%d], got [%d]",
+ 0, expire_date);
+
+ fail_unless(delayed_until == -1, "Wrong delay, expected [%d], got [%d]",
+ -1, delayed_until);
+
+ talloc_free(test_ctx);
+}
+
+static void cached_authentication_with_expiration(const char *username,
+ const char *password,
+ int expected_result)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+ time_t expire_date;
+ const char *val[2];
+ val[1] = NULL;
+ time_t now;
+ time_t expected_expire_date;
+ time_t delayed_until;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ fail_unless(ret == EOK, "Could not set up the test");
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->username = username;
+
+ val[0] = "1";
+ ret = confdb_add_param(test_ctx->confdb, true, CONFDB_PAM_CONF_ENTRY,
+ CONFDB_PAM_CRED_TIMEOUT, val);
+ if (ret != EOK) {
+ fail("Could not initialize provider");
+ talloc_free(test_ctx);
+ return;
+ }
+
+ now = time(NULL);
+ expected_expire_date = now + (24 * 60 * 60);
+ DEBUG(9, ("Setting SYSDB_LAST_ONLINE_AUTH to [%lld].\n", (long long) now));
+
+ data->attrs = sysdb_new_attrs(data);
+ ret = sysdb_attrs_add_time_t(data->attrs, SYSDB_LAST_ONLINE_AUTH, now);
+
+ req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ fail_unless(req != NULL, "sysdb_transaction_send failed.");
+
+ tevent_req_set_callback(req, test_set_user_attr, data);
+
+ ret = test_loop(data);
+ fail_unless(ret == EOK, "Could not modify user %s", data->username);
+ talloc_zfree(req);
+
+ data->finished = false;
+ req = sysdb_cache_auth_send(data, test_ctx->ev, test_ctx->sysdb,
+ test_ctx->domain, data->username,
+ (const uint8_t *) password, strlen(password),
+ test_ctx->confdb);
+ fail_unless(req != NULL, "sysdb_cache_password_send failed.");
+
+ tevent_req_set_callback(req, test_search_done, data);
+
+ ret = test_loop(data);
+ fail_unless(ret == EOK, "test_loop failed.");
+
+ ret = sysdb_cache_auth_recv(req, &expire_date, &delayed_until);
+ fail_unless(ret == expected_result, "sysdb_cache_auth request does not "
+ "return expected result [%d], got [%d].",
+ expected_result, ret);
+
+ fail_unless(expire_date == expected_expire_date,
+ "Wrong expire date, expected [%d], got [%d]",
+ expected_expire_date, expire_date);
+
+ fail_unless(delayed_until == -1, "Wrong delay, expected [%d], got [%d]",
+ -1, delayed_until);
+
+ talloc_free(test_ctx);
+}
+
+START_TEST (test_sysdb_cached_authentication_missing_password)
+{
+ TALLOC_CTX *tmp_ctx;
+ char *username;
+
+ tmp_ctx = talloc_new(NULL);
+ fail_unless(tmp_ctx != NULL, "talloc_new failed.");
+
+ username = talloc_asprintf(tmp_ctx, "testuser%d", _i);
+ fail_unless(username != NULL, "talloc_asprintf failed.");
+
+ cached_authentication_without_expiration(username, "abc", ENOENT);
+ cached_authentication_with_expiration(username, "abc", ENOENT);
+
+ talloc_free(tmp_ctx);
+
+}
+END_TEST
+
+START_TEST (test_sysdb_cached_authentication_wrong_password)
+{
+ TALLOC_CTX *tmp_ctx;
+ char *username;
+
+ tmp_ctx = talloc_new(NULL);
+ fail_unless(tmp_ctx != NULL, "talloc_new failed.");
+
+ username = talloc_asprintf(tmp_ctx, "testuser%d", _i);
+ fail_unless(username != NULL, "talloc_asprintf failed.");
+
+ cached_authentication_without_expiration(username, "abc", EINVAL);
+ cached_authentication_with_expiration(username, "abc", EINVAL);
+
+ talloc_free(tmp_ctx);
+
+}
+END_TEST
+
+START_TEST (test_sysdb_cached_authentication)
+{
+ TALLOC_CTX *tmp_ctx;
+ char *username;
+
+ tmp_ctx = talloc_new(NULL);
+ fail_unless(tmp_ctx != NULL, "talloc_new failed.");
+
+ username = talloc_asprintf(tmp_ctx, "testuser%d", _i);
+ fail_unless(username != NULL, "talloc_asprintf failed.");
+
+ cached_authentication_without_expiration(username, username, EOK);
+ cached_authentication_with_expiration(username, username, EOK);
+
+ talloc_free(tmp_ctx);
+
+}
+END_TEST
+
+START_TEST (test_sysdb_prepare_asq_test_user)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->groupname = talloc_asprintf(data, "testgroup%d", _i);
+ data->uid = ASQ_TEST_USER_UID;
+
+ req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!req) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_add_group_member, data);
+
+ ret = test_loop(data);
+ }
+
+ fail_if(ret != EOK, "Could not modify group %s", data->groupname);
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_asq_search)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ struct ldb_dn *user_dn;
+ int ret;
+ size_t msgs_count;
+ struct ldb_message **msgs;
+ int i;
+ char *gid_str;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->attrlist = talloc_array(data, const char *, 2);
+ fail_unless(data->attrlist != NULL, "talloc_array failed");
+
+ data->attrlist[0] = "gidNumber";
+ data->attrlist[1] = NULL;
+
+ user_dn = sysdb_user_dn(data->ctx->sysdb, data, "LOCAL", ASQ_TEST_USER);
+ fail_unless(user_dn != NULL, "sysdb_user_dn failed");
+
+ req = sysdb_asq_search_send(data, data->ev, test_ctx->sysdb, NULL,
+ test_ctx->domain, user_dn, NULL, "memberof",
+ data->attrlist);
+ if (!req) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_search_done, data);
+
+ ret = test_loop(data);
+
+ ret = sysdb_asq_search_recv(req, data, &msgs_count, &msgs);
+ talloc_zfree(req);
+ fail_unless(ret == EOK, "sysdb_asq_search_send failed");
+
+ fail_unless(msgs_count == 10, "wrong number of results, "
+ "found [%d] expected [10]", msgs_count);
+
+ for (i = 0; i < msgs_count; i++) {
+ fail_unless(msgs[i]->num_elements == 1, "wrong number of elements, "
+ "found [%d] expected [1]",
+ msgs[i]->num_elements);
+
+ fail_unless(msgs[i]->elements[0].num_values == 1,
+ "wrong number of values, found [%d] expected [1]",
+ msgs[i]->elements[0].num_values);
+
+ gid_str = talloc_asprintf(data, "%d", 28010 + i);
+ fail_unless(gid_str != NULL, "talloc_asprintf failed.");
+ fail_unless(strncmp(gid_str,
+ (const char *) msgs[i]->elements[0].values[0].data,
+ msgs[i]->elements[0].values[0].length) == 0,
+ "wrong value, found [%.*s] expected [%s]",
+ msgs[i]->elements[0].values[0].length,
+ msgs[i]->elements[0].values[0].data, gid_str);
+ }
+ }
+
+ fail_if(ret != EOK, "Failed to send ASQ search request.\n");
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_search_all_users)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+ int i;
+ char *uid_str;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->attrlist = talloc_array(data, const char *, 2);
+ fail_unless(data->attrlist != NULL, "talloc_array failed");
+
+ data->attrlist[0] = "uidNumber";
+ data->attrlist[1] = NULL;
+
+ req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!req) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_search_all_users, data);
+
+ ret = test_loop(data);
+ }
+
+ fail_if(ret != EOK, "Search failed");
+
+ fail_unless(data->msgs_count == 10,
+ "wrong number of results, found [%d] expected [10]",
+ data->msgs_count);
+
+ for (i = 0; i < data->msgs_count; i++) {
+ fail_unless(data->msgs[i]->num_elements == 1,
+ "wrong number of elements, found [%d] expected [1]",
+ data->msgs[i]->num_elements);
+
+ fail_unless(data->msgs[i]->elements[0].num_values == 1,
+ "wrong number of values, found [%d] expected [1]",
+ data->msgs[i]->elements[0].num_values);
+
+ uid_str = talloc_asprintf(data, "%d", 27010 + i);
+ fail_unless(uid_str != NULL, "talloc_asprintf failed.");
+ fail_unless(strncmp(uid_str,
+ (char *) data->msgs[i]->elements[0].values[0].data,
+ data->msgs[i]->elements[0].values[0].length) == 0,
+ "wrong value, found [%.*s] expected [%s]",
+ data->msgs[i]->elements[0].values[0].length,
+ data->msgs[i]->elements[0].values[0].data, uid_str);
+ }
+
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_delete_recursive)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *subreq;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+
+ subreq = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!subreq) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(subreq, test_delete_recursive, data);
+
+ ret = test_loop(data);
+ }
+
+ fail_if(ret != EOK, "Recursive delete failed");
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_attrs_replace_name)
+{
+ struct sysdb_attrs *attrs;
+ struct ldb_message_element *el;
+ int ret;
+
+ attrs = sysdb_new_attrs(NULL);
+ fail_unless(attrs != NULL, "sysdb_new_attrs failed");
+
+ ret = sysdb_attrs_add_string(attrs, "foo", "bar");
+ fail_unless(ret == EOK, "sysdb_attrs_add_string failed");
+
+ ret = sysdb_attrs_add_string(attrs, "fool", "bool");
+ fail_unless(ret == EOK, "sysdb_attrs_add_string failed");
+
+ ret = sysdb_attrs_add_string(attrs, "foot", "boot");
+ fail_unless(ret == EOK, "sysdb_attrs_add_string failed");
+
+ ret = sysdb_attrs_replace_name(attrs, "foo", "foot");
+ fail_unless(ret == EEXIST,
+ "sysdb_attrs_replace overwrites existing attribute");
+
+ ret = sysdb_attrs_replace_name(attrs, "foo", "oof");
+ fail_unless(ret == EOK, "sysdb_attrs_replace failed");
+
+ ret = sysdb_attrs_get_el(attrs, "foo", &el);
+ fail_unless(ret == EOK, "sysdb_attrs_get_el failed");
+ fail_unless(el->num_values == 0, "Attribute foo is not empty.");
+
+ ret = sysdb_attrs_get_el(attrs, "oof", &el);
+ fail_unless(ret == EOK, "sysdb_attrs_get_el failed");
+ fail_unless(el->num_values == 1,
+ "Wrong number of values for attribute oof, "
+ "expected [1] got [%d].", el->num_values);
+ fail_unless(strncmp("bar", (char *) el->values[0].data,
+ el->values[0].length) == 0,
+ "Wrong value, expected [bar] got [%.*s]", el->values[0].length,
+ el->values[0].data);
+
+ talloc_free(attrs);
+}
+END_TEST
+
+START_TEST (test_sysdb_memberof_store_group)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->gid = MBO_GROUP_BASE + _i;
+ data->groupname = talloc_asprintf(data, "testgroup%d", data->gid);
+
+ if (_i == 0) {
+ data->attrlist = NULL;
+ } else {
+ data->attrlist = talloc_array(data, const char *, 2);
+ fail_unless(data->attrlist != NULL, "talloc_array failed.");
+ data->attrlist[0] = talloc_asprintf(data, "testgroup%d", data->gid - 1);
+ data->attrlist[1] = NULL;
+ }
+
+ req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!req) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_memberof_store_group, data);
+
+ ret = test_loop(data);
+ }
+
+ fail_if(ret != EOK, "Could not store POSIX group #%d", data->gid);
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_memberof_close_loop)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->gid = MBO_GROUP_BASE;
+ data->groupname = talloc_asprintf(data, "testgroup%d", data->gid);
+
+ data->attrlist = talloc_array(data, const char *, 2);
+ fail_unless(data->attrlist != NULL, "talloc_array failed.");
+ data->attrlist[0] = talloc_asprintf(data, "testgroup%d", data->gid + 9);
+ data->attrlist[1] = NULL;
+
+ req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!req) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_memberof_store_group, data);
+
+ ret = test_loop(data);
+ }
+
+ fail_if(ret != EOK, "Could not store POSIX group #%d", data->gid);
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_memberof_store_user)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->uid = MBO_USER_BASE + _i;
+ data->gid = 0; /* MPG domain */
+ data->username = talloc_asprintf(data, "testuser%d", data->uid);
+
+ req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!req) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_store_user, data);
+
+ ret = test_loop(data);
+ }
+
+ fail_if(ret != EOK, "Could not store user %s", data->username);
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_memberof_add_group_member)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->groupname = talloc_asprintf(data, "testgroup%d", _i + MBO_GROUP_BASE);
+ data->uid = MBO_USER_BASE + _i;
+
+ req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);
+ if (!req) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_add_group_member, data);
+
+ ret = test_loop(data);
+ }
+
+ fail_if(ret != EOK, "Could not modify group %s", data->groupname);
+
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_memberof_check_memberuid_without_group_5)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->gid = _i + MBO_GROUP_BASE;
+
+ data->attrlist = talloc_array(data, const char *, 2);
+ fail_unless(data->attrlist != NULL, "tallo_array failed.");
+ data->attrlist[0] = "memberuid";
+ data->attrlist[1] = NULL;
+
+ req = sysdb_search_group_by_gid_send(data, data->ev, test_ctx->sysdb, NULL,
+ data->ctx->domain,
+ _i + MBO_GROUP_BASE,
+ data->attrlist);
+ if (!req) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_search_done, data);
+
+ ret = test_loop(data);
+
+ ret = sysdb_search_group_recv(req, data, &data->msg);
+ talloc_zfree(req);
+ if (_i == 5) {
+ fail_unless(ret == ENOENT,
+ "sysdb_search_group_by_gid_send found "
+ "already deleted group");
+ ret = EOK;
+ } else {
+ fail_unless(ret == EOK, "sysdb_search_group_by_gid_send failed");
+
+ fail_unless(data->msg->num_elements == 1,
+ "Wrong number of results, expected [1] got [%d]",
+ data->msg->num_elements);
+ fail_unless(strcmp(data->msg->elements[0].name, "memberuid") == 0,
+ "Wrong attribute name");
+ fail_unless(data->msg->elements[0].num_values == ((_i + 1) % 6),
+ "Wrong number of attribute values, "
+ "expected [%d] got [%d]", ((_i + 1) % 6),
+ data->msg->elements[0].num_values);
+ }
+ }
+
+ fail_if(ret != EOK, "Could not check group %d", data->gid);
+
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_memberof_check_memberuid)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->gid = _i + MBO_GROUP_BASE;
+
+ data->attrlist = talloc_array(data, const char *, 2);
+ fail_unless(data->attrlist != NULL, "tallo_array failed.");
+ data->attrlist[0] = "memberuid";
+ data->attrlist[1] = NULL;
+
+ req = sysdb_search_group_by_gid_send(data, data->ev, test_ctx->sysdb, NULL,
+ data->ctx->domain,
+ _i + MBO_GROUP_BASE,
+ data->attrlist);
+ if (!req) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_search_done, data);
+
+ ret = test_loop(data);
+
+ ret = sysdb_search_group_recv(req, data, &data->msg);
+ talloc_zfree(req);
+ fail_unless(ret == EOK, "sysdb_search_group_by_gid_send failed");
+
+ fail_unless(data->msg->num_elements == 1,
+ "Wrong number of results, expected [1] got [%d]",
+ data->msg->num_elements);
+ fail_unless(strcmp(data->msg->elements[0].name, "memberuid") == 0,
+ "Wrong attribute name");
+ fail_unless(data->msg->elements[0].num_values == _i + 1,
+ "Wrong number of attribute values, expected [%d] got [%d]",
+ _i + 1, data->msg->elements[0].num_values);
+ }
+
+ fail_if(ret != EOK, "Could not check group %d", data->gid);
+
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_memberof_check_memberuid_loop)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->gid = _i + MBO_GROUP_BASE;
+
+ data->attrlist = talloc_array(data, const char *, 2);
+ fail_unless(data->attrlist != NULL, "tallo_array failed.");
+ data->attrlist[0] = "memberuid";
+ data->attrlist[1] = NULL;
+
+ req = sysdb_search_group_by_gid_send(data, data->ev, test_ctx->sysdb, NULL,
+ data->ctx->domain,
+ _i + MBO_GROUP_BASE,
+ data->attrlist);
+ if (!req) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_search_done, data);
+
+ ret = test_loop(data);
+
+ ret = sysdb_search_group_recv(req, data, &data->msg);
+ talloc_zfree(req);
+ fail_unless(ret == EOK, "sysdb_search_group_by_gid_send failed");
+
+ fail_unless(data->msg->num_elements == 1,
+ "Wrong number of results, expected [1] got [%d]",
+ data->msg->num_elements);
+ fail_unless(strcmp(data->msg->elements[0].name, "memberuid") == 0,
+ "Wrong attribute name");
+ fail_unless(data->msg->elements[0].num_values == 10,
+ "Wrong number of attribute values, expected [%d] got [%d]",
+ 10, data->msg->elements[0].num_values);
+ }
+
+ fail_if(ret != EOK, "Could not check group %d", data->gid);
+
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_memberof_check_memberuid_loop_without_group_5)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ struct tevent_req *req;
+ int ret;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->gid = _i + MBO_GROUP_BASE;
+
+ data->attrlist = talloc_array(data, const char *, 2);
+ fail_unless(data->attrlist != NULL, "tallo_array failed.");
+ data->attrlist[0] = "memberuid";
+ data->attrlist[1] = NULL;
+
+ req = sysdb_search_group_by_gid_send(data, data->ev, test_ctx->sysdb, NULL,
+ data->ctx->domain,
+ _i + MBO_GROUP_BASE,
+ data->attrlist);
+ if (!req) {
+ ret = ENOMEM;
+ }
+
+ if (ret == EOK) {
+ tevent_req_set_callback(req, test_search_done, data);
+
+ ret = test_loop(data);
+
+ ret = sysdb_search_group_recv(req, data, &data->msg);
+ talloc_zfree(req);
+ if (_i == 5) {
+ fail_unless(ret == ENOENT,
+ "sysdb_search_group_by_gid_send found "
+ "already deleted group");
+ ret = EOK;
+ } else {
+ fail_unless(ret == EOK, "sysdb_search_group_by_gid_send failed");
+
+ fail_unless(data->msg->num_elements == 1,
+ "Wrong number of results, expected [1] got [%d]",
+ data->msg->num_elements);
+ fail_unless(strcmp(data->msg->elements[0].name, "memberuid") == 0,
+ "Wrong attribute name");
+ fail_unless(data->msg->elements[0].num_values == ((_i + 5) % 10),
+ "Wrong number of attribute values, expected [%d] got [%d]",
+ ((_i + 5) % 10), data->msg->elements[0].num_values);
+ }
+ }
+
+ fail_if(ret != EOK, "Could not check group %d", data->gid);
+
+ talloc_free(test_ctx);
+}
+END_TEST
+
+Suite *create_sysdb_suite(void)
+{
+ Suite *s = suite_create("sysdb");
+
+ TCase *tc_sysdb = tcase_create("SYSDB Tests");
+
+ /* Create a new user */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_add_user,27000,27010);
+
+ /* Verify the users were added */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_getpwnam, 27000, 27010);
+
+ /* Create a new group */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_add_group, 28000, 28010);
+
+ /* Verify the groups were added */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_getgrnam, 28000, 28010);
+
+ /* sysdb_store_user allows setting attributes for existing users */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_store_user_existing, 27000, 27010);
+
+ /* test the change */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_get_user_attr, 27000, 27010);
+
+ /* Remove the other half by gid */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_remove_local_group_by_gid, 28000, 28010);
+
+ /* Remove the other half by uid */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_remove_local_user_by_uid, 27000, 27010);
+
+ /* Create a new user */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_store_user, 27010, 27020);
+
+ /* Verify the users were added */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_getpwnam, 27010, 27020);
+
+ /* Verify the users can be queried by UID */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_getpwuid, 27010, 27020);
+
+ /* Enumerate the users */
+ tcase_add_test(tc_sysdb, test_sysdb_enumpwent);
+
+ /* Change their attribute */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_set_user_attr, 27010, 27020);
+
+ /* Verify the change */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_get_user_attr, 27010, 27020);
+
+ /* Create a new group */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_store_group, 28010, 28020);
+
+ /* Verify the groups were added */
+
+ /* Verify the groups can be queried by GID */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_getgrgid, 28010, 28020);
+
+ /* Enumerate the groups */
+ tcase_add_test(tc_sysdb, test_sysdb_enumgrent);
+
+ /* Add some members to the groups */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_add_group_member, 28010, 28020);
+
+ /* Authenticate with missing cached password */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_cached_authentication_missing_password,
+ 27010, 27011);
+
+ /* Add a cached password */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_cache_password, 27010, 27011);
+
+ /* Authenticate against cached password */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_cached_authentication_wrong_password,
+ 27010, 27011);
+ tcase_add_loop_test(tc_sysdb, test_sysdb_cached_authentication, 27010, 27011);
+
+ /* ASQ search test */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_prepare_asq_test_user, 28011, 28020);
+ tcase_add_test(tc_sysdb, test_sysdb_asq_search);
+
+ /* Test search with more than one result */
+ tcase_add_test(tc_sysdb, test_sysdb_search_all_users);
+
+ /* Remove the members from the groups */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_remove_group_member, 28010, 28020);
+
+ /* Remove the users by name */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_remove_local_user, 27010, 27020);
+
+ /* Remove the groups by name */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_remove_local_group, 28010, 28020);
+
+ /* test the ignore_not_found parameter for users */
+ tcase_add_test(tc_sysdb, test_sysdb_remove_nonexistent_user);
+
+ /* test the ignore_not_found parameter for groups */
+ tcase_add_test(tc_sysdb, test_sysdb_remove_nonexistent_group);
+
+ /* test custom operations */
+ tcase_add_loop_test(tc_sysdb, test_sysdb_store_custom, 29010, 29020);
+ tcase_add_test(tc_sysdb, test_sysdb_search_custom_by_name);
+ tcase_add_test(tc_sysdb, test_sysdb_update_custom);
+ tcase_add_test(tc_sysdb, test_sysdb_search_custom_update);
+ tcase_add_test(tc_sysdb, test_sysdb_search_custom);
+ tcase_add_test(tc_sysdb, test_sysdb_delete_custom);
+
+ /* test recursive delete */
+ tcase_add_test(tc_sysdb, test_sysdb_delete_recursive);
+
+ tcase_add_test(tc_sysdb, test_sysdb_attrs_replace_name);
+
+/* Add all test cases to the test suite */
+ suite_add_tcase(s, tc_sysdb);
+
+ TCase *tc_memberof = tcase_create("SYSDB member/memberof/memberuid Tests");
+
+ tcase_add_loop_test(tc_memberof, test_sysdb_memberof_store_group, 0, 10);
+ tcase_add_loop_test(tc_memberof, test_sysdb_memberof_store_user, 0, 10);
+ tcase_add_loop_test(tc_memberof, test_sysdb_memberof_add_group_member,
+ 0, 10);
+ tcase_add_loop_test(tc_memberof, test_sysdb_memberof_check_memberuid,
+ 0, 10);
+ tcase_add_loop_test(tc_memberof, test_sysdb_remove_local_group_by_gid,
+ MBO_GROUP_BASE + 5, MBO_GROUP_BASE + 6);
+ tcase_add_loop_test(tc_memberof,
+ test_sysdb_memberof_check_memberuid_without_group_5,
+ 0, 10);
+ tcase_add_loop_test(tc_memberof, test_sysdb_remove_local_group_by_gid,
+ MBO_GROUP_BASE , MBO_GROUP_BASE + 10);
+
+ tcase_add_loop_test(tc_memberof, test_sysdb_memberof_store_group, 0, 10);
+ tcase_add_test(tc_memberof, test_sysdb_memberof_close_loop);
+ tcase_add_loop_test(tc_memberof, test_sysdb_memberof_store_user, 0, 10);
+ tcase_add_loop_test(tc_memberof, test_sysdb_memberof_add_group_member,
+ 0, 10);
+ tcase_add_loop_test(tc_memberof, test_sysdb_memberof_check_memberuid_loop,
+ 0, 10);
+ tcase_add_loop_test(tc_memberof, test_sysdb_remove_local_group_by_gid,
+ MBO_GROUP_BASE + 5, MBO_GROUP_BASE + 6);
+ tcase_add_loop_test(tc_memberof,
+ test_sysdb_memberof_check_memberuid_loop_without_group_5,
+ 0, 10);
+ tcase_add_loop_test(tc_memberof, test_sysdb_remove_local_group_by_gid,
+ MBO_GROUP_BASE , MBO_GROUP_BASE + 10);
+
+ suite_add_tcase(s, tc_memberof);
+
+ return s;
+}
+
+int main(int argc, const char *argv[]) {
+ int opt;
+ int ret;
+ poptContext pc;
+ int failure_count;
+ Suite *sysdb_suite;
+ SRunner *sr;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ SSSD_MAIN_OPTS
+ { NULL }
+ };
+
+ pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch(opt) {
+ default:
+ fprintf(stderr, "\nInvalid option %s: %s\n\n",
+ poptBadOption(pc, 0), poptStrerror(opt));
+ poptPrintUsage(pc, stderr, 0);
+ return 1;
+ }
+ }
+ poptFreeContext(pc);
+
+ ret = unlink(TESTS_PATH"/"LOCAL_SYSDB_FILE);
+ if (ret != EOK && errno != ENOENT) {
+ fprintf(stderr, "Could not delete the test ldb file (%d) (%s)\n",
+ errno, strerror(errno));
+ return EXIT_FAILURE;
+ }
+
+ sysdb_suite = create_sysdb_suite();
+ sr = srunner_create(sysdb_suite);
+ /* If CK_VERBOSITY is set, use that, otherwise it defaults to CK_NORMAL */
+ srunner_run_all(sr, CK_ENV);
+ failure_count = srunner_ntests_failed(sr);
+ srunner_free(sr);
+ if (failure_count == 0) {
+ ret = unlink(TESTS_PATH"/"TEST_CONF_FILE);
+ if (ret != EOK) {
+ fprintf(stderr, "Could not delete the test config ldb file (%d) (%s)\n",
+ errno, strerror(errno));
+ return EXIT_FAILURE;
+ }
+ ret = unlink(TESTS_PATH"/"LOCAL_SYSDB_FILE);
+ if (ret != EOK) {
+ fprintf(stderr, "Could not delete the test config ldb file (%d) (%s)\n",
+ errno, strerror(errno));
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+ }
+ return EXIT_FAILURE;
+}