summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/providers/krb5/krb5_auth.c30
-rw-r--r--src/providers/krb5/krb5_utils.c423
-rw-r--r--src/providers/krb5/krb5_utils.h6
3 files changed, 88 insertions, 371 deletions
diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
index ca00ce7a..1ea179be 100644
--- a/src/providers/krb5/krb5_auth.c
+++ b/src/providers/krb5/krb5_auth.c
@@ -59,27 +59,25 @@ 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;
- /* 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;
- }
+ *active = false;
+ *valid = false;
- ret = old_cc_ops->check_existing(old_ccache, kr->uid, realm, kr->upn,
- valid);
- if (ret == ENOENT) {
+ ret = sss_krb5_cc_verify_ccache(old_ccache,
+ kr->uid, kr->gid,
+ realm, kr->upn);
+ switch (ret) {
+ case ERR_NOT_FOUND:
DEBUG(SSSDBG_TRACE_FUNC,
("Saved ccache %s doesn't exist.\n", old_ccache));
- return ret;
- }
- if (ret != EOK) {
+ return ENOENT;
+ case EINVAL:
+ /* cache found but no tgt or expired */
+ case EOK:
+ *valid = true;
+ break;
+ default:
DEBUG(SSSDBG_OP_FAILURE,
("Cannot check if saved ccache %s is valid\n",
old_ccache));
diff --git a/src/providers/krb5/krb5_utils.c b/src/providers/krb5/krb5_utils.c
index 463a5eb4..c4849e74 100644
--- a/src/providers/krb5/krb5_utils.c
+++ b/src/providers/krb5/krb5_utils.c
@@ -761,136 +761,6 @@ done:
return ret;
}
-static krb5_error_code check_for_valid_tgt(krb5_context context,
- krb5_ccache ccache,
- const char *realm,
- const char *client_princ_str,
- bool *result)
-{
- krb5_error_code krberr;
- TALLOC_CTX *tmp_ctx = NULL;
- krb5_creds mcred;
- krb5_creds cred;
- char *server_name = NULL;
- krb5_principal client_principal = NULL;
- krb5_principal server_principal = NULL;
-
- *result = false;
-
- tmp_ctx = talloc_new(NULL);
- if (tmp_ctx == NULL) {
- DEBUG(1, ("talloc_new failed.\n"));
- return ENOMEM;
- }
-
- server_name = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s", realm, realm);
- if (server_name == NULL) {
- DEBUG(1, ("talloc_asprintf failed.\n"));
- krberr = ENOMEM;
- goto done;
- }
-
- krberr = krb5_parse_name(context, server_name, &server_principal);
- if (krberr != 0) {
- DEBUG(1, ("krb5_parse_name failed.\n"));
- goto done;
- }
-
- krberr = krb5_parse_name(context, client_princ_str, &client_principal);
- if (krberr != 0) {
- DEBUG(1, ("krb5_parse_name failed.\n"));
- goto done;
- }
-
- memset(&mcred, 0, sizeof(mcred));
- memset(&cred, 0, sizeof(mcred));
- mcred.client = client_principal;
- mcred.server = server_principal;
-
- krberr = krb5_cc_retrieve_cred(context, ccache, 0, &mcred, &cred);
- if (krberr != 0) {
- DEBUG(1, ("krb5_cc_retrieve_cred failed.\n"));
- krberr = 0;
- goto done;
- }
-
- DEBUG(7, ("TGT end time [%d].\n", cred.times.endtime));
-
- if (cred.times.endtime > time(NULL)) {
- DEBUG(3, ("TGT is valid.\n"));
- *result = true;
- }
- krb5_free_cred_contents(context, &cred);
-
- krberr = 0;
-
-done:
- if (client_principal != NULL) {
- krb5_free_principal(context, client_principal);
- }
- if (server_principal != NULL) {
- krb5_free_principal(context, server_principal);
- }
- talloc_free(tmp_ctx);
- return krberr;
-}
-
-static errno_t
-check_cc_validity(const char *location,
- const char *realm,
- const char *princ,
- bool *_valid)
-{
- errno_t ret;
- bool valid = false;
- krb5_ccache ccache = NULL;
- krb5_context context = NULL;
- krb5_error_code krberr;
-
- krberr = krb5_init_context(&context);
- if (krberr) {
- DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to init kerberos context\n"));
- return EIO;
- }
-
- krberr = krb5_cc_resolve(context, location, &ccache);
- if (krberr == KRB5_FCC_NOFILE || ccache == NULL) {
- /* KRB5_FCC_NOFILE would be returned if the directory components
- * of the DIR cache do not exist, which is the case in /run
- * after a reboot
- */
- DEBUG(SSSDBG_TRACE_FUNC,
- ("ccache %s is missing or empty\n", location));
- valid = false;
- ret = EOK;
- goto done;
- } else if (krberr != 0) {
- KRB5_DEBUG(SSSDBG_OP_FAILURE, context, krberr);
- DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_cc_resolve failed.\n"));
- ret = EIO;
- goto done;
- }
-
- krberr = check_for_valid_tgt(context, ccache, realm, princ, &valid);
- if (krberr != EOK) {
- KRB5_DEBUG(SSSDBG_OP_FAILURE, context, krberr);
- DEBUG(SSSDBG_CRIT_FAILURE,
- ("Could not check if ccache contains a valid principal\n"));
- ret = EIO;
- goto done;
- }
-
- ret = EOK;
-
-done:
- if (ret == EOK) {
- *_valid = valid;
- }
- if (ccache) krb5_cc_close(context, ccache);
- krb5_free_context(context);
- return ret;
-}
-
struct sss_krb5_ccache {
struct sss_creds *creds;
@@ -1085,6 +955,78 @@ done:
return ret;
}
+errno_t sss_krb5_cc_verify_ccache(const char *ccname, uid_t uid, gid_t gid,
+ const char *realm, const char *principal)
+{
+ struct sss_krb5_ccache *cc = NULL;
+ TALLOC_CTX *tmp_ctx = NULL;
+ krb5_principal tgt_princ = NULL;
+ krb5_principal princ = NULL;
+ char *tgt_name;
+ krb5_creds mcred = { 0 };
+ krb5_creds cred = { 0 };
+ krb5_error_code kerr;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new failed.\n"));
+ return ENOMEM;
+ }
+
+ ret = sss_open_ccache_as_user(tmp_ctx, ccname, uid, gid, &cc);
+ if (ret) {
+ goto done;
+ }
+
+ tgt_name = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s", realm, realm);
+ if (!tgt_name) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new failed.\n"));
+ ret = ENOMEM;
+ goto done;
+ }
+
+ kerr = krb5_parse_name(cc->context, tgt_name, &tgt_princ);
+ if (kerr) {
+ KRB5_DEBUG(SSSDBG_CRIT_FAILURE, cc->context, kerr);
+ if (kerr == KRB5_PARSE_MALFORMED) ret = EINVAL;
+ else ret = ERR_INTERNAL;
+ goto done;
+ }
+
+ kerr = krb5_parse_name(cc->context, principal, &princ);
+ if (kerr) {
+ KRB5_DEBUG(SSSDBG_CRIT_FAILURE, cc->context, kerr);
+ if (kerr == KRB5_PARSE_MALFORMED) ret = EINVAL;
+ else ret = ERR_INTERNAL;
+ goto done;
+ }
+
+ mcred.client = princ;
+ mcred.server = tgt_princ;
+ mcred.times.endtime = time(NULL);
+
+ kerr = krb5_cc_retrieve_cred(cc->context, cc->ccache,
+ KRB5_TC_MATCH_TIMES, &mcred, &cred);
+ if (kerr) {
+ if (kerr == KRB5_CC_NOTFOUND) {
+ DEBUG(SSSDBG_TRACE_INTERNAL, ("TGT not found or expired.\n"));
+ ret = EINVAL;
+ } else {
+ KRB5_DEBUG(SSSDBG_CRIT_FAILURE, cc->context, kerr);
+ ret = ERR_INTERNAL;
+ }
+ }
+ krb5_free_cred_contents(cc->context, &cred);
+
+done:
+ if (tgt_princ) krb5_free_principal(cc->context, tgt_princ);
+ if (princ) krb5_free_principal(cc->context, princ);
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+
/*======== ccache back end utilities ========*/
struct sss_krb5_cc_be *
get_cc_be_ops(enum sss_krb5_cc_type type)
@@ -1139,105 +1081,9 @@ cc_file_create(const char *location, pcre *illegal_re,
return create_ccache_dir_head(filename, illegal_re, uid, gid, private_path);
}
-static errno_t
-cc_residual_exists(uid_t uid, const char *ccname,
- enum sss_krb5_cc_type type)
-{
- int ret;
- struct stat stat_buf;
-
- if (ccname == NULL || *ccname == '\0') {
- return EINVAL;
- }
-
- ret = lstat(ccname, &stat_buf);
-
- if (ret == -1) {
- ret = errno;
- if (ret == ENOENT) {
- DEBUG(SSSDBG_FUNC_DATA, ("Cache file [%s] does not exist, "
- "it will be recreated\n", ccname));
- return ENOENT;
- }
-
- DEBUG(SSSDBG_OP_FAILURE,
- ("stat failed [%d][%s].\n", ret, strerror(ret)));
- return ret;
- }
-
- 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) {
-#ifdef HAVE_KRB5_CC_COLLECTION
- case SSS_KRB5_TYPE_DIR:
- ret = S_ISDIR(stat_buf.st_mode);
- break;
-#endif /* HAVE_KRB5_CC_COLLECTION */
- 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;
- }
-
- return EOK;
-}
-
-errno_t
-cc_file_check_existing(const char *location, uid_t uid,
- const char *realm, const char *princ,
- bool *_valid)
-{
- errno_t ret;
- 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", location));
- return EINVAL;
- }
-
- if (filename[0] != '/') {
- DEBUG(SSSDBG_OP_FAILURE, ("Only absolute path names are allowed.\n"));
- return EINVAL;
- }
-
- ret = cc_residual_exists(uid, filename, SSS_KRB5_TYPE_FILE);
- if (ret != EOK) {
- if (ret != ENOENT) {
- DEBUG(SSSDBG_OP_FAILURE,
- ("Could not check if ccache is active.\n"));
- }
- return ret;
- }
-
- ret = check_cc_validity(location, realm, princ, &valid);
- if (ret != EOK) {
- return ret;
- }
-
- *_valid = valid;
- return EOK;
-}
-
struct sss_krb5_cc_be file_cc = {
.type = SSS_KRB5_TYPE_FILE,
.create = cc_file_create,
- .check_existing = cc_file_check_existing,
};
#ifdef HAVE_KRB5_CC_COLLECTION
@@ -1257,107 +1103,9 @@ cc_dir_create(const char *location, pcre *illegal_re,
return create_ccache_dir_head(dir_name, illegal_re, uid, gid, private_path);
}
-errno_t
-cc_dir_check_existing(const char *location, uid_t uid,
- const char *realm, const char *princ,
- bool *_valid)
-{
- bool valid;
- enum sss_krb5_cc_type type;
- const char *filename;
- const char *dir;
- char *tmp;
- char *primary_file;
- errno_t ret;
- TALLOC_CTX *tmp_ctx;
-
- type = sss_krb5_get_type(location);
- if (type != SSS_KRB5_TYPE_DIR) {
- DEBUG(SSSDBG_CRIT_FAILURE, ("%s is not of type DIR:\n", location));
- return EINVAL;
- }
-
- filename = sss_krb5_cc_file_path(location);
- if (!filename) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- ("Existing ccname does not contain path into the collection"));
- return EINVAL;
- }
-
- if (filename[0] != '/') {
- DEBUG(SSSDBG_CRIT_FAILURE,
- ("Only absolute path names are allowed.\n"));
- return EINVAL;
- }
-
- tmp_ctx = talloc_new(NULL);
- if (tmp_ctx == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, ("talloc_new failed.\n"));
- return ENOMEM;
- }
-
- tmp = talloc_strdup(tmp_ctx, filename);
- if (!tmp) {
- DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_strdup failed.\n"));
- ret = ENOMEM;
- goto done;
- }
-
- if (0 == strncmp(location, "DIR::", 5)) {
- dir = dirname(tmp);
- if (!dir) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- ("Cannot get base directory of %s.\n", tmp));
- ret = EINVAL;
- goto done;
- }
- } else {
- dir = tmp;
- }
-
- ret = cc_residual_exists(uid, dir, SSS_KRB5_TYPE_DIR);
- if (ret != EOK) {
- if (ret != ENOENT) {
- DEBUG(SSSDBG_OP_FAILURE,
- ("Could not check if ccache is active.\n"));
- }
- goto done;
- }
-
- /* If primary file isn't in ccache dir, we will ignore it.
- * But if primary file has wrong permissions, we will fail.
- */
- primary_file = talloc_asprintf(tmp_ctx, "%s/primary", dir);
- if (!primary_file) {
- DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_asprintf failed.\n"));
- ret = ENOMEM;
- goto done;
- }
- ret = cc_residual_exists(uid, primary_file, SSS_KRB5_TYPE_FILE);
- if (ret != EOK && ret != ENOENT) {
- DEBUG(SSSDBG_OP_FAILURE,
- ("Could not check if file 'primary' [%s] in dir ccache"
- " is active.\n", primary_file));
- goto done;
- }
-
- ret = check_cc_validity(location, realm, princ, &valid);
- if (ret != EOK) {
- goto done;
- }
-
- *_valid = valid;
- ret = EOK;
-
-done:
- talloc_free(tmp_ctx);
- return ret;
-}
-
struct sss_krb5_cc_be dir_cc = {
.type = SSS_KRB5_TYPE_DIR,
.create = cc_dir_create,
- .check_existing = cc_dir_check_existing,
};
@@ -1381,36 +1129,9 @@ cc_keyring_create(const char *location, pcre *illegal_re,
return EOK;
}
-errno_t
-cc_keyring_check_existing(const char *location, uid_t uid,
- const char *realm, const char *princ,
- bool *_valid)
-{
- errno_t ret;
- bool valid;
- const char *residual;
-
- residual = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_KEYRING);
- if (!residual) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- ("%s is not of type KEYRING:\n", location));
- return EINVAL;
- }
-
- /* Check if any user is actively using this cache */
- ret = check_cc_validity(location, realm, princ, &valid);
- if (ret != EOK) {
- return ret;
- }
-
- *_valid = valid;
- return EOK;
-}
-
struct sss_krb5_cc_be keyring_cc = {
.type = SSS_KRB5_TYPE_KEYRING,
.create = cc_keyring_create,
- .check_existing = cc_keyring_check_existing,
};
#endif /* HAVE_KRB5_CC_COLLECTION */
diff --git a/src/providers/krb5/krb5_utils.h b/src/providers/krb5/krb5_utils.h
index e2416662..b364f87a 100644
--- a/src/providers/krb5/krb5_utils.h
+++ b/src/providers/krb5/krb5_utils.h
@@ -45,16 +45,12 @@ errno_t check_if_cached_upn_needs_update(struct sysdb_ctx *sysdb,
/* 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 *valid);
/* 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;
};
extern struct sss_krb5_cc_be file_cc;
@@ -83,6 +79,8 @@ errno_t restore_creds(struct sss_creds *saved_creds);
errno_t sss_krb5_cc_destroy(const char *ccname, uid_t uid, gid_t gid);
errno_t sss_krb5_check_ccache_princ(uid_t uid, gid_t gid,
const char *ccname, const char *principal);
+errno_t sss_krb5_cc_verify_ccache(const char *ccname, uid_t uid, gid_t gid,
+ const char *realm, const char *principal);
errno_t get_ccache_file_data(const char *ccache_file, const char *client_name,
struct tgt_times *tgtt);