LCOV - code coverage report
Current view: top level - providers/ldap - ldap_auth.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 20 625 3.2 %
Date: 2016-06-29 Functions: 2 26 7.7 %

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

Generated by: LCOV version 1.10