summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakub Hrozek <jhrozek@redhat.com>2012-05-17 18:06:34 +0200
committerStephen Gallagher <sgallagh@redhat.com>2012-06-14 15:52:29 -0400
commitfd8595874aa06c8057740001ec465ba76b4af142 (patch)
tree34432d6fea33da9f25512da487cdbf9fc2b95f53
parent7b9f1e13c750fed76886513071a2b63949181ea4 (diff)
downloadsssd-fd8595874aa06c8057740001ec465ba76b4af142.tar.gz
sssd-fd8595874aa06c8057740001ec465ba76b4af142.tar.xz
sssd-fd8595874aa06c8057740001ec465ba76b4af142.zip
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.
-rw-r--r--Makefile.am3
-rw-r--r--src/providers/krb5/krb5_auth.c193
-rw-r--r--src/providers/krb5/krb5_auth.h1
-rw-r--r--src/providers/krb5/krb5_become_user.c2
-rw-r--r--src/providers/krb5/krb5_common.c12
-rw-r--r--src/providers/krb5/krb5_common.h3
-rw-r--r--src/providers/krb5/krb5_utils.c286
-rw-r--r--src/providers/krb5/krb5_utils.h33
-rw-r--r--src/tests/krb5_child-test.c38
-rw-r--r--src/tests/krb5_utils-tests.c44
10 files changed, 417 insertions, 198 deletions
diff --git a/Makefile.am b/Makefile.am
index 7bdc5930f..c5bde0712 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -758,6 +758,7 @@ krb5_utils_tests_SOURCES = \
src/providers/krb5/krb5_utils.c \
src/providers/krb5/krb5_common.c \
src/util/sss_krb5.c \
+ src/util/find_uid.c \
src/providers/data_provider_fo.c \
src/providers/data_provider_opts.c \
src/providers/data_provider_callbacks.c \
@@ -980,6 +981,7 @@ krb5_child_test_SOURCES = \
src/providers/krb5/krb5_become_user.c \
src/providers/krb5/krb5_common.c \
src/util/sss_krb5.c \
+ src/util/find_uid.c \
src/providers/data_provider_fo.c \
src/providers/data_provider_opts.c \
src/providers/data_provider_callbacks.c \
@@ -1159,6 +1161,7 @@ libsss_ldap_la_SOURCES = \
src/util/find_uid.c \
src/providers/ldap/ldap_init.c \
src/providers/krb5/krb5_common.c \
+ src/providers/krb5/krb5_utils.c \
src/util/user_info_msg.c \
src/util/sss_ldap.c \
src/util/sss_krb5.c
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);