From 8eab929b3fe38b33f31d22bce87f1a7b96db21c8 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 | 12 +- src/providers/krb5/krb5_auth.c | 19 ++- src/providers/krb5/krb5_auth.h | 6 + src/providers/krb5/krb5_common.c | 13 -- src/providers/krb5/krb5_init.c | 12 ++ src/providers/krb5/krb5_utils.c | 144 +++++++++++++- src/providers/krb5/krb5_utils.h | 8 +- src/tests/krb5_utils-tests.c | 407 +++++++++++++++++++++++++++++--------- 8 files changed, 505 insertions(+), 116 deletions(-) diff --git a/src/man/sssd-krb5.5.xml b/src/man/sssd-krb5.5.xml index 32b6c29..5a1d626 100644 --- a/src/man/sssd-krb5.5.xml +++ b/src/man/sssd-krb5.5.xml @@ -102,7 +102,17 @@ 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, except %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 (aka sticky bit, see + + chmod + 1 + for details) is created. Default: /tmp diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index 0e5230c..fde3b93 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -880,6 +880,7 @@ static void krb5_resolve_done(struct tevent_req *req) struct be_req *be_req = kr->req; char *msg; size_t offset = 0; + bool private_path = false; ret = be_resolve_server_recv(req, &kr->srv); talloc_zfree(req); @@ -915,12 +916,26 @@ 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, &private_path); if (kr->ccname == NULL) { DEBUG(1, ("expand_ccname_template failed.\n")); goto done; } + + if (private_path) { + ret = create_ccache_dir(kr, kr->ccname, + kr->krb5_ctx->illegal_path_re, + kr->uid, kr->gid, 0700); + } else { + ret = create_ccache_dir(kr, kr->ccname, + kr->krb5_ctx->illegal_path_re, + 0, 0, 01777); + } + 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_auth.h b/src/providers/krb5/krb5_auth.h index 3e11f27..825f3d6 100644 --- a/src/providers/krb5/krb5_auth.h +++ b/src/providers/krb5/krb5_auth.h @@ -26,6 +26,8 @@ #ifndef __KRB5_AUTH_H__ #define __KRB5_AUTH_H__ +#include + #include "util/sss_krb5.h" #include "providers/dp_backend.h" #include "providers/krb5/krb5_common.h" @@ -33,6 +35,8 @@ #define CCACHE_ENV_NAME "KRB5CCNAME" #define SSSD_KRB5_CHANGEPW_PRINCIPLE "SSSD_KRB5_CHANGEPW_PRINCIPLE" +#define ILLEGAL_PATH_PATTERN "//|/\\./|/\\.\\./" + typedef enum { INIT_PW, INIT_KT, RENEW, VALIDATE } action_type; struct krb5child_req { @@ -87,6 +91,8 @@ struct krb5_ctx { struct dp_option *opts; struct krb5_service *service; int child_debug_fd; + + pcre *illegal_path_re; }; void krb5_pam_handler(struct be_req *be_req); 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_init.c b/src/providers/krb5/krb5_init.c index 43cbc1b..4d21238 100644 --- a/src/providers/krb5/krb5_init.c +++ b/src/providers/krb5/krb5_init.c @@ -53,6 +53,9 @@ int sssm_krb5_auth_init(struct be_ctx *bectx, FILE *debug_filep; const char *krb5_servers; const char *krb5_realm; + const char *errstr; + int errval; + int errpos; if (krb5_options == NULL) { krb5_options = talloc_zero(bectx, struct krb5_options); @@ -135,6 +138,15 @@ int sssm_krb5_auth_init(struct be_ctx *bectx, fcntl(ctx->child_debug_fd, F_SETFD, v & ~FD_CLOEXEC); } + ctx->illegal_path_re = pcre_compile2(ILLEGAL_PATH_PATTERN, 0, + &errval, &errstr, &errpos, NULL); + if (ctx->illegal_path_re == NULL) { + DEBUG(1, ("Invalid Regular Expression pattern at position %d. " + "(Error: %d [%s])\n", errpos, errval, errstr)); + ret = EFAULT; + goto fail; + } + *ops = &krb5_auth_ops; *pvt_auth_data = ctx; return EOK; diff --git a/src/providers/krb5/krb5_utils.c b/src/providers/krb5/krb5_utils.c index a75ad78..d5d104b 100644 --- a/src/providers/krb5/krb5_utils.c +++ b/src/providers/krb5/krb5_utils.c @@ -29,13 +29,17 @@ #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, + bool *private_path) { char *copy; char *p; char *n; char *result = NULL; const char *dummy; + const char *cache_dir_tmpl; + + *private_path = false; if (template == NULL) { DEBUG(1, ("Missing template.\n")); @@ -72,6 +76,7 @@ char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr, } result = talloc_asprintf_append(result, "%s%s", p, kr->pd->user); + if (!expand_ccache_dir) *private_path = true; break; case 'U': if (kr->uid <= 0) { @@ -81,6 +86,7 @@ char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr, } result = talloc_asprintf_append(result, "%s%d", p, kr->uid); + if (!expand_ccache_dir) *private_path = true; break; case 'p': if (kr->upn == NULL) { @@ -89,6 +95,7 @@ char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr, return NULL; } result = talloc_asprintf_append(result, "%s%s", p, kr->upn); + if (!expand_ccache_dir) *private_path = true; break; case '%': result = talloc_asprintf_append(result, "%s%%", p); @@ -108,14 +115,29 @@ char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr, return NULL; } result = talloc_asprintf_append(result, "%s%s", p, kr->homedir); + if (!expand_ccache_dir) *private_path = true; 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, private_path); + 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 +165,115 @@ 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, + uid_t uid, gid_t gid, mode_t mode) +{ + 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, 0, 0, 0755); + if (ret != EOK) { + DEBUG(7, ("create_dir_with_parents failed.\n")); + return ret; + } + + old_umask = umask(0000); + ret = mkdir(dirname, mode); + umask(old_umask); + if (ret != EOK) { + DEBUG(1, ("mkdir [%s] failed: [%d][%s].\n", dirname, errno, + strerror(errno))); + return errno; + } + if (uid != 0) { + ret = chown(dirname, uid, gid); + if (ret != EOK) { + DEBUG(1, ("chown failed [%d][%s].\n", errno, strerror(errno))); + return errno; + } + } + + return EOK; +} + +errno_t create_ccache_dir(TALLOC_CTX *mem_ctx, const char *filename, + pcre *illegal_re, uid_t uid, gid_t gid, mode_t mode) +{ + int ret; + char *dirname; + char *end; + + 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; + } + + if (illegal_re != NULL) { + ret = pcre_exec(illegal_re, NULL, dirname, strlen(dirname), + 0, 0, NULL, 0); + if (ret == 0) { + DEBUG(1, ("Illegal pattern in ccache directory name [%s].\n", + dirname)); + return EINVAL; + } else if ( ret == PCRE_ERROR_NOMATCH) { + DEBUG(9, ("Ccache directory name [%s] does not contain " + "illegal patterns.\n", dirname)); + } else { + DEBUG(1, ("pcre_exec failed [%d].\n", ret)); + return EFAULT; + } + } + + end = strrchr(dirname, '/'); + if (end == NULL || end == dirname) { + DEBUG(1, ("Missing filename in [%s].\n", dirname)); + return EINVAL; + } + *end = '\0'; + + ret = create_dir_with_parents(mem_ctx, dirname, uid, gid, mode); + if (ret != EOK) { + DEBUG(1, ("create_dir_with_parents failed.\n")); + return ret; + } + + return EOK; +} diff --git a/src/providers/krb5/krb5_utils.h b/src/providers/krb5/krb5_utils.h index 7637041..e158cb8 100644 --- a/src/providers/krb5/krb5_utils.h +++ b/src/providers/krb5/krb5_utils.h @@ -32,8 +32,14 @@ #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, + bool *private_path); errno_t become_user(uid_t uid, gid_t gid); +errno_t create_dir_with_parents(TALLOC_CTX *mem_ctx, const char *dirname, + uid_t uid, gid_t gid, mode_t mode); + +errno_t create_ccache_dir(TALLOC_CTX *mem_ctx, const char *filename, + pcre *illegal_re, uid_t uid, gid_t gid, mode_t mode); #endif /* __KRB5_UTILS_H__ */ diff --git a/src/tests/krb5_utils-tests.c b/src/tests/krb5_utils-tests.c index 362daf4..8133e8e 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,174 @@ 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", + getuid(), getgid(), 01777); + 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", + getuid(), getgid(), 01777); + fail_unless(ret == EOK, "create_dir_with_parents failed."); + check_dir(TESTS_PATH"/a/b/c", getuid(), getgid(), 01777); + check_dir(TESTS_PATH"/a/b", getuid(), getgid(), 0755); + check_dir(TESTS_PATH"/a", getuid(), getgid(), 0755); + 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", getuid(), getgid(), 0777); + 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, NULL, uid, gid, 0700); + fail_unless(ret == EOK, "create_ccache_dir failed."); + + check_dir(dirname, uid, gid, 0700); + RMDIR(dirname); +} +END_TEST + +START_TEST(test_illegal_patterns) +{ + int ret; + char *cwd; + char *dirname; + char *filename; + uid_t uid = getuid(); + gid_t gid = getgid(); + pcre *illegal_re; + const char *errstr; + int errval; + int errpos; + + illegal_re = pcre_compile2(ILLEGAL_PATH_PATTERN, 0, + &errval, &errstr, &errpos, NULL); + fail_unless(illegal_re != NULL, "Invalid Regular Expression pattern at " + " position %d. (Error: %d [%s])\n", + errpos, errval, errstr); + + 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, "abc/./ccfile"); + fail_unless(filename != NULL, "talloc_asprintf failed."); + ret = create_ccache_dir(tmp_ctx, filename, illegal_re, uid, gid, 0700); + fail_unless(ret == EINVAL, "create_ccache_dir allowed relative path [%s].", + filename); + + filename = talloc_asprintf(tmp_ctx, "%s/abc/./ccfile", dirname); + fail_unless(filename != NULL, "talloc_asprintf failed."); + ret = create_ccache_dir(tmp_ctx, filename, illegal_re, uid, gid, 0700); + fail_unless(ret == EINVAL, "create_ccache_dir allowed " + "illegal pattern '/./' in filename [%s].", + filename); + + filename = talloc_asprintf(tmp_ctx, "%s/abc/../ccfile", dirname); + fail_unless(filename != NULL, "talloc_asprintf failed."); + ret = create_ccache_dir(tmp_ctx, filename, illegal_re, uid, gid, 0700); + fail_unless(ret == EINVAL, "create_ccache_dir allowed " + "illegal pattern '/../' in filename [%s].", + filename); + + filename = talloc_asprintf(tmp_ctx, "%s/abc//ccfile", dirname); + fail_unless(filename != NULL, "talloc_asprintf failed."); + ret = create_ccache_dir(tmp_ctx, filename, illegal_re, uid, gid, 0700); + fail_unless(ret == EINVAL, "create_ccache_dir allowed " + "illegal pattern '//' in filename [%s].", + filename); + +} +END_TEST + void setup_talloc_context(void) { int ret; @@ -96,138 +268,104 @@ 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 bool expected_private_path) { - const char *test_template = BASE"_%u_%U_%u"; - const char *expected = BASE"_"USERNAME"_"UID"_"USERNAME; char *result; + int ret; + bool private_path = false; + + ret = dp_opt_set_string(kr->krb5_ctx->opts, KRB5_CCACHEDIR, dir_template); + fail_unless(ret == EOK, "Failed to set Ccache dir"); - result = expand_ccname_template(tmp_ctx, kr, test_template); + result = expand_ccname_template(tmp_ctx, kr, file_template, true, + &private_path); - fail_unless(result != NULL, "Cannot expand template [%s].", test_template); + fail_unless(result != NULL, "Cannot expand template [%s].", file_template); fail_unless(strcmp(result, expected) == 0, "Expansion failed, result [%s], expected [%s].", result, expected); + fail_unless(private_path == expected_private_path, + "Unexprected private path, get [%s], expected [%s].", + private_path ? "true" : "false", + expected_private_path ? "true" : "false"); +} + +START_TEST(test_multiple_substitutions) +{ + do_test(BASE"_%u_%U_%u", CCACHE_DIR, BASE"_"USERNAME"_"UID"_"USERNAME, false); + do_test("%d/"FILENAME, BASE"_%u_%U_%u", + BASE"_"USERNAME"_"UID"_"USERNAME"/"FILENAME, true); } 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, false); + do_test("%d/"FILENAME, BASE"_%u", BASE"_"USERNAME"/"FILENAME, true); } 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, false); + do_test("%d/"FILENAME, BASE"_%U", BASE"_"UID"/"FILENAME, true); } 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, false); + do_test("%d/"FILENAME, BASE"_%p", BASE"_"PRINCIPLE_NAME"/"FILENAME, true); } 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, false); + do_test("%d/"FILENAME, BASE"_%r", BASE"_"REALM"/"FILENAME, false); } 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, false); + do_test("%d/"FILENAME, BASE"_%h", BASE"_"HOME_DIRECTORY"/"FILENAME, true); } END_TEST START_TEST(test_ccache_dir) { - const char *test_template = BASE"_%d"; - const char *expected = BASE"_"CCACHE_DIR; char *result; + int ret; + bool private_path = false; - result = expand_ccname_template(tmp_ctx, kr, test_template); + do_test(BASE"_%d", CCACHE_DIR, BASE"_"CCACHE_DIR, false); - 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, + &private_path); + + fail_unless(result == NULL, "Using %%d in ccache dir should fail."); + fail_unless(private_path == false, + "Unexprected private path, get [%s], expected [%s].", + private_path ? "true" : "false", "false"); } 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, false); + do_test("%d/"FILENAME, BASE"_%P", BASE"_"PID"/"FILENAME, false); } 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"_%", false); + do_test("%d/"FILENAME, BASE"_%%", BASE"_%/"FILENAME, false); } END_TEST @@ -235,11 +373,26 @@ START_TEST(test_unknow_template) { const char *test_template = BASE"_%X"; char *result; + int ret; + bool private_path = false; - result = expand_ccname_template(tmp_ctx, kr, test_template); + result = expand_ccname_template(tmp_ctx, kr, test_template, true, + &private_path); 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, + &private_path); + + fail_unless(result == NULL, "Unknown template [%s] should fail.", + test_template); + fail_unless(private_path == false, + "Unexprected private path, get [%s], expected [%s].", + private_path ? "true" : "false", "false"); } END_TEST @@ -247,11 +400,16 @@ START_TEST(test_NULL) { char *test_template = NULL; char *result; + bool private_path = false; - result = expand_ccname_template(tmp_ctx, kr, test_template); + result = expand_ccname_template(tmp_ctx, kr, test_template, true, + &private_path); fail_unless(result == NULL, "Expected NULL as a result for an empty input.", test_template); + fail_unless(private_path == false, + "Unexprected private path, get [%s], expected [%s].", + private_path ? "true" : "false", "false"); } END_TEST @@ -259,13 +417,18 @@ START_TEST(test_no_substitution) { const char *test_template = BASE; char *result; + bool private_path = false; - result = expand_ccname_template(tmp_ctx, kr, test_template); + result = expand_ccname_template(tmp_ctx, kr, test_template, true, + &private_path); 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); + fail_unless(private_path == false, + "Unexprected private path, get [%s], expected [%s].", + private_path ? "true" : "false", "false"); } END_TEST @@ -290,18 +453,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_illegal_patterns); + 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.1