diff options
-rw-r--r-- | src/providers/krb5/krb5_renew_tgt.c | 138 | ||||
-rw-r--r-- | src/providers/krb5/krb5_utils.c | 100 | ||||
-rw-r--r-- | src/providers/krb5/krb5_utils.h | 3 |
3 files changed, 241 insertions, 0 deletions
diff --git a/src/providers/krb5/krb5_renew_tgt.c b/src/providers/krb5/krb5_renew_tgt.c index 915def83b..cf50666ff 100644 --- a/src/providers/krb5/krb5_renew_tgt.c +++ b/src/providers/krb5/krb5_renew_tgt.c @@ -26,6 +26,7 @@ #include "util/util.h" #include "providers/krb5/krb5_common.h" #include "providers/krb5/krb5_auth.h" +#include "providers/krb5/krb5_utils.h" #define INITIAL_TGT_TABLE_SIZE 10 @@ -299,6 +300,139 @@ static void renew_del_cb(hash_entry_t *entry, hash_destroy_enum type, void *pvt) DEBUG(1, ("Unexpected value type [%d].\n", entry->value.type)); } +static errno_t check_ccache_file(struct renew_tgt_ctx *renew_tgt_ctx, + const char *ccache_file, const char *upn, + const char *user_name) +{ + int ret; + struct stat stat_buf; + struct tgt_times tgtt; + struct pam_data pd; + time_t now; + const char *filename; + + if (ccache_file == NULL || upn == NULL || user_name == NULL) { + DEBUG(6, ("Missing one of the needed attributes: [%s][%s][%s].\n", + ccache_file == NULL ? "cache file missing" : ccache_file, + upn == NULL ? "principal missing" : upn, + user_name == NULL ? "user name missing" : user_name)); + return EINVAL; + } + + if (strncmp(ccache_file, "FILE:", 5) == 0) { + filename = ccache_file + 5; + } else { + filename = ccache_file; + } + + ret = stat(filename, &stat_buf); + if (ret != EOK) { + if (ret == ENOENT) { + return EOK; + } + return ret; + } + + DEBUG(9, ("Found ccache file [%s].\n", ccache_file)); + + memset(&tgtt, 0, sizeof(tgtt)); + ret = get_ccache_file_data(ccache_file, upn, &tgtt); + if (ret != EOK) { + DEBUG(1, ("get_ccache_file_data failed.\n")); + return ret; + } + + memset(&pd, 0, sizeof(pd)); + pd.cmd = SSS_CMD_RENEW; + pd.user = discard_const_p(char, user_name); + now = time(NULL); + if (tgtt.renew_till > tgtt.endtime && tgtt.renew_till > now && + tgtt.endtime > now) { + DEBUG(7, ("Adding [%s] for automatic renewal.\n", ccache_file)); + ret = add_tgt_to_renew_table(renew_tgt_ctx->krb5_ctx, ccache_file, + &tgtt, &pd, upn); + if (ret != EOK) { + DEBUG(1, ("add_tgt_to_renew_table failed, " + "automatic renewal not possible.\n")); + } + } else { + DEBUG(9, ("TGT in [%s] for [%s] is too old.\n", ccache_file, upn)); + } + + return EOK; +} + +static errno_t check_ccache_files(struct renew_tgt_ctx *renew_tgt_ctx) +{ + TALLOC_CTX *tmp_ctx; + int ret; + const char *ccache_filter = "("SYSDB_CCACHE_FILE"=*)"; + const char *ccache_attrs[] = { SYSDB_CCACHE_FILE, SYSDB_UPN, SYSDB_NAME, + NULL }; + size_t msgs_count = 0; + struct ldb_message **msgs = NULL; + size_t c; + const char *ccache_file; + const char *upn; + const char *user_name; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(1, ("talloc_new failed.\n")); + return ENOMEM; + } + + ret = sysdb_search_users(tmp_ctx, renew_tgt_ctx->be_ctx->sysdb, + renew_tgt_ctx->be_ctx->domain, ccache_filter, + ccache_attrs, &msgs_count, &msgs); + if (ret != EOK) { + DEBUG(1, ("sysdb_search_users failed.\n")); + goto done; + } + + if (msgs_count == 0) { + DEBUG(9, ("No entries with ccache file found in cache.\n")); + ret = EOK; + goto done; + } + DEBUG(9, ("Found [%d] entries with ccache file in cache.\n", msgs_count)); + + for (c = 0; c < msgs_count; c++) { + user_name = ldb_msg_find_attr_as_string(msgs[c], SYSDB_NAME, NULL); + if (user_name == NULL) { + DEBUG(1, ("No user name found, this is a severe error, " + "but we ignore it here.\n")); + continue; + } + + upn = ldb_msg_find_attr_as_string(msgs[c], SYSDB_UPN, NULL); + if (upn == NULL) { + ret = krb5_get_simple_upn(tmp_ctx, renew_tgt_ctx->krb5_ctx, + user_name, &upn); + if (ret != EOK) { + DEBUG(1, ("krb5_get_simple_upn failed.\n")); + continue; + } + DEBUG(9, ("No upn stored in cache, using [%s].\n", upn)); + } + + ccache_file = ldb_msg_find_attr_as_string(msgs[c], SYSDB_CCACHE_FILE, + NULL); + + ret = check_ccache_file(renew_tgt_ctx, ccache_file, upn, user_name); + if (ret != EOK) { + DEBUG(5, ("Failed to check ccache file [%s].\n", ccache_file)); + } + } + + ret = EOK; + +done: + talloc_free(tmp_ctx); + + return ret; +} + errno_t init_renew_tgt(struct krb5_ctx *krb5_ctx, struct be_ctx *be_ctx, struct tevent_context *ev, time_t renew_intv) { @@ -325,6 +459,10 @@ errno_t init_renew_tgt(struct krb5_ctx *krb5_ctx, struct be_ctx *be_ctx, krb5_ctx->renew_tgt_ctx->timer_interval = renew_intv; krb5_ctx->renew_tgt_ctx->added_to_online_callbacks = false; + ret = check_ccache_files(krb5_ctx->renew_tgt_ctx); + if (ret != EOK) { + DEBUG(1, ("Failed to read ccache files, continuing ...\n")); + } next = tevent_timeval_current_ofs(krb5_ctx->renew_tgt_ctx->timer_interval, 0); diff --git a/src/providers/krb5/krb5_utils.c b/src/providers/krb5/krb5_utils.c index d3aa437eb..adb482286 100644 --- a/src/providers/krb5/krb5_utils.c +++ b/src/providers/krb5/krb5_utils.c @@ -396,3 +396,103 @@ done: talloc_free(tmp_ctx); return ret; } + +errno_t get_ccache_file_data(const char *ccache_file, const char *client_name, + struct tgt_times *tgtt) +{ + krb5_error_code kerr; + krb5_context ctx = NULL; + krb5_ccache cc = NULL; + krb5_principal client_princ = NULL; + krb5_principal server_princ = NULL; + char *server_name; + krb5_creds mcred; + krb5_creds cred; + + kerr = krb5_init_context(&ctx); + if (kerr != 0) { + DEBUG(1, ("krb5_init_context failed.\n")); + goto done; + } + + kerr = krb5_parse_name(ctx, client_name, &client_princ); + if (kerr != 0) { + DEBUG(1, ("krb5_parse_name failed.\n")); + goto done; + } + + server_name = talloc_asprintf(NULL, "krbtgt/%.*s@%.*s", + krb5_princ_realm(ctx, client_princ)->length, + krb5_princ_realm(ctx, client_princ)->data, + krb5_princ_realm(ctx, client_princ)->length, + krb5_princ_realm(ctx, client_princ)->data); + if (server_name == NULL) { + kerr = KRB5_CC_NOMEM; + DEBUG(1, ("talloc_asprintf failed.\n")); + goto done; + } + + kerr = krb5_parse_name(ctx, server_name, &server_princ); + talloc_free(server_name); + if (kerr != 0) { + DEBUG(1, ("krb5_parse_name failed.\n")); + goto done; + } + + kerr = krb5_cc_resolve(ctx, ccache_file, &cc); + if (kerr != 0) { + DEBUG(1, ("krb5_cc_resolve failed.\n")); + goto done; + } + + memset(&mcred, 0, sizeof(mcred)); + memset(&cred, 0, sizeof(mcred)); + + mcred.server = server_princ; + mcred.client = client_princ; + + kerr = krb5_cc_retrieve_cred(ctx, cc, 0, &mcred, &cred); + if (kerr != 0) { + DEBUG(1, ("krb5_cc_retrieve_cred failed.\n")); + goto done; + } + + tgtt->authtime = cred.times.authtime; + tgtt->starttime = cred.times.starttime; + tgtt->endtime = cred.times.endtime; + tgtt->renew_till = cred.times.renew_till; + + krb5_free_cred_contents(ctx, &cred); + + kerr = krb5_cc_close(ctx, cc); + if (kerr != 0) { + DEBUG(1, ("krb5_cc_close failed.\n")); + goto done; + } + cc = NULL; + + kerr = 0; + +done: + if (cc != NULL) { + krb5_cc_close(ctx, cc); + } + + if (client_princ != NULL) { + krb5_free_principal(ctx, client_princ); + } + + if (server_princ != NULL) { + krb5_free_principal(ctx, server_princ); + } + + if (ctx != NULL) { + krb5_free_context(ctx); + } + + if (kerr != 0) { + return EIO; + } + + return EOK; +} diff --git a/src/providers/krb5/krb5_utils.h b/src/providers/krb5/krb5_utils.h index be162bc72..8977e14f4 100644 --- a/src/providers/krb5/krb5_utils.h +++ b/src/providers/krb5/krb5_utils.h @@ -40,4 +40,7 @@ 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__ */ |