From 02e38eae1b9cb5df2036a707dafd86f6047c17de Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Mon, 19 Apr 2010 11:59:09 +0200 Subject: Add support for delayed kinit if offline If the configuration option krb5_store_password_if_offline is set to true and the backend is offline the plain text user password is stored and used to request a TGT if the backend becomes online. If available the Linux kernel key retention service is used. --- src/providers/krb5/krb5_auth.c | 76 +++++++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 26 deletions(-) (limited to 'src/providers/krb5/krb5_auth.c') diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index 48173ba7..a7aebe52 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -371,10 +371,10 @@ static errno_t fork_child(struct tevent_req *req, struct tevent_context *ev, /* We need to keep the root privileges to read the keytab file if * validation is enabled, otherwise we can drop them here and run * krb5_child with user privileges. - * If authtok_size is zero we are offline and want to create an empty - * ccache file. In this case we can drop the privileges, too. */ + * If we are offline and want to create an empty ccache file. In this + * case we can drop the privileges, too. */ if (!dp_opt_get_bool(kr->krb5_ctx->opts, KRB5_VALIDATE) || - kr->pd->authtok_size == 0) { + kr->is_offline) { ret = become_user(kr->uid, kr->gid); if (ret != EOK) { DEBUG(1, ("become_user failed.\n")); @@ -537,6 +537,7 @@ static void krb5_resolve_kpasswd_done(struct tevent_req *subreq); static void krb5_find_ccache_step(struct tevent_req *req); static void krb5_save_ccname_done(struct tevent_req *req); static void krb5_child_done(struct tevent_req *req); +static void krb5_pam_handler_cache_auth_step(struct tevent_req *req); struct krb5_auth_state { struct tevent_context *ev; @@ -897,40 +898,31 @@ static void krb5_find_ccache_step(struct tevent_req *req) DEBUG(9, ("Preparing for offline operation.\n")); kr->is_offline = true; - if (kr->valid_tgt_present) { - DEBUG(9, ("Valid TGT available, nothing to do.\n")); + if (kr->valid_tgt_present || kr->active_ccache_present) { + DEBUG(9, ("Valid TGT available or " + "ccache file is already in use.\n")); msg = talloc_asprintf(pd, "%s=%s", CCACHE_ENV_NAME, kr->ccname); if (msg == NULL) { DEBUG(1, ("talloc_asprintf failed.\n")); - ret = ENOMEM; - goto done; + } else { + ret = pam_add_response(pd, SSS_PAM_ENV_ITEM, strlen(msg) + 1, + (uint8_t *) msg); + if (ret != EOK) { + DEBUG(1, ("pam_add_response failed.\n")); + } } - ret = pam_add_response(pd, SSS_PAM_ENV_ITEM, strlen(msg) + 1, - (uint8_t *) msg); - if (ret != EOK) { - DEBUG(1, ("pam_add_response failed.\n")); + if (dp_opt_get_bool(kr->krb5_ctx->opts, + KRB5_STORE_PASSWORD_IF_OFFLINE)) { + krb5_pam_handler_cache_auth_step(req); + return; } state->pam_status = PAM_AUTHINFO_UNAVAIL; state->dp_err = DP_ERR_OFFLINE; ret = EOK; goto done; - } - memset(pd->authtok, 0, pd->authtok_size); - pd->authtok_size = 0; - if (kr->active_ccache_present) { - ret = krb5_save_ccname(state, state->be_ctx->sysdb, - state->be_ctx->domain, pd->user, - kr->ccname); - if (ret) { - DEBUG(1, ("krb5_save_ccname failed.\n")); - goto done; - } - - krb5_save_ccname_done(req); - return; } } @@ -1214,6 +1206,11 @@ static void krb5_save_ccname_done(struct tevent_req *req) char *password = NULL; if (kr->is_offline) { + if (dp_opt_get_bool(kr->krb5_ctx->opts,KRB5_STORE_PASSWORD_IF_OFFLINE)) { + krb5_pam_handler_cache_auth_step(req); + return; + } + DEBUG(4, ("Backend is marked offline, retry later!\n")); state->pam_status = PAM_AUTHINFO_UNAVAIL; state->dp_err = DP_ERR_OFFLINE; @@ -1277,6 +1274,34 @@ done: } +static void krb5_pam_handler_cache_auth_step(struct tevent_req *req) +{ + struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state); + struct pam_data *pd = state->pd; + struct krb5_ctx *krb5_ctx = state->kr->krb5_ctx; + int ret; + + ret = sysdb_cache_auth(state, state->be_ctx->sysdb, state->be_ctx->domain, + pd->user, pd->authtok, pd->authtok_size, + state->be_ctx->cdb, true, NULL, NULL); + if (ret != EOK) { + DEBUG(1, ("Offline authentication failed\n")); + state->pam_status = PAM_SYSTEM_ERR; + state->dp_err = DP_ERR_OK; + } else { + ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, + state->kr->uid); + if (ret != EOK) { + /* This error is not fatal */ + DEBUG(1, ("add_user_to_delayed_online_authentication failed.\n")); + } + state->pam_status = PAM_AUTHINFO_UNAVAIL; + state->dp_err = DP_ERR_OFFLINE; + } + + tevent_req_done(req); +} + static void krb_reply(struct be_req *req, int dp_err, int result) { req->fn(req, dp_err, result, NULL); @@ -1335,4 +1360,3 @@ void krb5_auth_done(struct tevent_req *req) krb_reply(be_req, dp_err, pd->pam_status); } - -- cgit