LCOV - code coverage report
Current view: top level - providers/krb5 - krb5_auth.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 637 0.0 %
Date: 2016-06-29 Functions: 0 18 0.0 %

          Line data    Source code
       1             : /*
       2             :     SSSD
       3             : 
       4             :     Kerberos 5 Backend Module
       5             : 
       6             :     Authors:
       7             :         Sumit Bose <sbose@redhat.com>
       8             : 
       9             :     Copyright (C) 2009-2010 Red Hat
      10             : 
      11             :     This program is free software; you can redistribute it and/or modify
      12             :     it under the terms of the GNU General Public License as published by
      13             :     the Free Software Foundation; either version 3 of the License, or
      14             :     (at your option) any later version.
      15             : 
      16             :     This program is distributed in the hope that it will be useful,
      17             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      18             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19             :     GNU General Public License for more details.
      20             : 
      21             :     You should have received a copy of the GNU General Public License
      22             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      23             : */
      24             : 
      25             : #include <errno.h>
      26             : #include <sys/time.h>
      27             : 
      28             : #include <sys/types.h>
      29             : #include <sys/wait.h>
      30             : #include <pwd.h>
      31             : #include <sys/stat.h>
      32             : 
      33             : #include <security/pam_modules.h>
      34             : 
      35             : #include "util/util.h"
      36             : #include "util/find_uid.h"
      37             : #include "util/auth_utils.h"
      38             : #include "db/sysdb.h"
      39             : #include "util/sss_utf8.h"
      40             : #include "util/child_common.h"
      41             : #include "providers/krb5/krb5_auth.h"
      42             : #include "providers/krb5/krb5_utils.h"
      43             : #include "providers/krb5/krb5_ccache.h"
      44             : 
      45           0 : static int krb5_mod_ccname(TALLOC_CTX *mem_ctx,
      46             :                            struct sysdb_ctx *sysdb,
      47             :                            struct sss_domain_info *domain,
      48             :                            const char *name,
      49             :                            const char *ccname,
      50             :                            int mod_op)
      51             : {
      52             :     TALLOC_CTX *tmpctx;
      53             :     struct sysdb_attrs *attrs;
      54             :     int ret;
      55             :     errno_t sret;
      56           0 :     bool in_transaction = false;
      57             : 
      58           0 :     if (name == NULL || ccname == NULL) {
      59           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Missing user or ccache name.\n");
      60           0 :         return EINVAL;
      61             :     }
      62             : 
      63           0 :     if (mod_op != SYSDB_MOD_REP && mod_op != SYSDB_MOD_DEL) {
      64           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported operation [%d].\n", mod_op);
      65           0 :         return EINVAL;
      66             :     }
      67             : 
      68           0 :     DEBUG(SSSDBG_TRACE_ALL, "%s ccname [%s] for user [%s].\n",
      69             :               mod_op == SYSDB_MOD_REP ? "Save" : "Delete", ccname, name);
      70             : 
      71           0 :     tmpctx = talloc_new(mem_ctx);
      72           0 :     if (!tmpctx) {
      73           0 :         return ENOMEM;
      74             :     }
      75             : 
      76           0 :     attrs = sysdb_new_attrs(tmpctx);
      77           0 :     if (!attrs) {
      78           0 :         ret = ENOMEM;
      79           0 :         goto done;
      80             :     }
      81             : 
      82           0 :     ret = sysdb_attrs_add_string(attrs, SYSDB_CCACHE_FILE, ccname);
      83           0 :     if (ret != EOK) {
      84           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_attrs_add_string failed.\n");
      85           0 :         goto done;
      86             :     }
      87             : 
      88           0 :     ret = sysdb_transaction_start(sysdb);
      89           0 :     if (ret != EOK) {
      90           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
      91             :               "Error %d starting transaction (%s)\n", ret, strerror(ret));
      92           0 :         goto done;
      93             :     }
      94           0 :     in_transaction = true;
      95             : 
      96           0 :     ret = sysdb_set_user_attr(domain, name, attrs, mod_op);
      97           0 :     if (ret != EOK) {
      98           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
      99           0 :         goto done;
     100             :     }
     101             : 
     102           0 :     ret = sysdb_transaction_commit(sysdb);
     103           0 :     if (ret != EOK) {
     104           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction!\n");
     105           0 :         goto done;
     106             :     }
     107           0 :     in_transaction = false;
     108             : 
     109             : done:
     110           0 :     if (in_transaction) {
     111           0 :         sret = sysdb_transaction_cancel(sysdb);
     112           0 :         if (sret != EOK) {
     113           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
     114             :         }
     115             :     }
     116           0 :     talloc_zfree(tmpctx);
     117           0 :     return ret;
     118             : }
     119             : 
     120           0 : static int krb5_save_ccname(TALLOC_CTX *mem_ctx,
     121             :                             struct sysdb_ctx *sysdb,
     122             :                             struct sss_domain_info *domain,
     123             :                             const char *name,
     124             :                             const char *ccname)
     125             : {
     126           0 :     return krb5_mod_ccname(mem_ctx, sysdb, domain, name, ccname,
     127             :                            SYSDB_MOD_REP);
     128             : }
     129             : 
     130           0 : static int krb5_delete_ccname(TALLOC_CTX *mem_ctx,
     131             :                               struct sysdb_ctx *sysdb,
     132             :                               struct sss_domain_info *domain,
     133             :                               const char *name,
     134             :                               const char *ccname)
     135             : {
     136           0 :     return krb5_mod_ccname(mem_ctx, sysdb, domain, name, ccname,
     137             :                            SYSDB_MOD_DEL);
     138             : }
     139             : 
     140           0 : static int krb5_cleanup(void *ptr)
     141             : {
     142           0 :     struct krb5child_req *kr = talloc_get_type(ptr, struct krb5child_req);
     143             : 
     144           0 :     if (kr == NULL) return EOK;
     145             : 
     146           0 :     memset(kr, 0, sizeof(struct krb5child_req));
     147             : 
     148           0 :     return EOK;
     149             : }
     150             : 
     151             : static errno_t
     152           0 : get_krb_primary(struct map_id_name_to_krb_primary *name_to_primary,
     153             :                 char *id_prov_name, bool cs, const char **_krb_primary)
     154             : {
     155             :     errno_t ret;
     156           0 :     int i = 0;
     157             : 
     158           0 :     while(name_to_primary != NULL &&
     159           0 :           name_to_primary[i].id_name != NULL &&
     160           0 :           name_to_primary[i].krb_primary != NULL) {
     161             : 
     162           0 :         if (sss_string_equal(cs, name_to_primary[i].id_name, id_prov_name)) {
     163           0 :             *_krb_primary = name_to_primary[i].krb_primary;
     164           0 :             ret = EOK;
     165           0 :             goto done;
     166             :         }
     167           0 :         i++;
     168             :     }
     169             : 
     170             :     /* Handle also the case of name_to_primary being NULL */
     171           0 :     ret = ENOENT;
     172             : 
     173             : done:
     174           0 :     return ret;
     175             : }
     176             : 
     177           0 : errno_t krb5_setup(TALLOC_CTX *mem_ctx, struct pam_data *pd,
     178             :                    struct krb5_ctx *krb5_ctx, bool cs,
     179             :                    struct krb5child_req **_krb5_req)
     180             : {
     181             :     struct krb5child_req *kr;
     182             :     const char *mapped_name;
     183             :     TALLOC_CTX *tmp_ctx;
     184             :     errno_t ret;
     185             : 
     186           0 :     tmp_ctx = talloc_new(NULL);
     187           0 :     if (tmp_ctx == NULL) {
     188           0 :         return ENOMEM;
     189             :     }
     190             : 
     191           0 :     kr = talloc_zero(tmp_ctx, struct krb5child_req);
     192           0 :     if (kr == NULL) {
     193           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
     194           0 :         ret = ENOMEM;
     195           0 :         goto done;
     196             :     }
     197           0 :     kr->is_offline = false;
     198           0 :     talloc_set_destructor((TALLOC_CTX *) kr, krb5_cleanup);
     199             : 
     200           0 :     kr->pd = pd;
     201           0 :     kr->krb5_ctx = krb5_ctx;
     202             : 
     203           0 :     ret = get_krb_primary(krb5_ctx->name_to_primary,
     204             :                           pd->user, cs, &mapped_name);
     205           0 :     if (ret == EOK) {
     206           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Setting mapped name to: %s\n", mapped_name);
     207           0 :         kr->user = mapped_name;
     208           0 :     } else if (ret == ENOENT) {
     209           0 :         DEBUG(SSSDBG_TRACE_ALL, "No mapping for: %s\n", pd->user);
     210           0 :         kr->user = pd->user;
     211             :     } else {
     212           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "get_krb_primary failed - %s:[%d]\n",
     213             :               sss_strerror(ret), ret);
     214           0 :         goto done;
     215             :     }
     216             : 
     217           0 :     ret = EOK;
     218             : 
     219             : done:
     220           0 :     if (ret == EOK) {
     221           0 :         *_krb5_req = talloc_steal(mem_ctx, kr);
     222             :     }
     223           0 :     talloc_free(tmp_ctx);
     224           0 :     return ret;
     225             : }
     226             : 
     227             : 
     228           0 : static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx,
     229             :                                   struct sss_domain_info *domain,
     230             :                                   struct confdb_ctx *cdb,
     231             :                                   struct pam_data *pd, uid_t uid,
     232             :                                   int *pam_status, int *dp_err)
     233             : {
     234           0 :     const char *password = NULL;
     235             :     errno_t ret;
     236             : 
     237           0 :     if (sss_authtok_get_type(pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) {
     238           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     239             :               "Delayed authentication is only available for password "
     240             :               "authentication (single factor).\n");
     241           0 :         return;
     242             :     }
     243             : 
     244           0 :     ret = sss_authtok_get_password(pd->authtok, &password, NULL);
     245           0 :     if (ret != EOK) {
     246           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     247             :               "Failed to get password [%d] %s\n", ret, strerror(ret));
     248           0 :         *pam_status = PAM_SYSTEM_ERR;
     249           0 :         *dp_err = DP_ERR_OK;
     250           0 :         return;
     251             :     }
     252             : 
     253           0 :     ret = sysdb_cache_auth(domain, pd->user,
     254             :                            password, cdb, true, NULL, NULL);
     255           0 :     if (ret != EOK) {
     256           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Offline authentication failed\n");
     257           0 :         *pam_status = cached_login_pam_status(ret);
     258           0 :         *dp_err = DP_ERR_OK;
     259           0 :         return;
     260             :     }
     261             : 
     262           0 :     ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, uid);
     263           0 :     if (ret != EOK) {
     264             :         /* This error is not fatal */
     265           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     266             :               "add_user_to_delayed_online_authentication failed.\n");
     267             :     }
     268           0 :     *pam_status = PAM_AUTHINFO_UNAVAIL;
     269           0 :     *dp_err = DP_ERR_OFFLINE;
     270             : }
     271             : 
     272           0 : static errno_t krb5_auth_prepare_ccache_name(struct krb5child_req *kr,
     273             :                                              struct ldb_message *user_msg,
     274             :                                              struct be_ctx *be_ctx)
     275             : {
     276             :     const char *ccname_template;
     277             : 
     278           0 :     ccname_template = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_CCNAME_TMPL);
     279             : 
     280           0 :     kr->ccname = expand_ccname_template(kr, kr, ccname_template,
     281           0 :                                         kr->krb5_ctx->illegal_path_re, true,
     282           0 :                                         be_ctx->domain->case_sensitive);
     283           0 :     if (kr->ccname == NULL) {
     284           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "expand_ccname_template failed.\n");
     285           0 :         return ENOMEM;
     286             :     }
     287             : 
     288           0 :     kr->old_ccname = ldb_msg_find_attr_as_string(user_msg,
     289             :                                                  SYSDB_CCACHE_FILE, NULL);
     290           0 :     if (kr->old_ccname == NULL) {
     291           0 :         DEBUG(SSSDBG_TRACE_LIBS,
     292             :                 "No ccache file for user [%s] found.\n", kr->pd->user);
     293             :     }
     294             : 
     295           0 :     return EOK;
     296             : }
     297             : 
     298           0 : static void krb5_auth_store_creds(struct sss_domain_info *domain,
     299             :                                   struct pam_data *pd)
     300             : {
     301           0 :     const char *password = NULL;
     302             :     const char *fa2;
     303             :     size_t password_len;
     304           0 :     size_t fa2_len = 0;
     305           0 :     int ret = EOK;
     306             : 
     307           0 :     switch(pd->cmd) {
     308             :         case SSS_CMD_RENEW:
     309             :             /* The authtok is set to the credential cache
     310             :              * during renewal. We don't want to save this
     311             :              * as the cached password.
     312             :              */
     313           0 :             break;
     314             :         case SSS_PAM_PREAUTH:
     315             :             /* There are no credentials available during pre-authentication,
     316             :              * nothing to do. */
     317           0 :             break;
     318             :         case SSS_PAM_AUTHENTICATE:
     319             :         case SSS_PAM_CHAUTHTOK_PRELIM:
     320           0 :             if (sss_authtok_get_type(pd->authtok) == SSS_AUTHTOK_TYPE_2FA) {
     321           0 :                 ret = sss_authtok_get_2fa(pd->authtok, &password, &password_len,
     322             :                                           &fa2, &fa2_len);
     323           0 :                 if (ret == EOK && password_len <
     324           0 :                                       domain->cache_credentials_min_ff_length) {
     325           0 :                     DEBUG(SSSDBG_FATAL_FAILURE,
     326             :                           "First factor is too short to be cache, "
     327             :                           "minimum length is [%u].\n",
     328             :                           domain->cache_credentials_min_ff_length);
     329           0 :                     ret = EINVAL;
     330             :                 }
     331             :             } else {
     332           0 :                 ret = sss_authtok_get_password(pd->authtok, &password, NULL);
     333             :             }
     334           0 :             break;
     335             :         case SSS_PAM_CHAUTHTOK:
     336           0 :             ret = sss_authtok_get_password(pd->newauthtok, &password, NULL);
     337           0 :             break;
     338             :         default:
     339           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
     340             :                   "unsupported PAM command [%d].\n", pd->cmd);
     341             :     }
     342             : 
     343           0 :     if (ret != EOK) {
     344           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     345             :               "Failed to get password [%d] %s\n", ret, strerror(ret));
     346             :         /* password caching failures are not fatal errors */
     347           0 :         return;
     348             :     }
     349             : 
     350           0 :     if (password == NULL) {
     351           0 :         if (pd->cmd != SSS_CMD_RENEW && pd->cmd != SSS_PAM_PREAUTH) {
     352           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
     353             :                   "password not available, offline auth may not work.\n");
     354             :             /* password caching failures are not fatal errors */
     355             :         }
     356           0 :         return;
     357             :     }
     358             : 
     359           0 :     ret = sysdb_cache_password_ex(domain, pd->user, password,
     360             :                                   sss_authtok_get_type(pd->authtok), fa2_len);
     361           0 :     if (ret) {
     362           0 :         DEBUG(SSSDBG_OP_FAILURE,
     363             :               "Failed to cache password, offline auth may not work."
     364             :                   " (%d)[%s]!?\n", ret, strerror(ret));
     365             :         /* password caching failures are not fatal errors */
     366             :     }
     367             : }
     368             : 
     369           0 : static bool is_otp_enabled(struct ldb_message *user_msg)
     370             : {
     371             :     struct ldb_message_element *el;
     372             :     size_t i;
     373             : 
     374           0 :     el = ldb_msg_find_element(user_msg, SYSDB_AUTH_TYPE);
     375           0 :     if (el == NULL) {
     376           0 :         return false;
     377             :     }
     378             : 
     379           0 :     for (i = 0; i < el->num_values; i++) {
     380           0 :         if (strcmp((const char * )el->values[i].data, "otp") == 0) {
     381           0 :             return true;
     382             :         }
     383             :     }
     384             : 
     385           0 :     return false;
     386             : }
     387             : 
     388             : /* krb5_auth request */
     389             : 
     390             : struct krb5_auth_state {
     391             :     struct tevent_context *ev;
     392             :     struct be_ctx *be_ctx;
     393             :     struct pam_data *pd;
     394             :     struct sysdb_ctx *sysdb;
     395             :     struct sss_domain_info *domain;
     396             :     struct krb5_ctx *krb5_ctx;
     397             :     struct krb5child_req *kr;
     398             : 
     399             :     bool search_kpasswd;
     400             : 
     401             :     int pam_status;
     402             :     int dp_err;
     403             : };
     404             : 
     405             : static void krb5_auth_resolve_done(struct tevent_req *subreq);
     406             : static void krb5_auth_done(struct tevent_req *subreq);
     407             : 
     408           0 : struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
     409             :                                   struct tevent_context *ev,
     410             :                                   struct be_ctx *be_ctx,
     411             :                                   struct pam_data *pd,
     412             :                                   struct krb5_ctx *krb5_ctx)
     413             : {
     414             :     const char **attrs;
     415             :     struct krb5_auth_state *state;
     416             :     struct ldb_result *res;
     417           0 :     struct krb5child_req *kr = NULL;
     418             :     const char *realm;
     419             :     struct tevent_req *req;
     420             :     struct tevent_req *subreq;
     421             :     enum sss_authtok_type authtok_type;
     422             :     int ret;
     423             :     bool otp;
     424             : 
     425           0 :     req = tevent_req_create(mem_ctx, &state, struct krb5_auth_state);
     426           0 :     if (req == NULL) {
     427           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create failed.\n");
     428           0 :         return NULL;
     429             :     }
     430             : 
     431           0 :     state->ev = ev;
     432           0 :     state->be_ctx = be_ctx;
     433           0 :     state->pd = pd;
     434           0 :     state->krb5_ctx = krb5_ctx;
     435           0 :     state->kr = NULL;
     436           0 :     state->pam_status = PAM_SYSTEM_ERR;
     437           0 :     state->dp_err = DP_ERR_FATAL;
     438             : 
     439           0 :     ret = get_domain_or_subdomain(be_ctx, pd->domain, &state->domain);
     440           0 :     if (ret != EOK) {
     441           0 :         DEBUG(SSSDBG_OP_FAILURE, "get_domain_or_subdomain failed.\n");
     442           0 :         goto done;
     443             :     }
     444             : 
     445           0 :     state->sysdb = state->domain->sysdb;
     446             : 
     447           0 :     authtok_type = sss_authtok_get_type(pd->authtok);
     448             : 
     449           0 :     switch (pd->cmd) {
     450             :         case SSS_PAM_AUTHENTICATE:
     451             :         case SSS_PAM_CHAUTHTOK:
     452           0 :             if (authtok_type != SSS_AUTHTOK_TYPE_PASSWORD
     453           0 :                     && authtok_type != SSS_AUTHTOK_TYPE_2FA) {
     454             :                 /* handle empty password gracefully */
     455           0 :                 if (authtok_type == SSS_AUTHTOK_TYPE_EMPTY) {
     456           0 :                     DEBUG(SSSDBG_CRIT_FAILURE,
     457             :                           "Illegal zero-length authtok for user [%s]\n",
     458             :                            pd->user);
     459           0 :                     state->pam_status = PAM_AUTH_ERR;
     460           0 :                     state->dp_err = DP_ERR_OK;
     461           0 :                     ret = EOK;
     462           0 :                     goto done;
     463             :                 }
     464             : 
     465           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     466             :                       "Wrong authtok type for user [%s]. " \
     467             :                        "Expected [%d], got [%d]\n", pd->user,
     468             :                           SSS_AUTHTOK_TYPE_PASSWORD,
     469             :                           authtok_type);
     470           0 :                 state->pam_status = PAM_SYSTEM_ERR;
     471           0 :                 state->dp_err = DP_ERR_FATAL;
     472           0 :                 ret = EINVAL;
     473           0 :                 goto done;
     474             :             }
     475           0 :             break;
     476             :         case SSS_PAM_CHAUTHTOK_PRELIM:
     477           0 :             if (pd->priv == 1 &&
     478             :                 authtok_type != SSS_AUTHTOK_TYPE_PASSWORD) {
     479           0 :                 DEBUG(SSSDBG_MINOR_FAILURE,
     480             :                       "Password reset by root is not supported.\n");
     481           0 :                 state->pam_status = PAM_PERM_DENIED;
     482           0 :                 state->dp_err = DP_ERR_OK;
     483           0 :                 ret = EOK;
     484           0 :                 goto done;
     485             :             }
     486           0 :             break;
     487             :         case SSS_CMD_RENEW:
     488           0 :             if (authtok_type != SSS_AUTHTOK_TYPE_CCFILE) {
     489           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     490             :                       "Wrong authtok type for user [%s]. " \
     491             :                        "Expected [%d], got [%d]\n", pd->user,
     492             :                           SSS_AUTHTOK_TYPE_CCFILE,
     493             :                           authtok_type);
     494           0 :                 state->pam_status = PAM_SYSTEM_ERR;
     495           0 :                 state->dp_err = DP_ERR_FATAL;
     496           0 :                 ret = EINVAL;
     497           0 :                 goto done;
     498             :             }
     499           0 :             break;
     500             :         case SSS_PAM_PREAUTH:
     501           0 :             break;
     502             :         default:
     503           0 :             DEBUG(SSSDBG_CONF_SETTINGS, "Unexpected pam task %d.\n", pd->cmd);
     504           0 :             state->pam_status = PAM_SYSTEM_ERR;
     505           0 :             state->dp_err = DP_ERR_FATAL;
     506           0 :             ret = EINVAL;
     507           0 :             goto done;
     508             :     }
     509             : 
     510           0 :     if (be_is_offline(be_ctx) &&
     511           0 :         (pd->cmd == SSS_PAM_CHAUTHTOK || pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM ||
     512           0 :          pd->cmd == SSS_CMD_RENEW)) {
     513           0 :         DEBUG(SSSDBG_TRACE_ALL,
     514             :               "Password changes and ticket renewal are not possible "
     515             :                   "while offline.\n");
     516           0 :         state->pam_status = PAM_AUTHINFO_UNAVAIL;
     517           0 :         state->dp_err = DP_ERR_OFFLINE;
     518           0 :         ret = EOK;
     519           0 :         goto done;
     520             :     }
     521             : 
     522           0 :     attrs = talloc_array(state, const char *, 8);
     523           0 :     if (attrs == NULL) {
     524           0 :         ret = ENOMEM;
     525           0 :         goto done;
     526             :     }
     527             : 
     528           0 :     attrs[0] = SYSDB_UPN;
     529           0 :     attrs[1] = SYSDB_HOMEDIR;
     530           0 :     attrs[2] = SYSDB_CCACHE_FILE;
     531           0 :     attrs[3] = SYSDB_UIDNUM;
     532           0 :     attrs[4] = SYSDB_GIDNUM;
     533           0 :     attrs[5] = SYSDB_CANONICAL_UPN;
     534           0 :     attrs[6] = SYSDB_AUTH_TYPE;
     535           0 :     attrs[7] = NULL;
     536             : 
     537           0 :     ret = krb5_setup(state, pd, krb5_ctx, state->domain->case_sensitive,
     538           0 :                      &state->kr);
     539           0 :     if (ret != EOK) {
     540           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "krb5_setup failed.\n");
     541           0 :         goto done;
     542             :     }
     543           0 :     kr = state->kr;
     544             : 
     545           0 :     ret = sysdb_get_user_attr_with_views(state, state->domain, state->pd->user,
     546             :                                          attrs, &res);
     547           0 :     if (ret) {
     548           0 :         DEBUG(SSSDBG_FUNC_DATA,
     549             :               "sysdb search for upn of user [%s] failed.\n", pd->user);
     550           0 :         state->pam_status = PAM_SYSTEM_ERR;
     551           0 :         state->dp_err = DP_ERR_OK;
     552           0 :         goto done;
     553             :     }
     554             : 
     555           0 :     realm = dp_opt_get_cstring(krb5_ctx->opts, KRB5_REALM);
     556           0 :     if (realm == NULL) {
     557           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Missing Kerberos realm.\n");
     558           0 :         ret = ENOENT;
     559           0 :         goto done;
     560             :     }
     561             : 
     562           0 :     switch (res->count) {
     563             :     case 0:
     564           0 :         DEBUG(SSSDBG_FUNC_DATA,
     565             :               "No attributes for user [%s] found.\n", pd->user);
     566           0 :         ret = ENOENT;
     567           0 :         goto done;
     568             :         break;
     569             : 
     570             :     case 1:
     571           0 :         ret = find_or_guess_upn(state, res->msgs[0], krb5_ctx, be_ctx->domain,
     572           0 :                                 kr->user, pd->domain, &kr->upn);
     573           0 :         if (ret != EOK) {
     574           0 :             DEBUG(SSSDBG_OP_FAILURE, "find_or_guess_upn failed.\n");
     575           0 :             goto done;
     576             :         }
     577             : 
     578           0 :         ret = compare_principal_realm(kr->upn, realm,
     579             :                                       &kr->upn_from_different_realm);
     580           0 :         if (ret != 0) {
     581           0 :             DEBUG(SSSDBG_OP_FAILURE, "compare_principal_realm failed.\n");
     582           0 :             goto done;
     583             :         }
     584             : 
     585           0 :         kr->homedir = sss_view_ldb_msg_find_attr_as_string(state->domain,
     586           0 :                                                            res->msgs[0],
     587             :                                                            SYSDB_HOMEDIR,
     588             :                                                            NULL);
     589           0 :         if (kr->homedir == NULL) {
     590           0 :             DEBUG(SSSDBG_CONF_SETTINGS,
     591             :                   "Home directory for user [%s] not known.\n", pd->user);
     592             :         }
     593             : 
     594           0 :         kr->uid = sss_view_ldb_msg_find_attr_as_uint64(state->domain,
     595           0 :                                                        res->msgs[0],
     596             :                                                        SYSDB_UIDNUM, 0);
     597           0 :         if (kr->uid == 0) {
     598           0 :             DEBUG(SSSDBG_CONF_SETTINGS,
     599             :                   "UID for user [%s] not known.\n", pd->user);
     600           0 :             ret = ENOENT;
     601           0 :             goto done;
     602             :         }
     603             : 
     604           0 :         kr->gid = sss_view_ldb_msg_find_attr_as_uint64(state->domain,
     605           0 :                                                        res->msgs[0],
     606             :                                                        SYSDB_GIDNUM, 0);
     607           0 :         if (kr->gid == 0) {
     608           0 :             DEBUG(SSSDBG_CONF_SETTINGS,
     609             :                   "GID for user [%s] not known.\n", pd->user);
     610           0 :             ret = ENOENT;
     611           0 :             goto done;
     612             :         }
     613             : 
     614           0 :         ret = krb5_auth_prepare_ccache_name(kr, res->msgs[0], state->be_ctx);
     615           0 :         if (ret != EOK) {
     616           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Cannot prepare ccache names!\n");
     617           0 :             goto done;
     618             :         }
     619           0 :         break;
     620             : 
     621             :     default:
     622           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     623             :               "User search for (%s) returned > 1 results!\n", pd->user);
     624           0 :         ret = EINVAL;
     625           0 :         goto done;
     626             :         break;
     627             :     }
     628             : 
     629           0 :     otp = is_otp_enabled(res->msgs[0]);
     630           0 :     if (pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM && otp == true) {
     631             :         /* To avoid consuming the OTP */
     632           0 :         DEBUG(SSSDBG_TRACE_FUNC,
     633             :               "Skipping password checks for OTP-enabled user\n");
     634           0 :         state->pam_status = PAM_SUCCESS;
     635           0 :         state->dp_err = DP_ERR_OK;
     636           0 :         ret = EOK;
     637           0 :         goto done;
     638             :     }
     639             : 
     640           0 :     kr->srv = NULL;
     641           0 :     kr->kpasswd_srv = NULL;
     642             : 
     643           0 :     state->search_kpasswd = false;
     644           0 :     subreq = be_resolve_server_send(state, state->ev, state->be_ctx,
     645           0 :                                     state->krb5_ctx->service->name,
     646           0 :                                     state->kr->srv == NULL ? true : false);
     647           0 :     if (!subreq) {
     648           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed resolver request.\n");
     649           0 :         ret = EIO;
     650           0 :         goto done;
     651             :     }
     652           0 :     tevent_req_set_callback(subreq, krb5_auth_resolve_done, req);
     653             : 
     654           0 :     return req;
     655             : 
     656             : done:
     657           0 :     if (ret == EOK) {
     658           0 :         tevent_req_done(req);
     659             :     } else {
     660           0 :         tevent_req_error(req, ret);
     661             :     }
     662           0 :     tevent_req_post(req, state->ev);
     663           0 :     return req;
     664             : }
     665             : 
     666           0 : static void krb5_auth_resolve_done(struct tevent_req *subreq)
     667             : {
     668           0 :     struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
     669           0 :     struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
     670           0 :     struct krb5child_req *kr = state->kr;
     671             :     int ret;
     672             : 
     673           0 :     if (!state->search_kpasswd) {
     674           0 :         ret = be_resolve_server_recv(subreq, kr, &kr->srv);
     675             :     } else {
     676           0 :         ret = be_resolve_server_recv(subreq, kr, &kr->kpasswd_srv);
     677             :     }
     678           0 :     talloc_zfree(subreq);
     679             : 
     680           0 :     if (state->search_kpasswd) {
     681           0 :         if ((ret != EOK) &&
     682           0 :             (kr->pd->cmd == SSS_PAM_CHAUTHTOK ||
     683           0 :              kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM)) {
     684             :             /* all kpasswd servers have been tried and none was found good,
     685             :              * but the kdc seems ok. Password changes are not possible but
     686             :              * authentication is. We return an PAM error here, but do not
     687             :              * mark the backend offline. */
     688           0 :             state->pam_status = PAM_AUTHTOK_LOCK_BUSY;
     689           0 :             state->dp_err = DP_ERR_OK;
     690           0 :             ret = EOK;
     691           0 :             goto done;
     692             :         }
     693             :     } else {
     694           0 :         if (ret != EOK) {
     695             :             /* all servers have been tried and none
     696             :              * was found good, setting offline,
     697             :              * but we still have to call the child to setup
     698             :              * the ccache file if we are performing auth */
     699           0 :             be_mark_dom_offline(state->domain, state->be_ctx);
     700           0 :             kr->is_offline = true;
     701             : 
     702           0 :             if (kr->pd->cmd == SSS_PAM_CHAUTHTOK ||
     703           0 :                 kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) {
     704           0 :                 DEBUG(SSSDBG_TRACE_FUNC,
     705             :                       "No KDC suitable for password change is available\n");
     706           0 :                 state->pam_status = PAM_AUTHTOK_LOCK_BUSY;
     707           0 :                 state->dp_err = DP_ERR_OK;
     708           0 :                 ret = EOK;
     709           0 :                 goto done;
     710             :             }
     711             :         } else {
     712           0 :             if (kr->krb5_ctx->kpasswd_service != NULL) {
     713           0 :                 state->search_kpasswd = true;
     714           0 :                 subreq = be_resolve_server_send(state,
     715             :                                     state->ev, state->be_ctx,
     716           0 :                                     state->krb5_ctx->kpasswd_service->name,
     717           0 :                                     kr->kpasswd_srv == NULL ? true : false);
     718           0 :                 if (subreq == NULL) {
     719           0 :                     DEBUG(SSSDBG_CRIT_FAILURE, "Resolver request failed.\n");
     720           0 :                     ret = EIO;
     721           0 :                     goto done;
     722             :                 }
     723           0 :                 tevent_req_set_callback(subreq, krb5_auth_resolve_done, req);
     724           0 :                 return;
     725             :             }
     726             :         }
     727             :     }
     728             : 
     729           0 :     if (!kr->is_offline) {
     730           0 :         kr->is_offline = be_is_offline(state->be_ctx);
     731             :     }
     732             : 
     733           0 :     if (!kr->is_offline
     734           0 :             && sss_domain_get_state(state->domain) == DOM_INACTIVE) {
     735           0 :         DEBUG(SSSDBG_TRACE_INTERNAL,
     736             :               "Subdomain %s is inactive, will proceed offline\n",
     737             :               state->domain->name);
     738           0 :         kr->is_offline = true;
     739             :     }
     740             : 
     741           0 :     if (kr->is_offline
     742           0 :             && sss_krb5_realm_has_proxy(dp_opt_get_cstring(kr->krb5_ctx->opts,
     743             :                                         KRB5_REALM))) {
     744           0 :         DEBUG(SSSDBG_TRACE_FUNC,
     745             :               "Resetting offline status, KDC proxy is in use\n");
     746           0 :         kr->is_offline = false;
     747             :     }
     748             : 
     749           0 :     subreq = handle_child_send(state, state->ev, kr);
     750           0 :     if (subreq == NULL) {
     751           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "handle_child_send failed.\n");
     752           0 :         ret = ENOMEM;
     753           0 :         goto done;
     754             :     }
     755           0 :     tevent_req_set_callback(subreq, krb5_auth_done, req);
     756           0 :     return;
     757             : 
     758             : done:
     759           0 :     if (ret == EOK) {
     760           0 :         tevent_req_done(req);
     761             :     } else {
     762           0 :         tevent_req_error(req, ret);
     763             :     }
     764             : }
     765             : 
     766           0 : static void krb5_auth_done(struct tevent_req *subreq)
     767             : {
     768           0 :     struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
     769           0 :     struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
     770           0 :     struct krb5child_req *kr = state->kr;
     771           0 :     struct pam_data *pd = state->pd;
     772             :     int ret;
     773           0 :     uint8_t *buf = NULL;
     774           0 :     ssize_t len = -1;
     775             :     struct krb5_child_response *res;
     776             :     struct fo_server *search_srv;
     777             :     krb5_deltat renew_interval_delta;
     778             :     char *renew_interval_str;
     779           0 :     time_t renew_interval_time = 0;
     780             :     bool use_enterprise_principal;
     781             : 
     782           0 :     ret = handle_child_recv(subreq, pd, &buf, &len);
     783           0 :     talloc_zfree(subreq);
     784           0 :     if (ret == ETIMEDOUT) {
     785             : 
     786           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "child timed out!\n");
     787             : 
     788           0 :         switch (pd->cmd) {
     789             :         case SSS_PAM_AUTHENTICATE:
     790             :         case SSS_CMD_RENEW:
     791           0 :             state->search_kpasswd = false;
     792           0 :             search_srv = kr->srv;
     793           0 :             break;
     794             :         case SSS_PAM_CHAUTHTOK:
     795             :         case SSS_PAM_CHAUTHTOK_PRELIM:
     796           0 :             if (state->kr->kpasswd_srv) {
     797           0 :                 state->search_kpasswd = true;
     798           0 :                 search_srv = kr->kpasswd_srv;
     799           0 :                 break;
     800             :             } else {
     801           0 :                 state->search_kpasswd = false;
     802           0 :                 search_srv = kr->srv;
     803           0 :                 break;
     804             :             }
     805             :         case SSS_PAM_PREAUTH:
     806           0 :             state->pam_status = PAM_CRED_UNAVAIL;
     807           0 :             state->dp_err = DP_ERR_OK;
     808           0 :             ret = EOK;
     809           0 :             goto done;
     810             :         default:
     811           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected PAM task\n");
     812           0 :             ret = EINVAL;
     813           0 :             goto done;
     814             :         }
     815             : 
     816           0 :         be_fo_set_port_status(state->be_ctx, state->krb5_ctx->service->name,
     817             :                               search_srv, PORT_NOT_WORKING);
     818           0 :         subreq = be_resolve_server_send(state, state->ev, state->be_ctx,
     819           0 :                                         state->krb5_ctx->service->name,
     820             :                                         search_srv == NULL ? true : false);
     821           0 :         if (subreq == NULL) {
     822           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Failed resolved request.\n");
     823           0 :             ret = ENOMEM;
     824           0 :             goto done;
     825             :         }
     826           0 :         tevent_req_set_callback(subreq, krb5_auth_resolve_done, req);
     827           0 :         return;
     828             : 
     829           0 :     } else if (ret != EOK) {
     830             : 
     831           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     832             :               "child failed (%d [%s])\n", ret, strerror(ret));
     833           0 :         goto done;
     834             :     }
     835             : 
     836             :     /* EOK */
     837             : 
     838           0 :     ret = parse_krb5_child_response(state, buf, len, pd,
     839           0 :                         state->be_ctx->domain->pwd_expiration_warning,
     840             :                         &res);
     841           0 :     if (ret) {
     842           0 :         DEBUG(SSSDBG_OP_FAILURE, "Could not parse child response [%d]: %s\n",
     843             :               ret, strerror(ret));
     844           0 :         goto done;
     845             :     }
     846             : 
     847           0 :     if (res->ccname) {
     848           0 :         kr->ccname = talloc_strdup(kr, res->ccname);
     849           0 :         if (!kr->ccname) {
     850           0 :             ret = ENOMEM;
     851           0 :             goto done;
     852             :         }
     853             :     }
     854             : 
     855           0 :     use_enterprise_principal = dp_opt_get_bool(kr->krb5_ctx->opts,
     856             :                                                KRB5_USE_ENTERPRISE_PRINCIPAL);
     857             : 
     858             :     /* Check if the cases of our upn are correct and update it if needed.
     859             :      * Fail if the upn differs by more than just the case for non-enterprise
     860             :      * principals. */
     861           0 :     if (res->correct_upn != NULL &&
     862           0 :         strcmp(kr->upn, res->correct_upn) != 0) {
     863           0 :         if (strcasecmp(kr->upn, res->correct_upn) == 0 ||
     864             :             use_enterprise_principal == true) {
     865           0 :             talloc_free(kr->upn);
     866           0 :             kr->upn = talloc_strdup(kr, res->correct_upn);
     867           0 :             if (kr->upn == NULL) {
     868           0 :                 DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
     869           0 :                 ret = ENOMEM;
     870           0 :                 goto done;
     871             :             }
     872             : 
     873           0 :             ret = check_if_cached_upn_needs_update(state->sysdb, state->domain,
     874           0 :                                                    pd->user, res->correct_upn);
     875           0 :             if (ret != EOK) {
     876           0 :                 DEBUG(SSSDBG_OP_FAILURE,
     877             :                       "check_if_cached_upn_needs_update failed.\n");
     878           0 :                 goto done;
     879             :             }
     880             :         } else {
     881           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "UPN used in the request [%s] and " \
     882             :                                         "returned UPN [%s] differ by more " \
     883             :                                         "than just the case.\n",
     884             :                                         kr->upn, res->correct_upn);
     885           0 :             ret = EINVAL;
     886           0 :             goto done;
     887             :         }
     888             :     }
     889             : 
     890             :     /* If the child request failed, but did not return an offline error code,
     891             :      * return with the status */
     892           0 :     switch (res->msg_status) {
     893             :     case ERR_OK:
     894             :         /* If the child request was successful and we run the first pass of the
     895             :          * change password request just return success. */
     896           0 :         if (pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) {
     897           0 :             state->pam_status = PAM_SUCCESS;
     898           0 :             state->dp_err = DP_ERR_OK;
     899           0 :             ret = EOK;
     900           0 :             goto done;
     901             :         }
     902           0 :         break;
     903             : 
     904             :     case ERR_NETWORK_IO:
     905           0 :         if (kr->kpasswd_srv != NULL &&
     906           0 :             (pd->cmd == SSS_PAM_CHAUTHTOK ||
     907           0 :              pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM)) {
     908             :             /* if using a dedicated kpasswd server for a chpass operation... */
     909             : 
     910           0 :             be_fo_set_port_status(state->be_ctx,
     911             :                                   state->krb5_ctx->kpasswd_service->name,
     912             :                                   kr->kpasswd_srv, PORT_NOT_WORKING);
     913             :             /* ..try to resolve next kpasswd server */
     914           0 :             state->search_kpasswd = true;
     915           0 :             subreq = be_resolve_server_send(state, state->ev, state->be_ctx,
     916           0 :                                 state->krb5_ctx->kpasswd_service->name,
     917           0 :                                 state->kr->kpasswd_srv == NULL ?  true : false);
     918           0 :             if (subreq == NULL) {
     919           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "Resolver request failed.\n");
     920           0 :                 ret = ENOMEM;
     921           0 :                 goto done;
     922             :             }
     923           0 :             tevent_req_set_callback(subreq, krb5_auth_resolve_done, req);
     924           0 :             return;
     925           0 :         } else if (kr->srv != NULL) {
     926             :             /* failed to use the KDC... */
     927           0 :             be_fo_set_port_status(state->be_ctx,
     928             :                                   state->krb5_ctx->service->name,
     929             :                                   kr->srv, PORT_NOT_WORKING);
     930             :             /* ..try to resolve next KDC */
     931           0 :             state->search_kpasswd = false;
     932           0 :             subreq = be_resolve_server_send(state, state->ev, state->be_ctx,
     933           0 :                                             state->krb5_ctx->service->name,
     934           0 :                                             kr->srv == NULL ?  true : false);
     935           0 :             if (subreq == NULL) {
     936           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "Resolver request failed.\n");
     937           0 :                 ret = ENOMEM;
     938           0 :                 goto done;
     939             :             }
     940           0 :             tevent_req_set_callback(subreq, krb5_auth_resolve_done, req);
     941           0 :             return;
     942             :         }
     943           0 :         break;
     944             : 
     945             :     case ERR_CREDS_EXPIRED_CCACHE:
     946           0 :         ret = krb5_delete_ccname(state, state->sysdb, state->domain,
     947           0 :                 pd->user, kr->old_ccname);
     948           0 :         if (ret != EOK) {
     949           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "krb5_delete_ccname failed.\n");
     950             :         }
     951             :         /* FALLTHROUGH */
     952             : 
     953             :     case ERR_CREDS_EXPIRED:
     954             :         /* If the password is expired we can safely remove the ccache from the
     955             :          * cache and disk if it is not actively used anymore. This will allow
     956             :          * to create a new random ccache if sshd with privilege separation is
     957             :          * used. */
     958           0 :         if (pd->cmd == SSS_PAM_AUTHENTICATE && !kr->active_ccache) {
     959           0 :             if (kr->old_ccname != NULL) {
     960           0 :                 ret = krb5_delete_ccname(state, state->sysdb, state->domain,
     961           0 :                                          pd->user, kr->old_ccname);
     962           0 :                 if (ret != EOK) {
     963           0 :                     DEBUG(SSSDBG_CRIT_FAILURE, "krb5_delete_ccname failed.\n");
     964             :                 }
     965             :             }
     966             :         }
     967             : 
     968           0 :         state->pam_status = PAM_NEW_AUTHTOK_REQD;
     969           0 :         state->dp_err = DP_ERR_OK;
     970           0 :         ret = EOK;
     971           0 :         goto done;
     972             : 
     973             :     case ERR_CREDS_INVALID:
     974           0 :         state->pam_status = PAM_CRED_ERR;
     975           0 :         state->dp_err = DP_ERR_OK;
     976           0 :         ret = EOK;
     977           0 :         goto done;
     978             : 
     979             :     case ERR_ACCOUNT_EXPIRED:
     980           0 :         state->pam_status = PAM_ACCT_EXPIRED;
     981           0 :         state->dp_err = DP_ERR_OK;
     982           0 :         ret = EOK;
     983           0 :         goto done;
     984             : 
     985             :     case ERR_ACCOUNT_LOCKED:
     986           0 :         state->pam_status = PAM_PERM_DENIED;
     987           0 :         state->dp_err = DP_ERR_OK;
     988           0 :         ret = EOK;
     989           0 :         goto done;
     990             : 
     991             :     case ERR_NO_CREDS:
     992           0 :         state->pam_status = PAM_CRED_UNAVAIL;
     993           0 :         state->dp_err = DP_ERR_OK;
     994           0 :         ret = EOK;
     995           0 :         goto done;
     996             : 
     997             :     case ERR_AUTH_FAILED:
     998           0 :         state->pam_status = PAM_AUTH_ERR;
     999           0 :         state->dp_err = DP_ERR_OK;
    1000           0 :         ret = EOK;
    1001           0 :         goto done;
    1002             : 
    1003             :     case ERR_CHPASS_FAILED:
    1004           0 :         state->pam_status = PAM_AUTHTOK_ERR;
    1005           0 :         state->dp_err = DP_ERR_OK;
    1006           0 :         ret = EOK;
    1007           0 :         goto done;
    1008             : 
    1009             :     default:
    1010           0 :         state->pam_status = PAM_SYSTEM_ERR;
    1011           0 :         state->dp_err = DP_ERR_OK;
    1012           0 :         ret = EOK;
    1013           0 :         goto done;
    1014             :     }
    1015             : 
    1016           0 :     if (kr->kpasswd_srv != NULL &&
    1017           0 :         (pd->cmd == SSS_PAM_CHAUTHTOK ||
    1018           0 :          pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM)) {
    1019             :         /* found a dedicated kpasswd server for a chpass operation */
    1020           0 :         be_fo_set_port_status(state->be_ctx,
    1021             :                               state->krb5_ctx->service->name,
    1022             :                               kr->kpasswd_srv, PORT_WORKING);
    1023           0 :     } else if (kr->srv != NULL) {
    1024             :         /* found a KDC */
    1025           0 :         be_fo_set_port_status(state->be_ctx, state->krb5_ctx->service->name,
    1026             :                               kr->srv, PORT_WORKING);
    1027             :     }
    1028             : 
    1029             :     /* Now only a successful authentication or password change is left.
    1030             :      *
    1031             :      * We expect that one of the messages in the received buffer contains
    1032             :      * the name of the credential cache file. */
    1033           0 :     if (kr->ccname == NULL) {
    1034           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Missing ccache name in child response.\n");
    1035           0 :         ret = EINVAL;
    1036           0 :         goto done;
    1037             :     }
    1038             : 
    1039           0 :     ret = krb5_save_ccname(state, state->sysdb, state->domain,
    1040           0 :                            pd->user, kr->ccname);
    1041           0 :     if (ret) {
    1042           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "krb5_save_ccname failed.\n");
    1043           0 :         goto done;
    1044             :     }
    1045           0 :     renew_interval_str = dp_opt_get_string(kr->krb5_ctx->opts,
    1046             :                          KRB5_RENEW_INTERVAL);
    1047           0 :     if (renew_interval_str != NULL) {
    1048           0 :         ret = krb5_string_to_deltat(renew_interval_str, &renew_interval_delta);
    1049           0 :         if (ret != EOK) {
    1050           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
    1051             :                  "Reading krb5_renew_interval failed.\n");
    1052           0 :             renew_interval_delta = 0;
    1053             :         }
    1054           0 :         renew_interval_time = renew_interval_delta;
    1055             :     }
    1056           0 :     if (res->msg_status == ERR_OK && renew_interval_time > 0 &&
    1057           0 :         (pd->cmd == SSS_PAM_AUTHENTICATE ||
    1058           0 :          pd->cmd == SSS_CMD_RENEW ||
    1059           0 :          pd->cmd == SSS_PAM_CHAUTHTOK) &&
    1060           0 :         (res->tgtt.renew_till > res->tgtt.endtime) &&
    1061           0 :         (kr->ccname != NULL)) {
    1062           0 :         DEBUG(SSSDBG_TRACE_LIBS,
    1063             :               "Adding [%s] for automatic renewal.\n", kr->ccname);
    1064           0 :         ret = add_tgt_to_renew_table(kr->krb5_ctx, kr->ccname, &(res->tgtt),
    1065           0 :                                      pd, kr->upn);
    1066           0 :         if (ret != EOK) {
    1067           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "add_tgt_to_renew_table failed, "
    1068             :                       "automatic renewal not possible.\n");
    1069             :         }
    1070             :     }
    1071             : 
    1072           0 :     if (kr->is_offline) {
    1073           0 :         if (dp_opt_get_bool(kr->krb5_ctx->opts,
    1074             :                             KRB5_STORE_PASSWORD_IF_OFFLINE)) {
    1075           0 :             krb5_auth_cache_creds(state->kr->krb5_ctx,
    1076             :                                   state->domain,
    1077           0 :                                   state->be_ctx->cdb,
    1078           0 :                                   state->pd, state->kr->uid,
    1079             :                                   &state->pam_status, &state->dp_err);
    1080             :         } else {
    1081           0 :             DEBUG(SSSDBG_CONF_SETTINGS,
    1082             :                   "Backend is marked offline, retry later!\n");
    1083           0 :             state->pam_status = PAM_AUTHINFO_UNAVAIL;
    1084           0 :             state->dp_err = DP_ERR_OFFLINE;
    1085             :         }
    1086           0 :         ret = EOK;
    1087           0 :         goto done;
    1088             :     }
    1089             : 
    1090           0 :     if (state->be_ctx->domain->cache_credentials == TRUE
    1091           0 :             && (!res->otp
    1092           0 :                 || (res->otp && sss_authtok_get_type(pd->authtok) ==
    1093             :                                                        SSS_AUTHTOK_TYPE_2FA))) {
    1094           0 :         krb5_auth_store_creds(state->domain, pd);
    1095             :     }
    1096             : 
    1097             :     /* The SSS_OTP message will prevent pam_sss from putting the entered
    1098             :      * password on the PAM stack for other modules to use. This is not needed
    1099             :      * when both factors were entered separately because here the first factor
    1100             :      * (long term password) can be passed to the other modules. */
    1101           0 :     if (res->otp == true && pd->cmd == SSS_PAM_AUTHENTICATE
    1102           0 :             && sss_authtok_get_type(pd->authtok) != SSS_AUTHTOK_TYPE_2FA) {
    1103           0 :         uint32_t otp_flag = 1;
    1104           0 :         ret = pam_add_response(pd, SSS_OTP, sizeof(uint32_t),
    1105             :                                (const uint8_t *) &otp_flag);
    1106           0 :         if (ret != EOK) {
    1107           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1108             :                   "pam_add_response failed: %d (%s).\n",
    1109             :                   ret, sss_strerror(ret));
    1110           0 :             state->pam_status = PAM_SYSTEM_ERR;
    1111           0 :             state->dp_err = DP_ERR_OK;
    1112           0 :             goto done;
    1113             :         }
    1114             :     }
    1115             : 
    1116           0 :     state->pam_status = PAM_SUCCESS;
    1117           0 :     state->dp_err = DP_ERR_OK;
    1118           0 :     ret = EOK;
    1119             : 
    1120             : done:
    1121           0 :     if (ret == EOK) {
    1122           0 :         tevent_req_done(req);
    1123             :     } else {
    1124           0 :         tevent_req_error(req, ret);
    1125             :     }
    1126             : 
    1127             : }
    1128             : 
    1129           0 : int krb5_auth_recv(struct tevent_req *req, int *pam_status, int *dp_err)
    1130             : {
    1131           0 :     struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
    1132           0 :     *pam_status = state->pam_status;
    1133           0 :     *dp_err = state->dp_err;
    1134             : 
    1135           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
    1136             : 
    1137           0 :     return EOK;
    1138             : }
    1139             : 
    1140             : struct krb5_pam_handler_state {
    1141             :     struct pam_data *pd;
    1142             : };
    1143             : 
    1144             : static void krb5_pam_handler_auth_done(struct tevent_req *subreq);
    1145             : static void krb5_pam_handler_access_done(struct tevent_req *subreq);
    1146             : 
    1147             : struct tevent_req *
    1148           0 : krb5_pam_handler_send(TALLOC_CTX *mem_ctx,
    1149             :                       struct krb5_ctx *krb5_ctx,
    1150             :                       struct pam_data *pd,
    1151             :                       struct dp_req_params *params)
    1152             : {
    1153             :     struct krb5_pam_handler_state *state;
    1154             :     struct tevent_req *subreq;
    1155             :     struct tevent_req *req;
    1156             : 
    1157           0 :     req = tevent_req_create(mem_ctx, &state,
    1158             :                             struct krb5_pam_handler_state);
    1159           0 :     if (req == NULL) {
    1160           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
    1161           0 :         return NULL;
    1162             :     }
    1163             : 
    1164           0 :     state->pd = pd;
    1165             : 
    1166           0 :     switch (pd->cmd) {
    1167             :         case SSS_PAM_AUTHENTICATE:
    1168             :         case SSS_CMD_RENEW:
    1169             :         case SSS_PAM_CHAUTHTOK_PRELIM:
    1170             :         case SSS_PAM_CHAUTHTOK:
    1171           0 :             subreq = krb5_auth_queue_send(state, params->ev, params->be_ctx,
    1172             :                                           pd, krb5_ctx);
    1173           0 :             if (subreq == NULL) {
    1174           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "krb5_auth_send failed.\n");
    1175           0 :                 pd->pam_status = PAM_SYSTEM_ERR;
    1176           0 :                 goto immediately;
    1177             :             }
    1178             : 
    1179           0 :             tevent_req_set_callback(subreq, krb5_pam_handler_auth_done, req);
    1180           0 :             break;
    1181             :         case SSS_PAM_ACCT_MGMT:
    1182           0 :             subreq = krb5_access_send(state, params->ev, params->be_ctx,
    1183             :                                       pd, krb5_ctx);
    1184           0 :             if (subreq == NULL) {
    1185           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "krb5_access_send failed.\n");
    1186           0 :                 pd->pam_status = PAM_SYSTEM_ERR;
    1187           0 :                 goto immediately;
    1188             :             }
    1189             : 
    1190           0 :             tevent_req_set_callback(subreq, krb5_pam_handler_access_done, req);
    1191           0 :             break;
    1192             :         case SSS_PAM_SETCRED:
    1193             :         case SSS_PAM_OPEN_SESSION:
    1194             :         case SSS_PAM_CLOSE_SESSION:
    1195           0 :             pd->pam_status = PAM_SUCCESS;
    1196           0 :             goto immediately;
    1197             :             break;
    1198             :         default:
    1199           0 :             DEBUG(SSSDBG_CONF_SETTINGS,
    1200             :                   "krb5 does not handles pam task %d.\n", pd->cmd);
    1201           0 :             pd->pam_status = PAM_MODULE_UNKNOWN;
    1202           0 :             goto immediately;
    1203             :     }
    1204             : 
    1205           0 :     return req;
    1206             : 
    1207             : immediately:
    1208             :     /* TODO For backward compatibility we always return EOK to DP now. */
    1209           0 :     tevent_req_done(req);
    1210           0 :     tevent_req_post(req, params->ev);
    1211             : 
    1212           0 :     return req;
    1213             : }
    1214             : 
    1215           0 : static void krb5_pam_handler_auth_done(struct tevent_req *subreq)
    1216             : {
    1217             :     struct krb5_pam_handler_state *state;
    1218             :     struct tevent_req *req;
    1219             :     errno_t ret;
    1220             : 
    1221           0 :     req = tevent_req_callback_data(subreq, struct tevent_req);
    1222           0 :     state = tevent_req_data(req, struct krb5_pam_handler_state);
    1223             : 
    1224           0 :     ret = krb5_auth_queue_recv(subreq, &state->pd->pam_status, NULL);
    1225           0 :     talloc_zfree(subreq);
    1226           0 :     if (ret != EOK) {
    1227           0 :         state->pd->pam_status = PAM_SYSTEM_ERR;
    1228             :     }
    1229             : 
    1230             :     /* TODO For backward compatibility we always return EOK to DP now. */
    1231           0 :     tevent_req_done(req);
    1232           0 : }
    1233             : 
    1234           0 : static void krb5_pam_handler_access_done(struct tevent_req *subreq)
    1235             : {
    1236             :     struct krb5_pam_handler_state *state;
    1237             :     struct tevent_req *req;
    1238             :     bool access_allowed;
    1239             :     errno_t ret;
    1240             : 
    1241           0 :     req = tevent_req_callback_data(subreq, struct tevent_req);
    1242           0 :     state = tevent_req_data(req, struct krb5_pam_handler_state);
    1243             : 
    1244           0 :     ret = krb5_access_recv(subreq, &access_allowed);
    1245           0 :     talloc_zfree(subreq);
    1246           0 :     if (ret != EOK) {
    1247           0 :         state->pd->pam_status = PAM_SYSTEM_ERR;
    1248             :     }
    1249             : 
    1250             : 
    1251           0 :     DEBUG(SSSDBG_TRACE_LIBS, "Access %s for user [%s].\n",
    1252             :           access_allowed ? "allowed" : "denied", state->pd->user);
    1253           0 :     state->pd->pam_status = access_allowed ? PAM_SUCCESS : PAM_PERM_DENIED;
    1254             : 
    1255             :     /* TODO For backward compatibility we always return EOK to DP now. */
    1256           0 :     tevent_req_done(req);
    1257           0 : }
    1258             : 
    1259             : errno_t
    1260           0 : krb5_pam_handler_recv(TALLOC_CTX *mem_ctx,
    1261             :                       struct tevent_req *req,
    1262             :                       struct pam_data **_data)
    1263             : {
    1264           0 :     struct krb5_pam_handler_state *state = NULL;
    1265             : 
    1266           0 :     state = tevent_req_data(req, struct krb5_pam_handler_state);
    1267             : 
    1268           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
    1269             : 
    1270           0 :     *_data = talloc_steal(mem_ctx, state->pd);
    1271             : 
    1272           0 :     return EOK;
    1273             : }

Generated by: LCOV version 1.10