krb5_auth.c revision 2745b0156f12df7a7eb93d57716233243658e4d9
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder/*
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder SSSD
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder Kerberos 5 Backend Module
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder Authors:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder Sumit Bose <sbose@redhat.com>
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder Copyright (C) 2009-2010 Red Hat
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
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
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
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 Maeder*/
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder#include <errno.h>
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder#include <sys/time.h>
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder#include <sys/types.h>
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder#include <sys/wait.h>
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder#include <pwd.h>
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder#include <sys/stat.h>
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder#include <security/pam_modules.h>
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder#include "util/util.h"
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder#include "util/find_uid.h"
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder#include "util/auth_utils.h"
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder#include "db/sysdb.h"
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder#include "util/child_common.h"
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder#include "providers/krb5/krb5_auth.h"
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder#include "providers/krb5/krb5_utils.h"
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder#include "providers/krb5/krb5_ccache.h"
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic int krb5_mod_ccname(TALLOC_CTX *mem_ctx,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct sysdb_ctx *sysdb,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct sss_domain_info *domain,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder const char *name,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder const char *ccname,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder int mod_op)
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder{
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder TALLOC_CTX *tmpctx;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct sysdb_attrs *attrs;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder int ret;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder errno_t sret;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder bool in_transaction = false;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (name == NULL || ccname == NULL) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "Missing user or ccache name.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return EINVAL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
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 return EINVAL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
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
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder tmpctx = talloc_new(mem_ctx);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (!tmpctx) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return ENOMEM;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder attrs = sysdb_new_attrs(tmpctx);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (!attrs) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = ENOMEM;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = sysdb_attrs_add_string(attrs, SYSDB_CCACHE_FILE, ccname);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (ret != EOK) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_attrs_add_string failed.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = sysdb_transaction_start(sysdb);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (ret != EOK) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "Error %d starting transaction (%s)\n", ret, strerror(ret));
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder in_transaction = true;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = sysdb_set_user_attr(domain, name, attrs, mod_op);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (ret != EOK) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = sysdb_transaction_commit(sysdb);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (ret != EOK) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction!\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder in_transaction = false;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederdone:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (in_transaction) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder sret = sysdb_transaction_cancel(sysdb);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (sret != EOK) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder talloc_zfree(tmpctx);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return ret;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder}
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic int krb5_save_ccname(TALLOC_CTX *mem_ctx,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct sysdb_ctx *sysdb,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct sss_domain_info *domain,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder const char *name,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder const char *ccname)
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder{
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return krb5_mod_ccname(mem_ctx, sysdb, domain, name, ccname,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder SYSDB_MOD_REP);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder}
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic int krb5_delete_ccname(TALLOC_CTX *mem_ctx,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct sysdb_ctx *sysdb,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct sss_domain_info *domain,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder const char *name,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder const char *ccname)
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder{
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return krb5_mod_ccname(mem_ctx, sysdb, domain, name, ccname,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder SYSDB_MOD_DEL);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder}
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic struct krb5_ctx *get_krb5_ctx(struct be_req *be_req)
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder{
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct pam_data *pd;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder pd = talloc_get_type(be_req_get_data(be_req), struct pam_data);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder switch (pd->cmd) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder case SSS_PAM_AUTHENTICATE:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder case SSS_CMD_RENEW:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return talloc_get_type(be_ctx->bet_info[BET_AUTH].pvt_bet_data,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct krb5_ctx);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder break;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder case SSS_PAM_ACCT_MGMT:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return talloc_get_type(be_ctx->bet_info[BET_ACCESS].pvt_bet_data,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct krb5_ctx);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder break;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder case SSS_PAM_CHAUTHTOK:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder case SSS_PAM_CHAUTHTOK_PRELIM:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return talloc_get_type(be_ctx->bet_info[BET_CHPASS].pvt_bet_data,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct krb5_ctx);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder break;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder default:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported PAM task.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return NULL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder}
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic int krb5_cleanup(void *ptr)
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder{
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct krb5child_req *kr = talloc_get_type(ptr, struct krb5child_req);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (kr == NULL) return EOK;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder memset(kr, 0, sizeof(struct krb5child_req));
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return EOK;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder}
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
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{
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct krb5child_req *kr = NULL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr = talloc_zero(mem_ctx, struct krb5child_req);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (kr == NULL) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return ENOMEM;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->is_offline = false;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->run_as_user = true;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder talloc_set_destructor((TALLOC_CTX *) kr, krb5_cleanup);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->pd = pd;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->krb5_ctx = krb5_ctx;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder *krb5_req = kr;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return EOK;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder}
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct sss_domain_info *domain,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct confdb_ctx *cdb,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct pam_data *pd, uid_t uid,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder int *pam_status, int *dp_err)
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder{
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder const char *password = NULL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder errno_t ret;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = sss_authtok_get_password(pd->authtok, &password, NULL);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (ret != EOK) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_FATAL_FAILURE,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "Failed to get password [%d] %s\n", ret, strerror(ret));
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder *pam_status = PAM_SYSTEM_ERR;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder *dp_err = DP_ERR_OK;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = sysdb_cache_auth(domain, pd->user,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder password, cdb, true, NULL, NULL);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (ret != EOK) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "Offline authentication failed\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder *pam_status = cached_login_pam_status(ret);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder *dp_err = DP_ERR_OK;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, uid);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (ret != EOK) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder /* This error is not fatal */
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "add_user_to_delayed_online_authentication failed.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder *pam_status = PAM_AUTHINFO_UNAVAIL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder *dp_err = DP_ERR_OFFLINE;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder}
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic errno_t krb5_auth_prepare_ccache_name(struct krb5child_req *kr,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct ldb_message *user_msg,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct be_ctx *be_ctx)
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder{
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder const char *ccname_template;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ccname_template = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_CCNAME_TMPL);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->ccname = expand_ccname_template(kr, kr, ccname_template,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->krb5_ctx->illegal_path_re, true,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder be_ctx->domain->case_sensitive);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (kr->ccname == NULL) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "expand_ccname_template failed.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return ENOMEM;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->old_ccname = ldb_msg_find_attr_as_string(user_msg,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder SYSDB_CCACHE_FILE, NULL);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (kr->old_ccname == NULL) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_TRACE_LIBS,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "No ccache file for user [%s] found.\n", kr->pd->user);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return EOK;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder}
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic void krb5_auth_store_creds(struct sss_domain_info *domain,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct pam_data *pd)
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder{
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder const char *password = NULL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder int ret = EOK;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder switch(pd->cmd) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder case SSS_CMD_RENEW:
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 */
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder break;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder case SSS_PAM_AUTHENTICATE:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder case SSS_PAM_CHAUTHTOK_PRELIM:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = sss_authtok_get_password(pd->authtok, &password, NULL);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder break;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder case SSS_PAM_CHAUTHTOK:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = sss_authtok_get_password(pd->newauthtok, &password, NULL);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder break;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder default:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_FATAL_FAILURE,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "unsupported PAM command [%d].\n", pd->cmd);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (ret != EOK) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_FATAL_FAILURE,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "Failed to get password [%d] %s\n", ret, strerror(ret));
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder /* password caching failures are not fatal errors */
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (password == NULL) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (pd->cmd != SSS_CMD_RENEW) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_FATAL_FAILURE,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "password not available, offline auth may not work.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder /* password caching failures are not fatal errors */
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = sysdb_cache_password(domain, pd->user, password);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (ret) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_OP_FAILURE,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "Failed to cache password, offline auth may not work."
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder " (%d)[%s]!?\n", ret, strerror(ret));
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder /* password caching failures are not fatal errors */
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder}
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder/* krb5_auth request */
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstruct krb5_auth_state {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct tevent_context *ev;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct be_ctx *be_ctx;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct pam_data *pd;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct sysdb_ctx *sysdb;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct sss_domain_info *domain;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct krb5_ctx *krb5_ctx;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct krb5child_req *kr;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder bool search_kpasswd;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder int pam_status;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder int dp_err;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder};
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic void krb5_auth_resolve_done(struct tevent_req *subreq);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic void krb5_auth_done(struct tevent_req *subreq);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstruct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct tevent_context *ev,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct be_ctx *be_ctx,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct pam_data *pd,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct krb5_ctx *krb5_ctx)
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder{
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder const char **attrs;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct krb5_auth_state *state;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct ldb_result *res;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct krb5child_req *kr = NULL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder const char *realm;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct tevent_req *req;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct tevent_req *subreq;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder int authtok_type;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder int ret;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder req = tevent_req_create(mem_ctx, &state, struct krb5_auth_state);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (req == NULL) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create failed.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return NULL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->ev = ev;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->be_ctx = be_ctx;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->pd = pd;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->krb5_ctx = krb5_ctx;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->kr = NULL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->pam_status = PAM_SYSTEM_ERR;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->dp_err = DP_ERR_FATAL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = get_domain_or_subdomain(be_ctx, pd->domain, &state->domain);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (ret != EOK) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_OP_FAILURE, "get_domain_or_subdomain failed.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->sysdb = state->domain->sysdb;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder authtok_type = sss_authtok_get_type(pd->authtok);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder switch (pd->cmd) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder case SSS_PAM_AUTHENTICATE:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder case SSS_PAM_CHAUTHTOK:
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 DEBUG(SSSDBG_CRIT_FAILURE,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "Illegal zero-length authtok for user [%s]\n",
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder pd->user);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->pam_status = PAM_AUTH_ERR;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->dp_err = DP_ERR_OK;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = EOK;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "Wrong authtok type for user [%s]. " \
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "Expected [%d], got [%d]\n", pd->user,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder SSS_AUTHTOK_TYPE_PASSWORD,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder authtok_type);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->pam_status = PAM_SYSTEM_ERR;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->dp_err = DP_ERR_FATAL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = EINVAL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder break;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder case SSS_PAM_CHAUTHTOK_PRELIM:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (pd->priv == 1 &&
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder authtok_type != SSS_AUTHTOK_TYPE_PASSWORD) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_MINOR_FAILURE,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "Password reset by root is not supported.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->pam_status = PAM_PERM_DENIED;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->dp_err = DP_ERR_OK;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = EOK;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder break;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder case SSS_CMD_RENEW:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (authtok_type != SSS_AUTHTOK_TYPE_CCFILE) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "Wrong authtok type for user [%s]. " \
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "Expected [%d], got [%d]\n", pd->user,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder SSS_AUTHTOK_TYPE_CCFILE,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder authtok_type);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->pam_status = PAM_SYSTEM_ERR;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->dp_err = DP_ERR_FATAL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = EINVAL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder break;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder default:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CONF_SETTINGS, "Unexpected pam task %d.\n", pd->cmd);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->pam_status = PAM_SYSTEM_ERR;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->dp_err = DP_ERR_FATAL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = EINVAL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (be_is_offline(be_ctx) &&
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder (pd->cmd == SSS_PAM_CHAUTHTOK || pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM ||
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder pd->cmd == SSS_CMD_RENEW)) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_TRACE_ALL,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "Password changes and ticket renewal are not possible "
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "while offline.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->pam_status = PAM_AUTHINFO_UNAVAIL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->dp_err = DP_ERR_OFFLINE;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = EOK;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder attrs = talloc_array(state, const char *, 7);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (attrs == NULL) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = ENOMEM;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder attrs[0] = SYSDB_UPN;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder attrs[1] = SYSDB_HOMEDIR;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder attrs[2] = SYSDB_CCACHE_FILE;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder attrs[3] = SYSDB_UIDNUM;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder attrs[4] = SYSDB_GIDNUM;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder attrs[5] = SYSDB_CANONICAL_UPN;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder attrs[6] = NULL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = krb5_setup(state, pd, krb5_ctx, &state->kr);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (ret != EOK) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "krb5_setup failed.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr = state->kr;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = sysdb_get_user_attr(state, state->domain, state->pd->user, attrs,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder &res);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (ret) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_FUNC_DATA,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "sysdb search for upn of user [%s] failed.\n", pd->user);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->pam_status = PAM_SYSTEM_ERR;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->dp_err = DP_ERR_OK;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder realm = dp_opt_get_cstring(krb5_ctx->opts, KRB5_REALM);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (realm == NULL) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "Missing Kerberos realm.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = ENOENT;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder switch (res->count) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder case 0:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_FUNC_DATA,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "No attributes for user [%s] found.\n", pd->user);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = ENOENT;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder break;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder case 1:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = find_or_guess_upn(state, res->msgs[0], krb5_ctx,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder be_ctx->domain, pd->user, pd->domain,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder &kr->upn);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (ret != EOK) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_OP_FAILURE, "find_or_guess_upn failed.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = compare_principal_realm(kr->upn, realm,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder &kr->upn_from_different_realm);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (ret != 0) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_OP_FAILURE, "compare_principal_realm failed.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->homedir = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_HOMEDIR,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder NULL);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (kr->homedir == NULL) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CONF_SETTINGS,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "Home directory for user [%s] not known.\n", pd->user);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->uid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_UIDNUM, 0);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (kr->uid == 0) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CONF_SETTINGS,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "UID for user [%s] not known.\n", pd->user);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = ENOENT;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->gid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_GIDNUM, 0);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (kr->gid == 0) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CONF_SETTINGS,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "GID for user [%s] not known.\n", pd->user);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = ENOENT;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = krb5_auth_prepare_ccache_name(kr, res->msgs[0], state->be_ctx);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (ret != EOK) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "Cannot prepare ccache names!\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder break;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder default:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "User search for (%s) returned > 1 results!\n", pd->user);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = EINVAL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder break;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->srv = NULL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->kpasswd_srv = NULL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->search_kpasswd = false;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder subreq = be_resolve_server_send(state, state->ev, state->be_ctx,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->krb5_ctx->service->name,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->kr->srv == NULL ? true : false);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (!subreq) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "Failed resolver request.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = EIO;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder tevent_req_set_callback(subreq, krb5_auth_resolve_done, req);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return req;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederdone:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (ret == EOK) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder tevent_req_done(req);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder } else {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder tevent_req_error(req, ret);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder tevent_req_post(req, state->ev);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return req;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder}
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic void krb5_auth_resolve_done(struct tevent_req *subreq)
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder{
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 struct krb5child_req *kr = state->kr;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder int ret;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (!state->search_kpasswd) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = be_resolve_server_recv(subreq, &kr->srv);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder } else {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = be_resolve_server_recv(subreq, &kr->kpasswd_srv);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder talloc_zfree(subreq);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (state->search_kpasswd) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if ((ret != EOK) &&
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder (kr->pd->cmd == SSS_PAM_CHAUTHTOK ||
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 state->pam_status = PAM_AUTHTOK_LOCK_BUSY;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->dp_err = DP_ERR_OK;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = EOK;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder } else {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (ret != EOK) {
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 be_mark_offline(state->be_ctx);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->is_offline = true;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (kr->pd->cmd == SSS_PAM_CHAUTHTOK ||
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_TRACE_FUNC,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder "No KDC suitable for password change is available\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->pam_status = PAM_AUTHTOK_LOCK_BUSY;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->dp_err = DP_ERR_OK;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = EOK;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder } else {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (kr->krb5_ctx->kpasswd_service != NULL) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->search_kpasswd = true;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder subreq = be_resolve_server_send(state,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->ev, state->be_ctx,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->krb5_ctx->kpasswd_service->name,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->kpasswd_srv == NULL ? true : false);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (subreq == NULL) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "Resolver request failed.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = EIO;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder tevent_req_set_callback(subreq, krb5_auth_resolve_done, req);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (!kr->is_offline) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->is_offline = be_is_offline(state->be_ctx);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
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 kr->krb5_ctx->use_fast) &&
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder (!kr->is_offline)) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->run_as_user = false;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder } else {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->run_as_user = true;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder subreq = handle_child_send(state, state->ev, kr);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (subreq == NULL) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "handle_child_send failed.\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = ENOMEM;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder tevent_req_set_callback(subreq, krb5_auth_done, req);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder return;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederdone:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (ret == EOK) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder tevent_req_done(req);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder } else {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder tevent_req_error(req, ret);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder}
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic void krb5_auth_done(struct tevent_req *subreq)
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder{
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 struct krb5child_req *kr = state->kr;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct pam_data *pd = state->pd;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder int ret;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder uint8_t *buf = NULL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ssize_t len = -1;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct krb5_child_response *res;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct fo_server *search_srv;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder krb5_deltat renew_interval_delta;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder char *renew_interval_str;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder time_t renew_interval_time = 0;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder bool use_enterprise_principal;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = handle_child_recv(subreq, pd, &buf, &len);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder talloc_zfree(subreq);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (ret == ETIMEDOUT) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "child timed out!\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder switch (pd->cmd) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder case SSS_PAM_AUTHENTICATE:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder case SSS_CMD_RENEW:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->search_kpasswd = false;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder search_srv = kr->srv;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder break;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder case SSS_PAM_CHAUTHTOK:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder case SSS_PAM_CHAUTHTOK_PRELIM:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (state->kr->kpasswd_srv) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->search_kpasswd = true;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder search_srv = kr->kpasswd_srv;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder break;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder } else {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder state->search_kpasswd = false;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder search_srv = kr->srv;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder break;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder default:
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected PAM task\n");
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = EINVAL;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder goto done;
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder }
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder
be_fo_set_port_status(state->be_ctx, state->krb5_ctx->service->name,
search_srv, PORT_NOT_WORKING);
subreq = be_resolve_server_send(state, state->ev, state->be_ctx,
state->krb5_ctx->service->name,
search_srv == NULL ? true : false);
if (subreq == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "Failed resolved request.\n");
ret = ENOMEM;
goto done;
}
tevent_req_set_callback(subreq, krb5_auth_resolve_done, req);
return;
} else if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"child failed (%d [%s])\n", ret, strerror(ret));
goto done;
}
/* EOK */
ret = parse_krb5_child_response(state, buf, len, pd,
state->be_ctx->domain->pwd_expiration_warning,
&res);
if (ret) {
DEBUG(SSSDBG_OP_FAILURE, "Could not parse child response [%d]: %s\n",
ret, strerror(ret));
goto done;
}
if (res->ccname) {
kr->ccname = talloc_strdup(kr, res->ccname);
if (!kr->ccname) {
ret = ENOMEM;
goto done;
}
}
use_enterprise_principal = dp_opt_get_bool(kr->krb5_ctx->opts,
KRB5_USE_ENTERPRISE_PRINCIPAL);
/* Check if the cases of our upn are correct and update it if needed.
* Fail if the upn differs by more than just the case for non-enterprise
* principals. */
if (res->correct_upn != NULL &&
strcmp(kr->upn, res->correct_upn) != 0) {
if (strcasecmp(kr->upn, res->correct_upn) == 0 ||
use_enterprise_principal == true) {
talloc_free(kr->upn);
kr->upn = talloc_strdup(kr, res->correct_upn);
if (kr->upn == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
ret = ENOMEM;
goto done;
}
ret = check_if_cached_upn_needs_update(state->sysdb, state->domain,
pd->user, res->correct_upn);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"check_if_cached_upn_needs_update failed.\n");
goto done;
}
} else {
DEBUG(SSSDBG_CRIT_FAILURE, "UPN used in the request [%s] and " \
"returned UPN [%s] differ by more " \
"than just the case.\n",
kr->upn, res->correct_upn);
ret = EINVAL;
goto done;
}
}
/* If the child request failed, but did not return an offline error code,
* return with the status */
switch (res->msg_status) {
case ERR_OK:
/* If the child request was successful and we run the first pass of the
* change password request just return success. */
if (pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) {
state->pam_status = PAM_SUCCESS;
state->dp_err = DP_ERR_OK;
ret = EOK;
goto done;
}
break;
case ERR_NETWORK_IO:
if (kr->kpasswd_srv != NULL &&
(pd->cmd == SSS_PAM_CHAUTHTOK ||
pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM)) {
/* if using a dedicated kpasswd server for a chpass operation... */
be_fo_set_port_status(state->be_ctx,
state->krb5_ctx->kpasswd_service->name,
kr->kpasswd_srv, PORT_NOT_WORKING);
/* ..try to resolve next kpasswd server */
state->search_kpasswd = true;
subreq = be_resolve_server_send(state, state->ev, state->be_ctx,
state->krb5_ctx->kpasswd_service->name,
state->kr->kpasswd_srv == NULL ? true : false);
if (subreq == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "Resolver request failed.\n");
ret = ENOMEM;
goto done;
}
tevent_req_set_callback(subreq, krb5_auth_resolve_done, req);
return;
} else if (kr->srv != NULL) {
/* failed to use the KDC... */
be_fo_set_port_status(state->be_ctx,
state->krb5_ctx->service->name,
kr->srv, PORT_NOT_WORKING);
/* ..try to resolve next KDC */
state->search_kpasswd = false;
subreq = be_resolve_server_send(state, state->ev, state->be_ctx,
state->krb5_ctx->service->name,
kr->srv == NULL ? true : false);
if (subreq == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "Resolver request failed.\n");
ret = ENOMEM;
goto done;
}
tevent_req_set_callback(subreq, krb5_auth_resolve_done, req);
return;
}
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 = 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");
}
}
}
state->pam_status = PAM_NEW_AUTHTOK_REQD;
state->dp_err = DP_ERR_OK;
ret = EOK;
goto done;
case ERR_CREDS_INVALID:
state->pam_status = PAM_CRED_ERR;
state->dp_err = DP_ERR_OK;
ret = EOK;
goto done;
case ERR_ACCOUNT_EXPIRED:
state->pam_status = PAM_ACCT_EXPIRED;
state->dp_err = DP_ERR_OK;
ret = EOK;
goto done;
case ERR_NO_CREDS:
state->pam_status = PAM_CRED_UNAVAIL;
state->dp_err = DP_ERR_OK;
ret = EOK;
goto done;
case ERR_AUTH_FAILED:
state->pam_status = PAM_AUTH_ERR;
state->dp_err = DP_ERR_OK;
ret = EOK;
goto done;
case ERR_CHPASS_FAILED:
state->pam_status = PAM_AUTHTOK_ERR;
state->dp_err = DP_ERR_OK;
ret = EOK;
goto done;
default:
state->pam_status = PAM_SYSTEM_ERR;
state->dp_err = DP_ERR_OK;
ret = EOK;
goto done;
}
if (kr->kpasswd_srv != NULL &&
(pd->cmd == SSS_PAM_CHAUTHTOK ||
pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM)) {
/* found a dedicated kpasswd server for a chpass operation */
be_fo_set_port_status(state->be_ctx,
state->krb5_ctx->service->name,
kr->kpasswd_srv, PORT_WORKING);
} else if (kr->srv != NULL) {
/* found a KDC */
be_fo_set_port_status(state->be_ctx, state->krb5_ctx->service->name,
kr->srv, PORT_WORKING);
}
/* Now only a successful authentication or password change is left.
*
* We expect that one of the messages in the received buffer contains
* the name of the credential cache file. */
if (kr->ccname == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "Missing ccache name in child response.\n");
ret = EINVAL;
goto done;
}
ret = krb5_save_ccname(state, state->sysdb, state->domain,
pd->user, kr->ccname);
if (ret) {
DEBUG(SSSDBG_CRIT_FAILURE, "krb5_save_ccname failed.\n");
goto done;
}
renew_interval_str = dp_opt_get_string(kr->krb5_ctx->opts,
KRB5_RENEW_INTERVAL);
if (renew_interval_str != NULL) {
ret = krb5_string_to_deltat(renew_interval_str, &renew_interval_delta);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE,
"Reading krb5_renew_interval failed.\n");
renew_interval_delta = 0;
}
renew_interval_time = renew_interval_delta;
}
if (res->msg_status == ERR_OK && renew_interval_time > 0 &&
(pd->cmd == SSS_PAM_AUTHENTICATE ||
pd->cmd == SSS_CMD_RENEW ||
pd->cmd == SSS_PAM_CHAUTHTOK) &&
(res->tgtt.renew_till > res->tgtt.endtime) &&
(kr->ccname != NULL)) {
DEBUG(SSSDBG_TRACE_LIBS,
"Adding [%s] for automatic renewal.\n", kr->ccname);
ret = add_tgt_to_renew_table(kr->krb5_ctx, kr->ccname, &(res->tgtt),
pd, kr->upn);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "add_tgt_to_renew_table failed, "
"automatic renewal not possible.\n");
}
}
if (kr->is_offline) {
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,
state->pd, state->kr->uid,
&state->pam_status, &state->dp_err);
} else {
DEBUG(SSSDBG_CONF_SETTINGS,
"Backend is marked offline, retry later!\n");
state->pam_status = PAM_AUTHINFO_UNAVAIL;
state->dp_err = DP_ERR_OFFLINE;
}
ret = EOK;
goto done;
}
if (state->be_ctx->domain->cache_credentials == TRUE && !res->otp) {
krb5_auth_store_creds(state->domain, pd);
}
if (res->otp == true && pd->cmd == SSS_PAM_AUTHENTICATE) {
uint32_t otp_flag = 1;
ret = pam_add_response(pd, SSS_OTP, sizeof(uint32_t),
(const uint8_t *) &otp_flag);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"pam_add_response failed: %d (%s).\n",
ret, sss_strerror(ret));
state->pam_status = PAM_SYSTEM_ERR;
state->dp_err = DP_ERR_OK;
goto done;
}
}
state->pam_status = PAM_SUCCESS;
state->dp_err = DP_ERR_OK;
ret = EOK;
done:
if (ret == EOK) {
tevent_req_done(req);
} else {
tevent_req_error(req, ret);
}
}
int krb5_auth_recv(struct tevent_req *req, int *pam_status, int *dp_err)
{
struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
*pam_status = state->pam_status;
*dp_err = state->dp_err;
TEVENT_REQ_RETURN_ON_ERROR(req);
return EOK;
}
void krb5_pam_handler_auth_done(struct tevent_req *req);
static void krb5_pam_handler_access_done(struct tevent_req *req);
void krb5_pam_handler(struct be_req *be_req)
{
struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
struct tevent_req *req;
struct pam_data *pd;
struct krb5_ctx *krb5_ctx;
int dp_err = DP_ERR_FATAL;
int ret;
pd = talloc_get_type(be_req_get_data(be_req), struct pam_data);
pd->pam_status = PAM_SYSTEM_ERR;
krb5_ctx = get_krb5_ctx(be_req);
if (krb5_ctx == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "Kerberos context not available.\n");
goto done;
}
switch (pd->cmd) {
case SSS_PAM_AUTHENTICATE:
case SSS_CMD_RENEW:
case SSS_PAM_CHAUTHTOK_PRELIM:
case SSS_PAM_CHAUTHTOK:
ret = add_to_wait_queue(be_req, pd, krb5_ctx);
if (ret == EOK) {
DEBUG(SSSDBG_TRACE_LIBS,
"Request successfully added to wait queue "
"of user [%s].\n", pd->user);
return;
} else if (ret == ENOENT) {
DEBUG(SSSDBG_TRACE_LIBS, "Wait queue of user [%s] is empty, "
"running request immediately.\n", pd->user);
} else {
DEBUG(SSSDBG_TRACE_LIBS,
"Failed to add request to wait queue of user [%s], "
"running request immediately.\n", pd->user);
}
req = krb5_auth_send(be_req, be_ctx->ev, be_ctx, pd, krb5_ctx);
if (req == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "krb5_auth_send failed.\n");
goto done;
}
tevent_req_set_callback(req, krb5_pam_handler_auth_done, be_req);
break;
case SSS_PAM_ACCT_MGMT:
req = krb5_access_send(be_req, be_ctx->ev, be_ctx, pd, krb5_ctx);
if (req == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "krb5_access_send failed.\n");
goto done;
}
tevent_req_set_callback(req, krb5_pam_handler_access_done, be_req);
break;
case SSS_PAM_SETCRED:
case SSS_PAM_OPEN_SESSION:
case SSS_PAM_CLOSE_SESSION:
pd->pam_status = PAM_SUCCESS;
dp_err = DP_ERR_OK;
goto done;
break;
default:
DEBUG(SSSDBG_CONF_SETTINGS,
"krb5 does not handles pam task %d.\n", pd->cmd);
pd->pam_status = PAM_MODULE_UNKNOWN;
dp_err = DP_ERR_OK;
goto done;
}
return;
done:
be_req_terminate(be_req, dp_err, pd->pam_status, NULL);
}
void krb5_pam_handler_auth_done(struct tevent_req *req)
{
int ret;
struct be_req *be_req = tevent_req_callback_data(req, struct be_req);
int pam_status;
int dp_err;
struct pam_data *pd;
struct krb5_ctx *krb5_ctx;
pd = talloc_get_type(be_req_get_data(be_req), struct pam_data);
ret = krb5_auth_recv(req, &pam_status, &dp_err);
talloc_zfree(req);
if (ret) {
pd->pam_status = PAM_SYSTEM_ERR;
dp_err = DP_ERR_OK;
} else {
pd->pam_status = pam_status;
}
krb5_ctx = get_krb5_ctx(be_req);
if (krb5_ctx != NULL) {
check_wait_queue(krb5_ctx, pd->user);
} else {
DEBUG(SSSDBG_CRIT_FAILURE, "Kerberos context not available.\n");
}
be_req_terminate(be_req, dp_err, pd->pam_status, NULL);
}
static void krb5_pam_handler_access_done(struct tevent_req *req)
{
int ret;
struct be_req *be_req = tevent_req_callback_data(req, struct be_req);
bool access_allowed;
struct pam_data *pd;
int dp_err = DP_ERR_OK;
pd = talloc_get_type(be_req_get_data(be_req), struct pam_data);
pd->pam_status = PAM_SYSTEM_ERR;
ret = krb5_access_recv(req, &access_allowed);
talloc_zfree(req);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"krb5_access request failed [%d][%s]\n", ret, strerror(ret));
goto done;
}
DEBUG(SSSDBG_TRACE_LIBS, "Access %s for user [%s].\n",
access_allowed ? "allowed" : "denied", pd->user);
pd->pam_status = access_allowed ? PAM_SUCCESS : PAM_PERM_DENIED;
dp_err = DP_ERR_OK;
done:
be_req_terminate(be_req, dp_err, pd->pam_status, NULL);
}