From ac0a2de24a0400dc08acf375184d20673872415c Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Tue, 23 Feb 2010 09:43:51 +0100 Subject: [PATCH] Add expandable sequences to krb5_ccachedir As with krb5_ccname_template sequences like %u can be used in the krb5_ccachedir parameter which are expanded at runtime. If the directory does not exist, it will be created. Depending on the used sequences it is created as a public or private directory. --- src/man/sssd-krb5.5.xml | 8 +- src/providers/krb5/krb5_auth.c | 13 ++- src/providers/krb5/krb5_common.c | 13 -- src/providers/krb5/krb5_utils.c | 134 ++++++++++++++- src/providers/krb5/krb5_utils.h | 7 +- src/tests/krb5_utils-tests.c | 350 ++++++++++++++++++++++++++++---------- 6 files changed, 409 insertions(+), 116 deletions(-) diff --git a/src/man/sssd-krb5.5.xml b/src/man/sssd-krb5.5.xml index 32b6c29..921d17c 100644 --- a/src/man/sssd-krb5.5.xml +++ b/src/man/sssd-krb5.5.xml @@ -102,7 +102,13 @@ krb5_ccachedir (string) - Directory to store credential caches. + Directory to store credential caches. All the + substitution sequences of krb5_ccname_template can + be used here, too, expect %d. If the directory does + not exist it will be created. If %u, %U, %p or %h + are used a private directory belonging to the user + is created. Otherwise a public directory with + restricted deletion flag is created. Default: /tmp diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index 0e5230c..3419838 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -915,12 +915,21 @@ static void krb5_resolve_done(struct tevent_req *req) } kr->ccname = expand_ccname_template(kr, kr, dp_opt_get_cstring(kr->krb5_ctx->opts, - KRB5_CCNAME_TMPL) - ); + KRB5_CCNAME_TMPL), + true); if (kr->ccname == NULL) { DEBUG(1, ("expand_ccname_template failed.\n")); goto done; } + + ret = create_ccache_dir(kr, kr->ccname, + dp_opt_get_cstring(kr->krb5_ctx->opts, + KRB5_CCACHEDIR), + kr->uid, kr->gid); + if (ret != EOK) { + DEBUG(1, ("create_ccache_dir failed.\n")); + goto done; + } } if (be_is_offline(be_req->be_ctx)) { diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c index 86676f4..7619e6a 100644 --- a/src/providers/krb5/krb5_common.c +++ b/src/providers/krb5/krb5_common.c @@ -47,7 +47,6 @@ errno_t check_and_export_options(struct dp_option *opts, char *value; const char *realm; const char *dummy; - struct stat stat_buf; char **list; realm = dp_opt_get_cstring(opts, KRB5_REALM); @@ -83,18 +82,6 @@ errno_t check_and_export_options(struct dp_option *opts, talloc_free(list); } - dummy = dp_opt_get_cstring(opts, KRB5_CCACHEDIR); - ret = lstat(dummy, &stat_buf); - if (ret != EOK) { - DEBUG(1, ("lstat for [%s] failed: [%d][%s].\n", dummy, errno, - strerror(errno))); - return ret; - } - if ( !S_ISDIR(stat_buf.st_mode) ) { - DEBUG(1, ("Value of krb5ccache_dir [%s] is not a directory.\n", dummy)); - return EINVAL; - } - dummy = dp_opt_get_cstring(opts, KRB5_CCNAME_TMPL); if (dummy == NULL) { DEBUG(1, ("Missing credential cache name template.\n")); diff --git a/src/providers/krb5/krb5_utils.c b/src/providers/krb5/krb5_utils.c index a75ad78..6a893f6 100644 --- a/src/providers/krb5/krb5_utils.c +++ b/src/providers/krb5/krb5_utils.c @@ -29,13 +29,14 @@ #include "util/util.h" char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr, - const char *template) + const char *template, bool expand_ccache_dir) { char *copy; char *p; char *n; char *result = NULL; const char *dummy; + const char *cache_dir_tmpl; if (template == NULL) { DEBUG(1, ("Missing template.\n")); @@ -110,12 +111,26 @@ char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr, result = talloc_asprintf_append(result, "%s%s", p, kr->homedir); break; case 'd': - dummy = dp_opt_get_string(kr->krb5_ctx->opts, KRB5_CCACHEDIR); - if (dummy == NULL) { - DEBUG(1, ("Missing credential cache directory.\n")); + if (expand_ccache_dir) { + cache_dir_tmpl = dp_opt_get_string(kr->krb5_ctx->opts, + KRB5_CCACHEDIR); + if (cache_dir_tmpl == NULL) { + DEBUG(1, ("Missing credential cache directory.\n")); + return NULL; + } + + dummy = expand_ccname_template(mem_ctx, kr, cache_dir_tmpl, + false); + if (dummy == NULL) { + DEBUG(1, ("Expanding credential cache directory " + "template failed.\n")); + return NULL; + } + result = talloc_asprintf_append(result, "%s%s", p, dummy); + } else { + DEBUG(1, ("'%%d' is not allowed in this template.\n")); return NULL; } - result = talloc_asprintf_append(result, "%s%s", p, dummy); break; case 'P': if (kr->pd->cli_pid == 0) { @@ -143,3 +158,112 @@ char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr, return result; } + +errno_t create_dir_with_parents(TALLOC_CTX *mem_ctx, const char *dirname) +{ + int ret; + struct stat stat_buf; + char *parent; + char *end; + mode_t old_umask; + + ret = lstat(dirname, &stat_buf); + if (ret == EOK) { + if ( !S_ISDIR(stat_buf.st_mode) ) { + DEBUG(1, ("[%s] is not a directory.\n", dirname)); + return EINVAL; + } + return EOK; + } else { + if (errno != ENOENT) { + DEBUG(1, ("lstat for [%s] failed: [%d][%s].\n", dirname, errno, + strerror(errno))); + return errno; + } + } + + parent = talloc_strdup(mem_ctx, dirname); + end = strrchr(parent, '/'); + if (end == NULL || end == parent) { + DEBUG(1, ("Cannot find parent directory of [%s], / is not allowed.\n", + dirname)); + return EINVAL; + } + *end = '\0'; + + ret = create_dir_with_parents(mem_ctx, parent); + if (ret != EOK) { + DEBUG(7, ("create_dir_with_parents failed.\n")); + return ret; + } + + old_umask = umask(0000); + ret = mkdir(dirname, 01777); + umask(old_umask); + if (ret != EOK) { + DEBUG(1, ("mkdir [%s] failed: [%d][%s].\n", dirname, errno, + strerror(errno))); + return errno; + } + + return EOK; +} + +errno_t create_ccache_dir(TALLOC_CTX *mem_ctx, const char *filename, + const char *ccache_dir_tmpl, uid_t priv_uid, + gid_t priv_gid) +{ + int ret; + char *dirname; + char *end; + const char *c; + + dirname = talloc_strdup(mem_ctx, filename); + if (dirname == NULL) { + DEBUG(1, ("talloc_strndup failed.\n")); + return ENOMEM; + } + + if (strncmp(dirname, "FILE:", 5) == 0) { + dirname = dirname + 5; + } + + if (*dirname != '/') { + DEBUG(1, ("Only absolute paths are allowed, not [%s] .\n", dirname)); + return EINVAL; + } + + end = strrchr(dirname, '/'); + if (end == NULL || end == dirname) { + DEBUG(1, ("Not allowed filename [%s].\n")); + return EINVAL; + } + *end = '\0'; + + ret = create_dir_with_parents(mem_ctx, dirname); + if (ret != EOK) { + DEBUG(1, ("create_dir_with_parents failed.\n")); + return ret; + } + + c = ccache_dir_tmpl; + while((c = strchr(c, '%')) != NULL) { + ++c; + if ( *c == 'u' || *c == 'U' || *c == 'p' || *c == 'h') { + ret = chmod(dirname, 0700); + if (ret != EOK) { + DEBUG(1, ("chmod failed [%d][%s].\n", errno, strerror(errno))); + return errno; + } + + ret = chown(dirname, priv_uid, priv_gid); + if (ret != EOK) { + DEBUG(1, ("chown failed [%d][%s].\n", errno, strerror(errno))); + return errno; + } + break; + } + } + + return EOK; +} diff --git a/src/providers/krb5/krb5_utils.h b/src/providers/krb5/krb5_utils.h index 7637041..ce407ec 100644 --- a/src/providers/krb5/krb5_utils.h +++ b/src/providers/krb5/krb5_utils.h @@ -32,8 +32,13 @@ #include "providers/data_provider.h" char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr, - const char *template); + const char *template, bool expand_ccache_dir); errno_t become_user(uid_t uid, gid_t gid); +errno_t create_dir_with_parents(TALLOC_CTX *mem_ctx, const char *dirname); + +errno_t create_ccache_dir(TALLOC_CTX *mem_ctx, const char *filename, + const char *ccache_dir_tmpl, uid_t priv_uid, + gid_t priv_gid); #endif /* __KRB5_UTILS_H__ */ diff --git a/src/tests/krb5_utils-tests.c b/src/tests/krb5_utils-tests.c index 362daf4..58f04fe 100644 --- a/src/tests/krb5_utils-tests.c +++ b/src/tests/krb5_utils-tests.c @@ -23,12 +23,16 @@ */ #include +#include #include #include "providers/krb5/krb5_utils.h" #include "providers/krb5/krb5_auth.h" +#define TESTS_PATH "tests_krb5_utils" + #define BASE "/abc/def" +#define FILENAME "ghi" #define USERNAME "testuser" #define UID "12345" @@ -43,6 +47,144 @@ extern struct dp_option default_krb5_opts[]; TALLOC_CTX *tmp_ctx = NULL; struct krb5child_req *kr; +#define RMDIR(__dir__) do { \ + ret = rmdir(__dir__); \ + fail_unless(ret == EOK, "rmdir [%s] failed, [%d][%s].", __dir__, \ + errno, strerror(errno)); \ +} while(0); + +void setup_create_dir(void) +{ + fail_unless(tmp_ctx == NULL, "Talloc context already initialized."); + tmp_ctx = talloc_new(NULL); + fail_unless(tmp_ctx != NULL, "Cannot create talloc context."); +} + +void teardown_create_dir(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."); +} + +static void check_dir(const char *dirname, uid_t uid, gid_t gid, mode_t mode) +{ + struct stat stat_buf; + int ret; + + ret = stat(dirname, &stat_buf); + fail_unless(ret == EOK, "stat failed [%d][%s].", errno, strerror(errno)); + + fail_unless(S_ISDIR(stat_buf.st_mode), "[%s] is not a directory.", dirname); + fail_unless(stat_buf.st_uid == uid, "uid does not match, " + "expected [%d], got [%d].", + uid, stat_buf.st_uid); + fail_unless(stat_buf.st_gid == gid, "gid does not match, " + "expected [%d], got [%d].", + gid, stat_buf.st_gid); + fail_unless((stat_buf.st_mode & ~S_IFMT) == mode, "mode does not match, " + "expected [%o], got [%o].", + mode, (stat_buf.st_mode & ~S_IFMT)); +} + +START_TEST(test_mkdir_simple) +{ + int ret; + + ret = create_dir_with_parents(tmp_ctx, TESTS_PATH"/abc"); + fail_unless(ret == EOK, "create_dir_with_parents failed."); + check_dir(TESTS_PATH"/abc", getuid(), getgid(), 01777); + + RMDIR(TESTS_PATH"/abc"); +} +END_TEST + +START_TEST(test_mkdir_parents) +{ + int ret; + + ret = create_dir_with_parents(tmp_ctx, TESTS_PATH"/a/b/c"); + fail_unless(ret == EOK, "create_dir_with_parents failed."); + check_dir(TESTS_PATH"/a/b/c", getuid(), getgid(), 01777); + RMDIR(TESTS_PATH"/a/b/c"); + RMDIR(TESTS_PATH"/a/b"); + RMDIR(TESTS_PATH"/a"); +} +END_TEST + +START_TEST(test_mkdir_nonexisting_parent) +{ + int ret; + + ret = create_dir_with_parents(tmp_ctx, "/a/b/c"); + fail_unless(ret == EINVAL, "create_dir_with_parents did not return EINVAL."); +} +END_TEST + +START_TEST(test_priv_ccache_dir) +{ + int ret; + char *cwd; + char *dirname; + char *filename; + uid_t uid = getuid(); + gid_t gid = getgid(); + + if (uid == 0) { + uid = 12345; + gid = 12345; + } + + cwd = getcwd(NULL, 0); + fail_unless(cwd != NULL, "getcwd failed."); + + dirname = talloc_asprintf(tmp_ctx, "%s/%s/priv_ccdir", cwd, TESTS_PATH); + free(cwd); + fail_unless(dirname != NULL, "talloc_asprintf failed."); + filename = talloc_asprintf(tmp_ctx, "%s/ccfile", dirname); + fail_unless(filename != NULL, "talloc_asprintf failed."); + + ret = create_ccache_dir(tmp_ctx, filename, "/abc_%u_abc", uid, gid); + fail_unless(ret == EOK, "create_ccache_dir failed."); + + check_dir(dirname, uid, gid, 0700); + RMDIR(dirname); +} +END_TEST + +START_TEST(test_pub_ccache_dir) +{ + int ret; + char *cwd; + char *dirname; + char *filename; + uid_t uid = getuid(); + gid_t gid = getgid(); + + if (uid == 0) { + uid = 12345; + gid = 12345; + } + + cwd = getcwd(NULL, 0); + fail_unless(cwd != NULL, "getcwd failed."); + + dirname = talloc_asprintf(tmp_ctx, "%s/%s/pub_ccdir", cwd, TESTS_PATH); + free(cwd); + fail_unless(dirname != NULL, "talloc_asprintf failed."); + filename = talloc_asprintf(tmp_ctx, "%s/ccfile", dirname); + fail_unless(filename != NULL, "talloc_asprintf failed."); + + ret = create_ccache_dir(tmp_ctx, filename, "/abc_%%_abc", uid, gid); + fail_unless(ret == EOK, "create_ccache_dir failed."); + + check_dir(dirname, getuid(), getgid(), 01777); + RMDIR(dirname); +} +END_TEST + void setup_talloc_context(void) { int ret; @@ -96,138 +238,93 @@ void free_talloc_context(void) fail_unless(ret == 0, "Connot free talloc context."); } -START_TEST(test_multiple_substitutions) +static void do_test(const char *file_template, const char *dir_template, + const char *expected) { - const char *test_template = BASE"_%u_%U_%u"; - const char *expected = BASE"_"USERNAME"_"UID"_"USERNAME; char *result; + int ret; - result = expand_ccname_template(tmp_ctx, kr, test_template); + ret = dp_opt_set_string(kr->krb5_ctx->opts, KRB5_CCACHEDIR, dir_template); + fail_unless(ret == EOK, "Failed to set Ccache dir"); - fail_unless(result != NULL, "Cannot expand template [%s].", test_template); + result = expand_ccname_template(tmp_ctx, kr, file_template, true); + + fail_unless(result != NULL, "Cannot expand template [%s].", file_template); fail_unless(strcmp(result, expected) == 0, "Expansion failed, result [%s], expected [%s].", result, expected); } + +START_TEST(test_multiple_substitutions) +{ + do_test(BASE"_%u_%U_%u", CCACHE_DIR, BASE"_"USERNAME"_"UID"_"USERNAME); + do_test("%d/"FILENAME, BASE"_%u_%U_%u", + BASE"_"USERNAME"_"UID"_"USERNAME"/"FILENAME); +} 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); + do_test(BASE"_%u", CCACHE_DIR, BASE"_"USERNAME); + do_test("%d/"FILENAME, BASE"_%u", BASE"_"USERNAME"/"FILENAME); } 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); + do_test(BASE"_%U", CCACHE_DIR, BASE"_"UID); + do_test("%d/"FILENAME, BASE"_%U", BASE"_"UID"/"FILENAME); } 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); + do_test(BASE"_%p", CCACHE_DIR, BASE"_"PRINCIPLE_NAME); + do_test("%d/"FILENAME, BASE"_%p", BASE"_"PRINCIPLE_NAME"/"FILENAME); } 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); + do_test(BASE"_%r", CCACHE_DIR, BASE"_"REALM); + do_test("%d/"FILENAME, BASE"_%r", BASE"_"REALM"/"FILENAME); } 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); + do_test(BASE"_%h", CCACHE_DIR, BASE"_"HOME_DIRECTORY); + do_test("%d/"FILENAME, BASE"_%h", BASE"_"HOME_DIRECTORY"/"FILENAME); } END_TEST START_TEST(test_ccache_dir) { - const char *test_template = BASE"_%d"; - const char *expected = BASE"_"CCACHE_DIR; char *result; + int ret; - result = expand_ccname_template(tmp_ctx, kr, test_template); + do_test(BASE"_%d", CCACHE_DIR, BASE"_"CCACHE_DIR); - fail_unless(result != NULL, "Cannot expand template [%s].", test_template); - fail_unless(strcmp(result, expected) == 0, - "Expansion failed, result [%s], expected [%s].", - result, expected); + ret = dp_opt_set_string(kr->krb5_ctx->opts, KRB5_CCACHEDIR, BASE"_%d"); + fail_unless(ret == EOK, "Failed to set Ccache dir"); + + result = expand_ccname_template(tmp_ctx, kr, "%d/"FILENAME, true); + + fail_unless(result == NULL, "Using %%d in ccache dir should fail."); } 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); + do_test(BASE"_%P", CCACHE_DIR, BASE"_"PID); + do_test("%d/"FILENAME, BASE"_%P", BASE"_"PID"/"FILENAME); } 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); + do_test(BASE"_%%", CCACHE_DIR, BASE"_%"); + do_test("%d/"FILENAME, BASE"_%%", BASE"_%/"FILENAME); } END_TEST @@ -235,8 +332,17 @@ START_TEST(test_unknow_template) { const char *test_template = BASE"_%X"; char *result; + int ret; - result = expand_ccname_template(tmp_ctx, kr, test_template); + result = expand_ccname_template(tmp_ctx, kr, test_template, true); + + fail_unless(result == NULL, "Unknown template [%s] should fail.", + test_template); + + ret = dp_opt_set_string(kr->krb5_ctx->opts, KRB5_CCACHEDIR, BASE"_%X"); + fail_unless(ret == EOK, "Failed to set Ccache dir"); + test_template = "%d/"FILENAME; + result = expand_ccname_template(tmp_ctx, kr, test_template, true); fail_unless(result == NULL, "Unknown template [%s] should fail.", test_template); @@ -248,7 +354,7 @@ START_TEST(test_NULL) char *test_template = NULL; char *result; - result = expand_ccname_template(tmp_ctx, kr, test_template); + result = expand_ccname_template(tmp_ctx, kr, test_template, true); fail_unless(result == NULL, "Expected NULL as a result for an empty input.", test_template); @@ -260,7 +366,7 @@ START_TEST(test_no_substitution) const char *test_template = BASE; char *result; - result = expand_ccname_template(tmp_ctx, kr, test_template); + result = expand_ccname_template(tmp_ctx, kr, test_template, true); fail_unless(result != NULL, "Cannot expand template [%s].", test_template); fail_unless(strcmp(result, test_template) == 0, @@ -290,18 +396,74 @@ Suite *krb5_utils_suite (void) tcase_add_test (tc_ccname_template, test_multiple_substitutions); suite_add_tcase (s, tc_ccname_template); + TCase *tc_create_dir = tcase_create("create_dir"); + tcase_add_checked_fixture (tc_create_dir, setup_create_dir, + teardown_create_dir); + tcase_add_test (tc_create_dir, test_mkdir_simple); + tcase_add_test (tc_create_dir, test_mkdir_parents); + tcase_add_test (tc_create_dir, test_mkdir_nonexisting_parent); + tcase_add_test (tc_create_dir, test_priv_ccache_dir); + tcase_add_test (tc_create_dir, test_pub_ccache_dir); + suite_add_tcase (s, tc_create_dir); + return s; } -int main(void) +int main(int argc, const char *argv[]) { - 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; + int ret; + int opt; + poptContext pc; + int number_failed; + + 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 = mkdir(TESTS_PATH, 0775); + if (ret != EOK) { + fprintf(stderr, "Could not create empty directory [%s]. ", TESTS_PATH); + if (errno == EEXIST) { + fprintf(stderr, "Please remove [%s].\n", TESTS_PATH); + } else { + fprintf(stderr, "[%d][%s].\n", errno, strerror(errno)); + } + + return 1; + } + + 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); + if (number_failed == 0) { + ret = rmdir(TESTS_PATH); + if (ret != EOK) { + fprintf(stderr, "Cannot remove [%s]: [%d][%s].\n", TESTS_PATH, + errno, strerror(errno)); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; + } + + return EXIT_FAILURE; } -- 1.6.6