LCOV - code coverage report
Current view: top level - providers/ldap - ldap_auth.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 20 620 3.2 %
Date: 2015-10-19 Functions: 2 24 8.3 %

          Line data    Source code
       1             : /*
       2             :     SSSD
       3             : 
       4             :     LDAP Backend Module
       5             : 
       6             :     Authors:
       7             :         Sumit Bose <sbose@redhat.com>
       8             : 
       9             :     Copyright (C) 2008 Red Hat
      10             :     Copyright (C) 2010, rhafer@suse.de, Novell Inc.
      11             : 
      12             :     This program is free software; you can redistribute it and/or modify
      13             :     it under the terms of the GNU General Public License as published by
      14             :     the Free Software Foundation; either version 3 of the License, or
      15             :     (at your option) any later version.
      16             : 
      17             :     This program is distributed in the hope that it will be useful,
      18             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      19             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      20             :     GNU General Public License for more details.
      21             : 
      22             :     You should have received a copy of the GNU General Public License
      23             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      24             : */
      25             : 
      26             : #ifdef WITH_MOZLDAP
      27             : #define LDAP_OPT_SUCCESS LDAP_SUCCESS
      28             : #define LDAP_TAG_EXOP_MODIFY_PASSWD_ID  ((ber_tag_t) 0x80U)
      29             : #define LDAP_TAG_EXOP_MODIFY_PASSWD_OLD ((ber_tag_t) 0x81U)
      30             : #define LDAP_TAG_EXOP_MODIFY_PASSWD_NEW ((ber_tag_t) 0x82U)
      31             : #endif
      32             : 
      33             : #include "config.h"
      34             : 
      35             : #include <time.h>
      36             : #include <errno.h>
      37             : #include <sys/time.h>
      38             : #include <strings.h>
      39             : 
      40             : #include <shadow.h>
      41             : #include <security/pam_modules.h>
      42             : 
      43             : #include "util/util.h"
      44             : #include "util/user_info_msg.h"
      45             : #include "db/sysdb.h"
      46             : #include "providers/ldap/ldap_common.h"
      47             : #include "providers/ldap/sdap_async.h"
      48             : #include "providers/ldap/sdap_async_private.h"
      49             : #include "providers/ldap/ldap_auth.h"
      50             : #include "providers/ldap/sdap_access.h"
      51             : 
      52             : #define LDAP_PWEXPIRE_WARNING_TIME 0
      53             : 
      54           0 : static errno_t add_expired_warning(struct pam_data *pd, long exp_time)
      55             : {
      56             :     int ret;
      57             :     uint32_t *data;
      58             : 
      59           0 :     if (exp_time < 0 || exp_time > UINT32_MAX) {
      60           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Time to expire out of range.\n");
      61           0 :         return EINVAL;
      62             :     }
      63             : 
      64           0 :     data = talloc_array(pd, uint32_t, 2);
      65           0 :     if (data == NULL) {
      66           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
      67           0 :         return ENOMEM;
      68             :     }
      69             : 
      70           0 :     data[0] = SSS_PAM_USER_INFO_EXPIRE_WARN;
      71           0 :     data[1] = (uint32_t) exp_time;
      72             : 
      73           0 :     ret = pam_add_response(pd, SSS_PAM_USER_INFO, 2 * sizeof(uint32_t),
      74             :                            (uint8_t *) data);
      75           0 :     if (ret != EOK) {
      76           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
      77             :     }
      78             : 
      79           0 :     return EOK;
      80             : }
      81             : 
      82           6 : static errno_t check_pwexpire_kerberos(const char *expire_date, time_t now,
      83             :                                        struct pam_data *pd,
      84             :                                        int pwd_exp_warning)
      85             : {
      86             :     time_t expire_time;
      87             :     int expiration_warning;
      88           6 :     int ret = ERR_INTERNAL;
      89             : 
      90           6 :     ret = sss_utc_to_time_t(expire_date, "%Y%m%d%H%M%SZ",
      91             :                             &expire_time);
      92           6 :     if (ret != EOK) {
      93           2 :         DEBUG(SSSDBG_MINOR_FAILURE, "sss_utc_to_time_t failed with %d:%s.\n",
      94             :               ret, sss_strerror(ret));
      95           2 :         return ret;
      96             :     }
      97             : 
      98           4 :     DEBUG(SSSDBG_TRACE_ALL,
      99             :           "Time info: tzname[0] [%s] tzname[1] [%s] timezone [%ld] "
     100             :            "daylight [%d] now [%ld] expire_time [%ld].\n", tzname[0],
     101             :            tzname[1], timezone, daylight, now, expire_time);
     102             : 
     103           4 :     if (difftime(now, expire_time) > 0.0) {
     104           2 :         DEBUG(SSSDBG_CONF_SETTINGS, "Kerberos password expired.\n");
     105           2 :         ret = ERR_PASSWORD_EXPIRED;
     106             :     } else {
     107           2 :         if (pwd_exp_warning >= 0) {
     108           2 :             expiration_warning = pwd_exp_warning;
     109             :         } else {
     110           0 :             expiration_warning = KERBEROS_PWEXPIRE_WARNING_TIME;
     111             :         }
     112           2 :         if (pd != NULL &&
     113           0 :             (difftime(now + expiration_warning, expire_time) > 0.0 ||
     114             :             expiration_warning == 0)) {
     115           0 :             ret = add_expired_warning(pd, (long) difftime(expire_time, now));
     116           0 :             if (ret != EOK) {
     117           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "add_expired_warning failed.\n");
     118             :             }
     119             :         }
     120           2 :         ret = EOK;
     121             :     }
     122             : 
     123           4 :     return ret;
     124             : }
     125             : 
     126           0 : static errno_t check_pwexpire_shadow(struct spwd *spwd, time_t now,
     127             :                                      struct pam_data *pd)
     128             : {
     129             :     long today;
     130             :     long password_age;
     131             :     long exp;
     132             :     int ret;
     133             : 
     134           0 :     if (spwd->sp_lstchg <= 0) {
     135           0 :         DEBUG(SSSDBG_CONF_SETTINGS,
     136             :               "Last change day is not set, new password needed.\n");
     137           0 :         return ERR_PASSWORD_EXPIRED;
     138             :     }
     139             : 
     140           0 :     today = (long) (now / (60 * 60 *24));
     141           0 :     password_age = today - spwd->sp_lstchg;
     142           0 :     if (password_age < 0) {
     143           0 :         DEBUG(SSSDBG_OP_FAILURE,
     144             :               "The last password change time is in the future!.\n");
     145           0 :         return EOK;
     146             :     }
     147             : 
     148           0 :     if ((spwd->sp_expire != -1 && today > spwd->sp_expire) ||
     149           0 :         (spwd->sp_max != -1 && spwd->sp_inact != -1 &&
     150           0 :          password_age > spwd->sp_max + spwd->sp_inact))
     151             :     {
     152           0 :         DEBUG(SSSDBG_CONF_SETTINGS, "Account expired.\n");
     153           0 :         return ERR_ACCOUNT_EXPIRED;
     154             :     }
     155             : 
     156           0 :     if (spwd->sp_max != -1 && password_age > spwd->sp_max) {
     157           0 :         DEBUG(SSSDBG_CONF_SETTINGS, "Password expired.\n");
     158           0 :         return ERR_PASSWORD_EXPIRED;
     159             :     }
     160             : 
     161           0 :     if (pd != NULL && spwd->sp_max != -1 && spwd->sp_warn != -1 &&
     162           0 :         password_age > spwd->sp_max - spwd->sp_warn ) {
     163             : 
     164             :         /* add_expired_warning() expects time in seconds */
     165           0 :         exp = (spwd->sp_max - password_age) * (60 * 60 * 24);
     166           0 :         if (exp == 0) {
     167             :             /* Seconds until next midnight */
     168           0 :             exp = ((today + 1) * (60 * 60 * 24)) - now;
     169             :         }
     170             : 
     171           0 :         ret = add_expired_warning(pd, exp);
     172           0 :         if (ret != EOK) {
     173           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "add_expired_warning failed.\n");
     174             :         }
     175             :     }
     176             : 
     177           0 :     return EOK;
     178             : }
     179             : 
     180           0 : static errno_t check_pwexpire_ldap(struct pam_data *pd,
     181             :                                    struct sdap_ppolicy_data *ppolicy,
     182             :                                    int pwd_exp_warning)
     183             : {
     184           0 :     int ret = EOK;
     185             : 
     186           0 :     if (ppolicy->grace >= 0 || ppolicy->expire > 0) {
     187             :         uint32_t *data;
     188             :         uint32_t *ptr;
     189             : 
     190           0 :         if (pwd_exp_warning < 0) {
     191           0 :             pwd_exp_warning = 0;
     192             :         }
     193             : 
     194           0 :         data = talloc_size(pd, 2* sizeof(uint32_t));
     195           0 :         if (data == NULL) {
     196           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
     197           0 :             return ENOMEM;
     198             :         }
     199             : 
     200           0 :         ptr = data;
     201           0 :         if (ppolicy->grace >= 0) {
     202           0 :             *ptr = SSS_PAM_USER_INFO_GRACE_LOGIN;
     203           0 :             ptr++;
     204           0 :             *ptr = ppolicy->grace;
     205           0 :         } else if (ppolicy->expire > 0) {
     206           0 :             if (pwd_exp_warning != 0 && ppolicy->expire > pwd_exp_warning) {
     207             :                 /* do not warn */
     208           0 :                 goto done;
     209             :             }
     210             : 
     211             :             /* send warning */
     212           0 :             *ptr = SSS_PAM_USER_INFO_EXPIRE_WARN;
     213           0 :             ptr++;
     214           0 :             *ptr = ppolicy->expire;
     215             :         }
     216             : 
     217           0 :         ret = pam_add_response(pd, SSS_PAM_USER_INFO, 2* sizeof(uint32_t),
     218             :                                (uint8_t*)data);
     219           0 :         if (ret != EOK) {
     220           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
     221             :         }
     222             :     }
     223             : 
     224             : done:
     225           0 :     return ret;
     226             : }
     227             : 
     228           6 : errno_t check_pwexpire_policy(enum pwexpire pw_expire_type,
     229             :                               void *pw_expire_data,
     230             :                               struct pam_data *pd,
     231             :                               int pwd_expiration_warning)
     232             : {
     233             :     errno_t ret;
     234             : 
     235           6 :     switch (pw_expire_type) {
     236             :     case PWEXPIRE_SHADOW:
     237           0 :         ret = check_pwexpire_shadow(pw_expire_data, time(NULL), pd);
     238           0 :         break;
     239             :     case PWEXPIRE_KERBEROS:
     240           6 :         ret = check_pwexpire_kerberos(pw_expire_data, time(NULL), pd,
     241             :                                       pwd_expiration_warning);
     242           6 :         break;
     243             :     case PWEXPIRE_LDAP_PASSWORD_POLICY:
     244           0 :         ret = check_pwexpire_ldap(pd, pw_expire_data,
     245             :                                   pwd_expiration_warning);
     246           0 :         break;
     247             :     case PWEXPIRE_NONE:
     248           0 :         ret = EOK;
     249           0 :         break;
     250             :     default:
     251           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Unknown password expiration type.\n");
     252           0 :         ret = EINVAL;
     253             :     }
     254             : 
     255           6 :     return ret;
     256             : }
     257             : 
     258             : static errno_t
     259           0 : find_password_expiration_attributes(TALLOC_CTX *mem_ctx,
     260             :                                     const struct ldb_message *msg,
     261             :                                     struct dp_option *opts,
     262             :                                     enum pwexpire *type, void **data)
     263             : {
     264             :     const char *mark;
     265             :     const char *val;
     266             :     struct spwd *spwd;
     267             :     const char *pwd_policy;
     268             :     int ret;
     269             : 
     270           0 :     *type = PWEXPIRE_NONE;
     271           0 :     *data = NULL;
     272             : 
     273           0 :     pwd_policy = dp_opt_get_string(opts, SDAP_PWD_POLICY);
     274           0 :     if (pwd_policy == NULL) {
     275           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Missing password policy.\n");
     276           0 :         return EINVAL;
     277             :     }
     278             : 
     279           0 :     if (strcasecmp(pwd_policy, PWD_POL_OPT_NONE) == 0) {
     280           0 :         DEBUG(SSSDBG_TRACE_ALL, "No password policy requested.\n");
     281           0 :         return EOK;
     282           0 :     } else if (strcasecmp(pwd_policy, PWD_POL_OPT_MIT) == 0) {
     283           0 :         mark = ldb_msg_find_attr_as_string(msg, SYSDB_KRBPW_LASTCHANGE, NULL);
     284           0 :         if (mark != NULL) {
     285           0 :             DEBUG(SSSDBG_TRACE_ALL,
     286             :                   "Found Kerberos password expiration attributes.\n");
     287           0 :             val = ldb_msg_find_attr_as_string(msg, SYSDB_KRBPW_EXPIRATION,
     288             :                                               NULL);
     289           0 :             if (val != NULL) {
     290           0 :                 *data = talloc_strdup(mem_ctx, val);
     291           0 :                 if (*data == NULL) {
     292           0 :                     DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n");
     293           0 :                     return ENOMEM;
     294             :                 }
     295           0 :                 *type = PWEXPIRE_KERBEROS;
     296             : 
     297           0 :                 return EOK;
     298             :             }
     299             :         } else {
     300           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     301             :                   "No Kerberos password expiration attributes found, "
     302             :                       "but MIT Kerberos password policy was requested. "
     303             :                       "Access will be denied.\n");
     304           0 :             return EACCES;
     305             :         }
     306           0 :     } else if (strcasecmp(pwd_policy, PWD_POL_OPT_SHADOW) == 0) {
     307           0 :         mark = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_LASTCHANGE, NULL);
     308           0 :         if (mark != NULL) {
     309           0 :             DEBUG(SSSDBG_TRACE_ALL,
     310             :                   "Found shadow password expiration attributes.\n");
     311           0 :             spwd = talloc_zero(mem_ctx, struct spwd);
     312           0 :             if (spwd == NULL) {
     313           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
     314           0 :                 return ENOMEM;
     315             :             }
     316             : 
     317           0 :             val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_LASTCHANGE, NULL);
     318           0 :             ret = string_to_shadowpw_days(val, &spwd->sp_lstchg);
     319           0 :             if (ret != EOK) goto shadow_fail;
     320             : 
     321           0 :             val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_MIN, NULL);
     322           0 :             ret = string_to_shadowpw_days(val, &spwd->sp_min);
     323           0 :             if (ret != EOK) goto shadow_fail;
     324             : 
     325           0 :             val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_MAX, NULL);
     326           0 :             ret = string_to_shadowpw_days(val, &spwd->sp_max);
     327           0 :             if (ret != EOK) goto shadow_fail;
     328             : 
     329           0 :             val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_WARNING, NULL);
     330           0 :             ret = string_to_shadowpw_days(val, &spwd->sp_warn);
     331           0 :             if (ret != EOK) goto shadow_fail;
     332             : 
     333           0 :             val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_INACTIVE, NULL);
     334           0 :             ret = string_to_shadowpw_days(val, &spwd->sp_inact);
     335           0 :             if (ret != EOK) goto shadow_fail;
     336             : 
     337           0 :             val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_EXPIRE, NULL);
     338           0 :             ret = string_to_shadowpw_days(val, &spwd->sp_expire);
     339           0 :             if (ret != EOK) goto shadow_fail;
     340             : 
     341           0 :             *data = spwd;
     342           0 :             *type = PWEXPIRE_SHADOW;
     343             : 
     344           0 :             return EOK;
     345             :         } else {
     346           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "No shadow password attributes found, "
     347             :                       "but shadow password policy was requested. "
     348             :                       "Access will be denied.\n");
     349           0 :             return EACCES;
     350             :         }
     351             :     }
     352             : 
     353           0 :     DEBUG(SSSDBG_TRACE_ALL, "No password expiration attributes found.\n");
     354           0 :     return EOK;
     355             : 
     356             : shadow_fail:
     357           0 :         talloc_free(spwd);
     358           0 :         return ret;
     359             : }
     360             : 
     361             : /* ==Get-User-DN========================================================== */
     362             : struct get_user_dn_state {
     363             :     const char *username;
     364             : 
     365             :     char *orig_dn;
     366             : };
     367             : 
     368             : static void get_user_dn_done(struct tevent_req *subreq);
     369             : 
     370           0 : static struct tevent_req *get_user_dn_send(TALLOC_CTX *memctx,
     371             :                                            struct tevent_context *ev,
     372             :                                            struct sss_domain_info *domain,
     373             :                                            struct sdap_handle *sh,
     374             :                                            struct sdap_options *opts,
     375             :                                            const char *username)
     376             : {
     377             :     struct tevent_req *req;
     378             :     struct tevent_req *subreq;
     379             :     struct get_user_dn_state *state;
     380             :     char *clean_name;
     381             :     char *filter;
     382             :     const char **attrs;
     383             :     errno_t ret;
     384             : 
     385           0 :     req = tevent_req_create(memctx, &state, struct get_user_dn_state);
     386           0 :     if (!req) return NULL;
     387             : 
     388           0 :     state->username = username;
     389             : 
     390           0 :     ret = sss_filter_sanitize(state, username, &clean_name);
     391           0 :     if (ret != EOK) {
     392           0 :         goto done;
     393             :     }
     394             : 
     395           0 :     filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",
     396           0 :                              opts->user_map[SDAP_AT_USER_NAME].name,
     397             :                              clean_name,
     398           0 :                              opts->user_map[SDAP_OC_USER].name);
     399           0 :     talloc_zfree(clean_name);
     400           0 :     if (filter == NULL) {
     401           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to build the base filter\n");
     402           0 :         ret = ENOMEM;
     403           0 :         goto done;
     404             :     }
     405             : 
     406             :     /* We're mostly interested in the DN anyway */
     407           0 :     attrs = talloc_array(state, const char *, 3);
     408           0 :     if (attrs == NULL) {
     409           0 :         ret = ENOMEM;
     410           0 :         goto done;
     411             :     }
     412           0 :     attrs[0] = "objectclass";
     413           0 :     attrs[1] = opts->user_map[SDAP_AT_USER_NAME].name;
     414           0 :     attrs[2] = NULL;
     415             : 
     416           0 :     subreq = sdap_search_user_send(state, ev, domain, opts,
     417           0 :                                    opts->sdom->user_search_bases,
     418             :                                    sh, attrs, filter,
     419             :                                    dp_opt_get_int(opts->basic,
     420             :                                                   SDAP_SEARCH_TIMEOUT),
     421             :                                    SDAP_LOOKUP_SINGLE);
     422           0 :     if (!subreq) {
     423           0 :         ret = ENOMEM;
     424           0 :         goto done;
     425             :     }
     426           0 :     tevent_req_set_callback(subreq, get_user_dn_done, req);
     427           0 :     return req;
     428             : 
     429             : done:
     430           0 :     if (ret == EOK) {
     431           0 :         tevent_req_done(req);
     432             :     } else {
     433           0 :         tevent_req_error(req, ret);
     434             :     }
     435           0 :     tevent_req_post(req, ev);
     436           0 :     return req;
     437             : }
     438             : 
     439           0 : static void get_user_dn_done(struct tevent_req *subreq)
     440             : {
     441             :     errno_t ret;
     442           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     443             :                                                       struct tevent_req);
     444           0 :     struct get_user_dn_state *state = tevent_req_data(req,
     445             :                                                     struct get_user_dn_state);
     446             :     struct ldb_message_element *el;
     447             :     struct sysdb_attrs **users;
     448             :     size_t count;
     449             : 
     450           0 :     ret = sdap_search_user_recv(state, subreq, NULL, &users, &count);
     451           0 :     talloc_zfree(subreq);
     452           0 :     if (ret && ret != ENOENT) {
     453           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to retrieve users\n");
     454           0 :         tevent_req_error(req, ret);
     455           0 :         return;
     456             :     }
     457             : 
     458           0 :     if (count == 0) {
     459           0 :         DEBUG(SSSDBG_OP_FAILURE, "No such user\n");
     460           0 :         tevent_req_error(req, ENOMEM);
     461           0 :         return;
     462           0 :     } else if (count > 1) {
     463           0 :         DEBUG(SSSDBG_OP_FAILURE, "Multiple users matched\n");
     464           0 :         tevent_req_error(req, EIO);
     465           0 :         return;
     466             :     }
     467             : 
     468             :     /* exactly one user. Get the originalDN */
     469           0 :     ret = sysdb_attrs_get_el_ext(users[0], SYSDB_ORIG_DN, false, &el);
     470           0 :     if (ret != EOK) {
     471           0 :         DEBUG(SSSDBG_OP_FAILURE,
     472             :               "originalDN is not available for [%s].\n", state->username);
     473           0 :         tevent_req_error(req, ret);
     474           0 :         return;
     475             :     }
     476             : 
     477           0 :     state->orig_dn = talloc_strdup(state, (const char *) el->values[0].data);
     478           0 :     if (state->orig_dn == NULL) {
     479           0 :         tevent_req_error(req, ENOMEM);
     480           0 :         return;
     481             :     }
     482             : 
     483           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "Found originalDN [%s] for [%s]\n",
     484             :           state->orig_dn, state->username);
     485           0 :     tevent_req_done(req);
     486             : }
     487             : 
     488           0 : static int get_user_dn_recv(TALLOC_CTX *mem_ctx, struct tevent_req *req,
     489             :                             char **orig_dn)
     490             : {
     491           0 :     struct get_user_dn_state *state = tevent_req_data(req,
     492             :                                                     struct get_user_dn_state);
     493             : 
     494           0 :     if (orig_dn) {
     495           0 :         *orig_dn = talloc_move(mem_ctx, &state->orig_dn);
     496             :     }
     497             : 
     498           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     499             : 
     500           0 :     return EOK;
     501             : }
     502             : 
     503           0 : int get_user_dn(TALLOC_CTX *memctx,
     504             :                        struct sss_domain_info *domain,
     505             :                        struct sdap_options *opts,
     506             :                        const char *username,
     507             :                        char **user_dn,
     508             :                        enum pwexpire *user_pw_expire_type,
     509             :                        void **user_pw_expire_data)
     510             : {
     511             :     TALLOC_CTX *tmpctx;
     512             :     enum pwexpire pw_expire_type;
     513             :     void *pw_expire_data;
     514             :     struct ldb_result *res;
     515             :     const char **attrs;
     516             :     const char *dn;
     517             :     int ret;
     518             : 
     519           0 :     tmpctx = talloc_new(memctx);
     520           0 :     if (!tmpctx) {
     521           0 :         return ENOMEM;
     522             :     }
     523             : 
     524           0 :     attrs = talloc_array(tmpctx, const char *, 11);
     525           0 :     if (!attrs) {
     526           0 :         ret = ENOMEM;
     527           0 :         goto done;
     528             :     }
     529             : 
     530           0 :     attrs[0] = SYSDB_ORIG_DN;
     531           0 :     attrs[1] = SYSDB_SHADOWPW_LASTCHANGE;
     532           0 :     attrs[2] = SYSDB_SHADOWPW_MIN;
     533           0 :     attrs[3] = SYSDB_SHADOWPW_MAX;
     534           0 :     attrs[4] = SYSDB_SHADOWPW_WARNING;
     535           0 :     attrs[5] = SYSDB_SHADOWPW_INACTIVE;
     536           0 :     attrs[6] = SYSDB_SHADOWPW_EXPIRE;
     537           0 :     attrs[7] = SYSDB_KRBPW_LASTCHANGE;
     538           0 :     attrs[8] = SYSDB_KRBPW_EXPIRATION;
     539           0 :     attrs[9] = SYSDB_PWD_ATTRIBUTE;
     540           0 :     attrs[10] = NULL;
     541             : 
     542           0 :     ret = sysdb_get_user_attr(tmpctx, domain, username, attrs, &res);
     543           0 :     if (ret) {
     544           0 :         goto done;
     545             :     }
     546             : 
     547           0 :     switch (res->count) {
     548             :     case 0:
     549             :         /* No such user entry? Look it up */
     550           0 :         ret = EAGAIN;
     551           0 :         break;
     552             : 
     553             :     case 1:
     554           0 :         dn = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_ORIG_DN, NULL);
     555           0 :         if (dn == NULL) {
     556             :             /* The user entry has no original DN. This is the case when the ID
     557             :              * provider is not LDAP-based (proxy perhaps) */
     558           0 :             ret = EAGAIN;
     559           0 :             break;
     560             :         }
     561             : 
     562           0 :         dn = talloc_strdup(tmpctx, dn);
     563           0 :         if (!dn) {
     564           0 :             ret = ENOMEM;
     565           0 :             break;
     566             :         }
     567             : 
     568           0 :         ret = find_password_expiration_attributes(tmpctx,
     569           0 :                                                   res->msgs[0],
     570             :                                                   opts->basic,
     571             :                                                   &pw_expire_type,
     572             :                                                   &pw_expire_data);
     573           0 :         if (ret != EOK) {
     574           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     575             :                   "find_password_expiration_attributes failed.\n");
     576             :         }
     577           0 :         break;
     578             : 
     579             :     default:
     580           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     581             :               "User search by name (%s) returned > 1 results!\n",
     582             :                   username);
     583           0 :         ret = EFAULT;
     584           0 :         break;
     585             :     }
     586             : 
     587             : done:
     588           0 :     if (ret == EOK) {
     589           0 :         *user_dn = talloc_strdup(memctx, dn);
     590           0 :         if (!*user_dn) {
     591           0 :             ret = ENOMEM;
     592             :         }
     593             :         /* pw_expire_data may be NULL */
     594           0 :         *user_pw_expire_data = talloc_steal(memctx, pw_expire_data);
     595           0 :         *user_pw_expire_type = pw_expire_type;
     596             :     }
     597             : 
     598           0 :     talloc_zfree(tmpctx);
     599           0 :     return ret;
     600             : }
     601             : 
     602             : /* ==Authenticate-User==================================================== */
     603             : 
     604             : struct auth_state {
     605             :     struct tevent_context *ev;
     606             :     struct sdap_auth_ctx *ctx;
     607             :     const char *username;
     608             :     struct sss_auth_token *authtok;
     609             :     struct sdap_service *sdap_service;
     610             : 
     611             :     struct sdap_handle *sh;
     612             : 
     613             :     char *dn;
     614             :     enum pwexpire pw_expire_type;
     615             :     void *pw_expire_data;
     616             : 
     617             :     struct fo_server *srv;
     618             : };
     619             : 
     620             : static struct tevent_req *auth_get_server(struct tevent_req *req);
     621             : static void auth_get_dn_done(struct tevent_req *subreq);
     622             : static void auth_do_bind(struct tevent_req *req);
     623             : static void auth_resolve_done(struct tevent_req *subreq);
     624             : static void auth_connect_done(struct tevent_req *subreq);
     625             : static void auth_bind_user_done(struct tevent_req *subreq);
     626             : 
     627           0 : static struct tevent_req *auth_send(TALLOC_CTX *memctx,
     628             :                                     struct tevent_context *ev,
     629             :                                     struct sdap_auth_ctx *ctx,
     630             :                                     const char *username,
     631             :                                     struct sss_auth_token *authtok,
     632             :                                     bool try_chpass_service)
     633             : {
     634             :     struct tevent_req *req;
     635             :     struct auth_state *state;
     636             : 
     637           0 :     req = tevent_req_create(memctx, &state, struct auth_state);
     638           0 :     if (!req) return NULL;
     639             : 
     640             :     /* The token must be a password token */
     641           0 :     if (sss_authtok_get_type(authtok) != SSS_AUTHTOK_TYPE_PASSWORD) {
     642           0 :         tevent_req_error(req, ERR_AUTH_FAILED);
     643           0 :         return tevent_req_post(req, ev);
     644             :     }
     645             : 
     646           0 :     state->ev = ev;
     647           0 :     state->ctx = ctx;
     648           0 :     state->username = username;
     649           0 :     state->authtok = authtok;
     650           0 :     state->srv = NULL;
     651           0 :     if (try_chpass_service && ctx->chpass_service != NULL &&
     652           0 :         ctx->chpass_service->name != NULL) {
     653           0 :         state->sdap_service = ctx->chpass_service;
     654             :     } else {
     655           0 :         state->sdap_service = ctx->service;
     656             :     }
     657             : 
     658           0 :     if (!auth_get_server(req)) goto fail;
     659             : 
     660           0 :     return req;
     661             : 
     662             : fail:
     663           0 :     talloc_zfree(req);
     664           0 :     return NULL;
     665             : }
     666             : 
     667           0 : static struct tevent_req *auth_get_server(struct tevent_req *req)
     668             : {
     669             :     struct tevent_req *next_req;
     670           0 :     struct auth_state *state = tevent_req_data(req,
     671             :                                                struct auth_state);
     672             : 
     673             :      /* NOTE: this call may cause service->uri to be refreshed
     674             :       * with a new valid server. Do not use service->uri before */
     675           0 :     next_req = be_resolve_server_send(state,
     676             :                                       state->ev,
     677           0 :                                       state->ctx->be,
     678           0 :                                       state->sdap_service->name,
     679           0 :                                       state->srv == NULL ? true : false);
     680           0 :     if (!next_req) {
     681           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "be_resolve_server_send failed.\n");
     682           0 :         return NULL;
     683             :     }
     684             : 
     685           0 :     tevent_req_set_callback(next_req, auth_resolve_done, req);
     686           0 :     return next_req;
     687             : }
     688             : 
     689           0 : static void auth_resolve_done(struct tevent_req *subreq)
     690             : {
     691           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     692             :                                                       struct tevent_req);
     693           0 :     struct auth_state *state = tevent_req_data(req,
     694             :                                                     struct auth_state);
     695             :     int ret;
     696             :     bool use_tls;
     697             : 
     698           0 :     ret = be_resolve_server_recv(subreq, &state->srv);
     699           0 :     talloc_zfree(subreq);
     700           0 :     if (ret) {
     701             :         /* all servers have been tried and none
     702             :          * was found good, go offline */
     703           0 :         tevent_req_error(req, ETIMEDOUT);
     704           0 :         return;
     705             :     }
     706             : 
     707             :     /* Determine whether we need to use TLS */
     708           0 :     if (sdap_is_secure_uri(state->ctx->service->uri)) {
     709           0 :         DEBUG(SSSDBG_TRACE_INTERNAL,
     710             :               "[%s] is a secure channel. No need to run START_TLS\n",
     711             :                   state->ctx->service->uri);
     712           0 :         use_tls = false;
     713             :     } else {
     714             : 
     715             :         /* Check for undocumented debugging feature to disable TLS
     716             :          * for authentication. This should never be used in production
     717             :          * for obvious reasons.
     718             :          */
     719           0 :         use_tls = !dp_opt_get_bool(state->ctx->opts->basic, SDAP_DISABLE_AUTH_TLS);
     720           0 :         if (!use_tls) {
     721           0 :             sss_log(SSS_LOG_ALERT, "LDAP authentication being performed over "
     722             :                                    "insecure connection. This should be done "
     723             :                                    "for debugging purposes only.");
     724             :         }
     725             :     }
     726             : 
     727           0 :     subreq = sdap_connect_send(state, state->ev, state->ctx->opts,
     728           0 :                                state->sdap_service->uri,
     729           0 :                                state->sdap_service->sockaddr, use_tls);
     730           0 :     if (!subreq) {
     731           0 :         tevent_req_error(req, ENOMEM);
     732           0 :         return;
     733             :     }
     734             : 
     735           0 :     tevent_req_set_callback(subreq, auth_connect_done, req);
     736             : }
     737             : 
     738           0 : static void auth_connect_done(struct tevent_req *subreq)
     739             : {
     740           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     741             :                                                       struct tevent_req);
     742           0 :     struct auth_state *state = tevent_req_data(req,
     743             :                                                     struct auth_state);
     744             :     int ret;
     745             : 
     746           0 :     ret = sdap_connect_recv(subreq, state, &state->sh);
     747           0 :     talloc_zfree(subreq);
     748           0 :     if (ret) {
     749           0 :         if (state->srv) {
     750             :             /* mark this server as bad if connection failed */
     751           0 :             be_fo_set_port_status(state->ctx->be,
     752             :                                   state->sdap_service->name,
     753             :                                   state->srv, PORT_NOT_WORKING);
     754             :         }
     755             : 
     756           0 :         if (auth_get_server(req) == NULL) {
     757           0 :             tevent_req_error(req, ENOMEM);
     758             :         }
     759           0 :         return;
     760           0 :     } else if (state->srv) {
     761           0 :         be_fo_set_port_status(state->ctx->be, state->sdap_service->name,
     762             :                               state->srv, PORT_WORKING);
     763             :     }
     764             : 
     765             :     /* In case the ID provider is set to proxy, this might be the first
     766             :      * LDAP operation at all, so we need to set the connection status
     767             :      */
     768           0 :     if (state->sh->connected == false) {
     769           0 :         ret = sdap_set_connected(state->sh, state->ev);
     770           0 :         if (ret) {
     771           0 :             DEBUG(SSSDBG_OP_FAILURE, "Cannot set connected status\n");
     772           0 :             tevent_req_error(req, ret);
     773           0 :             return;
     774             :         }
     775             :     }
     776             : 
     777           0 :     ret = get_user_dn(state, state->ctx->be->domain,
     778           0 :                       state->ctx->opts, state->username, &state->dn,
     779             :                       &state->pw_expire_type, &state->pw_expire_data);
     780           0 :     if (ret == EOK) {
     781             :         /* All required user data was pre-cached during an identity lookup.
     782             :          * We can proceed with the bind */
     783           0 :         auth_do_bind(req);
     784           0 :         return;
     785           0 :     } else if (ret == EAGAIN) {
     786             :         /* The cached user entry was missing the bind DN. Need to look
     787             :          * it up based on user name in order to perform the bind */
     788           0 :         subreq = get_user_dn_send(req, state->ev, state->ctx->be->domain,
     789           0 :                                   state->sh, state->ctx->opts, state->username);
     790           0 :         if (subreq == NULL) {
     791           0 :             tevent_req_error(req, ENOMEM);
     792           0 :             return;
     793             :         }
     794           0 :         tevent_req_set_callback(subreq, auth_get_dn_done, req);
     795           0 :         return;
     796             :     }
     797             : 
     798           0 :     tevent_req_error(req, ret);
     799           0 :     return;
     800             : }
     801             : 
     802           0 : static void auth_get_dn_done(struct tevent_req *subreq)
     803             : {
     804           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     805             :                                                       struct tevent_req);
     806           0 :     struct auth_state *state = tevent_req_data(req, struct auth_state);
     807             :     errno_t ret;
     808             : 
     809           0 :     ret = get_user_dn_recv(state, subreq, &state->dn);
     810           0 :     talloc_zfree(subreq);
     811           0 :     if (ret != EOK) {
     812           0 :         tevent_req_error(req, ERR_ACCOUNT_UNKNOWN);
     813           0 :         return;
     814             :     }
     815             : 
     816             :     /* The DN was found with an LDAP lookup
     817             :      * We can proceed with the bind */
     818           0 :     return auth_do_bind(req);
     819             : }
     820             : 
     821           0 : static void auth_do_bind(struct tevent_req *req)
     822             : {
     823           0 :     struct auth_state *state = tevent_req_data(req, struct auth_state);
     824             :     struct tevent_req *subreq;
     825             : 
     826           0 :     subreq = sdap_auth_send(state, state->ev, state->sh,
     827           0 :                             NULL, NULL, state->dn,
     828             :                             state->authtok,
     829           0 :                             dp_opt_get_int(state->ctx->opts->basic,
     830             :                                            SDAP_OPT_TIMEOUT));
     831           0 :     if (!subreq) {
     832           0 :         tevent_req_error(req, ENOMEM);
     833           0 :         return;
     834             :     }
     835             : 
     836           0 :     tevent_req_set_callback(subreq, auth_bind_user_done, req);
     837             : }
     838             : 
     839           0 : static void auth_bind_user_done(struct tevent_req *subreq)
     840             : {
     841           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     842             :                                                       struct tevent_req);
     843           0 :     struct auth_state *state = tevent_req_data(req,
     844             :                                                     struct auth_state);
     845             :     int ret;
     846           0 :     struct sdap_ppolicy_data *ppolicy = NULL;
     847             : 
     848           0 :     ret = sdap_auth_recv(subreq, state, &ppolicy);
     849           0 :     talloc_zfree(subreq);
     850           0 :     if (ppolicy != NULL) {
     851           0 :         DEBUG(SSSDBG_TRACE_ALL,"Found ppolicy data, "
     852             :                  "assuming LDAP password policies are active.\n");
     853           0 :         state->pw_expire_type = PWEXPIRE_LDAP_PASSWORD_POLICY;
     854           0 :         state->pw_expire_data = ppolicy;
     855             :     }
     856           0 :     switch (ret) {
     857             :     case EOK:
     858           0 :         break;
     859             :     case ETIMEDOUT:
     860             :     case ERR_NETWORK_IO:
     861           0 :         if (auth_get_server(req) == NULL) {
     862           0 :             tevent_req_error(req, ENOMEM);
     863             :         }
     864           0 :         return;
     865             :     default:
     866           0 :         tevent_req_error(req, ret);
     867           0 :         return;
     868             :     }
     869             : 
     870           0 :     tevent_req_done(req);
     871             : }
     872             : 
     873           0 : static errno_t auth_recv(struct tevent_req *req, TALLOC_CTX *memctx,
     874             :                          struct sdap_handle **sh, char **dn,
     875             :                          enum pwexpire *pw_expire_type, void **pw_expire_data)
     876             : {
     877           0 :     struct auth_state *state = tevent_req_data(req, struct auth_state);
     878             : 
     879           0 :     if (sh != NULL) {
     880           0 :         *sh = talloc_steal(memctx, state->sh);
     881           0 :         if (*sh == NULL) return ENOMEM;
     882             :     }
     883             : 
     884           0 :     if (dn != NULL) {
     885           0 :         *dn = talloc_steal(memctx, state->dn);
     886           0 :         if (*dn == NULL) return ENOMEM;
     887             :     }
     888             : 
     889           0 :     if (pw_expire_data != NULL) {
     890           0 :         *pw_expire_data = talloc_steal(memctx, state->pw_expire_data);
     891             :     }
     892             : 
     893           0 :     *pw_expire_type = state->pw_expire_type;
     894             : 
     895           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     896             : 
     897           0 :     return EOK;
     898             : }
     899             : 
     900             : /* ==Perform-Password-Change===================== */
     901             : 
     902             : struct sdap_pam_chpass_state {
     903             :     struct be_req *breq;
     904             :     struct pam_data *pd;
     905             :     const char *username;
     906             :     char *dn;
     907             :     struct sdap_handle *sh;
     908             : 
     909             :     struct sdap_auth_ctx *ctx;
     910             : };
     911             : 
     912             : static void sdap_auth4chpass_done(struct tevent_req *req);
     913             : static void sdap_pam_chpass_done(struct tevent_req *req);
     914             : 
     915           0 : void sdap_pam_chpass_handler(struct be_req *breq)
     916             : {
     917           0 :     struct be_ctx *be_ctx = be_req_get_be_ctx(breq);
     918             :     struct sdap_pam_chpass_state *state;
     919             :     struct sdap_auth_ctx *ctx;
     920             :     struct tevent_req *subreq;
     921             :     struct pam_data *pd;
     922           0 :     int dp_err = DP_ERR_FATAL;
     923             : 
     924           0 :     ctx = talloc_get_type(be_ctx->bet_info[BET_CHPASS].pvt_bet_data,
     925             :                           struct sdap_auth_ctx);
     926           0 :     pd = talloc_get_type(be_req_get_data(breq), struct pam_data);
     927             : 
     928           0 :     if (be_is_offline(ctx->be)) {
     929           0 :         DEBUG(SSSDBG_CONF_SETTINGS,
     930             :               "Backend is marked offline, retry later!\n");
     931           0 :         pd->pam_status = PAM_AUTHINFO_UNAVAIL;
     932           0 :         dp_err = DP_ERR_OFFLINE;
     933           0 :         goto done;
     934             :     }
     935             : 
     936           0 :     if ((pd->priv == 1) && (pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) &&
     937           0 :         (sss_authtok_get_type(pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD)) {
     938           0 :         DEBUG(SSSDBG_CONF_SETTINGS,
     939             :               "Password reset by root is not supported.\n");
     940           0 :         pd->pam_status = PAM_PERM_DENIED;
     941           0 :         dp_err = DP_ERR_OK;
     942           0 :         goto done;
     943             :     }
     944             : 
     945           0 :     DEBUG(SSSDBG_OP_FAILURE,
     946             :           "starting password change request for user [%s].\n", pd->user);
     947             : 
     948           0 :     pd->pam_status = PAM_SYSTEM_ERR;
     949             : 
     950           0 :     if (pd->cmd != SSS_PAM_CHAUTHTOK && pd->cmd != SSS_PAM_CHAUTHTOK_PRELIM) {
     951           0 :         DEBUG(SSSDBG_OP_FAILURE,
     952             :               "chpass target was called by wrong pam command.\n");
     953           0 :         goto done;
     954             :     }
     955             : 
     956           0 :     state = talloc_zero(breq, struct sdap_pam_chpass_state);
     957           0 :     if (!state) goto done;
     958             : 
     959           0 :     state->breq = breq;
     960           0 :     state->pd = pd;
     961           0 :     state->username = pd->user;
     962           0 :     state->ctx = ctx;
     963             : 
     964           0 :     subreq = auth_send(breq, be_ctx->ev, ctx,
     965             :                        state->username, pd->authtok, true);
     966           0 :     if (!subreq) goto done;
     967             : 
     968           0 :     tevent_req_set_callback(subreq, sdap_auth4chpass_done, state);
     969           0 :     return;
     970             : 
     971             : done:
     972           0 :     be_req_terminate(breq, dp_err, pd->pam_status, NULL);
     973             : }
     974             : 
     975             : static void sdap_lastchange_done(struct tevent_req *req);
     976           0 : static void sdap_auth4chpass_done(struct tevent_req *req)
     977             : {
     978           0 :     struct sdap_pam_chpass_state *state =
     979           0 :                     tevent_req_callback_data(req, struct sdap_pam_chpass_state);
     980           0 :     struct be_ctx *be_ctx = be_req_get_be_ctx(state->breq);
     981             :     struct tevent_req *subreq;
     982             :     enum pwexpire pw_expire_type;
     983             :     void *pw_expire_data;
     984           0 :     int dp_err = DP_ERR_FATAL;
     985             :     int ret;
     986             :     size_t msg_len;
     987             :     uint8_t *msg;
     988             : 
     989           0 :     ret = auth_recv(req, state, &state->sh, &state->dn,
     990             :                     &pw_expire_type, &pw_expire_data);
     991           0 :     talloc_zfree(req);
     992           0 :     if ((ret == EOK || ret == ERR_PASSWORD_EXPIRED) &&
     993           0 :         state->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) {
     994           0 :         DEBUG(SSSDBG_TRACE_ALL,
     995             :               "Initial authentication for change password operation "
     996             :                   "successful.\n");
     997           0 :         state->pd->pam_status = PAM_SUCCESS;
     998           0 :         dp_err = DP_ERR_OK;
     999           0 :         goto done;
    1000             :     }
    1001             : 
    1002           0 :     if (ret == EOK) {
    1003           0 :         switch (pw_expire_type) {
    1004             :         case PWEXPIRE_SHADOW:
    1005           0 :             ret = check_pwexpire_shadow(pw_expire_data, time(NULL), NULL);
    1006           0 :             break;
    1007             :         case PWEXPIRE_KERBEROS:
    1008           0 :             ret = check_pwexpire_kerberos(pw_expire_data, time(NULL), NULL,
    1009           0 :                                           be_ctx->domain->pwd_expiration_warning);
    1010             : 
    1011           0 :             if (ret == ERR_PASSWORD_EXPIRED) {
    1012           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
    1013             :                       "LDAP provider cannot change kerberos "
    1014             :                           "passwords.\n");
    1015           0 :                 state->pd->pam_status = PAM_SYSTEM_ERR;
    1016           0 :                 goto done;
    1017             :             }
    1018           0 :             break;
    1019             :         case PWEXPIRE_LDAP_PASSWORD_POLICY:
    1020             :         case PWEXPIRE_NONE:
    1021           0 :             break;
    1022             :         default:
    1023           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Unknown password expiration type.\n");
    1024           0 :                 state->pd->pam_status = PAM_SYSTEM_ERR;
    1025           0 :                 goto done;
    1026             :         }
    1027             :     }
    1028             : 
    1029           0 :     switch (ret) {
    1030             :     case EOK:
    1031             :     case ERR_PASSWORD_EXPIRED:
    1032           0 :         DEBUG(SSSDBG_TRACE_LIBS,
    1033             :               "user [%s] successfully authenticated.\n", state->dn);
    1034           0 :         if (pw_expire_type == PWEXPIRE_SHADOW) {
    1035             : /* TODO: implement async ldap modify request */
    1036           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1037             :                   "Changing shadow password attributes not implemented.\n");
    1038           0 :             state->pd->pam_status = PAM_MODULE_UNKNOWN;
    1039           0 :             goto done;
    1040             :         } else {
    1041             :             const char *password;
    1042             :             const char *new_password;
    1043             :             int timeout;
    1044             : 
    1045           0 :             ret = sss_authtok_get_password(state->pd->authtok,
    1046             :                                            &password, NULL);
    1047           0 :             if (ret) {
    1048           0 :                 state->pd->pam_status = PAM_SYSTEM_ERR;
    1049           0 :                 goto done;
    1050             :             }
    1051           0 :             ret = sss_authtok_get_password(state->pd->newauthtok,
    1052             :                                            &new_password, NULL);
    1053           0 :             if (ret) {
    1054           0 :                 state->pd->pam_status = PAM_SYSTEM_ERR;
    1055           0 :                 goto done;
    1056             :             }
    1057             : 
    1058           0 :             timeout = dp_opt_get_int(state->ctx->opts->basic, SDAP_OPT_TIMEOUT);
    1059             : 
    1060           0 :             subreq = sdap_exop_modify_passwd_send(state, be_ctx->ev,
    1061             :                                                   state->sh, state->dn,
    1062             :                                                   password, new_password,
    1063             :                                                   timeout);
    1064           0 :             if (!subreq) {
    1065           0 :                 DEBUG(SSSDBG_OP_FAILURE,
    1066             :                       "Failed to change password for %s\n", state->username);
    1067           0 :                 goto done;
    1068             :             }
    1069           0 :             tevent_req_set_callback(subreq, sdap_pam_chpass_done, state);
    1070           0 :             return;
    1071             :         }
    1072             :         break;
    1073             :     case ERR_AUTH_DENIED:
    1074             :     case ERR_AUTH_FAILED:
    1075           0 :         state->pd->pam_status = PAM_AUTH_ERR;
    1076           0 :         ret = pack_user_info_chpass_error(state->pd, "Old password not accepted.",
    1077             :                                           &msg_len, &msg);
    1078           0 :         if (ret != EOK) {
    1079           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1080             :                   "pack_user_info_chpass_error failed.\n");
    1081             :         } else {
    1082           0 :             ret = pam_add_response(state->pd, SSS_PAM_USER_INFO, msg_len,
    1083             :                                     msg);
    1084           0 :             if (ret != EOK) {
    1085           0 :                DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
    1086             :             }
    1087             :         }
    1088             : 
    1089           0 :         break;
    1090             :     case ETIMEDOUT:
    1091             :     case ERR_NETWORK_IO:
    1092           0 :         state->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
    1093           0 :         be_mark_offline(be_ctx);
    1094           0 :         dp_err = DP_ERR_OFFLINE;
    1095           0 :         break;
    1096             :     default:
    1097           0 :         state->pd->pam_status = PAM_SYSTEM_ERR;
    1098             :     }
    1099             : 
    1100             : done:
    1101           0 :     be_req_terminate(state->breq, dp_err, state->pd->pam_status, NULL);
    1102             : }
    1103             : 
    1104           0 : static void sdap_pam_chpass_done(struct tevent_req *req)
    1105             : {
    1106           0 :     struct sdap_pam_chpass_state *state =
    1107           0 :                     tevent_req_callback_data(req, struct sdap_pam_chpass_state);
    1108           0 :     struct be_ctx *be_ctx = be_req_get_be_ctx(state->breq);
    1109           0 :     int dp_err = DP_ERR_FATAL;
    1110             :     int ret;
    1111           0 :     char *user_error_message = NULL;
    1112             :     char *lastchanged_name;
    1113             :     struct tevent_req *subreq;
    1114             :     size_t msg_len;
    1115             :     uint8_t *msg;
    1116             : 
    1117           0 :     ret = sdap_exop_modify_passwd_recv(req, state, &user_error_message);
    1118           0 :     talloc_zfree(req);
    1119             : 
    1120           0 :     switch (ret) {
    1121             :     case EOK:
    1122           0 :         state->pd->pam_status = PAM_SUCCESS;
    1123           0 :         dp_err = DP_ERR_OK;
    1124           0 :         break;
    1125             :     case ERR_CHPASS_DENIED:
    1126           0 :         state->pd->pam_status = PAM_NEW_AUTHTOK_REQD;
    1127           0 :         break;
    1128             :     case ERR_NETWORK_IO:
    1129           0 :         state->pd->pam_status = PAM_AUTHTOK_ERR;
    1130           0 :         break;
    1131             :     default:
    1132           0 :         state->pd->pam_status = PAM_SYSTEM_ERR;
    1133           0 :         break;
    1134             :     }
    1135             : 
    1136           0 :     if (state->pd->pam_status != PAM_SUCCESS && user_error_message != NULL) {
    1137           0 :         ret = pack_user_info_chpass_error(state->pd, user_error_message,
    1138             :                                             &msg_len, &msg);
    1139           0 :         if (ret != EOK) {
    1140           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "pack_user_info_chpass_error failed.\n");
    1141             :         } else {
    1142           0 :             ret = pam_add_response(state->pd, SSS_PAM_USER_INFO, msg_len,
    1143             :                                     msg);
    1144           0 :             if (ret != EOK) {
    1145           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
    1146             :             }
    1147             :         }
    1148             :     }
    1149             : 
    1150           0 :     if (state->pd->pam_status == PAM_SUCCESS &&
    1151           0 :         dp_opt_get_bool(state->ctx->opts->basic,
    1152             :                         SDAP_CHPASS_UPDATE_LAST_CHANGE)) {
    1153           0 :         lastchanged_name = state->ctx->opts->user_map[SDAP_AT_SP_LSTCHG].name;
    1154             : 
    1155           0 :         subreq = sdap_modify_shadow_lastchange_send(state, be_ctx->ev,
    1156           0 :                                                     state->sh, state->dn,
    1157             :                                                     lastchanged_name);
    1158           0 :         if (subreq == NULL) {
    1159           0 :             state->pd->pam_status = PAM_SYSTEM_ERR;
    1160           0 :             goto done;
    1161             :         }
    1162             : 
    1163           0 :         tevent_req_set_callback(subreq, sdap_lastchange_done, state);
    1164           0 :         return;
    1165             :     }
    1166             : 
    1167             : done:
    1168           0 :     be_req_terminate(state->breq, dp_err, state->pd->pam_status, NULL);
    1169             : }
    1170             : 
    1171           0 : static void sdap_lastchange_done(struct tevent_req *req)
    1172             : {
    1173           0 :     struct sdap_pam_chpass_state *state =
    1174           0 :                     tevent_req_callback_data(req, struct sdap_pam_chpass_state);
    1175           0 :     int dp_err = DP_ERR_FATAL;
    1176             :     errno_t ret;
    1177             : 
    1178           0 :     ret = sdap_modify_shadow_lastchange_recv(req);
    1179           0 :     if (ret != EOK) {
    1180           0 :         state->pd->pam_status = PAM_SYSTEM_ERR;
    1181           0 :         goto done;
    1182             :     }
    1183             : 
    1184           0 :     dp_err = DP_ERR_OK;
    1185           0 :     state->pd->pam_status = PAM_SUCCESS;
    1186             : 
    1187             : done:
    1188           0 :     be_req_terminate(state->breq, dp_err, state->pd->pam_status, NULL);
    1189           0 : }
    1190             : 
    1191             : /* ==Perform-User-Authentication-and-Password-Caching===================== */
    1192             : 
    1193             : struct sdap_pam_auth_state {
    1194             :     struct be_req *breq;
    1195             :     struct pam_data *pd;
    1196             : };
    1197             : 
    1198             : static void sdap_pam_auth_done(struct tevent_req *req);
    1199             : 
    1200           0 : void sdap_pam_auth_handler(struct be_req *breq)
    1201             : {
    1202           0 :     struct be_ctx *be_ctx = be_req_get_be_ctx(breq);
    1203             :     struct sdap_pam_auth_state *state;
    1204             :     struct sdap_auth_ctx *ctx;
    1205             :     struct tevent_req *subreq;
    1206             :     struct pam_data *pd;
    1207           0 :     int dp_err = DP_ERR_FATAL;
    1208             : 
    1209           0 :     ctx = talloc_get_type(be_ctx->bet_info[BET_AUTH].pvt_bet_data,
    1210             :                           struct sdap_auth_ctx);
    1211           0 :     pd = talloc_get_type(be_req_get_data(breq), struct pam_data);
    1212             : 
    1213           0 :     if (be_is_offline(ctx->be)) {
    1214           0 :         DEBUG(SSSDBG_CONF_SETTINGS,
    1215             :               "Backend is marked offline, retry later!\n");
    1216           0 :         pd->pam_status = PAM_AUTHINFO_UNAVAIL;
    1217           0 :         dp_err = DP_ERR_OFFLINE;
    1218           0 :         goto done;
    1219             :     }
    1220             : 
    1221           0 :     pd->pam_status = PAM_SYSTEM_ERR;
    1222             : 
    1223           0 :     switch (pd->cmd) {
    1224             :     case SSS_PAM_AUTHENTICATE:
    1225             :     case SSS_PAM_CHAUTHTOK_PRELIM:
    1226             : 
    1227           0 :         state = talloc_zero(breq, struct sdap_pam_auth_state);
    1228           0 :         if (!state) goto done;
    1229             : 
    1230           0 :         state->breq = breq;
    1231           0 :         state->pd = pd;
    1232             : 
    1233           0 :         subreq = auth_send(breq, be_ctx->ev, ctx,
    1234           0 :                            pd->user, pd->authtok,
    1235           0 :                            pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM ? true : false);
    1236           0 :         if (!subreq) goto done;
    1237             : 
    1238           0 :         tevent_req_set_callback(subreq, sdap_pam_auth_done, state);
    1239           0 :         return;
    1240             : 
    1241             :     case SSS_PAM_CHAUTHTOK:
    1242           0 :         break;
    1243             : 
    1244             :     case SSS_PAM_ACCT_MGMT:
    1245             :     case SSS_PAM_SETCRED:
    1246             :     case SSS_PAM_OPEN_SESSION:
    1247             :     case SSS_PAM_CLOSE_SESSION:
    1248           0 :         pd->pam_status = PAM_SUCCESS;
    1249           0 :         dp_err = DP_ERR_OK;
    1250           0 :         break;
    1251             :     default:
    1252           0 :         pd->pam_status = PAM_MODULE_UNKNOWN;
    1253           0 :         dp_err = DP_ERR_OK;
    1254             :     }
    1255             : 
    1256             : done:
    1257           0 :     be_req_terminate(breq, dp_err, pd->pam_status, NULL);
    1258             : }
    1259             : 
    1260           0 : static void sdap_pam_auth_done(struct tevent_req *req)
    1261             : {
    1262           0 :     struct sdap_pam_auth_state *state =
    1263           0 :                     tevent_req_callback_data(req, struct sdap_pam_auth_state);
    1264           0 :     struct be_ctx *be_ctx = be_req_get_be_ctx(state->breq);
    1265             :     enum pwexpire pw_expire_type;
    1266             :     void *pw_expire_data;
    1267             :     const char *password;
    1268           0 :     int dp_err = DP_ERR_OK;
    1269             :     int ret;
    1270             : 
    1271           0 :     ret = auth_recv(req, state, NULL, NULL,
    1272             :                     &pw_expire_type, &pw_expire_data);
    1273           0 :     talloc_zfree(req);
    1274             : 
    1275           0 :     if (ret == EOK) {
    1276           0 :         ret = check_pwexpire_policy(pw_expire_type, pw_expire_data, state->pd,
    1277           0 :                                     be_ctx->domain->pwd_expiration_warning);
    1278           0 :         if (ret == EINVAL) {
    1279             :             /* Unknown password expiration type. */
    1280           0 :             state->pd->pam_status = PAM_SYSTEM_ERR;
    1281           0 :             goto done;
    1282             :         }
    1283             :     }
    1284             : 
    1285           0 :     switch (ret) {
    1286             :     case EOK:
    1287           0 :         state->pd->pam_status = PAM_SUCCESS;
    1288           0 :         break;
    1289             :     case ERR_AUTH_DENIED:
    1290           0 :         state->pd->pam_status = PAM_PERM_DENIED;
    1291           0 :         break;
    1292             :     case ERR_AUTH_FAILED:
    1293           0 :         state->pd->pam_status = PAM_AUTH_ERR;
    1294           0 :         break;
    1295             :     case ETIMEDOUT:
    1296             :     case ERR_NETWORK_IO:
    1297           0 :         state->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
    1298           0 :         break;
    1299             :     case ERR_ACCOUNT_EXPIRED:
    1300           0 :         state->pd->pam_status = PAM_ACCT_EXPIRED;
    1301           0 :         break;
    1302             :     case ERR_PASSWORD_EXPIRED:
    1303           0 :         state->pd->pam_status = PAM_NEW_AUTHTOK_REQD;
    1304           0 :         break;
    1305             :     default:
    1306           0 :         state->pd->pam_status = PAM_SYSTEM_ERR;
    1307           0 :         dp_err = DP_ERR_FATAL;
    1308             :     }
    1309             : 
    1310           0 :     if (ret == ETIMEDOUT || ret == ERR_NETWORK_IO) {
    1311           0 :         be_mark_offline(be_ctx);
    1312           0 :         dp_err = DP_ERR_OFFLINE;
    1313           0 :         goto done;
    1314             :     }
    1315             : 
    1316           0 :     if (ret == EOK && be_ctx->domain->cache_credentials) {
    1317             : 
    1318           0 :         ret = sss_authtok_get_password(state->pd->authtok, &password, NULL);
    1319           0 :         if (ret == EOK) {
    1320           0 :             ret = sysdb_cache_password(be_ctx->domain, state->pd->user,
    1321             :                                        password);
    1322             :         }
    1323             : 
    1324             :         /* password caching failures are not fatal errors */
    1325           0 :         if (ret != EOK) {
    1326           0 :             DEBUG(SSSDBG_OP_FAILURE, "Failed to cache password for %s\n",
    1327             :                       state->pd->user);
    1328             :         } else {
    1329           0 :             DEBUG(SSSDBG_CONF_SETTINGS, "Password successfully cached for %s\n",
    1330             :                       state->pd->user);
    1331             :         }
    1332             :     }
    1333             : 
    1334             : done:
    1335           0 :     be_req_terminate(state->breq, dp_err, state->pd->pam_status, NULL);
    1336           0 : }

Generated by: LCOV version 1.10