From fd8595874aa06c8057740001ec465ba76b4af142 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Thu, 17 May 2012 18:06:34 +0200 Subject: Add a credential cache back end structure To be able to add support for new credential cache types easily, this patch creates a new structure sss_krb5_cc_be that defines common operations with a credential cache, such as create, check if used or remove. --- src/providers/krb5/krb5_auth.c | 193 +++++++++++------------ src/providers/krb5/krb5_auth.h | 1 + src/providers/krb5/krb5_become_user.c | 2 +- src/providers/krb5/krb5_common.c | 12 +- src/providers/krb5/krb5_common.h | 3 + src/providers/krb5/krb5_utils.c | 286 +++++++++++++++++++++++++++++----- src/providers/krb5/krb5_utils.h | 33 +++- src/tests/krb5_child-test.c | 38 ++--- src/tests/krb5_utils-tests.c | 44 +++--- 9 files changed, 414 insertions(+), 198 deletions(-) (limited to 'src') diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index 7c622dbea..9b503f47a 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -39,107 +39,76 @@ #include "providers/krb5/krb5_auth.h" #include "providers/krb5/krb5_utils.h" -static errno_t safe_remove_old_ccache_file(const char *old_ccache_file, - const char *new_ccache_file) +static errno_t safe_remove_old_ccache_file(struct sss_krb5_cc_be *cc_be, + const char *princ, + const char *old_ccache, + const char *new_ccache) { int ret; - size_t old_offset = 0; - size_t new_offset = 0; + enum sss_krb5_cc_type old_type; + struct sss_krb5_cc_be *old_cc_ops; - if (new_ccache_file == NULL) { - DEBUG(1, ("Missing new ccache file, " - "old ccache file is not deleted.\n")); - return EINVAL; + if (old_ccache == NULL) { + DEBUG(SSSDBG_FUNC_DATA, ("No old ccache, nothing to do\n")); + return EOK; } - if (old_ccache_file != NULL) { - if (strncmp(old_ccache_file, "FILE:", 5) == 0) { - old_offset = 5; - } - if (strncmp(new_ccache_file, "FILE:", 5) == 0) { - new_offset = 5; - } - if (strcmp(old_ccache_file + old_offset, - new_ccache_file + new_offset) == 0) { - DEBUG(7, ("New and old ccache file are the same, " - "no one will be deleted.\n")); - return EOK; - } - if (old_ccache_file[old_offset] != '/') { - DEBUG(1, ("Ccache file name [%s] is not an absolute path.\n", - old_ccache_file + old_offset)); - return EINVAL; - } - ret = unlink(old_ccache_file + old_offset); - if (ret == -1 && errno != ENOENT) { - ret = errno; - DEBUG(1, ("unlink [%s] failed [%d][%s].\n", old_ccache_file, ret, - strerror(ret))); - return ret; - } + if (new_ccache == NULL) { + DEBUG(SSSDBG_OP_FAILURE, + ("Missing new ccache file, old ccache file is not deleted.\n")); + return EINVAL; } - return EOK; -} - -static errno_t check_if_ccache_file_is_used(uid_t uid, const char *ccname, - bool *result) -{ - int ret; - size_t offset = 0; - struct stat stat_buf; - const char *filename; - bool active; - - *result = false; - - if (ccname == NULL || *ccname == '\0') { + old_type = sss_krb5_get_type(old_ccache); + old_cc_ops = get_cc_be_ops(old_type); + if (!old_cc_ops) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot get ccache operations\n")); return EINVAL; } - if (strncmp(ccname, "FILE:", 5) == 0) { - offset = 5; + if (cc_be->type == old_type && + strcmp(old_ccache, new_ccache) == 0) { + DEBUG(SSSDBG_TRACE_FUNC, ("New and old ccache file are the same, " + "no one will be deleted.\n")); + return EOK; } - filename = ccname + offset; - - if (filename[0] != '/') { - DEBUG(1, ("Only absolute path names are allowed.\n")); - return EINVAL; + ret = old_cc_ops->remove(old_ccache); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("Cannot remove ccache [%s]\n", old_ccache)); + return EIO; } - ret = lstat(filename, &stat_buf); + return EOK; +} - if (ret == -1 && errno != ENOENT) { - DEBUG(1, ("stat failed [%d][%s].\n", errno, strerror(errno))); - return errno; - } else if (ret == EOK) { - if (stat_buf.st_uid != uid) { - DEBUG(1, ("Cache file [%s] exists, but is owned by [%d] instead of " - "[%d].\n", filename, stat_buf.st_uid, uid)); - return EINVAL; - } +static errno_t +check_old_ccache(const char *old_ccache, struct krb5child_req *kr, + const char *realm, bool *active, bool *valid) +{ + struct sss_krb5_cc_be *old_cc_ops; + errno_t ret; - if (!S_ISREG(stat_buf.st_mode)) { - DEBUG(1, ("Cache file [%s] exists, but is not a regular file.\n", - filename)); - return EINVAL; - } + /* ccache file might be of a different type if the user changed + * configuration + */ + old_cc_ops = get_cc_be_ops_ccache(old_ccache); + if (old_cc_ops == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("Cannot get operations on saved ccache %s\n", old_ccache)); + return EINVAL; } - ret = check_if_uid_is_active(uid, &active); + ret = old_cc_ops->check_existing(old_ccache, kr->uid, realm, + kr->upn, active, valid); if (ret != EOK) { - DEBUG(1, ("check_if_uid_is_active failed.\n")); + DEBUG(SSSDBG_OP_FAILURE, + ("Cannot check if saved ccache %s is active and valid\n", + old_ccache)); return ret; } - if (!active) { - DEBUG(5, ("User [%d] is not active\n", uid)); - } else { - DEBUG(9, ("User [%d] is still active, reusing ccache file [%s].\n", - uid, filename)); - *result = true; - } return EOK; } @@ -332,7 +301,6 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx, struct krb5child_req *kr = NULL; const char *ccache_file = NULL; const char *realm; - krb5_error_code kerr; struct tevent_req *req; struct tevent_req *subreq; int ret; @@ -457,22 +425,20 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx, goto done; } + /* The type of the ccache might change during the request if we + * end up reusing an old ccache */ + kr->cc_be = krb5_ctx->cc_be; + ccache_file = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_CCACHE_FILE, NULL); if (ccache_file != NULL) { - ret = check_if_ccache_file_is_used(kr->uid, ccache_file, - &kr->active_ccache_present); + ret = check_old_ccache(ccache_file, kr, realm, + &kr->active_ccache_present, + &kr->valid_tgt_present); if (ret != EOK) { - DEBUG(1, ("check_if_ccache_file_is_used failed.\n")); - goto done; - } - - kerr = check_for_valid_tgt(ccache_file, realm, kr->upn, - &kr->valid_tgt_present); - if (kerr != 0) { - DEBUG(1, ("check_for_valid_tgt failed.\n")); - ret = kerr; + DEBUG(SSSDBG_CRIT_FAILURE, + ("check_if_ccache_file_is_used failed.\n")); goto done; } } else { @@ -639,13 +605,27 @@ static void krb5_find_ccache_step(struct tevent_req *req) goto done; } - ret = create_ccache_dir(kr, kr->ccname, + ret = kr->cc_be->create(kr->ccname, kr->krb5_ctx->illegal_path_re, kr->uid, kr->gid, private_path); if (ret != EOK) { - DEBUG(1, ("create_ccache_dir failed.\n")); + DEBUG(SSSDBG_OP_FAILURE, ("ccache creation failed.\n")); goto done; } + } else { + DEBUG(SSSDBG_MINOR_FAILURE, + ("Saved ccache %s if of different type than ccache in " + "configuration file, reusing the old ccache\n")); + + kr->cc_be = get_cc_be_ops_ccache(kr->old_ccname); + if (kr->cc_be == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("Cannot get operations on saved ccache %s\n", + kr->old_ccname)); + ret = EINVAL; + goto done; + } + } if (kr->is_offline) { @@ -725,6 +705,7 @@ static void krb5_child_done(struct tevent_req *subreq) uint8_t *buf = NULL; ssize_t len = -1; struct krb5_child_response *res; + const char *store_ccname; ret = handle_child_recv(subreq, pd, &buf, &len); talloc_zfree(subreq); @@ -777,7 +758,8 @@ static void krb5_child_done(struct tevent_req *subreq) if (res->msg_status == PAM_NEW_AUTHTOK_REQD) { if (pd->cmd == SSS_PAM_AUTHENTICATE && !kr->active_ccache_present) { if (kr->old_ccname != NULL) { - ret = safe_remove_old_ccache_file(kr->old_ccname, "dummy"); + ret = safe_remove_old_ccache_file(kr->cc_be, kr->upn, + kr->old_ccname, "dummy"); if (ret != EOK) { DEBUG(1, ("Failed to remove old ccache file [%s], " "please remove it manually.\n", kr->old_ccname)); @@ -851,16 +833,25 @@ static void krb5_child_done(struct tevent_req *subreq) goto done; } - if (kr->old_ccname != NULL) { - ret = safe_remove_old_ccache_file(kr->old_ccname, kr->ccname); - if (ret != EOK) { - DEBUG(1, ("Failed to remove old ccache file [%s], " - "please remove it manually.\n", kr->old_ccname)); - } + store_ccname = kr->cc_be->ccache_for_princ(kr, kr->ccname, + kr->upn); + if (store_ccname == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("No ccache for %s in %s?\n", kr->upn, kr->ccname)); + ret = EIO; + goto done; + } + + ret = safe_remove_old_ccache_file(kr->cc_be, kr->upn, + kr->old_ccname, store_ccname); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + ("Failed to remove old ccache file [%s], " + "please remove it manually.\n", kr->old_ccname)); } ret = krb5_save_ccname(state, state->be_ctx->sysdb, - pd->user, kr->ccname); + pd->user, store_ccname); if (ret) { DEBUG(1, ("krb5_save_ccname failed.\n")); goto done; diff --git a/src/providers/krb5/krb5_auth.h b/src/providers/krb5/krb5_auth.h index 5cc22dfe8..cc079ba93 100644 --- a/src/providers/krb5/krb5_auth.h +++ b/src/providers/krb5/krb5_auth.h @@ -41,6 +41,7 @@ struct krb5child_req { struct pam_data *pd; struct krb5_ctx *krb5_ctx; + struct sss_krb5_cc_be *cc_be; const char *ccname; const char *old_ccname; const char *homedir; diff --git a/src/providers/krb5/krb5_become_user.c b/src/providers/krb5/krb5_become_user.c index 351f539a3..cc4e6a58a 100644 --- a/src/providers/krb5/krb5_become_user.c +++ b/src/providers/krb5/krb5_become_user.c @@ -31,7 +31,7 @@ errno_t become_user(uid_t uid, gid_t gid) { int ret; - DEBUG(9, ("Trying to become user [%d][%d].\n", uid, gid)); + DEBUG(SSSDBG_FUNC_DATA, ("Trying to become user [%d][%d].\n", uid, gid)); ret = setgid(gid); if (ret == -1) { DEBUG(1, ("setgid failed [%d][%s].\n", errno, strerror(errno))); diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c index 022745d61..91816662b 100644 --- a/src/providers/krb5/krb5_common.c +++ b/src/providers/krb5/krb5_common.c @@ -31,6 +31,7 @@ #include "providers/dp_backend.h" #include "providers/krb5/krb5_common.h" #include "providers/krb5/krb5_opts.h" +#include "providers/krb5/krb5_utils.h" errno_t check_and_export_lifetime(struct dp_option *opts, const int opt_id, const char *env_name) @@ -95,6 +96,7 @@ errno_t check_and_export_options(struct dp_option *opts, const char *dummy; char *use_fast_str; char *fast_principal; + enum sss_krb5_cc_type cc_be; realm = dp_opt_get_cstring(opts, KRB5_REALM); if (realm == NULL) { @@ -178,11 +180,15 @@ errno_t check_and_export_options(struct dp_option *opts, DEBUG(1, ("Missing credential cache name template.\n")); return EINVAL; } - if (dummy[0] != '/' && strncmp(dummy, "FILE:", 5) != 0) { - DEBUG(1, ("Currently only file based credential caches are supported " - "and krb5ccname_template must start with '/' or 'FILE:'\n")); + + cc_be = sss_krb5_get_type(dummy); + if (cc_be != SSS_KRB5_TYPE_FILE || dummy[0] != '/') { + DEBUG(SSSDBG_CONF_SETTINGS, + ("Currently only file based credential caches are supported " + "and krb5ccname_template must start with '/' or 'FILE:'\n")); return EINVAL; } + krb5_ctx->cc_be = &file_cc; return EOK; } diff --git a/src/providers/krb5/krb5_common.h b/src/providers/krb5/krb5_common.h index 950505f12..029ebf6ed 100644 --- a/src/providers/krb5/krb5_common.h +++ b/src/providers/krb5/krb5_common.h @@ -84,6 +84,7 @@ struct krb5_service { struct fo_service; struct deferred_auth_ctx; struct renew_tgt_ctx; +struct sss_krb5_cc_be; struct krb5_ctx { /* opts taken from kinit */ @@ -115,6 +116,7 @@ struct krb5_ctx { struct krb5_service *kpasswd_service; int child_debug_fd; + struct sss_krb5_cc_be *cc_be; pcre *illegal_path_re; struct deferred_auth_ctx *deferred_auth_ctx; @@ -171,4 +173,5 @@ errno_t remove_krb5_info_files(TALLOC_CTX *mem_ctx, const char *realm); errno_t krb5_get_simple_upn(TALLOC_CTX *mem_ctx, struct krb5_ctx *krb5_ctx, const char *username, const char **_upn); + #endif /* __KRB5_COMMON_H__ */ diff --git a/src/providers/krb5/krb5_utils.c b/src/providers/krb5/krb5_utils.c index 9d199e1f5..9f02fe332 100644 --- a/src/providers/krb5/krb5_utils.c +++ b/src/providers/krb5/krb5_utils.c @@ -26,6 +26,7 @@ #include "providers/krb5/krb5_utils.h" #include "providers/krb5/krb5_auth.h" +#include "src/util/find_uid.h" #include "util/util.h" char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr, @@ -307,38 +308,46 @@ done: return ret; } -errno_t create_ccache_dir(TALLOC_CTX *mem_ctx, const char *filename, - pcre *illegal_re, uid_t uid, gid_t gid, - bool private_path) +static errno_t +check_ccache_re(const char *filename, pcre *illegal_re) +{ + errno_t ret; + + ret = pcre_exec(illegal_re, NULL, filename, strlen(filename), + 0, 0, NULL, 0); + if (ret == 0) { + DEBUG(SSSDBG_OP_FAILURE, + ("Illegal pattern in ccache directory name [%s].\n", filename)); + return EINVAL; + } else if (ret == PCRE_ERROR_NOMATCH) { + DEBUG(SSSDBG_TRACE_LIBS, + ("Ccache directory name [%s] does not contain " + "illegal patterns.\n", filename)); + return EOK; + } + + DEBUG(SSSDBG_CRIT_FAILURE, ("pcre_exec failed [%d].\n", ret)); + return EFAULT; +} + +static errno_t +create_ccache_dir(const char *dirname, pcre *illegal_re, + uid_t uid, gid_t gid, bool private_path) { int ret = EFAULT; - char *dirname; - char *end; struct stat parent_stat; struct string_list *missing_parents = NULL; struct string_list *li = NULL; mode_t old_umask; mode_t new_dir_mode; - size_t offset = 0; TALLOC_CTX *tmp_ctx = NULL; - tmp_ctx = talloc_new(mem_ctx); + tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { DEBUG(1, ("talloc_new failed.\n")); return ENOMEM; } - if (strncmp(filename, "FILE:", 5) == 0) { - offset = 5; - } - - dirname = talloc_strdup(tmp_ctx, filename + offset); - if (dirname == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - ret = ENOMEM; - goto done; - } - if (*dirname != '/') { DEBUG(1, ("Only absolute paths are allowed, not [%s] .\n", dirname)); ret = EINVAL; @@ -346,31 +355,12 @@ errno_t create_ccache_dir(TALLOC_CTX *mem_ctx, const char *filename, } 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)); - ret = EINVAL; - goto done; - } 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)); - ret = EFAULT; + ret = check_ccache_re(dirname, illegal_re); + if (ret != EOK) { goto done; } } - end = strrchr(dirname, '/'); - if (end == NULL || end == dirname) { - DEBUG(1, ("Missing filename in [%s].\n", dirname)); - ret = EINVAL; - goto done; - } - *end = '\0'; - ret = find_ccdir_parent_data(tmp_ctx, dirname, &parent_stat, &missing_parents); if (ret != EOK) { @@ -527,3 +517,221 @@ done: return EOK; } + +/*======== ccache back end utilities ========*/ +struct sss_krb5_cc_be * +get_cc_be_ops(enum sss_krb5_cc_type type) +{ + struct sss_krb5_cc_be *be; + + switch (type) { + case SSS_KRB5_TYPE_FILE: + be = &file_cc; + break; + case SSS_KRB5_TYPE_UNKNOWN: + be = NULL; + break; + } + + return be; +} + +struct sss_krb5_cc_be * +get_cc_be_ops_ccache(const char *ccache) +{ + enum sss_krb5_cc_type type; + + type = sss_krb5_get_type(ccache); + return get_cc_be_ops(type); +} + +/*======== Operations on the FILE: back end ========*/ +errno_t +cc_file_create(const char *location, pcre *illegal_re, + uid_t uid, gid_t gid, bool private_path) +{ + const char *filename; + char *dirname; + char *end; + TALLOC_CTX *tmp_ctx = NULL; + errno_t ret; + + filename = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_FILE); + if (filename == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("Bad ccache type %s\n", location)); + return EINVAL; + } + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new failed.\n")); + return ENOMEM; + } + + dirname = talloc_strdup(tmp_ctx, filename); + if (dirname == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_strdup failed.\n")); + ret = ENOMEM; + goto done; + } + + end = strrchr(dirname, '/'); + if (end == NULL || end == dirname) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Missing filename in [%s].\n", dirname)); + ret = EINVAL; + goto done; + } + *end = '\0'; + + ret = create_ccache_dir(dirname, illegal_re, uid, gid, private_path); +done: + talloc_free(tmp_ctx); + return ret; +} + +static errno_t +cc_residual_is_used(uid_t uid, const char *ccname, + enum sss_krb5_cc_type type, bool *result) +{ + int ret; + struct stat stat_buf; + bool active; + + *result = false; + + if (ccname == NULL || *ccname == '\0') { + return EINVAL; + } + + ret = lstat(ccname, &stat_buf); + + if (ret == -1 && errno != ENOENT) { + ret = errno; + DEBUG(SSSDBG_OP_FAILURE, + ("stat failed [%d][%s].\n", ret, strerror(ret))); + return ret; + } else if (ret == EOK) { + if (stat_buf.st_uid != uid) { + DEBUG(SSSDBG_OP_FAILURE, + ("Cache file [%s] exists, but is owned by [%d] instead of " + "[%d].\n", ccname, stat_buf.st_uid, uid)); + return EINVAL; + } + + switch (type) { + case SSS_KRB5_TYPE_FILE: + ret = S_ISREG(stat_buf.st_mode); + break; + default: + DEBUG(SSSDBG_CRIT_FAILURE, ("Unsupported ccache type\n")); + return EINVAL; + } + + if (ret == 0) { + DEBUG(SSSDBG_OP_FAILURE, + ("Cache file [%s] exists, but is not the expected type\n", + ccname)); + return EINVAL; + } + } + + ret = check_if_uid_is_active(uid, &active); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("check_if_uid_is_active failed.\n")); + return ret; + } + + if (!active) { + DEBUG(SSSDBG_TRACE_FUNC, ("User [%d] is not active\n", uid)); + } else { + DEBUG(SSSDBG_TRACE_LIBS, + ("User [%d] is still active, reusing ccache [%s].\n", + uid, ccname)); + *result = true; + } + return EOK; +} + +errno_t +cc_file_check_existing(const char *location, uid_t uid, + const char *realm, const char *princ, + bool *_active, bool *_valid) +{ + errno_t ret; + bool active; + bool valid; + const char *filename; + + filename = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_FILE); + if (!filename) { + DEBUG(SSSDBG_CRIT_FAILURE, ("%s is not of type FILE:\n")); + return EINVAL; + } + + if (filename[0] != '/') { + DEBUG(SSSDBG_OP_FAILURE, ("Only absolute path names are allowed.\n")); + return EINVAL; + } + + ret = cc_residual_is_used(uid, filename, SSS_KRB5_TYPE_FILE, &active); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not check if ccache is active\n")); + return ret; + } + + ret = check_for_valid_tgt(location, realm, princ, &valid); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + ("Could not check if ccache contains a valid principal\n")); + return ret; + } + + *_active = active; + *_valid = valid; + return EOK; +} + +const char * +cc_file_cache_for_princ(TALLOC_CTX *mem_ctx, const char *location, + const char *princ) +{ + return talloc_strdup(mem_ctx, location); +} + +errno_t +cc_file_remove(const char *location) +{ + errno_t ret; + const char *filename; + + filename = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_FILE); + if (!filename) { + DEBUG(SSSDBG_CRIT_FAILURE, ("%s is not of type FILE:\n")); + return EINVAL; + } + + if (filename[0] != '/') { + DEBUG(SSSDBG_CRIT_FAILURE, + ("Ccache file name [%s] is not an absolute path.\n", filename)); + return EINVAL; + } + + errno = 0; + ret = unlink(filename); + if (ret == -1 && errno != ENOENT) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + ("unlink [%s] failed [%d][%s].\n", filename, ret, + strerror(ret))); + return ret; + } + return EOK; +} + +struct sss_krb5_cc_be file_cc = { + .type = SSS_KRB5_TYPE_FILE, + .create = cc_file_create, + .check_existing = cc_file_check_existing, + .ccache_for_princ = cc_file_cache_for_princ, + .remove = cc_file_remove, +}; diff --git a/src/providers/krb5/krb5_utils.h b/src/providers/krb5/krb5_utils.h index 7cc57d42f..87bba2bae 100644 --- a/src/providers/krb5/krb5_utils.h +++ b/src/providers/krb5/krb5_utils.h @@ -31,16 +31,41 @@ #include "providers/krb5/krb5_auth.h" #include "providers/data_provider.h" +/* Operations on a credential cache */ +typedef errno_t (*cc_be_create_fn)(const char *location, pcre *illegal_re, + uid_t uid, gid_t gid, bool private_path); +typedef errno_t (*cc_be_check_existing)(const char *location, uid_t uid, + const char *realm, const char *princ, + bool *active, bool *valid); +typedef const char * (*cc_be_ccache_for_princ)(TALLOC_CTX *mem_ctx, + const char *location, + const char *princ); +typedef errno_t (*cc_be_remove)(const char *location); + +/* A ccache back end */ +struct sss_krb5_cc_be { + enum sss_krb5_cc_type type; + + cc_be_create_fn create; + cc_be_check_existing check_existing; + cc_be_ccache_for_princ ccache_for_princ; + cc_be_remove remove; +}; + +struct sss_krb5_cc_be file_cc; + +errno_t cc_file_create(const char *filename, pcre *illegal_re, + uid_t uid, gid_t gid, bool private_path); + +struct sss_krb5_cc_be *get_cc_be_ops(enum sss_krb5_cc_type type); +struct sss_krb5_cc_be *get_cc_be_ops_ccache(const char *ccache); + char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr, const char *template, bool file_mode, bool case_sensitive, bool *private_path); errno_t become_user(uid_t uid, gid_t gid); -errno_t create_ccache_dir(TALLOC_CTX *mem_ctx, const char *filename, - pcre *illegal_re, uid_t uid, gid_t gid, - bool private_path); - errno_t get_ccache_file_data(const char *ccache_file, const char *client_name, struct tgt_times *tgtt); #endif /* __KRB5_UTILS_H__ */ diff --git a/src/tests/krb5_child-test.c b/src/tests/krb5_child-test.c index 4dde996a0..2ca655310 100644 --- a/src/tests/krb5_child-test.c +++ b/src/tests/krb5_child-test.c @@ -39,6 +39,7 @@ #include "providers/krb5/krb5_utils.h" extern struct dp_option default_krb5_opts[]; +extern struct sss_krb5_cc_be file_cc; static krb5_context krb5_error_ctx; #define KRB5_DEBUG(level, krb5_error) do { \ @@ -118,6 +119,8 @@ create_dummy_krb5_ctx(TALLOC_CTX *mem_ctx, const char *realm) krb5_ctx = talloc_zero(mem_ctx, struct krb5_ctx); if (!krb5_ctx) return NULL; + krb5_ctx->cc_be = &file_cc; + krb5_ctx->illegal_path_re = pcre_compile2(ILLEGAL_PATH_PATTERN, 0, &errval, &errstr, &errpos, NULL); if (krb5_ctx->illegal_path_re == NULL) { @@ -250,14 +253,16 @@ create_dummy_req(TALLOC_CTX *mem_ctx, const char *user, DEBUG(SSSDBG_FUNC_DATA, ("ccname [%s] uid [%llu] gid [%llu]\n", kr->ccname, kr->uid, kr->gid)); - ret = create_ccache_dir(kr, kr->ccname, - kr->krb5_ctx->illegal_path_re, - kr->uid, kr->gid, private); + ret = kr->krb5_ctx->cc_be->create(kr->ccname, + kr->krb5_ctx->illegal_path_re, + kr->uid, kr->gid, private); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("create_ccache_dir failed.\n")); - goto fail; } + } else { + kr->ccname = talloc_strdup(kr, ccname); } + if (!kr->ccname) goto fail; return kr; @@ -375,29 +380,6 @@ done: return ret; } -static void -remove_ccache(const char *cc) -{ - size_t offset = 0; - errno_t ret; - - if (strncmp(cc, "FILE:", 5) == 0) { - offset = 5; - } - if (cc[offset] != '/') { - DEBUG(SSSDBG_FATAL_FAILURE, - ("ccname [%s] does not contain absolute path?\n", cc)); - } - - errno = 0; - ret = unlink(cc+offset); - if (ret == -1) { - ret = errno; - DEBUG(SSSDBG_FATAL_FAILURE, - ("unlink [%s] failed [%d]: %s\n", cc, ret, strerror(ret))); - } -} - int main(int argc, const char *argv[]) { @@ -542,7 +524,7 @@ main(int argc, const char *argv[]) ret = 0; done: if (rm_ccache && ctx->res && ctx->res->ccname) { - remove_ccache(ctx->res->ccname); + ctx->kr->krb5_ctx->cc_be->remove(ctx->res->ccname); } free(password); talloc_free(ctx); diff --git a/src/tests/krb5_utils-tests.c b/src/tests/krb5_utils-tests.c index aacc384de..4a572488f 100644 --- a/src/tests/krb5_utils-tests.c +++ b/src/tests/krb5_utils-tests.c @@ -117,14 +117,14 @@ START_TEST(test_pub_ccache_dir) ret = chmod(testpath, 0754); fail_unless(ret == EOK, "chmod failed."); - ret = create_ccache_dir(tmp_ctx, filename, NULL, 12345, 12345, false); - fail_unless(ret == EINVAL, "create_ccache_dir does not return EINVAL " + ret = cc_file_create(filename, NULL, 12345, 12345, false); + fail_unless(ret == EINVAL, "cc_file_create does not return EINVAL " "while x-bit is missing."); ret = chmod(testpath, 0755); fail_unless(ret == EOK, "chmod failed."); - ret = create_ccache_dir(tmp_ctx, filename, NULL, 12345, 12345, false); - fail_unless(ret == EOK, "create_ccache_dir failed."); + ret = cc_file_create(filename, NULL, 12345, 12345, false); + fail_unless(ret == EOK, "cc_file_create failed."); check_dir(subdirname, 0, 0, 01777); RMDIR(subdirname); @@ -158,7 +158,7 @@ START_TEST(test_pub_ccache_dir_in_user_dir) filename = talloc_asprintf(tmp_ctx, "%s/ccfile", subdirname); fail_unless(filename != NULL, "talloc_asprintf failed."); - ret = create_ccache_dir(tmp_ctx, filename, NULL, 12345, 12345, false); + ret = cc_file_create(filename, NULL, 12345, 12345, false); fail_unless(ret == EINVAL, "Creating public ccache dir in user dir " "does not failed with EINVAL."); @@ -193,14 +193,14 @@ START_TEST(test_priv_ccache_dir) ret = chmod(testpath, 0754); fail_unless(ret == EOK, "chmod failed."); - ret = create_ccache_dir(tmp_ctx, filename, NULL, uid, gid, true); - fail_unless(ret == EINVAL, "create_ccache_dir does not return EINVAL " + ret = cc_file_create(filename, NULL, uid, gid, true); + fail_unless(ret == EINVAL, "cc_file_create does not return EINVAL " "while x-bit is missing."); ret = chmod(testpath, 0755); fail_unless(ret == EOK, "chmod failed."); - ret = create_ccache_dir(tmp_ctx, filename, NULL, uid, gid, true); - fail_unless(ret == EOK, "create_ccache_dir failed."); + ret = cc_file_create(filename, NULL, uid, gid, true); + fail_unless(ret == EOK, "cc_file_create failed."); check_dir(subdir, uid, gid, 0700); RMDIR(subdir); @@ -248,14 +248,14 @@ START_TEST(test_private_ccache_dir_in_user_dir) ret = chmod(user_dir, 0600); fail_unless(ret == EOK, "chmod failed."); - ret = create_ccache_dir(tmp_ctx, filename, NULL, uid, gid, true); - fail_unless(ret == EINVAL, "create_ccache_dir does not return EINVAL " + ret = cc_file_create(filename, NULL, uid, gid, true); + fail_unless(ret == EINVAL, "cc_file_create does not return EINVAL " "while x-bit is missing."); ret = chmod(user_dir, 0700); fail_unless(ret == EOK, "chmod failed."); - ret = create_ccache_dir(tmp_ctx, filename, NULL, uid, gid, true); - fail_unless(ret == EOK, "create_ccache_dir failed."); + ret = cc_file_create(filename, NULL, uid, gid, true); + fail_unless(ret == EOK, "cc_file_create failed."); check_dir(dn3, uid, gid, 0700); RMDIR(dn3); @@ -292,7 +292,7 @@ START_TEST(test_private_ccache_dir_in_wrong_user_dir) filename = talloc_asprintf(tmp_ctx, "%s/ccfile", subdirname); fail_unless(filename != NULL, "talloc_asprintf failed."); - ret = create_ccache_dir(tmp_ctx, filename, NULL, 12345, 12345, true); + ret = cc_file_create(filename, NULL, 12345, 12345, true); fail_unless(ret == EINVAL, "Creating private ccache dir in wrong user " "dir does not failed with EINVAL."); @@ -329,28 +329,28 @@ START_TEST(test_illegal_patterns) 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, true); - fail_unless(ret == EINVAL, "create_ccache_dir allowed relative path [%s].", + ret = cc_file_create(filename, illegal_re, uid, gid, true); + fail_unless(ret == EINVAL, "cc_file_create 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, true); - fail_unless(ret == EINVAL, "create_ccache_dir allowed " + ret = cc_file_create(filename, illegal_re, uid, gid, true); + fail_unless(ret == EINVAL, "cc_file_create 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, true); - fail_unless(ret == EINVAL, "create_ccache_dir allowed " + ret = cc_file_create(filename, illegal_re, uid, gid, true); + fail_unless(ret == EINVAL, "cc_file_create 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, true); - fail_unless(ret == EINVAL, "create_ccache_dir allowed " + ret = cc_file_create(filename, illegal_re, uid, gid, true); + fail_unless(ret == EINVAL, "cc_file_create allowed " "illegal pattern '//' in filename [%s].", filename); -- cgit