krb5_auth.c revision 2745b0156f12df7a7eb93d57716233243658e4d9
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder Kerberos 5 Backend Module
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder Sumit Bose <sbose@redhat.com>
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder Copyright (C) 2009-2010 Red Hat
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder This program is free software; you can redistribute it and/or modify
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder it under the terms of the GNU General Public License as published by
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder the Free Software Foundation; either version 3 of the License, or
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder (at your option) any later version.
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder This program is distributed in the hope that it will be useful,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder but WITHOUT ANY WARRANTY; without even the implied warranty of
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder GNU General Public License for more details.
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder You should have received a copy of the GNU General Public License
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder along with this program. If not, see <http://www.gnu.org/licenses/>.
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic int krb5_mod_ccname(TALLOC_CTX *mem_ctx,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "Missing user or ccache name.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (mod_op != SYSDB_MOD_REP && mod_op != SYSDB_MOD_DEL) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported operation [%d].\n", mod_op);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_TRACE_ALL, "%s ccname [%s] for user [%s].\n",
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder mod_op == SYSDB_MOD_REP ? "Save" : "Delete", ccname, name);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = sysdb_attrs_add_string(attrs, SYSDB_CCACHE_FILE, ccname);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_attrs_add_string failed.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "Error %d starting transaction (%s)\n", ret, strerror(ret));
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = sysdb_set_user_attr(domain, name, attrs, mod_op);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction!\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic int krb5_save_ccname(TALLOC_CTX *mem_ctx,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return krb5_mod_ccname(mem_ctx, sysdb, domain, name, ccname,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic int krb5_delete_ccname(TALLOC_CTX *mem_ctx,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return krb5_mod_ccname(mem_ctx, sysdb, domain, name, ccname,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic struct krb5_ctx *get_krb5_ctx(struct be_req *be_req)
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder pd = talloc_get_type(be_req_get_data(be_req), struct pam_data);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return talloc_get_type(be_ctx->bet_info[BET_AUTH].pvt_bet_data,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return talloc_get_type(be_ctx->bet_info[BET_ACCESS].pvt_bet_data,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return talloc_get_type(be_ctx->bet_info[BET_CHPASS].pvt_bet_data,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported PAM task.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct krb5child_req *kr = talloc_get_type(ptr, struct krb5child_req);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder memset(kr, 0, sizeof(struct krb5child_req));
b53688bfed888214b485cf76439d57262d80e0a7Christian Maedererrno_t krb5_setup(TALLOC_CTX *mem_ctx, struct pam_data *pd,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct krb5_ctx *krb5_ctx, struct krb5child_req **krb5_req)
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr = talloc_zero(mem_ctx, struct krb5child_req);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder talloc_set_destructor((TALLOC_CTX *) kr, krb5_cleanup);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = sss_authtok_get_password(pd->authtok, &password, NULL);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "Failed to get password [%d] %s\n", ret, strerror(ret));
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "Offline authentication failed\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder *pam_status = cached_login_pam_status(ret);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, uid);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder /* This error is not fatal */
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "add_user_to_delayed_online_authentication failed.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic errno_t krb5_auth_prepare_ccache_name(struct krb5child_req *kr,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ccname_template = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_CCNAME_TMPL);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->ccname = expand_ccname_template(kr, kr, ccname_template,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "expand_ccname_template failed.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->old_ccname = ldb_msg_find_attr_as_string(user_msg,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "No ccache file for user [%s] found.\n", kr->pd->user);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic void krb5_auth_store_creds(struct sss_domain_info *domain,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder /* The authtok is set to the credential cache
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder * during renewal. We don't want to save this
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder * as the cached password.
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = sss_authtok_get_password(pd->authtok, &password, NULL);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = sss_authtok_get_password(pd->newauthtok, &password, NULL);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "unsupported PAM command [%d].\n", pd->cmd);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "Failed to get password [%d] %s\n", ret, strerror(ret));
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder /* password caching failures are not fatal errors */
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "password not available, offline auth may not work.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder /* password caching failures are not fatal errors */
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = sysdb_cache_password(domain, pd->user, password);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "Failed to cache password, offline auth may not work."
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder /* password caching failures are not fatal errors */
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder/* krb5_auth request */
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic void krb5_auth_resolve_done(struct tevent_req *subreq);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic void krb5_auth_done(struct tevent_req *subreq);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstruct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder req = tevent_req_create(mem_ctx, &state, struct krb5_auth_state);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create failed.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = get_domain_or_subdomain(be_ctx, pd->domain, &state->domain);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_OP_FAILURE, "get_domain_or_subdomain failed.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder authtok_type = sss_authtok_get_type(pd->authtok);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (authtok_type != SSS_AUTHTOK_TYPE_PASSWORD) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder /* handle empty password gracefully */
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (authtok_type == SSS_AUTHTOK_TYPE_EMPTY) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "Illegal zero-length authtok for user [%s]\n",
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "Wrong authtok type for user [%s]. " \
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder authtok_type != SSS_AUTHTOK_TYPE_PASSWORD) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "Password reset by root is not supported.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (authtok_type != SSS_AUTHTOK_TYPE_CCFILE) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "Wrong authtok type for user [%s]. " \
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CONF_SETTINGS, "Unexpected pam task %d.\n", pd->cmd);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder (pd->cmd == SSS_PAM_CHAUTHTOK || pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM ||
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "Password changes and ticket renewal are not possible "
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "while offline.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder attrs = talloc_array(state, const char *, 7);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = krb5_setup(state, pd, krb5_ctx, &state->kr);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "krb5_setup failed.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = sysdb_get_user_attr(state, state->domain, state->pd->user, attrs,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "sysdb search for upn of user [%s] failed.\n", pd->user);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder realm = dp_opt_get_cstring(krb5_ctx->opts, KRB5_REALM);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "Missing Kerberos realm.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "No attributes for user [%s] found.\n", pd->user);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = find_or_guess_upn(state, res->msgs[0], krb5_ctx,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_OP_FAILURE, "find_or_guess_upn failed.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = compare_principal_realm(kr->upn, realm,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_OP_FAILURE, "compare_principal_realm failed.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->homedir = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_HOMEDIR,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "Home directory for user [%s] not known.\n", pd->user);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->uid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_UIDNUM, 0);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "UID for user [%s] not known.\n", pd->user);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->gid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_GIDNUM, 0);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "GID for user [%s] not known.\n", pd->user);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = krb5_auth_prepare_ccache_name(kr, res->msgs[0], state->be_ctx);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "Cannot prepare ccache names!\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "User search for (%s) returned > 1 results!\n", pd->user);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder subreq = be_resolve_server_send(state, state->ev, state->be_ctx,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "Failed resolver request.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder tevent_req_set_callback(subreq, krb5_auth_resolve_done, req);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic void krb5_auth_resolve_done(struct tevent_req *subreq)
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = be_resolve_server_recv(subreq, &kr->srv);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = be_resolve_server_recv(subreq, &kr->kpasswd_srv);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM)) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder /* all kpasswd servers have been tried and none was found good,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder * but the kdc seems ok. Password changes are not possible but
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder * authentication is. We return an PAM error here, but do not
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder * mark the backend offline. */
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder /* all servers have been tried and none
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder * was found good, setting offline,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder * but we still have to call the child to setup
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder * the ccache file if we are performing auth */
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "No KDC suitable for password change is available\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (kr->krb5_ctx->kpasswd_service != NULL) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "Resolver request failed.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder tevent_req_set_callback(subreq, krb5_auth_resolve_done, req);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->is_offline = be_is_offline(state->be_ctx);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder /* We need to keep the root privileges to read the keytab file if
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder * validation or FAST is enabled, otherwise we can drop them and run
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder * krb5_child with user privileges.
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder * If we are offline we want to create an empty ccache file. In this
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder * case we can drop the privileges, too. */
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if ((dp_opt_get_bool(kr->krb5_ctx->opts, KRB5_VALIDATE) ||
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder subreq = handle_child_send(state, state->ev, kr);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "handle_child_send failed.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder tevent_req_set_callback(subreq, krb5_auth_done, req);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic void krb5_auth_done(struct tevent_req *subreq)
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = handle_child_recv(subreq, pd, &buf, &len);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "child timed out!\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected PAM task\n");
goto done;
goto done;
&res);
if (ret) {
goto done;
goto done;
use_enterprise_principal == true) {
goto done;
goto done;
goto done;
case ERR_OK:
goto done;
case ERR_NETWORK_IO:
goto done;
goto done;
case ERR_CREDS_EXPIRED_CCACHE:
case ERR_CREDS_EXPIRED:
goto done;
case ERR_CREDS_INVALID:
goto done;
case ERR_ACCOUNT_EXPIRED:
goto done;
case ERR_NO_CREDS:
goto done;
case ERR_AUTH_FAILED:
goto done;
case ERR_CHPASS_FAILED:
goto done;
goto done;
goto done;
if (ret) {
goto done;
renew_interval_delta = 0;
goto done;
goto done;
done:
return EOK;
int ret;
goto done;
case SSS_PAM_AUTHENTICATE:
case SSS_CMD_RENEW:
case SSS_PAM_CHAUTHTOK_PRELIM:
case SSS_PAM_CHAUTHTOK:
goto done;
case SSS_PAM_ACCT_MGMT:
goto done;
case SSS_PAM_SETCRED:
case SSS_PAM_OPEN_SESSION:
case SSS_PAM_CLOSE_SESSION:
goto done;
goto done;
done:
int ret;
int pam_status;
int dp_err;
if (ret) {
int ret;
bool access_allowed;
goto done;
done: