summaryrefslogtreecommitdiffstats
path: root/src/tests/util-tests.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tests/util-tests.c')
-rw-r--r--src/tests/util-tests.c1257
1 files changed, 1257 insertions, 0 deletions
diff --git a/src/tests/util-tests.c b/src/tests/util-tests.c
new file mode 100644
index 0000000..d0a1c6e
--- /dev/null
+++ b/src/tests/util-tests.c
@@ -0,0 +1,1257 @@
+/*
+ SSSD
+
+ util-tests.c
+
+ Authors:
+ Stephen Gallagher <sgallagh@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 <popt.h>
+#include <talloc.h>
+#include <check.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <arpa/inet.h>
+
+#include "util/util.h"
+#include "util/sss_utf8.h"
+#include "shared/murmurhash3.h"
+#include "tests/common_check.h"
+
+#define FILENAME_TEMPLATE "tests-atomicio-XXXXXX"
+char *filename;
+int atio_fd;
+
+START_TEST(test_add_string_to_list)
+{
+ int ret;
+
+ char **list = NULL;
+
+ ret = add_string_to_list(NULL, NULL, NULL);
+ ck_assert_msg(ret == EINVAL, "NULL input accepted");
+
+ ret = add_string_to_list(global_talloc_context, "ABC", &list);
+ ck_assert_msg(ret == EOK, "Adding string to non-existing list failed.");
+ ck_assert_msg(list != NULL, "No new list created.");
+ ck_assert_msg(list[0] != NULL, "String not added to new list.");
+ ck_assert_msg(strcmp(list[0], "ABC") == 0,
+ "Wrong string added to newly created list.");
+ ck_assert_msg(list[1] == NULL,
+ "Missing terminating NULL in newly created list.");
+
+ ret = add_string_to_list(global_talloc_context, "DEF", &list);
+ ck_assert_msg(ret == EOK, "Adding string to list failed.");
+ ck_assert_msg(list != NULL, "No list returned.");
+ ck_assert_msg(strcmp(list[0], "ABC") == 0, "Wrong first string in new list.");
+ ck_assert_msg(strcmp(list[1], "DEF") == 0, "Wrong string added to list.");
+ ck_assert_msg(list[2] == NULL, "Missing terminating NULL.");
+
+ list[0] = NULL;
+ ret = add_string_to_list(global_talloc_context, "ABC", &list);
+ ck_assert_msg(ret == EOK, "Adding string to empty list failed.");
+ ck_assert_msg(list != NULL, "No list returned.");
+ ck_assert_msg(list[0] != NULL, "String not added to empty list.");
+ ck_assert_msg(strcmp(list[0], "ABC") == 0,
+ "Wrong string added to empty list.");
+ ck_assert_msg(list[1] == NULL,
+ "Missing terminating NULL in newly created list.");
+
+ talloc_free(list);
+}
+END_TEST
+
+START_TEST(test_string_in_list)
+{
+ bool is_in;
+ char *empty_list[] = {NULL};
+ char *list[] = {discard_const("ABC"),
+ discard_const("DEF"),
+ discard_const("GHI"),
+ NULL};
+
+ is_in = string_in_list(NULL, NULL, false);
+ ck_assert_msg(!is_in, "NULL string is in NULL list.");
+
+ is_in = string_in_list(NULL, empty_list, false);
+ ck_assert_msg(!is_in, "NULL string is in empty list.");
+
+ is_in = string_in_list(NULL, list, false);
+ ck_assert_msg(!is_in, "NULL string is in list.");
+
+ is_in = string_in_list("ABC", NULL, false);
+ ck_assert_msg(!is_in, "String is in NULL list.");
+
+ is_in = string_in_list("ABC", empty_list, false);
+ ck_assert_msg(!is_in, "String is in empty list.");
+
+ is_in = string_in_list("ABC", list, false);
+ ck_assert_msg(is_in, "String is not in list.");
+
+ is_in = string_in_list("abc", list, false);
+ ck_assert_msg(is_in, "String is not case in-sensitive list.");
+
+ is_in = string_in_list("abc", list, true);
+ ck_assert_msg(!is_in, "Wrong string found in case sensitive list.");
+
+ is_in = string_in_list("123", list, false);
+ ck_assert_msg(!is_in, "Wrong string found in list.");
+
+}
+END_TEST
+
+START_TEST(test_string_in_list_size)
+{
+ bool is_in;
+ const char *empty_list[] = {};
+ size_t empty_list_size = 0;
+ const char *list[] = {discard_const("ABC"),
+ discard_const("DEF"),
+ discard_const("GHI")};
+ size_t list_size = sizeof(list) / sizeof(list[0]);
+
+ is_in = string_in_list_size(NULL, NULL, 0, false);
+ ck_assert_msg(!is_in, "NULL string is in NULL list.");
+
+ is_in = string_in_list_size(NULL, empty_list, empty_list_size, false);
+ ck_assert_msg(!is_in, "NULL string is in empty list.");
+
+ is_in = string_in_list_size(NULL, list, list_size, false);
+ ck_assert_msg(!is_in, "NULL string is in list.");
+
+ is_in = string_in_list_size("ABC", NULL, 0, false);
+ ck_assert_msg(!is_in, "String is in NULL list.");
+
+ is_in = string_in_list_size("ABC", empty_list, empty_list_size, false);
+ ck_assert_msg(!is_in, "String is in empty list.");
+
+ is_in = string_in_list_size("ABC", list, list_size, false);
+ ck_assert_msg(is_in, "String is not in list.");
+
+ is_in = string_in_list_size("abc", list, list_size, false);
+ ck_assert_msg(is_in, "String is not case in-sensitive list.");
+
+ is_in = string_in_list_size("abc", list, list_size, true);
+ ck_assert_msg(!is_in, "Wrong string found in case sensitive list.");
+
+ is_in = string_in_list_size("123", list, list_size, false);
+ ck_assert_msg(!is_in, "Wrong string found in list.");
+
+ is_in = string_in_list_size("GHI", list, list_size - 1, false);
+ ck_assert_msg(!is_in, "Size limit not respected.");
+}
+END_TEST
+
+START_TEST(test_parse_args)
+{
+ struct pa_testcase {
+ const char *argstr;
+ const char **parsed;
+ };
+
+ TALLOC_CTX *test_ctx;
+ int i, ii;
+ int ret;
+ char **parsed;
+ char **only_ret;
+ char **only_exp;
+ char **both;
+
+ test_ctx = talloc_new(NULL);
+
+ /* Positive tests */
+ const char *parsed1[] = { "foo", NULL };
+ const char *parsed2[] = { "foo", "a", NULL };
+ const char *parsed3[] = { "foo", "b", NULL };
+ const char *parsed4[] = { "foo", "a c", NULL };
+ const char *parsed5[] = { "foo", "a", "d", NULL };
+ const char *parsed6[] = { "foo", "a", "e", NULL };
+ const char *parsed7[] = { "foo", "a", "f", NULL };
+ const char *parsed8[] = { "foo", "a\tg", NULL };
+ const char *parsed9[] = { "foo", NULL };
+ const char *parsed10[] = { " ", "foo", "\t", "\\'", NULL };
+ const char *parsed11[] = { "a", NULL };
+ struct pa_testcase tc[] = {
+ { "foo", parsed1 },
+ { "foo a", parsed2 },
+ { "foo b", parsed3 },
+ { "foo a\\ c", parsed4 },
+ { "foo a d ", parsed5 },
+ { "foo a e ", parsed6 },
+ { "foo\ta\t \tf \t", parsed7 },
+ { "foo a\\\tg", parsed8 },
+ { " foo ", parsed9 },
+ { "\\ foo \\\t \\' ", parsed10 },
+ { "a", parsed11 },
+ { " ", NULL },
+ { "", NULL },
+ { " \t ", NULL },
+ { NULL, NULL }
+ };
+
+ for (i=0; tc[i].argstr != NULL; i++) {
+ parsed = parse_args(tc[i].argstr);
+ sss_ck_fail_if_msg(parsed == NULL && tc[i].parsed != NULL,
+ "Could not parse correct %d argument string '%s'\n",
+ i, tc[i].argstr);
+
+ ret = diff_string_lists(test_ctx, parsed, discard_const(tc[i].parsed),
+ &only_ret, &only_exp, &both);
+ ck_assert_msg(ret == EOK, "diff_string_lists returned error [%d]", ret);
+ ck_assert_msg(only_ret[0] == NULL, "The parser returned more data than expected\n");
+ ck_assert_msg(only_exp[0] == NULL, "The parser returned less data than expected\n");
+
+ if (parsed) {
+ int parsed_len;
+ int expected_len;
+
+ for (parsed_len=0; parsed[parsed_len]; ++parsed_len);
+ for (expected_len=0; tc[i].parsed[expected_len]; ++expected_len);
+
+ ck_assert_msg(parsed_len == expected_len,
+ "Test %d: length of 1st array [%d] != length of 2nd "
+ "array[%d]\n", i, parsed_len, expected_len);
+
+ for (ii = 0; parsed[ii]; ii++) free(parsed[ii]);
+ free(parsed);
+ }
+ }
+
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST(test_diff_string_lists)
+{
+ TALLOC_CTX *test_ctx;
+ char **l1;
+ char **l2;
+ char **l3;
+ char **only_l1;
+ char **only_l2;
+ char **both;
+ int ret;
+
+ test_ctx = talloc_new(NULL);
+
+ /* Test with all values returned */
+ l1 = talloc_array(test_ctx, char *, 4);
+ l1[0] = talloc_strdup(l1, "a");
+ l1[1] = talloc_strdup(l1, "b");
+ l1[2] = talloc_strdup(l1, "c");
+ l1[3] = NULL;
+
+ l2 = talloc_array(test_ctx, char *, 4);
+ l2[0] = talloc_strdup(l1, "d");
+ l2[1] = talloc_strdup(l1, "c");
+ l2[2] = talloc_strdup(l1, "b");
+ l2[3] = NULL;
+
+ ret = diff_string_lists(test_ctx,
+ l1, l2,
+ &only_l1, &only_l2, &both);
+
+ ck_assert_msg(ret == EOK, "diff_string_lists returned error [%d]", ret);
+ ck_assert_msg(strcmp(only_l1[0], "a") == 0, "Missing \"a\" from only_l1");
+ ck_assert_msg(only_l1[1] == NULL, "only_l1 not NULL-terminated");
+ ck_assert_msg(strcmp(only_l2[0], "d") == 0, "Missing \"d\" from only_l2");
+ ck_assert_msg(only_l2[1] == NULL, "only_l2 not NULL-terminated");
+ ck_assert_msg(strcmp(both[0], "c") == 0, "Missing \"c\" from both");
+ ck_assert_msg(strcmp(both[1], "b") == 0, "Missing \"b\" from both");
+ ck_assert_msg(both[2] == NULL, "both not NULL-terminated");
+
+ talloc_zfree(only_l1);
+ talloc_zfree(only_l2);
+ talloc_zfree(both);
+
+ /* Test with restricted return values */
+ ret = diff_string_lists(test_ctx,
+ l1, l2,
+ &only_l1, &only_l2, NULL);
+
+ ck_assert_msg(ret == EOK, "diff_string_lists returned error [%d]", ret);
+ ck_assert_msg(strcmp(only_l1[0], "a") == 0, "Missing \"a\" from only_l1");
+ ck_assert_msg(only_l1[1] == NULL, "only_l1 not NULL-terminated");
+ ck_assert_msg(strcmp(only_l2[0], "d") == 0, "Missing \"d\" from only_l2");
+ ck_assert_msg(only_l2[1] == NULL, "only_l2 not NULL-terminated");
+ ck_assert_msg(both == NULL, "Nothing returned to both");
+
+ talloc_zfree(only_l1);
+ talloc_zfree(only_l2);
+ talloc_zfree(both);
+
+ ret = diff_string_lists(test_ctx,
+ l1, l2,
+ &only_l1, NULL, NULL);
+
+ ck_assert_msg(ret == EOK, "diff_string_lists returned error [%d]", ret);
+ ck_assert_msg(strcmp(only_l1[0], "a") == 0, "Missing \"a\" from only_l1");
+ ck_assert_msg(only_l1[1] == NULL, "only_l1 not NULL-terminated");
+ ck_assert_msg(only_l2 == NULL, "Nothing returned to only_l2");
+ ck_assert_msg(both == NULL, "Nothing returned to both");
+
+ talloc_zfree(only_l1);
+ talloc_zfree(only_l2);
+ talloc_zfree(both);
+
+ ret = diff_string_lists(test_ctx,
+ l1, l2,
+ NULL, &only_l2, NULL);
+
+ ck_assert_msg(ret == EOK, "diff_string_lists returned error [%d]", ret);
+ ck_assert_msg(strcmp(only_l2[0], "d") == 0, "Missing \"d\" from only_l2");
+ ck_assert_msg(only_l2[1] == NULL, "only_l2 not NULL-terminated");
+ ck_assert_msg(only_l1 == NULL, "Nothing returned to only_l1");
+ ck_assert_msg(both == NULL, "Nothing returned to both");
+
+ talloc_zfree(only_l1);
+ talloc_zfree(only_l2);
+ talloc_zfree(both);
+
+ /* Test with no overlap */
+ l3 = talloc_array(test_ctx, char *, 4);
+ l3[0] = talloc_strdup(l1, "d");
+ l3[1] = talloc_strdup(l1, "e");
+ l3[2] = talloc_strdup(l1, "f");
+ l3[3] = NULL;
+
+ ret = diff_string_lists(test_ctx,
+ l1, l3,
+ &only_l1, &only_l2, &both);
+
+ ck_assert_msg(ret == EOK, "diff_string_lists returned error [%d]", ret);
+ ck_assert_msg(strcmp(only_l1[0], "a") == 0, "Missing \"a\" from only_l1");
+ ck_assert_msg(strcmp(only_l1[1], "b") == 0, "Missing \"b\" from only_l1");
+ ck_assert_msg(strcmp(only_l1[2], "c") == 0, "Missing \"c\" from only_l1");
+ ck_assert_msg(only_l1[3] == NULL, "only_l1 not NULL-terminated");
+ ck_assert_msg(strcmp(only_l2[0], "d") == 0, "Missing \"f\" from only_l2");
+ ck_assert_msg(strcmp(only_l2[1], "e") == 0, "Missing \"e\" from only_l2");
+ ck_assert_msg(strcmp(only_l2[2], "f") == 0, "Missing \"d\" from only_l2");
+ ck_assert_msg(only_l2[3] == NULL, "only_l2 not NULL-terminated");
+ ck_assert_msg(both[0] == NULL, "both should have zero entries");
+
+ talloc_zfree(only_l1);
+ talloc_zfree(only_l2);
+ talloc_zfree(both);
+
+ /* Test with 100% overlap */
+ ret = diff_string_lists(test_ctx,
+ l1, l1,
+ &only_l1, &only_l2, &both);
+
+ ck_assert_msg(ret == EOK, "diff_string_lists returned error [%d]", ret);
+ ck_assert_msg(only_l1[0] == NULL, "only_l1 should have zero entries");
+ ck_assert_msg(only_l2[0] == NULL, "only_l2 should have zero entries");
+ ck_assert_msg(strcmp(both[0], "a") == 0, "Missing \"a\" from both");
+ ck_assert_msg(strcmp(both[1], "b") == 0, "Missing \"b\" from both");
+ ck_assert_msg(strcmp(both[2], "c") == 0, "Missing \"c\" from both");
+ ck_assert_msg(both[3] == NULL, "both is not NULL-terminated");
+
+ talloc_zfree(only_l1);
+ talloc_zfree(only_l2);
+ talloc_zfree(both);
+
+ /* Test with no second list */
+ ret = diff_string_lists(test_ctx,
+ l1, NULL,
+ &only_l1, &only_l2, &both);
+
+ ck_assert_msg(ret == EOK, "diff_string_lists returned error [%d]", ret);
+ ck_assert_msg(strcmp(only_l1[0], "a") == 0, "Missing \"a\" from only_l1");
+ ck_assert_msg(strcmp(only_l1[1], "b") == 0, "Missing \"b\" from only_l1");
+ ck_assert_msg(strcmp(only_l1[2], "c") == 0, "Missing \"c\" from only_l1");
+ ck_assert_msg(only_l1[3] == NULL, "only_l1 not NULL-terminated");
+ ck_assert_msg(only_l2[0] == NULL, "only_l2 should have zero entries");
+ ck_assert_msg(both[0] == NULL, "both should have zero entries");
+
+ talloc_free(test_ctx);
+}
+END_TEST
+
+
+START_TEST(test_sss_filter_sanitize)
+{
+ errno_t ret;
+ char *sanitized = NULL;
+
+ TALLOC_CTX *test_ctx = talloc_new(NULL);
+ sss_ck_fail_if_msg(test_ctx == NULL, "Out of memory");
+
+ const char no_specials[] = "username";
+ ret = sss_filter_sanitize(test_ctx, no_specials, &sanitized);
+ ck_assert_msg(ret == EOK, "no_specials error [%d][%s]",
+ ret, strerror(ret));
+ ck_assert_msg(strcmp(no_specials, sanitized)==0,
+ "Expected [%s], got [%s]",
+ no_specials, sanitized);
+
+ const char has_asterisk[] = "*username";
+ const char has_asterisk_expected[] = "\\2ausername";
+ ret = sss_filter_sanitize(test_ctx, has_asterisk, &sanitized);
+ ck_assert_msg(ret == EOK, "has_asterisk error [%d][%s]",
+ ret, strerror(ret));
+ ck_assert_msg(strcmp(has_asterisk_expected, sanitized)==0,
+ "Expected [%s], got [%s]",
+ has_asterisk_expected, sanitized);
+
+ const char has_lparen[] = "user(name";
+ const char has_lparen_expected[] = "user\\28name";
+ ret = sss_filter_sanitize(test_ctx, has_lparen, &sanitized);
+ ck_assert_msg(ret == EOK, "has_lparen error [%d][%s]",
+ ret, strerror(ret));
+ ck_assert_msg(strcmp(has_lparen_expected, sanitized)==0,
+ "Expected [%s], got [%s]",
+ has_lparen_expected, sanitized);
+
+ const char has_rparen[] = "user)name";
+ const char has_rparen_expected[] = "user\\29name";
+ ret = sss_filter_sanitize(test_ctx, has_rparen, &sanitized);
+ ck_assert_msg(ret == EOK, "has_rparen error [%d][%s]",
+ ret, strerror(ret));
+ ck_assert_msg(strcmp(has_rparen_expected, sanitized)==0,
+ "Expected [%s], got [%s]",
+ has_rparen_expected, sanitized);
+
+ const char has_backslash[] = "username\\";
+ const char has_backslash_expected[] = "username\\5c";
+ ret = sss_filter_sanitize(test_ctx, has_backslash, &sanitized);
+ ck_assert_msg(ret == EOK, "has_backslash error [%d][%s]",
+ ret, strerror(ret));
+ ck_assert_msg(strcmp(has_backslash_expected, sanitized)==0,
+ "Expected [%s], got [%s]",
+ has_backslash_expected, sanitized);
+
+ const char has_all[] = "\\(user)*name";
+ const char has_all_expected[] = "\\5c\\28user\\29\\2aname";
+ ret = sss_filter_sanitize(test_ctx, has_all, &sanitized);
+ ck_assert_msg(ret == EOK, "has_all error [%d][%s]",
+ ret, strerror(ret));
+ ck_assert_msg(strcmp(has_all_expected, sanitized)==0,
+ "Expected [%s], got [%s]",
+ has_all_expected, sanitized);
+
+ /* Input is reused from previous test - "\\(user)*name" */
+ const char has_all_allow_asterisk_expected[] = "\\5c\\28user\\29*name";
+ ret = sss_filter_sanitize_ex(test_ctx, has_all, &sanitized, "*");
+ ck_assert_msg(ret == EOK, "has_all error [%d][%s]",
+ ret, strerror(ret));
+ ck_assert_msg(strcmp(has_all_allow_asterisk_expected, sanitized)==0,
+ "Expected [%s], got [%s]",
+ has_all_expected, sanitized);
+
+ const char has_new_line[] = "user\nname";
+ const char has_new_line_expected[] = "user\\0aname";
+ ret = sss_filter_sanitize(test_ctx, has_new_line, &sanitized);
+ ck_assert_msg(ret == EOK, "has_new_line error [%d][%s]",
+ ret, strerror(ret));
+ ck_assert_msg(strcmp(has_new_line_expected, sanitized) == 0,
+ "Expected [%s], got [%s]",
+ has_new_line_expected, sanitized);
+
+ const char has_carriage_ret[] = "user\rname";
+ const char has_carriage_ret_expected[] = "user\\0dname";
+ ret = sss_filter_sanitize(test_ctx, has_carriage_ret, &sanitized);
+ ck_assert_msg(ret == EOK, "has_carriage_ret error [%d][%s]",
+ ret, strerror(ret));
+ ck_assert_msg(strcmp(has_carriage_ret_expected, sanitized) == 0,
+ "Expected [%s], got [%s]",
+ has_carriage_ret_expected, sanitized);
+
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST(test_fd_nonblocking)
+{
+ int fd;
+ int flags;
+ errno_t ret;
+
+ fd = open("/dev/null", O_RDONLY);
+ ck_assert_msg(fd > 0,
+ "open failed with errno: %d", errno);
+
+ flags = fcntl(fd, F_GETFL, 0);
+ sss_ck_fail_if_msg(flags & O_NONBLOCK,
+ "Unexpected flag O_NONBLOCK[%x] in [%x]", O_NONBLOCK, flags);
+
+ ret = sss_fd_nonblocking(fd);
+ ck_assert_msg(ret == EOK, "sss_fd_nonblocking failed with error: %d", ret);
+ flags = fcntl(fd, F_GETFL, 0);
+ ck_assert_msg(flags & O_NONBLOCK,
+ "Flag O_NONBLOCK[%x] is missing in [%x]", O_NONBLOCK, flags);
+ close(fd);
+}
+END_TEST
+
+START_TEST(test_size_t_overflow)
+{
+ ck_assert_msg(!SIZE_T_OVERFLOW(1, 1), "unexpected overflow");
+ ck_assert_msg(!SIZE_T_OVERFLOW(SIZE_MAX, 0), "unexpected overflow");
+ ck_assert_msg(!SIZE_T_OVERFLOW(SIZE_MAX-10, 10), "unexpected overflow");
+ ck_assert_msg(SIZE_T_OVERFLOW(SIZE_MAX, 1), "overflow not detected");
+ ck_assert_msg(SIZE_T_OVERFLOW(SIZE_MAX, SIZE_MAX),
+ "overflow not detected");
+ ck_assert_msg(SIZE_T_OVERFLOW(SIZE_MAX, ULLONG_MAX),
+ "overflow not detected");
+ ck_assert_msg(SIZE_T_OVERFLOW(SIZE_MAX, -10), "overflow not detected");
+}
+END_TEST
+
+START_TEST(test_utf8_talloc_str_lowercase)
+{
+ const char munchen_utf8_upcase[] = { 'M', 0xC3, 0x9C, 'N', 'C', 'H', 'E', 'N', 0x0 };
+ const char munchen_utf8_lowcase[] = { 'm', 0xC3, 0xBC, 'n', 'c', 'h', 'e', 'n', 0x0 };
+ char *lcase;
+
+ TALLOC_CTX *test_ctx;
+ test_ctx = talloc_new(NULL);
+ sss_ck_fail_if_msg(test_ctx == NULL, "Failed to allocate memory");
+
+ lcase = sss_tc_utf8_str_tolower(test_ctx, munchen_utf8_upcase);
+ sss_ck_fail_if_msg(memcmp(lcase, munchen_utf8_lowcase, strlen(lcase)),
+ "Unexpected binary values");
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST(test_utf8_caseeq)
+{
+ const uint8_t munchen_utf8_upcase[] = { 'M', 0xC3, 0x9C, 'N', 'C', 'H', 'E', 'N', 0x0 };
+ const uint8_t munchen_utf8_lowcase[] = { 'm', 0xC3, 0xBC, 'n', 'c', 'h', 'e', 'n', 0x0 };
+ const uint8_t czech_utf8_lowcase[] = { 0xC4, 0x8D, 'e', 'c', 'h', 0x0 };
+ const uint8_t czech_utf8_upcase[] = { 0xC4, 0x8C, 'e', 'c', 'h', 0x0 };
+ const uint8_t czech_utf8_lowcase_neg[] = { 0xC4, 0x8E, 'e', 'c', 'h', 0x0 };
+ errno_t ret;
+
+ ret = sss_utf8_case_eq(munchen_utf8_upcase, munchen_utf8_lowcase);
+ ck_assert_msg(ret == EOK, "Latin 1 Supplement comparison failed\n");
+
+ ret = sss_utf8_case_eq(czech_utf8_upcase, czech_utf8_lowcase);
+ ck_assert_msg(ret == EOK, "Latin Extended A comparison failed\n");
+
+ ret = sss_utf8_case_eq(czech_utf8_upcase, czech_utf8_lowcase_neg);
+ sss_ck_fail_if_msg(ret == EOK, "Negative test succeeded\n");
+}
+END_TEST
+
+START_TEST(test_utf8_check)
+{
+ const char *invalid = "ad\351la\357d";
+ const uint8_t valid[] = { 'M', 0xC3, 0x9C, 'N', 'C', 'H', 'E', 'N', 0x0 };
+ bool ret;
+
+ ret = sss_utf8_check(valid, strlen((const char *) valid));
+ ck_assert_msg(ret == true, "Positive test failed\n");
+
+ ret = sss_utf8_check((const uint8_t *) invalid, strlen(invalid));
+ ck_assert_msg(ret == false, "Negative test succeeded\n");
+}
+END_TEST
+
+START_TEST(test_murmurhash3_check)
+{
+ const char *tests[6] = { "1052800007", "1052800008", "1052800000",
+ "abcdefghijk", "abcdefghili", "abcdefgh000" };
+ uint32_t results[6];
+ int i, j;
+
+ for (i = 0; i< 6; i++) {
+ results[i] = murmurhash3(tests[i],
+ strlen(tests[i]),
+ 0xdeadbeef);
+ for (j = 0; j < i; j++) {
+ sss_ck_fail_if_msg(results[i] == results[j],
+ "Values have to be different. '%"PRIu32"' == '%"PRIu32"'",
+ results[i], results[j]);
+ }
+ }
+}
+END_TEST
+
+START_TEST(test_murmurhash3_random)
+{
+ char test[16];
+ uint32_t result1;
+ uint32_t result2;
+ unsigned int init_seed;
+ unsigned int seed;
+ size_t len;
+ int i;
+
+ /* generate a random string so each time we test with different values */
+ init_seed = time(0);
+ seed = init_seed;
+ /* use also random length (min len = 1) */
+ len = 1 + rand_r(&seed) % 14;
+ for (i = 0; i < len; i++) {
+ test[i] = 1 + rand_r(&seed) % 254;
+ }
+ test[len] = '\0'; /* null terminate */
+
+ fprintf(stdout, "test_murmurhash3_random seed: %u\n", init_seed);
+
+ result1 = murmurhash3(test, len + 1, init_seed);
+ result2 = murmurhash3(test, len + 1, init_seed);
+ ck_assert_int_eq(result1, result2);
+}
+END_TEST
+
+void setup_atomicio(void)
+{
+ int ret;
+ mode_t old_umask;
+
+ filename = strdup(FILENAME_TEMPLATE);
+ ck_assert_msg(filename != NULL, "strdup failed");
+
+ atio_fd = -1;
+ old_umask = umask(SSS_DFL_UMASK);
+ ret = mkstemp(filename);
+ umask(old_umask);
+ ck_assert_msg(ret != -1, "mkstemp failed [%d][%s]", errno, strerror(errno));
+ atio_fd = ret;
+}
+
+void teardown_atomicio(void)
+{
+ int ret;
+
+ if (atio_fd != -1) {
+ ret = close(atio_fd);
+ ck_assert_msg(ret == 0, "close failed [%d][%s]", errno, strerror(errno));
+ }
+
+ ck_assert_msg(filename != NULL, "unknown filename");
+ ret = unlink(filename);
+ free(filename);
+ ck_assert_msg(ret == 0, "unlink failed [%d][%s]", errno, strerror(errno));
+}
+
+START_TEST(test_atomicio_read_from_file)
+{
+ const ssize_t bufsize = 64;
+ char buf[64];
+ int fd;
+ ssize_t numread;
+ errno_t ret;
+
+ fd = open("/dev/zero", O_RDONLY);
+ sss_ck_fail_if_msg(fd == -1, "Cannot open /dev/zero");
+
+ errno = 0;
+ numread = sss_atomic_read_s(fd, buf, bufsize);
+ ret = errno;
+
+ ck_assert_msg(ret == 0, "Error %d while reading\n", ret);
+ ck_assert_msg(numread == bufsize,
+ "Read %zd bytes expected %zd\n", numread, bufsize);
+ close(fd);
+}
+END_TEST
+
+START_TEST(test_atomicio_read_from_small_file)
+{
+ char wbuf[] = "foobar";
+ ssize_t wsize = strlen(wbuf)+1;
+ ssize_t numwritten;
+ char rbuf[64];
+ ssize_t numread;
+ errno_t ret;
+
+ sss_ck_fail_if_msg(atio_fd < 0, "No fd to test?\n");
+
+ errno = 0;
+ numwritten = sss_atomic_write_s(atio_fd, wbuf, wsize);
+ ret = errno;
+
+ ck_assert_msg(ret == 0, "Error %d while writing\n", ret);
+ ck_assert_msg(numwritten == wsize,
+ "Wrote %zd bytes expected %zd\n", numwritten, wsize);
+
+ fsync(atio_fd);
+ lseek(atio_fd, 0, SEEK_SET);
+
+ errno = 0;
+ numread = sss_atomic_read_s(atio_fd, rbuf, 64);
+ ret = errno;
+
+ ck_assert_msg(ret == 0, "Error %d while reading\n", ret);
+ ck_assert_msg(numread == numwritten,
+ "Read %zd bytes expected %zd\n", numread, numwritten);
+}
+END_TEST
+
+START_TEST(test_atomicio_read_from_large_file)
+{
+ char wbuf[] = "123456781234567812345678";
+ ssize_t wsize = strlen(wbuf)+1;
+ ssize_t numwritten;
+ char rbuf[8];
+ ssize_t numread;
+ ssize_t total;
+ errno_t ret;
+
+ sss_ck_fail_if_msg(atio_fd < 0, "No fd to test?\n");
+
+ errno = 0;
+ numwritten = sss_atomic_write_s(atio_fd, wbuf, wsize);
+ ret = errno;
+
+ ck_assert_msg(ret == 0, "Error %d while writing\n", ret);
+ ck_assert_msg(numwritten == wsize,
+ "Wrote %zd bytes expected %zd\n", numwritten, wsize);
+
+ fsync(atio_fd);
+ lseek(atio_fd, 0, SEEK_SET);
+
+ total = 0;
+ do {
+ errno = 0;
+ numread = sss_atomic_read_s(atio_fd, rbuf, 8);
+ ret = errno;
+
+ sss_ck_fail_if_msg(numread == -1, "Read error %d: %s\n", ret, strerror(ret));
+ total += numread;
+ } while (numread != 0);
+
+ ck_assert_msg(ret == 0, "Error %d while reading\n", ret);
+ ck_assert_msg(total == numwritten,
+ "Read %zd bytes expected %zd\n", numread, numwritten);
+}
+END_TEST
+
+START_TEST(test_atomicio_read_exact_sized_file)
+{
+ char wbuf[] = "12345678";
+ ssize_t wsize = strlen(wbuf)+1;
+ ssize_t numwritten;
+ char rbuf[9];
+ ssize_t numread;
+ errno_t ret;
+
+ sss_ck_fail_if_msg(atio_fd < 0, "No fd to test?\n");
+
+ errno = 0;
+ numwritten = sss_atomic_write_s(atio_fd, wbuf, wsize);
+ ret = errno;
+
+ ck_assert_msg(ret == 0, "Error %d while writing\n", ret);
+ ck_assert_msg(numwritten == wsize,
+ "Wrote %zd bytes expected %zd\n", numwritten, wsize);
+
+ fsync(atio_fd);
+ lseek(atio_fd, 0, SEEK_SET);
+
+ errno = 0;
+ numread = sss_atomic_read_s(atio_fd, rbuf, 9);
+ ret = errno;
+
+ ck_assert_msg(ret == 0, "Error %d while reading\n", ret);
+ ck_assert_msg(numread == numwritten,
+ "Read %zd bytes expected %zd\n", numread, numwritten);
+
+ ck_assert_msg(rbuf[8] == '\0', "String not NULL terminated?");
+ ck_assert_msg(strcmp(wbuf, rbuf) == 0, "Read something else than wrote?");
+
+ /* We've reached end-of-file, next read must return 0 */
+ errno = 0;
+ numread = sss_atomic_read_s(atio_fd, rbuf, 9);
+ ret = errno;
+
+ ck_assert_msg(ret == 0, "Error %d while reading\n", ret);
+ ck_assert_msg(numread == 0, "More data to read?");
+}
+END_TEST
+
+START_TEST(test_atomicio_read_from_empty_file)
+{
+ char buf[64];
+ int fd;
+ ssize_t numread;
+ errno_t ret;
+
+ fd = open("/dev/null", O_RDONLY);
+ sss_ck_fail_if_msg(fd == -1, "Cannot open /dev/null");
+
+ errno = 0;
+ numread = sss_atomic_read_s(fd, buf, 64);
+ ret = errno;
+
+ ck_assert_msg(ret == 0, "Error %d while reading\n", ret);
+ ck_assert_msg(numread == 0,
+ "Read %zd bytes expected 0\n", numread);
+ close(fd);
+}
+END_TEST
+
+struct split_data {
+ const char *input;
+ const char **expected_list;
+ bool trim;
+ bool skip_empty;
+ int expected_size;
+ int expected_ret;
+};
+
+START_TEST(test_split_on_separator)
+{
+ TALLOC_CTX *mem = global_talloc_context;
+ errno_t ret;
+ char **list = NULL;
+ int size;
+ const char *str_ref;
+ const char *str_out;
+ int i;
+ int a;
+ int num_of_tests;
+ struct split_data sts[] = {
+ {
+ "one,two,three", /* input string */
+ (const char *[]){"one", "two", "three", NULL}, /* expec. output list */
+ false, false, /* trim, skip_empty */
+ 3, 0 /* expec. size, expec. retval */
+ },
+ {
+ "one,two,three",
+ (const char *[]){"one", "two", "three", NULL},
+ true, true,
+ 3, 0
+ },
+ {
+ " one, two ,three ",
+ (const char*[]){"one", "two", "three", NULL},
+ true, true,
+ 3, 0
+ },
+ {
+ /* If skip empty is false, single comma means "empty,empty" */
+ ",",
+ (const char*[]){"", "", NULL, NULL},
+ false, false,
+ 2, 0
+ },
+ {
+ "one, ,",
+ (const char*[]){"one", " ", "NULL", "NULL"},
+ false, true,
+ 2, 0
+ },
+ {
+ ", ,,",
+ (const char*[]){NULL},
+ true, true,
+ 0, 0
+ },
+ {
+ NULL,
+ NULL,
+ false, false,
+ 0, EINVAL
+ },
+ };
+ num_of_tests = sizeof(sts) / sizeof(struct split_data);
+
+ for (a = 0; a < num_of_tests; a++) {
+ ret = split_on_separator(mem, sts[a].input, ',', sts[a].trim,
+ sts[a].skip_empty, &list, &size);
+
+ ck_assert_msg(ret == sts[a].expected_ret,
+ "split_on_separator failed [%d]: %s\n", ret,
+ strerror(ret));
+ if (ret) {
+ continue;
+ }
+ ck_assert_msg(size == sts[a].expected_size, "Returned wrong size %d "
+ "(expected %d).\n", size, sts[a].expected_size);
+
+ for (i = 0; str_ref = sts[a].expected_list[i], str_out = list[i]; i++) {
+ ck_assert_msg(strcmp(str_ref, str_out) == 0,
+ "Expected:%s Got:%s\n", str_ref, str_out);
+ }
+ talloc_free(list);
+ list = NULL;
+ }
+}
+END_TEST
+
+struct check_ip_test_data {
+ const char *str_ipaddr;
+ uint8_t flags;
+ bool expected_ret;
+};
+
+START_TEST(test_check_ipv4_addr)
+{
+ int a;
+ int num_of_tests;
+ int ret;
+ bool bret;
+ struct in_addr addr;
+ struct check_ip_test_data tst_data[] = {
+ {
+ "192.168.100.1", /* input IPv4 address */
+ 0, /* flags value */
+ true /* Expected return value */
+ },
+ {
+ "224.0.0.22", /* multicast address */
+ SSS_NO_MULTICAST,
+ false
+ },
+ {
+ "192.186.0.224",
+ SSS_NO_MULTICAST,
+ true
+ },
+ {
+ "127.0.0.1",
+ SSS_NO_LOOPBACK,
+ false
+ },
+ {
+ "169.254.0.11",
+ SSS_NO_LINKLOCAL,
+ false
+ },
+ {
+ "255.255.255.255",
+ SSS_NO_BROADCAST,
+ false
+ },
+ {
+ "255.255.255.255",
+ SSS_NO_SPECIAL,
+ false
+ },
+ {
+ "192.168.254.169",
+ SSS_NO_SPECIAL,
+ true
+ },
+ };
+
+ num_of_tests = sizeof(tst_data) / sizeof(struct check_ip_test_data);
+
+ for (a = 0; a < num_of_tests; a++) {
+ /* fill sockaddr_in structure */
+
+ ret = inet_pton(AF_INET, tst_data[a].str_ipaddr, &addr);
+ sss_ck_fail_if_msg(ret != 1, "inet_pton failed.");
+
+ bret = check_ipv4_addr(&addr, tst_data[a].flags);
+ ck_assert_msg(bret == tst_data[a].expected_ret,
+ "check_ipv4_addr failed (iteration %d)", a);
+ }
+}
+END_TEST
+
+START_TEST(test_check_ipv6_addr)
+{
+ int a;
+ int num_of_tests;
+ int ret;
+ bool bret;
+ struct in6_addr addr;
+ struct check_ip_test_data tst_data[] = {
+ {
+ "fde9:7e3f:1ed3:24a5::4", /* input IPv6 address */
+ 0, /* flags value */
+ true /* Expected return value */
+ },
+ {
+ "fe80::f2de:f1ff:fefa:67f0",
+ SSS_NO_LINKLOCAL,
+ false
+ },
+ {
+ "::1",
+ SSS_NO_LOOPBACK,
+ false
+ },
+ {
+ "ff00::123",
+ SSS_NO_MULTICAST,
+ false
+ },
+ {
+ "ff00::321",
+ SSS_NO_SPECIAL,
+ false
+ },
+ };
+
+ num_of_tests = sizeof(tst_data) / sizeof(struct check_ip_test_data);
+
+ for (a = 0; a < num_of_tests; a++) {
+ /* fill sockaddr_in structure */
+
+ ret = inet_pton(AF_INET6, tst_data[a].str_ipaddr, &addr);
+ sss_ck_fail_if_msg(ret != 1, "inet_pton failed.");
+
+ bret = check_ipv6_addr(&addr, tst_data[a].flags);
+ ck_assert_msg(bret == tst_data[a].expected_ret,
+ "check_ipv6_addr failed (iteration %d)", a);
+
+ }
+}
+END_TEST
+
+START_TEST(test_is_host_in_domain)
+{
+ struct {
+ const char *host;
+ const char *domain;
+ bool expected;
+ } data[] = {{"example.com", "example.com", true},
+ {"client.example.com", "example.com", true},
+ {"client.child.example.com", "example.com", true},
+ {"example.com", "child.example.com", false},
+ {"client.example.com", "child.example.com", false},
+ {"client.child.example.com", "child.example.com", true},
+ {"my.com", "example.com", false},
+ {"myexample.com", "example.com", false},
+ {NULL, NULL, false}};
+ bool ret;
+ int i;
+
+ for (i = 0; data[i].host != NULL; i++) {
+ ret = is_host_in_domain(data[i].host, data[i].domain);
+ sss_ck_fail_if_msg(ret != data[i].expected, "Host: %s, Domain: %s, Expected: %d, "
+ "Got: %d\n", data[i].host, data[i].domain,
+ data[i].expected, ret);
+ }
+}
+END_TEST
+
+START_TEST(test_known_service)
+{
+ const char * const * svcs;
+ bool found_nss = false;
+ int i;
+
+ /* Just make sure we can't find a bogus service and nss
+ * is always available
+ */
+ svcs = get_known_services();
+ for (i = 0; svcs[i]; i++) {
+ ck_assert_str_ne(svcs[i], "nosuchservice");
+ if (strcmp(svcs[i], "nss") == 0) {
+ found_nss = true;
+ }
+ }
+
+ ck_assert(found_nss == true);
+}
+END_TEST
+
+static void convert_time_tz(const char* tz)
+{
+ errno_t ret, ret2;
+ time_t unix_time;
+ const char *orig_tz = NULL;
+
+ orig_tz = getenv("TZ");
+ if (orig_tz == NULL) {
+ orig_tz = "";
+ }
+
+ if (tz) {
+ ret = setenv("TZ", tz, 1);
+ sss_ck_fail_if_msg(ret == -1,
+ "setenv failed with errno: %d", errno);
+ }
+
+ ret = sss_utc_to_time_t("20140801115742Z", "%Y%m%d%H%M%SZ", &unix_time);
+
+ /* restore */
+ if (orig_tz != NULL) {
+ ret2 = setenv("TZ", orig_tz, 1);
+ sss_ck_fail_if_msg(ret2 == -1,
+ "setenv failed with errno: %d", errno);
+ }
+ ck_assert_msg(ret == EOK && difftime(1406894262, unix_time) == 0,
+ "Expecting 1406894262 got: ret[%d] unix_time[%"SPRItime"]",
+ ret, unix_time);
+}
+
+START_TEST(test_convert_time)
+{
+ const char *format = "%Y%m%d%H%M%SZ";
+ time_t unix_time;
+ errno_t ret;
+
+ ret = sss_utc_to_time_t("20150127133540P", format, &unix_time);
+ ck_assert_msg(ret == ERR_TIMESPEC_NOT_SUPPORTED,
+ "sss_utc_to_time_t must fail with %d. got: %d",
+ ERR_TIMESPEC_NOT_SUPPORTED, ret);
+ ret = sss_utc_to_time_t("0Z", format, &unix_time);
+ ck_assert_msg(ret == EINVAL,
+ "sss_utc_to_time_t must fail with EINVAL. got: %d", ret);
+ ret = sss_utc_to_time_t("000001010000Z", format, &unix_time);
+ ck_assert_msg(ret == EINVAL,
+ "sss_utc_to_time_t must fail with EINVAL. got: %d", ret);
+
+ /* test that results are still same no matter what timezone is set */
+ convert_time_tz(NULL);
+
+ convert_time_tz("GST-1");
+
+ convert_time_tz("GST-2");
+}
+END_TEST
+
+START_TEST(test_sss_strerror_err_last)
+{
+ ck_assert_str_eq(sss_strerror(ERR_LAST), "ERR_LAST");
+}
+END_TEST
+
+START_TEST(test_sss_strerror_string_validation)
+{
+ enum sssd_errors idx;
+ const char *error;
+ size_t len;
+ char last_character;
+
+ for (idx = ERR_BASE; idx < ERR_LAST; ++idx) {
+ error = sss_strerror(idx);
+ sss_ck_fail_if_msg(error == NULL, "sss_strerror returned NULL for valid index");
+
+ len = strlen(error);
+ sss_ck_fail_if_msg(len == 0, "sss_strerror returned empty string");
+
+ last_character = error[len - 1];
+ sss_ck_fail_if_msg(isalpha(last_character) == 0 && last_character != ')',
+ "Error string [%s] must finish with alphabetic character\n",
+ error);
+ }
+}
+END_TEST
+
+Suite *util_suite(void)
+{
+ Suite *s = suite_create("util");
+
+ TCase *tc_util = tcase_create("util");
+
+ tcase_add_checked_fixture(tc_util,
+ ck_leak_check_setup,
+ ck_leak_check_teardown);
+ tcase_add_test (tc_util, test_diff_string_lists);
+ tcase_add_test (tc_util, test_sss_filter_sanitize);
+ tcase_add_test (tc_util, test_size_t_overflow);
+ tcase_add_test (tc_util, test_parse_args);
+ tcase_add_test (tc_util, test_add_string_to_list);
+ tcase_add_test (tc_util, test_string_in_list);
+ tcase_add_test (tc_util, test_string_in_list_size);
+ tcase_add_test (tc_util, test_split_on_separator);
+ tcase_add_test (tc_util, test_check_ipv4_addr);
+ tcase_add_test (tc_util, test_check_ipv6_addr);
+ tcase_add_test (tc_util, test_is_host_in_domain);
+ tcase_add_test (tc_util, test_known_service);
+ tcase_add_test (tc_util, test_fd_nonblocking);
+ tcase_set_timeout(tc_util, 60);
+
+ TCase *tc_utf8 = tcase_create("utf8");
+ tcase_add_test (tc_utf8, test_utf8_talloc_str_lowercase);
+ tcase_add_test (tc_utf8, test_utf8_caseeq);
+ tcase_add_test (tc_utf8, test_utf8_check);
+
+ tcase_set_timeout(tc_utf8, 60);
+
+ TCase *tc_mh3 = tcase_create("murmurhash3");
+ tcase_add_test (tc_mh3, test_murmurhash3_check);
+ tcase_add_test (tc_mh3, test_murmurhash3_random);
+ tcase_set_timeout(tc_mh3, 60);
+
+ TCase *tc_atomicio = tcase_create("atomicio");
+ tcase_add_checked_fixture (tc_atomicio,
+ setup_atomicio,
+ teardown_atomicio);
+ tcase_add_test(tc_atomicio, test_atomicio_read_from_file);
+ tcase_add_test(tc_atomicio, test_atomicio_read_from_small_file);
+ tcase_add_test(tc_atomicio, test_atomicio_read_from_large_file);
+ tcase_add_test(tc_atomicio, test_atomicio_read_exact_sized_file);
+ tcase_add_test(tc_atomicio, test_atomicio_read_from_empty_file);
+
+ TCase *tc_convert_time = tcase_create("convert_time");
+ tcase_add_checked_fixture(tc_convert_time,
+ ck_leak_check_setup,
+ ck_leak_check_teardown);
+ tcase_add_test(tc_convert_time, test_convert_time);
+
+ TCase *tc_sss_strerror = tcase_create("sss_strerror");
+ tcase_add_test(tc_sss_strerror, test_sss_strerror_err_last);
+ tcase_add_test(tc_sss_strerror, test_sss_strerror_string_validation);
+
+ suite_add_tcase (s, tc_util);
+ suite_add_tcase (s, tc_utf8);
+ suite_add_tcase (s, tc_mh3);
+ suite_add_tcase (s, tc_atomicio);
+ suite_add_tcase (s, tc_convert_time);
+ suite_add_tcase (s, tc_sss_strerror);
+
+ return s;
+}
+
+int main(int argc, const char *argv[])
+{
+ int opt;
+ int failure_count;
+ poptContext pc;
+ Suite *s = util_suite();
+ SRunner *sr = srunner_create (s);
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ SSSD_MAIN_OPTS
+ POPT_TABLEEND
+ };
+
+ /* Set debug level to invalid value so we can decide if -d 0 was used. */
+ debug_level = SSSDBG_INVALID;
+
+ 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_CLI_INIT(debug_level);
+
+ tests_set_cwd();
+
+ srunner_run_all(sr, CK_ENV);
+ failure_count = srunner_ntests_failed (sr);
+ srunner_free (sr);
+ if (failure_count == 0) {
+ return EXIT_SUCCESS;
+ }
+ return EXIT_FAILURE;
+}