krb5_ccache.c revision 7c5cd2e7711621af9163a41393e88896a91ac33b
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek Kerberos 5 Backend Module -- ccache related utilities
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek Sumit Bose <sbose@redhat.com>
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek Jakub Hrozek <jhrozek@redhat.com>
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek Copyright (C) 2014 Red Hat
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek This program is free software; you can redistribute it and/or modify
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek it under the terms of the GNU General Public License as published by
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek the Free Software Foundation; either version 3 of the License, or
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek (at your option) any later version.
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek This program is distributed in the hope that it will be useful,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek but WITHOUT ANY WARRANTY; without even the implied warranty of
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek GNU General Public License for more details.
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek You should have received a copy of the GNU General Public License
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek along with this program. If not, see <http://www.gnu.org/licenses/>.
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekstatic errno_t find_ccdir_parent_data(TALLOC_CTX *mem_ctx,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek "stat for [%s] failed: [%d][%s].\n", ccdirname, ret,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek "talloc_zero failed.\n");
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek "talloc_strdup failed.\n");
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek "talloc_strdup failed.\n");
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek /* We'll remove all trailing slashes from the back so that
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * we only pass /some/path to find_ccdir_parent_data, not
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek "Cannot find parent directory of [%s], / is not allowed.\n",
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = find_ccdir_parent_data(mem_ctx, parent, parent_stat, missing_parents);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekstatic errno_t check_parent_stat(struct stat *parent_stat, uid_t uid)
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (parent_stat->st_uid != 0 && parent_stat->st_uid != uid) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek "Private directory can only be created below a directory "
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek "belonging to root or to [%"SPRIuid"].\n", uid);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek "Parent directory does not have the search bit set for "
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek "the owner.\n");
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek "Parent directory does not have the search bit set for "
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek "others.\n");
7c5cd2e7711621af9163a41393e88896a91ac33bJakub Hrozekstatic errno_t create_ccache_dir(const char *ccdirname, uid_t uid, gid_t gid)
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek "talloc_new failed.\n");
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek "Only absolute paths are allowed, not [%s] .\n", ccdirname);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = find_ccdir_parent_data(tmp_ctx, ccdirname, &parent_stat,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek "find_ccdir_parent_data failed.\n");
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek "Check the ownership and permissions of krb5_ccachedir: [%s].\n",
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek "chown failed [%d][%s].\n", ret, strerror(ret));
7c5cd2e7711621af9163a41393e88896a91ac33bJakub Hrozekerrno_t sss_krb5_precreate_ccache(const char *ccname, uid_t uid, gid_t gid)
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek /* only FILE and DIR types need precreation so far, we ignore any
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * other type */
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n");
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek /* We'll remove all trailing slashes from the back so that
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * we only pass /some/path to find_ccdir_parent_data, not
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, "Cannot find parent directory of [%s], "
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek struct sss_krb5_ccache *cc = talloc_get_type(mem, struct sss_krb5_ccache);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekstatic errno_t sss_open_ccache_as_user(TALLOC_CTX *mem_ctx,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek cc = talloc_zero(mem_ctx, struct sss_krb5_ccache);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek talloc_set_destructor((TALLOC_CTX *)cc, sss_free_krb5_ccache);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = switch_creds(cc, uid, gid, 0, NULL, &cc->creds);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek kerr = krb5_cc_resolve(cc->context, ccname, &cc->ccache);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (kerr == KRB5_FCC_NOFILE || cc->ccache == NULL) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_TRACE_FUNC, "ccache %s is missing or empty\n", ccname);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek } else if (kerr != 0) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek KRB5_DEBUG(SSSDBG_OP_FAILURE, cc->context, kerr);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_resolve failed.\n");
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekstatic errno_t sss_destroy_ccache(struct sss_krb5_ccache *cc)
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek kerr = krb5_cc_destroy(cc->context, cc->ccache);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek KRB5_DEBUG(SSSDBG_OP_FAILURE, cc->context, kerr);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_destroy failed.\n");
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek /* krb5_cc_destroy frees cc->ccache in all events */
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekerrno_t sss_krb5_cc_destroy(const char *ccname, uid_t uid, gid_t gid)
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = sss_open_ccache_as_user(tmp_ctx, ccname, uid, gid, &cc);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek/* This function is called only as a way to validate that we have the
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * right cache */
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekerrno_t sss_krb5_check_ccache_princ(uid_t uid, gid_t gid,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = sss_open_ccache_as_user(tmp_ctx, ccname, uid, gid, &cc);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek cc_type = krb5_cc_get_type(cc->context, cc->ccache);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek "Searching for [%s] in cache of type [%s]\n", principal, cc_type);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek kerr = krb5_parse_name(cc->context, principal, &kprinc);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek KRB5_DEBUG(SSSDBG_OP_FAILURE, cc->context, kerr);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, "krb5_parse_name failed.\n");
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek kerr = krb5_cc_get_principal(cc->context, cc->ccache, &ccprinc);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek KRB5_DEBUG(SSSDBG_OP_FAILURE, cc->context, kerr);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_get_principal failed.\n");
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (krb5_principal_compare(cc->context, kprinc, ccprinc) == TRUE) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek /* found in the primary ccache */
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (krb5_cc_support_switch(cc->context, cc_type)) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek kerr = krb5_cc_set_default_name(cc->context, ccname);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek KRB5_DEBUG(SSSDBG_MINOR_FAILURE, cc->context, kerr);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek /* try to continue despite failure */
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek kerr = krb5_cc_cache_match(cc->context, kprinc, &cc->ccache);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek KRB5_DEBUG(SSSDBG_TRACE_INTERNAL, cc->context, kerr);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek#endif /* HAVE_KRB5_CC_COLLECTION */
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekstatic errno_t sss_low_level_path_check(const char *ccname)
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek /* only FILE and DIR types need file checks so far, we ignore any
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * other type */
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekerrno_t sss_krb5_cc_verify_ccache(const char *ccname, uid_t uid, gid_t gid,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek /* first of all verify if the old ccache file/dir exists as we may be
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * trying to verify if an old ccache exists at all. If no file/dir
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * exists bail out immediately otherwise a following krb5_cc_resolve()
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek * call may actually create paths and files we do not want to have
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new failed.\n");
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = sss_open_ccache_as_user(tmp_ctx, ccname, uid, gid, &cc);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek tgt_name = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s", realm, realm);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new failed.\n");
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek kerr = krb5_parse_name(cc->context, tgt_name, &tgt_princ);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek KRB5_DEBUG(SSSDBG_CRIT_FAILURE, cc->context, kerr);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (kerr == KRB5_PARSE_MALFORMED) ret = EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek kerr = krb5_parse_name(cc->context, principal, &princ);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek KRB5_DEBUG(SSSDBG_CRIT_FAILURE, cc->context, kerr);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (kerr == KRB5_PARSE_MALFORMED) ret = EINVAL;
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek kerr = krb5_cc_retrieve_cred(cc->context, cc->ccache,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (kerr == KRB5_CC_NOTFOUND || kerr == KRB5_FCC_NOFILE) {
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_TRACE_INTERNAL, "TGT not found or expired.\n");
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek KRB5_DEBUG(SSSDBG_CRIT_FAILURE, cc->context, kerr);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (tgt_princ) krb5_free_principal(cc->context, tgt_princ);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek if (princ) krb5_free_principal(cc->context, princ);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekerrno_t get_ccache_file_data(const char *ccache_file, const char *client_name,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, "krb5_init_context failed.\n");
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek kerr = krb5_parse_name(ctx, client_name, &client_princ);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, "krb5_parse_name failed.\n");
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek sss_krb5_princ_realm(ctx, client_princ, &realm_name, &realm_length);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek server_name = talloc_asprintf(NULL, "krbtgt/%.*s@%.*s",
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek kerr = krb5_parse_name(ctx, server_name, &server_princ);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, "krb5_parse_name failed.\n");
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_resolve failed.\n");
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek kerr = krb5_cc_retrieve_cred(ctx, cc, 0, &mcred, &cred);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_retrieve_cred failed.\n");
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_close failed.\n");
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozekerrno_t safe_remove_old_ccache_file(const char *old_ccache,
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek DEBUG(SSSDBG_TRACE_FUNC, "New and old ccache file are the same, "
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek "none will be deleted.\n");