Skip to content

Commit

Permalink
KRB5: Move all ccache operations to krb5_child.c
Browse files Browse the repository at this point in the history
The credential cache operations must be now performed by the krb5_child
completely, because the sssd_be process might be running as the sssd
user who doesn't have access to the ccaches.

src/providers/krb5/krb5_ccache.c is still linked against libsss_krb5
until we fix Kerberos ticket renewal as non-root.

Also includes a new error code that indicates that the back end should
remove the old ccache attribute -- the child can't do that if it's
running as the user.

Related:
https://fedorahosted.org/sssd/ticket/2370

Reviewed-by: Sumit Bose <[email protected]>
Reviewed-by: Lukáš Slebodník <[email protected]>
  • Loading branch information
jhrozek committed Nov 18, 2014
1 parent 7c5cd2e commit 2745b01
Show file tree
Hide file tree
Showing 9 changed files with 281 additions and 248 deletions.
13 changes: 11 additions & 2 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -2496,27 +2496,36 @@ libsss_ad_la_LDFLAGS = \

krb5_child_SOURCES = \
src/providers/krb5/krb5_child.c \
src/providers/krb5/krb5_ccache.c \
src/providers/dp_pam_data_util.c \
src/util/user_info_msg.c \
src/util/sss_krb5.c \
src/util/find_uid.c \
src/util/atomic_io.c \
src/util/authtok.c \
src/util/util.c \
src/util/signal.c \
src/util/strtonum.c \
src/util/become_user.c \
src/sss_client/common.c \
$(NULL)
krb5_child_CFLAGS = \
$(AM_CFLAGS) \
$(POPT_CFLAGS) \
$(KRB5_CFLAGS)
$(KRB5_CFLAGS) \
$(PCRE_CFLAGS) \
$(SYSTEMD_LOGIN_CFLAGS) \
$(NULL)
krb5_child_LDADD = \
libsss_debug.la \
$(TALLOC_LIBS) \
$(POPT_LIBS) \
$(DHASH_LIBS) \
$(KRB5_LIBS) \
$(CLIENT_LIBS)
$(CLIENT_LIBS) \
$(PCRE_LIBS) \
$(SYSTEMD_LOGIN_LIBS) \
$(NULL)

ldap_child_SOURCES = \
src/providers/ldap/ldap_child.c \
Expand Down
223 changes: 28 additions & 195 deletions src/providers/krb5/krb5_auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,45 +41,6 @@
#include "providers/krb5/krb5_utils.h"
#include "providers/krb5/krb5_ccache.h"

static errno_t
check_old_ccache(const char *old_ccache, struct krb5child_req *kr,
const char *realm, bool *active, bool *valid)
{
errno_t ret;

*active = false;
*valid = false;

ret = sss_krb5_cc_verify_ccache(old_ccache,
kr->uid, kr->gid,
realm, kr->upn);
switch (ret) {
case ERR_NOT_FOUND:
case ENOENT:
DEBUG(SSSDBG_TRACE_FUNC,
"Saved ccache %s doesn't exist.\n", old_ccache);
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);
return ret;
}

ret = check_if_uid_is_active(kr->uid, active);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "check_if_uid_is_active failed.\n");
return ret;
}

return EOK;
}

static int krb5_mod_ccname(TALLOC_CTX *mem_ctx,
struct sysdb_ctx *sysdb,
struct sss_domain_info *domain,
Expand Down Expand Up @@ -225,7 +186,6 @@ errno_t krb5_setup(TALLOC_CTX *mem_ctx, struct pam_data *pd,
return ENOMEM;
}
kr->is_offline = false;
kr->active_ccache = true;
kr->run_as_user = true;
talloc_set_destructor((TALLOC_CTX *) kr, krb5_cleanup);

Expand Down Expand Up @@ -276,47 +236,26 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx,
}

static errno_t krb5_auth_prepare_ccache_name(struct krb5child_req *kr,
struct ldb_message *user_msg,
struct be_ctx *be_ctx)
{
const char *ccname_template;
errno_t ret;

if (!kr->is_offline) {
kr->is_offline = be_is_offline(be_ctx);
}
ccname_template = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_CCNAME_TMPL);

/* The ccache file should be (re)created if one of the following conditions
* is true:
* - it doesn't exist (kr->ccname == NULL)
* - the backend is online and the current ccache file is not used, i.e
* the related user is currently not logged in and it is not a renewal
* request
* (!kr->is_offline && !kr->active_ccache && kr->pd->cmd != SSS_CMD_RENEW)
* - the backend is offline and the current cache file not used and
* it does not contain a valid tgt
* (kr->is_offline && !kr->active_ccache && !kr->valid_tgt)
*/
if (kr->ccname == NULL ||
(kr->is_offline && !kr->active_ccache && !kr->valid_tgt) ||
(!kr->is_offline && !kr->active_ccache && kr->pd->cmd != SSS_CMD_RENEW)) {
DEBUG(SSSDBG_TRACE_ALL, "Recreating ccache file.\n");
ccname_template = dp_opt_get_cstring(kr->krb5_ctx->opts,
KRB5_CCNAME_TMPL);
kr->ccname = expand_ccname_template(kr, kr, ccname_template,
kr->krb5_ctx->illegal_path_re,
true,
be_ctx->domain->case_sensitive);
if (kr->ccname == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "expand_ccname_template failed.\n");
return ENOMEM;
}
kr->ccname = expand_ccname_template(kr, kr, ccname_template,
kr->krb5_ctx->illegal_path_re, true,
be_ctx->domain->case_sensitive);
if (kr->ccname == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "expand_ccname_template failed.\n");
return ENOMEM;
}

ret = sss_krb5_precreate_ccache(kr->ccname,
kr->uid, kr->gid);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "ccache creation failed.\n");
return ret;
}
kr->old_ccname = ldb_msg_find_attr_as_string(user_msg,
SYSDB_CCACHE_FILE, NULL);
if (kr->old_ccname == NULL) {
DEBUG(SSSDBG_TRACE_LIBS,
"No ccache file for user [%s] found.\n", kr->pd->user);
}

return EOK;
Expand Down Expand Up @@ -402,7 +341,6 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
struct krb5_auth_state *state;
struct ldb_result *res;
struct krb5child_req *kr = NULL;
const char *ccache_file = NULL;
const char *realm;
struct tevent_req *req;
struct tevent_req *subreq;
Expand Down Expand Up @@ -588,45 +526,10 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
goto done;
}

ccache_file = ldb_msg_find_attr_as_string(res->msgs[0],
SYSDB_CCACHE_FILE,
NULL);
if (ccache_file != NULL) {
ret = check_old_ccache(ccache_file, kr, realm,
&kr->active_ccache,
&kr->valid_tgt);
if (ret == ENOENT) {
DEBUG(SSSDBG_FUNC_DATA,
"Ignoring ccache attribute [%s], because it doesn't"
"exist.\n", ccache_file);
ccache_file = NULL;
} else if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"check_if_ccache_file_is_used failed.\n");
ccache_file = NULL;
}
} else {
kr->active_ccache = false;
kr->valid_tgt = false;
DEBUG(SSSDBG_CONF_SETTINGS,
"No ccache file for user [%s] found.\n", pd->user);
}
DEBUG(SSSDBG_TRACE_ALL,
"Ccache_file is [%s] and is %s active and TGT is %s valid.\n",
ccache_file ? ccache_file : "not set",
kr->active_ccache ? "" : "not",
kr->valid_tgt ? "" : "not");
if (ccache_file != NULL) {
kr->ccname = ccache_file;
kr->old_ccname = talloc_strdup(kr, ccache_file);
if (kr->old_ccname == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n");
ret = ENOMEM;
goto done;
}
} else {
kr->ccname = NULL;
kr->old_ccname = NULL;
ret = krb5_auth_prepare_ccache_name(kr, res->msgs[0], state->be_ctx);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "Cannot prepare ccache names!\n");
goto done;
}
break;

Expand Down Expand Up @@ -669,7 +572,6 @@ static void krb5_auth_resolve_done(struct tevent_req *subreq)
struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
struct krb5child_req *kr = state->kr;
char *msg;
int ret;

if (!state->search_kpasswd) {
Expand Down Expand Up @@ -728,45 +630,8 @@ static void krb5_auth_resolve_done(struct tevent_req *subreq)
}
}

ret = krb5_auth_prepare_ccache_name(kr, state->be_ctx);
if (ret) {
goto done;
}

if (kr->is_offline) {
DEBUG(SSSDBG_TRACE_ALL, "Preparing for offline operation.\n");

if (kr->valid_tgt || kr->active_ccache) {
DEBUG(SSSDBG_TRACE_ALL, "Valid TGT available or "
"ccache file is already in use.\n");
kr->ccname = kr->old_ccname;
msg = talloc_asprintf(kr->pd,
"%s=%s", CCACHE_ENV_NAME, kr->ccname);
if (msg == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
} else {
ret = pam_add_response(kr->pd, SSS_PAM_ENV_ITEM,
strlen(msg) + 1, (uint8_t *) msg);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
}
}

if (dp_opt_get_bool(kr->krb5_ctx->opts,
KRB5_STORE_PASSWORD_IF_OFFLINE)) {
krb5_auth_cache_creds(state->kr->krb5_ctx,
state->domain,
state->be_ctx->cdb,
kr->pd, kr->uid,
&state->pam_status, &state->dp_err);
} else {
state->pam_status = PAM_AUTHINFO_UNAVAIL;
state->dp_err = DP_ERR_OFFLINE;
}
ret = EOK;
goto done;

}
if (!kr->is_offline) {
kr->is_offline = be_is_offline(state->be_ctx);
}

/* We need to keep the root privileges to read the keytab file if
Expand Down Expand Up @@ -814,7 +679,6 @@ static void krb5_auth_done(struct tevent_req *subreq)
char *renew_interval_str;
time_t renew_interval_time = 0;
bool use_enterprise_principal;
uint32_t user_info_type;

ret = handle_child_recv(subreq, pd, &buf, &len);
talloc_zfree(subreq);
Expand Down Expand Up @@ -974,21 +838,21 @@ static void krb5_auth_done(struct tevent_req *subreq)
}
break;

case ERR_CREDS_EXPIRED_CCACHE:
ret = krb5_delete_ccname(state, state->sysdb, state->domain,
pd->user, kr->old_ccname);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "krb5_delete_ccname failed.\n");
}
/* FALLTHROUGH */

case ERR_CREDS_EXPIRED:
/* If the password is expired we can safely remove the ccache from the
* cache and disk if it is not actively used anymore. This will allow
* to create a new random ccache if sshd with privilege separation is
* used. */
if (pd->cmd == SSS_PAM_AUTHENTICATE && !kr->active_ccache) {
if (kr->old_ccname != NULL) {
ret = safe_remove_old_ccache_file(kr->old_ccname, NULL,
kr->uid, kr->gid);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Failed to remove old ccache file [%s], "
"please remove it manually.\n", kr->old_ccname);
}

ret = krb5_delete_ccname(state, state->sysdb, state->domain,
pd->user, kr->old_ccname);
if (ret != EOK) {
Expand Down Expand Up @@ -1062,37 +926,6 @@ static void krb5_auth_done(struct tevent_req *subreq)
goto done;
}

ret = sss_krb5_check_ccache_princ(kr->uid, kr->gid, kr->ccname, kr->upn);
if (ret) {
if (res->otp == true && pd->cmd == SSS_PAM_CHAUTHTOK) {
DEBUG(SSSDBG_IMPORTANT_INFO,
"Password change succeeded but currently "
"post-chpass kinit is not implemented\n");

user_info_type = SSS_PAM_USER_INFO_OTP_CHPASS;
ret = pam_add_response(pd, SSS_PAM_USER_INFO, sizeof(uint32_t),
(const uint8_t *) &user_info_type);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
/* Not fatal */
}
} else {
DEBUG(SSSDBG_CRIT_FAILURE,
"No ccache for %s in %s?\n", kr->upn, kr->ccname);
goto done;
}
}

if (kr->old_ccname) {
ret = safe_remove_old_ccache_file(kr->old_ccname, kr->ccname,
kr->uid, kr->gid);
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->sysdb, state->domain,
pd->user, kr->ccname);
if (ret) {
Expand Down
Loading

0 comments on commit 2745b01

Please sign in to comment.