LCOV - code coverage report
Current view: top level - providers/ldap - sdap_access.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 14 781 1.8 %
Date: 2016-06-29 Functions: 1 33 3.0 %

          Line data    Source code
       1             : /*
       2             :     SSSD
       3             : 
       4             :     sdap_access.c
       5             : 
       6             :     Authors:
       7             :         Stephen Gallagher <sgallagh@redhat.com>
       8             : 
       9             :     Copyright (C) 2010 Red Hat
      10             : 
      11             :     This program is free software; you can redistribute it and/or modify
      12             :     it under the terms of the GNU General Public License as published by
      13             :     the Free Software Foundation; either version 3 of the License, or
      14             :     (at your option) any later version.
      15             : 
      16             :     This program is distributed in the hope that it will be useful,
      17             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      18             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19             :     GNU General Public License for more details.
      20             : 
      21             :     You should have received a copy of the GNU General Public License
      22             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      23             : */
      24             : 
      25             : #include "config.h"
      26             : 
      27             : #include <time.h>
      28             : #include <sys/param.h>
      29             : #include <security/pam_modules.h>
      30             : #include <talloc.h>
      31             : #include <tevent.h>
      32             : #include <errno.h>
      33             : 
      34             : #include "util/util.h"
      35             : #include "util/strtonum.h"
      36             : #include "db/sysdb.h"
      37             : #include "providers/ldap/ldap_common.h"
      38             : #include "providers/ldap/sdap.h"
      39             : #include "providers/ldap/sdap_access.h"
      40             : #include "providers/ldap/sdap_async.h"
      41             : #include "providers/data_provider.h"
      42             : #include "providers/backend.h"
      43             : #include "providers/ldap/ldap_auth.h"
      44             : 
      45             : #define PERMANENTLY_LOCKED_ACCOUNT "000001010000Z"
      46             : #define MALFORMED_FILTER "Malformed access control filter [%s]\n"
      47             : 
      48             : enum sdap_pwpolicy_mode {
      49             :     PWP_LOCKOUT_ONLY,
      50             :     PWP_LOCKOUT_EXPIRE,
      51             :     PWP_SENTINEL,
      52             : };
      53             : 
      54             : static errno_t perform_pwexpire_policy(TALLOC_CTX *mem_ctx,
      55             :                                        struct sss_domain_info *domain,
      56             :                                        struct pam_data *pd,
      57             :                                        struct sdap_options *opts);
      58             : 
      59             : static errno_t sdap_save_user_cache_bool(struct sss_domain_info *domain,
      60             :                                          const char *username,
      61             :                                          const char *attr_name,
      62             :                                          bool value);
      63             : 
      64             : static errno_t sdap_get_basedn_user_entry(struct ldb_message *user_entry,
      65             :                                           const char *username,
      66             :                                           const char **_basedn);
      67             : 
      68             : static struct tevent_req *
      69             : sdap_access_ppolicy_send(TALLOC_CTX *mem_ctx,
      70             :                          struct tevent_context *ev,
      71             :                          struct be_ctx *be_ctx,
      72             :                          struct sss_domain_info *domain,
      73             :                          struct sdap_access_ctx *access_ctx,
      74             :                          struct sdap_id_conn_ctx *conn,
      75             :                          const char *username,
      76             :                          struct ldb_message *user_entry,
      77             :                          enum sdap_pwpolicy_mode pwpol_mod);
      78             : 
      79             : static struct tevent_req *sdap_access_filter_send(TALLOC_CTX *mem_ctx,
      80             :                                              struct tevent_context *ev,
      81             :                                              struct be_ctx *be_ctx,
      82             :                                              struct sss_domain_info *domain,
      83             :                                              struct sdap_access_ctx *access_ctx,
      84             :                                              struct sdap_id_conn_ctx *conn,
      85             :                                              const char *username,
      86             :                                              struct ldb_message *user_entry);
      87             : 
      88             : static errno_t sdap_access_filter_recv(struct tevent_req *req);
      89             : 
      90             : static errno_t sdap_access_ppolicy_recv(struct tevent_req *req);
      91             : 
      92             : static errno_t sdap_account_expired(struct sdap_access_ctx *access_ctx,
      93             :                                     struct pam_data *pd,
      94             :                                     struct ldb_message *user_entry);
      95             : 
      96             : static  errno_t sdap_access_service(struct pam_data *pd,
      97             :                                     struct ldb_message *user_entry);
      98             : 
      99             : static errno_t sdap_access_host(struct ldb_message *user_entry);
     100             : 
     101             : enum sdap_access_control_type {
     102             :     SDAP_ACCESS_CONTROL_FILTER,
     103             :     SDAP_ACCESS_CONTROL_PPOLICY_LOCK,
     104             : };
     105             : 
     106             : struct sdap_access_req_ctx {
     107             :     struct pam_data *pd;
     108             :     struct tevent_context *ev;
     109             :     struct sdap_access_ctx *access_ctx;
     110             :     struct sdap_id_conn_ctx *conn;
     111             :     struct be_ctx *be_ctx;
     112             :     struct sss_domain_info *domain;
     113             :     struct ldb_message *user_entry;
     114             :     size_t current_rule;
     115             :     enum sdap_access_control_type ac_type;
     116             : };
     117             : 
     118             : static errno_t sdap_access_check_next_rule(struct sdap_access_req_ctx *state,
     119             :                                            struct tevent_req *req);
     120             : static void sdap_access_done(struct tevent_req *subreq);
     121             : 
     122             : struct tevent_req *
     123           0 : sdap_access_send(TALLOC_CTX *mem_ctx,
     124             :                  struct tevent_context *ev,
     125             :                  struct be_ctx *be_ctx,
     126             :                  struct sss_domain_info *domain,
     127             :                  struct sdap_access_ctx *access_ctx,
     128             :                  struct sdap_id_conn_ctx *conn,
     129             :                  struct pam_data *pd)
     130             : {
     131             :     errno_t ret;
     132             :     struct sdap_access_req_ctx *state;
     133             :     struct tevent_req *req;
     134             :     struct ldb_result *res;
     135           0 :     const char *attrs[] = { "*", NULL };
     136             : 
     137           0 :     req = tevent_req_create(mem_ctx, &state, struct sdap_access_req_ctx);
     138           0 :     if (req == NULL) {
     139           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create failed.\n");
     140           0 :         return NULL;
     141             :     }
     142             : 
     143           0 :     state->be_ctx = be_ctx;
     144           0 :     state->domain = domain;
     145           0 :     state->pd = pd;
     146           0 :     state->ev = ev;
     147           0 :     state->access_ctx = access_ctx;
     148           0 :     state->conn = conn;
     149           0 :     state->current_rule = 0;
     150             : 
     151           0 :     DEBUG(SSSDBG_TRACE_FUNC,
     152             :           "Performing access check for user [%s]\n", pd->user);
     153             : 
     154           0 :     if (access_ctx->access_rule[0] == LDAP_ACCESS_EMPTY) {
     155           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     156             :               "No access rules defined, access denied.\n");
     157           0 :         ret = ERR_ACCESS_DENIED;
     158           0 :         goto done;
     159             :     }
     160             : 
     161             :     /* Get original user DN, domain already points to the right (sub)domain */
     162           0 :     ret = sysdb_get_user_attr(state, domain, pd->user, attrs, &res);
     163           0 :     if (ret != EOK) {
     164           0 :         if (ret == ENOENT) {
     165             :             /* If we can't find the user, return access denied */
     166           0 :             ret = ERR_ACCESS_DENIED;
     167           0 :             goto done;
     168             :         }
     169           0 :         goto done;
     170             :     }
     171             :     else {
     172           0 :         if (res->count == 0) {
     173             :             /* If we can't find the user, return access denied */
     174           0 :             ret = ERR_ACCESS_DENIED;
     175           0 :             goto done;
     176             :         }
     177             : 
     178           0 :         if (res->count != 1) {
     179           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     180             :                   "Invalid response from sysdb_get_user_attr\n");
     181           0 :             ret = EINVAL;
     182           0 :             goto done;
     183             :         }
     184             :     }
     185             : 
     186           0 :     state->user_entry = res->msgs[0];
     187             : 
     188           0 :     ret = sdap_access_check_next_rule(state, req);
     189           0 :     if (ret == EAGAIN) {
     190           0 :         return req;
     191             :     }
     192             : 
     193             : done:
     194           0 :     if (ret == EOK) {
     195           0 :         tevent_req_done(req);
     196             :     } else {
     197           0 :         tevent_req_error(req, ret);
     198             :     }
     199           0 :     tevent_req_post(req, ev);
     200           0 :     return req;
     201             : }
     202             : 
     203           0 : static errno_t sdap_access_check_next_rule(struct sdap_access_req_ctx *state,
     204             :                                            struct tevent_req *req)
     205             : {
     206             :     struct tevent_req *subreq;
     207           0 :     int ret = EOK;
     208             : 
     209           0 :     while (ret == EOK) {
     210           0 :         switch (state->access_ctx->access_rule[state->current_rule]) {
     211             :         case LDAP_ACCESS_EMPTY:
     212             :             /* we are done with no errors */
     213           0 :             return EOK;
     214             : 
     215             :         /* This option is deprecated by LDAP_ACCESS_PPOLICY */
     216             :         case LDAP_ACCESS_LOCKOUT:
     217           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     218             :                   "WARNING: %s option is deprecated and might be removed in "
     219             :                   "a future release. Please migrate to %s option instead.\n",
     220             :                   LDAP_ACCESS_LOCK_NAME, LDAP_ACCESS_PPOLICY_NAME);
     221             : 
     222           0 :             subreq = sdap_access_ppolicy_send(state, state->ev, state->be_ctx,
     223             :                                               state->domain,
     224             :                                               state->access_ctx,
     225             :                                               state->conn,
     226           0 :                                               state->pd->user,
     227             :                                               state->user_entry,
     228             :                                               PWP_LOCKOUT_ONLY);
     229           0 :             if (subreq == NULL) {
     230           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     231             :                       "sdap_access_ppolicy_send failed.\n");
     232           0 :                 return ENOMEM;
     233             :             }
     234             : 
     235           0 :             state->ac_type = SDAP_ACCESS_CONTROL_PPOLICY_LOCK;
     236             : 
     237           0 :             tevent_req_set_callback(subreq, sdap_access_done, req);
     238           0 :             return EAGAIN;
     239             : 
     240             :         case LDAP_ACCESS_PPOLICY:
     241           0 :             subreq = sdap_access_ppolicy_send(state, state->ev, state->be_ctx,
     242             :                                               state->domain,
     243             :                                               state->access_ctx,
     244             :                                               state->conn,
     245           0 :                                               state->pd->user,
     246             :                                               state->user_entry,
     247             :                                               PWP_LOCKOUT_EXPIRE);
     248           0 :             if (subreq == NULL) {
     249           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     250             :                       "sdap_access_ppolicy_send failed.\n");
     251           0 :                 return ENOMEM;
     252             :             }
     253             : 
     254           0 :             state->ac_type = SDAP_ACCESS_CONTROL_PPOLICY_LOCK;
     255             : 
     256           0 :             tevent_req_set_callback(subreq, sdap_access_done, req);
     257           0 :             return EAGAIN;
     258             : 
     259             :         case LDAP_ACCESS_FILTER:
     260           0 :             subreq = sdap_access_filter_send(state, state->ev, state->be_ctx,
     261             :                                              state->domain,
     262             :                                              state->access_ctx,
     263             :                                              state->conn,
     264           0 :                                              state->pd->user,
     265             :                                              state->user_entry);
     266           0 :             if (subreq == NULL) {
     267           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "sdap_access_filter_send failed.\n");
     268           0 :                 return ENOMEM;
     269             :             }
     270             : 
     271           0 :             state->ac_type = SDAP_ACCESS_CONTROL_FILTER;
     272             : 
     273           0 :             tevent_req_set_callback(subreq, sdap_access_done, req);
     274           0 :             return EAGAIN;
     275             : 
     276             :         case LDAP_ACCESS_EXPIRE:
     277           0 :             ret = sdap_account_expired(state->access_ctx,
     278             :                                        state->pd, state->user_entry);
     279           0 :             break;
     280             : 
     281             :         case LDAP_ACCESS_EXPIRE_POLICY_REJECT:
     282           0 :             ret = perform_pwexpire_policy(state, state->domain, state->pd,
     283           0 :                                           state->access_ctx->id_ctx->opts);
     284           0 :             if (ret == ERR_PASSWORD_EXPIRED) {
     285           0 :                 ret = ERR_PASSWORD_EXPIRED_REJECT;
     286             :             }
     287           0 :             break;
     288             : 
     289             :         case LDAP_ACCESS_EXPIRE_POLICY_WARN:
     290           0 :             ret = perform_pwexpire_policy(state, state->domain, state->pd,
     291           0 :                                           state->access_ctx->id_ctx->opts);
     292           0 :             if (ret == ERR_PASSWORD_EXPIRED) {
     293           0 :                 ret = ERR_PASSWORD_EXPIRED_WARN;
     294             :             }
     295           0 :             break;
     296             : 
     297             :         case LDAP_ACCESS_EXPIRE_POLICY_RENEW:
     298           0 :             ret = perform_pwexpire_policy(state, state->domain, state->pd,
     299           0 :                                           state->access_ctx->id_ctx->opts);
     300           0 :             if (ret == ERR_PASSWORD_EXPIRED) {
     301           0 :                 ret = ERR_PASSWORD_EXPIRED_RENEW;
     302             :             }
     303           0 :             break;
     304             : 
     305             :         case LDAP_ACCESS_SERVICE:
     306           0 :             ret = sdap_access_service( state->pd, state->user_entry);
     307           0 :             break;
     308             : 
     309             :         case LDAP_ACCESS_HOST:
     310           0 :             ret = sdap_access_host(state->user_entry);
     311           0 :             break;
     312             : 
     313             :         default:
     314           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     315             :                   "Unexpected access rule type. Access denied.\n");
     316           0 :             ret = ERR_ACCESS_DENIED;
     317             :         }
     318             : 
     319           0 :         state->current_rule++;
     320             :     }
     321             : 
     322           0 :     return ret;
     323             : }
     324             : 
     325           0 : static void sdap_access_done(struct tevent_req *subreq)
     326             : {
     327             :     errno_t ret;
     328             :     struct tevent_req *req;
     329             :     struct sdap_access_req_ctx *state;
     330             : 
     331           0 :     req = tevent_req_callback_data(subreq, struct tevent_req);
     332           0 :     state = tevent_req_data(req, struct sdap_access_req_ctx);
     333             : 
     334             :     /* process subrequest */
     335           0 :     switch(state->ac_type) {
     336             :     case SDAP_ACCESS_CONTROL_FILTER:
     337           0 :         ret = sdap_access_filter_recv(subreq);
     338           0 :         break;
     339             :     case SDAP_ACCESS_CONTROL_PPOLICY_LOCK:
     340           0 :         ret = sdap_access_ppolicy_recv(subreq);
     341           0 :         break;
     342             :     default:
     343           0 :         ret = EINVAL;
     344           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "Unknown access control type: %d.\n",
     345             :               state->ac_type);
     346           0 :         break;
     347             :     }
     348             : 
     349           0 :     talloc_zfree(subreq);
     350           0 :     if (ret != EOK) {
     351           0 :         if (ret == ERR_ACCESS_DENIED) {
     352           0 :             DEBUG(SSSDBG_TRACE_FUNC, "Access was denied.\n");
     353             :         } else {
     354           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     355             :                   "Error retrieving access check result.\n");
     356             :         }
     357           0 :         tevent_req_error(req, ret);
     358           0 :         return;
     359             :     }
     360             : 
     361           0 :     state->current_rule++;
     362             : 
     363           0 :     ret = sdap_access_check_next_rule(state, req);
     364           0 :     switch (ret) {
     365             :     case EAGAIN:
     366           0 :         return;
     367             :     case EOK:
     368           0 :         tevent_req_done(req);
     369           0 :         return;
     370             :     default:
     371           0 :         tevent_req_error(req, ret);
     372           0 :         return;
     373             :     }
     374             : }
     375             : 
     376           0 : errno_t sdap_access_recv(struct tevent_req *req)
     377             : {
     378           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     379             : 
     380           0 :     return EOK;
     381             : }
     382             : 
     383             : #define SHADOW_EXPIRE_MSG "Account expired according to shadow attributes"
     384             : 
     385           0 : static errno_t sdap_account_expired_shadow(struct pam_data *pd,
     386             :                                            struct ldb_message *user_entry)
     387             : {
     388             :     int ret;
     389             :     const char *val;
     390             :     long sp_expire;
     391             :     long today;
     392             : 
     393           0 :     DEBUG(SSSDBG_TRACE_FUNC,
     394             :           "Performing access shadow check for user [%s]\n", pd->user);
     395             : 
     396           0 :     val = ldb_msg_find_attr_as_string(user_entry, SYSDB_SHADOWPW_EXPIRE, NULL);
     397           0 :     if (val == NULL) {
     398           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "Shadow expire attribute not found. "
     399             :                   "Access will be granted.\n");
     400           0 :         return EOK;
     401             :     }
     402           0 :     ret = string_to_shadowpw_days(val, &sp_expire);
     403           0 :     if (ret != EOK) {
     404           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to retrieve shadow expire date.\n");
     405           0 :         return ret;
     406             :     }
     407             : 
     408           0 :     today = (long) (time(NULL) / (60 * 60 * 24));
     409           0 :     if (sp_expire > 0 && today > sp_expire) {
     410             : 
     411           0 :         ret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
     412             :                                sizeof(SHADOW_EXPIRE_MSG),
     413             :                                (const uint8_t *) SHADOW_EXPIRE_MSG);
     414           0 :         if (ret != EOK) {
     415           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
     416             :         }
     417             : 
     418           0 :         return ERR_ACCOUNT_EXPIRED;
     419             :     }
     420             : 
     421           0 :     return EOK;
     422             : }
     423             : 
     424             : #define UAC_ACCOUNTDISABLE 0x00000002
     425             : #define AD_NEVER_EXP 0x7fffffffffffffffLL
     426             : #define AD_TO_UNIX_TIME_CONST 11644473600LL
     427             : #define AD_DISABLE_MESSAGE "The user account is disabled on the AD server"
     428             : #define AD_EXPIRED_MESSAGE "The user account is expired on the AD server"
     429             : 
     430           0 : static bool ad_account_expired(uint64_t expiration_time)
     431             : {
     432             :     time_t now;
     433             :     int err;
     434             :     uint64_t nt_now;
     435             : 
     436           0 :     if (expiration_time == 0 || expiration_time == AD_NEVER_EXP) {
     437           0 :         return false;
     438             :     }
     439             : 
     440           0 :     now = time(NULL);
     441           0 :     if (now == ((time_t) -1)) {
     442           0 :         err = errno;
     443           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     444             :               "time failed [%d][%s].\n", err, strerror(err));
     445           0 :         return true;
     446             :     }
     447             : 
     448             :     /* NT timestamps start at 1601-01-01 and use a 100ns base */
     449           0 :     nt_now = (now + AD_TO_UNIX_TIME_CONST) * 1000 * 1000 * 10;
     450             : 
     451           0 :     if (nt_now > expiration_time) {
     452           0 :         return true;
     453             :     }
     454             : 
     455           0 :     return false;
     456             : }
     457             : 
     458           0 : static errno_t sdap_account_expired_ad(struct pam_data *pd,
     459             :                                        struct ldb_message *user_entry)
     460             : {
     461             :     uint32_t uac;
     462             :     uint64_t expiration_time;
     463             :     int ret;
     464             : 
     465           0 :     DEBUG(SSSDBG_TRACE_FUNC,
     466             :           "Performing AD access check for user [%s]\n", pd->user);
     467             : 
     468           0 :     uac = ldb_msg_find_attr_as_uint(user_entry, SYSDB_AD_USER_ACCOUNT_CONTROL,
     469             :                                     0);
     470           0 :     DEBUG(SSSDBG_TRACE_ALL, "User account control for user [%s] is [%X].\n",
     471             :               pd->user, uac);
     472             : 
     473           0 :     expiration_time = ldb_msg_find_attr_as_uint64(user_entry,
     474             :                                                   SYSDB_AD_ACCOUNT_EXPIRES, 0);
     475           0 :     DEBUG(SSSDBG_TRACE_ALL,
     476             :           "Expiration time for user [%s] is [%"PRIu64"].\n",
     477             :            pd->user, expiration_time);
     478             : 
     479           0 :     if (uac & UAC_ACCOUNTDISABLE) {
     480             : 
     481           0 :         ret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
     482             :                                sizeof(AD_DISABLE_MESSAGE),
     483             :                                (const uint8_t *) AD_DISABLE_MESSAGE);
     484           0 :         if (ret != EOK) {
     485           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
     486             :         }
     487             : 
     488           0 :         return ERR_ACCESS_DENIED;
     489             : 
     490           0 :     } else if (ad_account_expired(expiration_time)) {
     491             : 
     492           0 :         ret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
     493             :                                sizeof(AD_EXPIRED_MESSAGE),
     494             :                                (const uint8_t *) AD_EXPIRED_MESSAGE);
     495           0 :         if (ret != EOK) {
     496           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
     497             :         }
     498             : 
     499           0 :         return ERR_ACCOUNT_EXPIRED;
     500             :     }
     501             : 
     502           0 :     return EOK;
     503             : }
     504             : 
     505             : #define RHDS_LOCK_MSG "The user account is locked on the server"
     506             : 
     507           0 : static errno_t sdap_account_expired_rhds(struct pam_data *pd,
     508             :                                          struct ldb_message *user_entry)
     509             : {
     510             :     bool locked;
     511             :     int ret;
     512             : 
     513           0 :     DEBUG(SSSDBG_TRACE_FUNC,
     514             :           "Performing RHDS access check for user [%s]\n", pd->user);
     515             : 
     516           0 :     locked = ldb_msg_find_attr_as_bool(user_entry, SYSDB_NS_ACCOUNT_LOCK, false);
     517           0 :     DEBUG(SSSDBG_TRACE_ALL, "Account for user [%s] is%s locked.\n", pd->user,
     518             :               locked ? "" : " not" );
     519             : 
     520           0 :     if (locked) {
     521           0 :         ret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
     522             :                                sizeof(RHDS_LOCK_MSG),
     523             :                                (const uint8_t *) RHDS_LOCK_MSG);
     524           0 :         if (ret != EOK) {
     525           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
     526             :         }
     527             : 
     528           0 :         return ERR_ACCESS_DENIED;
     529             :     }
     530             : 
     531           0 :     return EOK;
     532             : }
     533             : 
     534             : #define NDS_DISABLE_MSG "The user account is disabled on the server"
     535             : #define NDS_EXPIRED_MSG "The user account is expired"
     536             : #define NDS_TIME_MAP_MSG "The user account is not allowed at this time"
     537             : 
     538           7 : bool nds_check_expired(const char *exp_time_str)
     539             : {
     540             :     time_t expire_time;
     541             :     time_t now;
     542             :     errno_t ret;
     543             : 
     544           7 :     if (exp_time_str == NULL) {
     545           1 :         DEBUG(SSSDBG_TRACE_ALL,
     546             :               "ndsLoginExpirationTime is not set, access granted.\n");
     547           1 :         return false;
     548             :     }
     549             : 
     550           6 :     ret = sss_utc_to_time_t(exp_time_str, "%Y%m%d%H%M%SZ",
     551             :                             &expire_time);
     552           6 :     if (ret != EOK) {
     553           2 :         DEBUG(SSSDBG_MINOR_FAILURE, "sss_utc_to_time_t failed with %d:%s.\n",
     554             :               ret, sss_strerror(ret));
     555           2 :         return true;
     556             :     }
     557             : 
     558           4 :     now = time(NULL);
     559           4 :     DEBUG(SSSDBG_TRACE_ALL,
     560             :           "Time info: tzname[0] [%s] tzname[1] [%s] timezone [%ld] "
     561             :            "daylight [%d] now [%ld] expire_time [%ld].\n", tzname[0],
     562             :            tzname[1], timezone, daylight, now, expire_time);
     563             : 
     564           4 :     if (difftime(now, expire_time) > 0.0) {
     565           1 :         DEBUG(SSSDBG_CONF_SETTINGS, "NDS account expired.\n");
     566           1 :         return true;
     567             :     }
     568             : 
     569           3 :     return false;
     570             : }
     571             : 
     572             : /* There is no real documentation of the byte string value of
     573             :  * loginAllowedTimeMap, but some good example code in
     574             :  * http://http://developer.novell.com/documentation/samplecode/extjndi_sample/CheckBind.java.html
     575             :  */
     576           0 : static bool nds_check_time_map(const struct ldb_val *time_map)
     577             : {
     578             :     time_t now;
     579             :     struct tm *tm_now;
     580             :     size_t map_index;
     581             :     div_t q;
     582           0 :     uint8_t mask = 0;
     583             : 
     584           0 :     if (time_map == NULL) {
     585           0 :         DEBUG(SSSDBG_TRACE_ALL,
     586             :               "loginAllowedTimeMap is missing, access granted.\n");
     587           0 :         return false;
     588             :     }
     589             : 
     590           0 :     if (time_map->length != 42) {
     591           0 :         DEBUG(SSSDBG_FUNC_DATA,
     592             :               "Allowed time map has the wrong size, "
     593             :                "got [%zu], expected 42.\n", time_map->length);
     594           0 :         return true;
     595             :     }
     596             : 
     597           0 :     now = time(NULL);
     598           0 :     tm_now = gmtime(&now);
     599             : 
     600           0 :     map_index = tm_now->tm_wday * 48 + tm_now->tm_hour * 2 +
     601           0 :                 (tm_now->tm_min < 30 ? 0 : 1);
     602             : 
     603           0 :     if (map_index > 335) {
     604           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     605             :               "Unexpected index value [%zu] for time map.\n", map_index);
     606           0 :         return true;
     607             :     }
     608             : 
     609           0 :     q = div(map_index, 8);
     610             : 
     611           0 :     if (q.quot > 41 || q.quot < 0 || q.rem > 7 || q.rem < 0) {
     612           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     613             :               "Unexpected result of div(), [%zu][%d][%d].\n",
     614             :                map_index, q.quot, q.rem);
     615           0 :         return true;
     616             :     }
     617             : 
     618           0 :     if (q.rem > 0) {
     619           0 :         mask = 1 << q.rem;
     620             :     }
     621             : 
     622           0 :     if (time_map->data[q.quot] & mask) {
     623           0 :         DEBUG(SSSDBG_CONF_SETTINGS, "Access allowed by time map.\n");
     624           0 :         return false;
     625             :     }
     626             : 
     627           0 :     return true;
     628             : }
     629             : 
     630           0 : static errno_t sdap_account_expired_nds(struct pam_data *pd,
     631             :                                          struct ldb_message *user_entry)
     632             : {
     633           0 :     bool locked = true;
     634             :     int ret;
     635             :     const char *exp_time_str;
     636             :     const struct ldb_val *time_map;
     637             : 
     638           0 :     DEBUG(SSSDBG_TRACE_FUNC,
     639             :           "Performing NDS access check for user [%s]\n", pd->user);
     640             : 
     641           0 :     locked = ldb_msg_find_attr_as_bool(user_entry, SYSDB_NDS_LOGIN_DISABLED,
     642             :                                        false);
     643           0 :     DEBUG(SSSDBG_TRACE_ALL, "Account for user [%s] is%s disabled.\n", pd->user,
     644             :               locked ? "" : " not");
     645             : 
     646           0 :     if (locked) {
     647           0 :         ret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
     648             :                                sizeof(NDS_DISABLE_MSG),
     649             :                                (const uint8_t *) NDS_DISABLE_MSG);
     650           0 :         if (ret != EOK) {
     651           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
     652             :         }
     653             : 
     654           0 :         return ERR_ACCESS_DENIED;
     655             : 
     656             :     } else {
     657           0 :         exp_time_str = ldb_msg_find_attr_as_string(user_entry,
     658             :                                                 SYSDB_NDS_LOGIN_EXPIRATION_TIME,
     659             :                                                 NULL);
     660           0 :         locked = nds_check_expired(exp_time_str);
     661             : 
     662           0 :         DEBUG(SSSDBG_TRACE_ALL,
     663             :               "Account for user [%s] is%s expired.\n", pd->user,
     664             :                   locked ? "" : " not");
     665             : 
     666           0 :         if (locked) {
     667           0 :             ret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
     668             :                                    sizeof(NDS_EXPIRED_MSG),
     669             :                                    (const uint8_t *) NDS_EXPIRED_MSG);
     670           0 :             if (ret != EOK) {
     671           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
     672             :             }
     673             : 
     674           0 :             return ERR_ACCESS_DENIED;
     675             : 
     676             :         } else {
     677           0 :             time_map = ldb_msg_find_ldb_val(user_entry,
     678             :                                             SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP);
     679             : 
     680           0 :             locked = nds_check_time_map(time_map);
     681             : 
     682           0 :             DEBUG(SSSDBG_TRACE_ALL,
     683             :                   "Account for user [%s] is%s locked at this time.\n",
     684             :                       pd->user, locked ? "" : " not");
     685             : 
     686           0 :             if (locked) {
     687           0 :                 ret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
     688             :                                        sizeof(NDS_TIME_MAP_MSG),
     689             :                                        (const uint8_t *) NDS_TIME_MAP_MSG);
     690           0 :                 if (ret != EOK) {
     691           0 :                     DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
     692             :                 }
     693             : 
     694           0 :                 return ERR_ACCESS_DENIED;
     695             :             }
     696             :         }
     697             :     }
     698             : 
     699           0 :     return EOK;
     700             : }
     701             : 
     702           0 : static errno_t sdap_account_expired(struct sdap_access_ctx *access_ctx,
     703             :                                     struct pam_data *pd,
     704             :                                     struct ldb_message *user_entry)
     705             : {
     706             :     const char *expire;
     707             :     int ret;
     708             : 
     709           0 :     expire = dp_opt_get_cstring(access_ctx->id_ctx->opts->basic,
     710             :                                 SDAP_ACCOUNT_EXPIRE_POLICY);
     711           0 :     if (expire == NULL) {
     712           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     713             :               "Missing account expire policy. Access denied\n");
     714           0 :         return ERR_ACCESS_DENIED;
     715             :     } else {
     716           0 :         if (strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_SHADOW) == 0) {
     717           0 :             ret = sdap_account_expired_shadow(pd, user_entry);
     718           0 :             if (ret == ERR_ACCOUNT_EXPIRED) {
     719           0 :                 DEBUG(SSSDBG_TRACE_FUNC,
     720             :                       "sdap_account_expired_shadow: %s.\n", sss_strerror(ret));
     721           0 :             } else if (ret != EOK) {
     722           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     723             :                       "sdap_account_expired_shadow failed.\n");
     724             :             }
     725           0 :         } else if (strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_AD) == 0) {
     726           0 :             ret = sdap_account_expired_ad(pd, user_entry);
     727           0 :             if (ret == ERR_ACCOUNT_EXPIRED || ret == ERR_ACCESS_DENIED) {
     728           0 :                 DEBUG(SSSDBG_TRACE_FUNC,
     729             :                       "sdap_account_expired_ad: %s.\n", sss_strerror(ret));
     730           0 :             } else if (ret != EOK) {
     731           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "sdap_account_expired_ad failed.\n");
     732             :             }
     733           0 :         } else if (strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_RHDS) == 0 ||
     734           0 :                    strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_IPA) == 0 ||
     735           0 :                    strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_389DS) == 0) {
     736           0 :             ret = sdap_account_expired_rhds(pd, user_entry);
     737           0 :             if (ret == ERR_ACCESS_DENIED) {
     738           0 :                 DEBUG(SSSDBG_TRACE_FUNC,
     739             :                       "sdap_account_expired_rhds: %s.\n", sss_strerror(ret));
     740           0 :             } else if (ret != EOK) {
     741           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     742             :                       "sdap_account_expired_rhds failed.\n");
     743             :             }
     744             : 
     745           0 :             if (ret == EOK &&
     746           0 :                     strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_IPA) == 0) {
     747           0 :                 DEBUG(SSSDBG_TRACE_FUNC,
     748             :                       "IPA access control succeeded, checking AD "
     749             :                       "access control\n");
     750           0 :                 ret = sdap_account_expired_ad(pd, user_entry);
     751           0 :                 if (ret == ERR_ACCOUNT_EXPIRED || ret == ERR_ACCESS_DENIED) {
     752           0 :                     DEBUG(SSSDBG_TRACE_FUNC,
     753             :                         "sdap_account_expired_ad: %s.\n", sss_strerror(ret));
     754           0 :                 } else if (ret != EOK) {
     755           0 :                     DEBUG(SSSDBG_CRIT_FAILURE,
     756             :                           "sdap_account_expired_ad failed.\n");
     757             :                 }
     758             :             }
     759           0 :         } else if (strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_NDS) == 0) {
     760           0 :             ret = sdap_account_expired_nds(pd, user_entry);
     761           0 :             if (ret == ERR_ACCESS_DENIED) {
     762           0 :                 DEBUG(SSSDBG_TRACE_FUNC,
     763             :                       "sdap_account_expired_nds: %s.\n", sss_strerror(ret));
     764           0 :             } else if (ret != EOK) {
     765           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     766             :                       "sdap_account_expired_nds failed.\n");
     767             :             }
     768             :         } else {
     769           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     770             :                   "Unsupported LDAP account expire policy [%s]. "
     771             :                       "Access denied.\n", expire);
     772           0 :             ret = ERR_ACCESS_DENIED;
     773             :         }
     774             :     }
     775             : 
     776           0 :     return ret;
     777             : }
     778             : 
     779           0 : static errno_t perform_pwexpire_policy(TALLOC_CTX *mem_ctx,
     780             :                                        struct sss_domain_info *domain,
     781             :                                        struct pam_data *pd,
     782             :                                        struct sdap_options *opts)
     783             : {
     784             :     enum pwexpire pw_expire_type;
     785             :     void *pw_expire_data;
     786             :     errno_t ret;
     787             :     char *dn;
     788             : 
     789           0 :     ret = get_user_dn(mem_ctx, domain, opts, pd->user, &dn, &pw_expire_type,
     790             :                       &pw_expire_data);
     791           0 :     if (ret != EOK) {
     792           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "get_user_dn returned %d:[%s].\n",
     793             :               ret, sss_strerror(ret));
     794           0 :         goto done;
     795             :     }
     796             : 
     797           0 :     ret = check_pwexpire_policy(pw_expire_type, pw_expire_data, pd,
     798             :                                 domain->pwd_expiration_warning);
     799           0 :     if (ret != EOK) {
     800           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     801             :               "check_pwexpire_policy returned %d:[%s].\n",
     802             :               ret, sss_strerror(ret));
     803           0 :         goto done;
     804             :     }
     805             : 
     806             : done:
     807           0 :     return ret;
     808             : }
     809             : 
     810             : struct sdap_access_filter_req_ctx {
     811             :     const char *username;
     812             :     const char *filter;
     813             :     struct tevent_context *ev;
     814             :     struct sdap_access_ctx *access_ctx;
     815             :     struct sdap_options *opts;
     816             :     struct sdap_id_conn_ctx *conn;
     817             :     struct sdap_id_op *sdap_op;
     818             :     struct sysdb_handle *handle;
     819             :     struct sss_domain_info *domain;
     820             :     /* cached result of access control checks */
     821             :     bool cached_access;
     822             :     const char *basedn;
     823             : };
     824             : 
     825             : static errno_t sdap_access_decide_offline(bool cached_ac);
     826             : static int sdap_access_filter_retry(struct tevent_req *req);
     827             : static void sdap_access_ppolicy_connect_done(struct tevent_req *subreq);
     828             : static errno_t sdap_access_ppolicy_get_lockout_step(struct tevent_req *req);
     829             : static void sdap_access_filter_connect_done(struct tevent_req *subreq);
     830             : static void sdap_access_filter_done(struct tevent_req *req);
     831           0 : static struct tevent_req *sdap_access_filter_send(TALLOC_CTX *mem_ctx,
     832             :                                              struct tevent_context *ev,
     833             :                                              struct be_ctx *be_ctx,
     834             :                                              struct sss_domain_info *domain,
     835             :                                              struct sdap_access_ctx *access_ctx,
     836             :                                              struct sdap_id_conn_ctx *conn,
     837             :                                              const char *username,
     838             :                                              struct ldb_message *user_entry)
     839             : {
     840             :     struct sdap_access_filter_req_ctx *state;
     841             :     struct tevent_req *req;
     842             :     char *clean_username;
     843           0 :     errno_t ret = ERR_INTERNAL;
     844             :     char *name;
     845             : 
     846           0 :     req = tevent_req_create(mem_ctx, &state, struct sdap_access_filter_req_ctx);
     847           0 :     if (req == NULL) {
     848           0 :         return NULL;
     849             :     }
     850             : 
     851           0 :     if (access_ctx->filter == NULL || *access_ctx->filter == '\0') {
     852             :         /* If no filter is set, default to restrictive */
     853           0 :         DEBUG(SSSDBG_TRACE_FUNC, "No filter set. Access is denied.\n");
     854           0 :         ret = ERR_ACCESS_DENIED;
     855           0 :         goto done;
     856             :     }
     857             : 
     858           0 :     state->filter = NULL;
     859           0 :     state->username = username;
     860           0 :     state->opts = access_ctx->id_ctx->opts;
     861           0 :     state->conn = conn;
     862           0 :     state->ev = ev;
     863           0 :     state->access_ctx = access_ctx;
     864           0 :     state->domain = domain;
     865             : 
     866           0 :     DEBUG(SSSDBG_TRACE_FUNC,
     867             :           "Performing access filter check for user [%s]\n", username);
     868             : 
     869           0 :     state->cached_access = ldb_msg_find_attr_as_bool(user_entry,
     870             :                                                      SYSDB_LDAP_ACCESS_FILTER,
     871             :                                                      false);
     872             : 
     873             :     /* Ok, we have one result, check if we are online or offline */
     874           0 :     if (be_is_offline(be_ctx)) {
     875             :         /* Ok, we're offline. Return from the cache */
     876           0 :         ret = sdap_access_decide_offline(state->cached_access);
     877           0 :         goto done;
     878             :     }
     879             : 
     880           0 :     ret = sdap_get_basedn_user_entry(user_entry, state->username,
     881           0 :                                      &state->basedn);
     882           0 :     if (ret != EOK) {
     883           0 :         goto done;
     884             :     }
     885             : 
     886             :     /* Construct the filter */
     887             :     /* Subdomain users are identified by FQDN. We need to use just the username */
     888           0 :     ret = sss_parse_name(state, domain->names, username, NULL, &name);
     889           0 :     if (ret != EOK) {
     890           0 :         DEBUG(SSSDBG_OP_FAILURE,
     891             :               "Could not parse [%s] into name and "
     892             :                "domain components, access might fail\n", username);
     893           0 :         name = discard_const(username);
     894             :     }
     895             : 
     896           0 :     ret = sss_filter_sanitize(state, name, &clean_username);
     897           0 :     if (ret != EOK) {
     898           0 :         goto done;
     899             :     }
     900             : 
     901           0 :     state->filter = talloc_asprintf(
     902             :         state,
     903             :         "(&(%s=%s)(objectclass=%s)%s)",
     904           0 :         state->opts->user_map[SDAP_AT_USER_NAME].name,
     905             :         clean_username,
     906           0 :         state->opts->user_map[SDAP_OC_USER].name,
     907           0 :         state->access_ctx->filter);
     908           0 :     if (state->filter == NULL) {
     909           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Could not construct access filter\n");
     910           0 :         ret = ENOMEM;
     911           0 :         goto done;
     912             :     }
     913           0 :     talloc_zfree(clean_username);
     914             : 
     915           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Checking filter against LDAP\n");
     916             : 
     917           0 :     state->sdap_op = sdap_id_op_create(state,
     918           0 :                                        state->conn->conn_cache);
     919           0 :     if (!state->sdap_op) {
     920           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
     921           0 :         ret = ENOMEM;
     922           0 :         goto done;
     923             :     }
     924             : 
     925           0 :     ret = sdap_access_filter_retry(req);
     926           0 :     if (ret != EOK) {
     927           0 :         goto done;
     928             :     }
     929             : 
     930           0 :     return req;
     931             : 
     932             : done:
     933           0 :     if (ret == EOK) {
     934           0 :         tevent_req_done(req);
     935             :     } else {
     936           0 :         tevent_req_error(req, ret);
     937             :     }
     938           0 :     tevent_req_post(req, ev);
     939           0 :     return req;
     940             : }
     941             : 
     942             : /* Helper function,
     943             :  * cached_ac => access granted
     944             :  * !cached_ac => access denied
     945             :  */
     946           0 : static errno_t sdap_access_decide_offline(bool cached_ac)
     947             : {
     948           0 :     if (cached_ac) {
     949           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Access granted by cached credentials\n");
     950           0 :         return EOK;
     951             :     } else {
     952           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Access denied by cached credentials\n");
     953           0 :         return ERR_ACCESS_DENIED;
     954             :     }
     955             : }
     956             : 
     957           0 : static int sdap_access_filter_retry(struct tevent_req *req)
     958             : {
     959           0 :     struct sdap_access_filter_req_ctx *state =
     960           0 :             tevent_req_data(req, struct sdap_access_filter_req_ctx);
     961             :     struct tevent_req *subreq;
     962             :     int ret;
     963             : 
     964           0 :     subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
     965           0 :     if (!subreq) {
     966           0 :         DEBUG(SSSDBG_OP_FAILURE,
     967             :               "sdap_id_op_connect_send failed: %d (%s)\n", ret, strerror(ret));
     968           0 :         return ret;
     969             :     }
     970             : 
     971           0 :     tevent_req_set_callback(subreq, sdap_access_filter_connect_done, req);
     972           0 :     return EOK;
     973             : }
     974             : 
     975           0 : static void sdap_access_filter_connect_done(struct tevent_req *subreq)
     976             : {
     977           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     978             :                                                       struct tevent_req);
     979           0 :     struct sdap_access_filter_req_ctx *state =
     980           0 :             tevent_req_data(req, struct sdap_access_filter_req_ctx);
     981             :     int ret, dp_error;
     982             : 
     983           0 :     ret = sdap_id_op_connect_recv(subreq, &dp_error);
     984           0 :     talloc_zfree(subreq);
     985             : 
     986           0 :     if (ret != EOK) {
     987           0 :         if (dp_error == DP_ERR_OFFLINE) {
     988           0 :             ret = sdap_access_decide_offline(state->cached_access);
     989           0 :             if (ret == EOK) {
     990           0 :                 tevent_req_done(req);
     991           0 :                 return;
     992             :             }
     993             :         }
     994             : 
     995           0 :         tevent_req_error(req, ret);
     996           0 :         return;
     997             :     }
     998             : 
     999             :     /* Connection to LDAP succeeded
    1000             :      * Send filter request
    1001             :      */
    1002           0 :     subreq = sdap_get_generic_send(state,
    1003             :                                    state->ev,
    1004             :                                    state->opts,
    1005             :                                    sdap_id_op_handle(state->sdap_op),
    1006             :                                    state->basedn,
    1007             :                                    LDAP_SCOPE_BASE,
    1008             :                                    state->filter, NULL,
    1009             :                                    NULL, 0,
    1010           0 :                                    dp_opt_get_int(state->opts->basic,
    1011             :                                                   SDAP_SEARCH_TIMEOUT),
    1012             :                                    false);
    1013           0 :     if (subreq == NULL) {
    1014           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Could not start LDAP communication\n");
    1015           0 :         tevent_req_error(req, EIO);
    1016           0 :         return;
    1017             :     }
    1018             : 
    1019           0 :     tevent_req_set_callback(subreq, sdap_access_filter_done, req);
    1020             : }
    1021             : 
    1022           0 : static void sdap_access_filter_done(struct tevent_req *subreq)
    1023             : {
    1024             :     int ret, tret, dp_error;
    1025             :     size_t num_results;
    1026           0 :     bool found = false;
    1027             :     struct sysdb_attrs **results;
    1028           0 :     struct tevent_req *req =
    1029           0 :             tevent_req_callback_data(subreq, struct tevent_req);
    1030           0 :     struct sdap_access_filter_req_ctx *state =
    1031           0 :             tevent_req_data(req, struct sdap_access_filter_req_ctx);
    1032             : 
    1033           0 :     ret = sdap_get_generic_recv(subreq, state,
    1034             :                                 &num_results, &results);
    1035           0 :     talloc_zfree(subreq);
    1036             : 
    1037           0 :     ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
    1038           0 :     if (ret != EOK) {
    1039           0 :         if (dp_error == DP_ERR_OK) {
    1040             :             /* retry */
    1041           0 :             tret = sdap_access_filter_retry(req);
    1042           0 :             if (tret == EOK) {
    1043           0 :                 return;
    1044             :             }
    1045           0 :         } else if (dp_error == DP_ERR_OFFLINE) {
    1046           0 :             ret = sdap_access_decide_offline(state->cached_access);
    1047           0 :         } else if (ret == ERR_INVALID_FILTER) {
    1048           0 :             sss_log(SSS_LOG_ERR, MALFORMED_FILTER, state->filter);
    1049           0 :             DEBUG(SSSDBG_CRIT_FAILURE, MALFORMED_FILTER, state->filter);
    1050           0 :             ret = ERR_ACCESS_DENIED;
    1051             :         } else {
    1052           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1053             :                   "sdap_get_generic_send() returned error [%d][%s]\n",
    1054             :                       ret, sss_strerror(ret));
    1055             :         }
    1056             : 
    1057           0 :         goto done;
    1058             :     }
    1059             : 
    1060             :     /* Check the number of responses we got
    1061             :      * If it's exactly 1, we passed the check
    1062             :      * If it's < 1, we failed the check
    1063             :      * Anything else is an error
    1064             :      */
    1065           0 :     if (num_results < 1) {
    1066           0 :         DEBUG(SSSDBG_CONF_SETTINGS,
    1067             :               "User [%s] was not found with the specified filter. "
    1068             :                   "Denying access.\n", state->username);
    1069           0 :         found = false;
    1070             :     }
    1071           0 :     else if (results == NULL) {
    1072           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "num_results > 0, but results is NULL\n");
    1073           0 :         ret = ERR_INTERNAL;
    1074           0 :         goto done;
    1075             :     }
    1076           0 :     else if (num_results > 1) {
    1077             :         /* It should not be possible to get more than one reply
    1078             :          * here, since we're doing a base-scoped search
    1079             :          */
    1080           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Received multiple replies\n");
    1081           0 :         ret = ERR_INTERNAL;
    1082           0 :         goto done;
    1083             :     }
    1084             :     else { /* Ok, we got a single reply */
    1085           0 :         found = true;
    1086             :     }
    1087             : 
    1088           0 :     if (found) {
    1089             :         /* Save "allow" to the cache for future offline access checks. */
    1090           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Access granted by online lookup\n");
    1091           0 :         ret = EOK;
    1092             :     }
    1093             :     else {
    1094             :         /* Save "disallow" to the cache for future offline
    1095             :          * access checks.
    1096             :          */
    1097           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Access denied by online lookup\n");
    1098           0 :         ret = ERR_ACCESS_DENIED;
    1099             :     }
    1100             : 
    1101           0 :     tret = sdap_save_user_cache_bool(state->domain, state->username,
    1102             :                                      SYSDB_LDAP_ACCESS_FILTER, found);
    1103           0 :     if (tret != EOK) {
    1104             :         /* Failing to save to the cache is non-fatal.
    1105             :          * Just return the result.
    1106             :          */
    1107           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set user access attribute\n");
    1108           0 :         goto done;
    1109             :     }
    1110             : 
    1111             : done:
    1112           0 :     if (ret == EOK) {
    1113           0 :         tevent_req_done(req);
    1114             :     }
    1115             :     else {
    1116           0 :         tevent_req_error(req, ret);
    1117             :     }
    1118             : }
    1119             : 
    1120           0 : static errno_t sdap_access_filter_recv(struct tevent_req *req)
    1121             : {
    1122           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
    1123             : 
    1124           0 :     return EOK;
    1125             : }
    1126             : 
    1127             : #define AUTHR_SRV_MISSING_MSG "Authorized service attribute missing, " \
    1128             :                               "access denied"
    1129             : #define AUTHR_SRV_DENY_MSG "Access denied by authorized service attribute"
    1130             : #define AUTHR_SRV_NO_MATCH_MSG "Authorized service attribute has " \
    1131             :                                "no matching rule, access denied"
    1132             : 
    1133           0 : static errno_t sdap_access_service(struct pam_data *pd,
    1134             :                                    struct ldb_message *user_entry)
    1135             : {
    1136             :     errno_t ret, tret;
    1137             :     struct ldb_message_element *el;
    1138             :     unsigned int i;
    1139             :     char *service;
    1140             : 
    1141           0 :     el = ldb_msg_find_element(user_entry, SYSDB_AUTHORIZED_SERVICE);
    1142           0 :     if (!el || el->num_values == 0) {
    1143           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    1144             :               "Missing authorized services. Access denied\n");
    1145             : 
    1146           0 :         tret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
    1147             :                                sizeof(AUTHR_SRV_MISSING_MSG),
    1148             :                                (const uint8_t *) AUTHR_SRV_MISSING_MSG);
    1149           0 :         if (tret != EOK) {
    1150           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
    1151             :         }
    1152             : 
    1153           0 :         return ERR_ACCESS_DENIED;
    1154             :     }
    1155             : 
    1156           0 :     ret = ENOENT;
    1157             : 
    1158           0 :     for (i = 0; i < el->num_values; i++) {
    1159           0 :         service = (char *)el->values[i].data;
    1160           0 :         if (service[0] == '!' &&
    1161           0 :                 strcasecmp(pd->service, service+1) == 0) {
    1162             :             /* This service is explicitly denied */
    1163           0 :             DEBUG(SSSDBG_CONF_SETTINGS, "Access denied by [%s]\n", service);
    1164             : 
    1165           0 :             tret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
    1166             :                                    sizeof(AUTHR_SRV_DENY_MSG),
    1167             :                                    (const uint8_t *) AUTHR_SRV_DENY_MSG);
    1168           0 :             if (tret != EOK) {
    1169           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
    1170             :             }
    1171             : 
    1172             :             /* A denial trumps all. Break here */
    1173           0 :             return ERR_ACCESS_DENIED;
    1174             : 
    1175           0 :         } else if (strcasecmp(pd->service, service) == 0) {
    1176             :             /* This service is explicitly allowed */
    1177           0 :             DEBUG(SSSDBG_CONF_SETTINGS, "Access granted for [%s]\n", service);
    1178             :             /* We still need to loop through to make sure
    1179             :              * that it's not also explicitly denied
    1180             :              */
    1181           0 :             ret = EOK;
    1182           0 :         } else if (strcmp("*", service) == 0) {
    1183             :             /* This user has access to all services */
    1184           0 :             DEBUG(SSSDBG_CONF_SETTINGS, "Access granted to all services\n");
    1185             :             /* We still need to loop through to make sure
    1186             :              * that it's not also explicitly denied
    1187             :              */
    1188           0 :             ret = EOK;
    1189             :         }
    1190             :     }
    1191             : 
    1192           0 :     if (ret == ENOENT) {
    1193           0 :         DEBUG(SSSDBG_CONF_SETTINGS, "No matching service rule found\n");
    1194             : 
    1195           0 :         tret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
    1196             :                                sizeof(AUTHR_SRV_NO_MATCH_MSG),
    1197             :                                (const uint8_t *) AUTHR_SRV_NO_MATCH_MSG);
    1198           0 :         if (tret != EOK) {
    1199           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
    1200             :         }
    1201             : 
    1202           0 :         ret = ERR_ACCESS_DENIED;
    1203             :     }
    1204             : 
    1205           0 :     return ret;
    1206             : }
    1207             : 
    1208           0 : static errno_t sdap_save_user_cache_bool(struct sss_domain_info *domain,
    1209             :                                          const char *username,
    1210             :                                          const char *attr_name,
    1211             :                                          bool value)
    1212             : {
    1213             :     errno_t ret;
    1214             :     struct sysdb_attrs *attrs;
    1215             : 
    1216           0 :     attrs = sysdb_new_attrs(NULL);
    1217           0 :     if (attrs == NULL) {
    1218           0 :         ret = ENOMEM;
    1219           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Could not set up attrs\n");
    1220           0 :         goto done;
    1221             :     }
    1222             : 
    1223           0 :     ret = sysdb_attrs_add_bool(attrs, attr_name, value);
    1224           0 :     if (ret != EOK) {
    1225           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Could not set up attrs\n");
    1226           0 :         goto done;
    1227             :     }
    1228             : 
    1229           0 :     ret = sysdb_set_user_attr(domain, username, attrs, SYSDB_MOD_REP);
    1230           0 :     if (ret != EOK) {
    1231           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set user access attribute\n");
    1232           0 :         goto done;
    1233             :     }
    1234             : 
    1235             : done:
    1236           0 :     talloc_free(attrs);
    1237           0 :     return ret;
    1238             : }
    1239             : 
    1240           0 : static errno_t sdap_access_host(struct ldb_message *user_entry)
    1241             : {
    1242             :     errno_t ret;
    1243             :     struct ldb_message_element *el;
    1244             :     unsigned int i;
    1245             :     char *host;
    1246             :     char hostname[HOST_NAME_MAX + 1];
    1247             : 
    1248           0 :     el = ldb_msg_find_element(user_entry, SYSDB_AUTHORIZED_HOST);
    1249           0 :     if (!el || el->num_values == 0) {
    1250           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Missing hosts. Access denied\n");
    1251           0 :         return ERR_ACCESS_DENIED;
    1252             :     }
    1253             : 
    1254           0 :     if (gethostname(hostname, HOST_NAME_MAX) == -1) {
    1255           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    1256             :               "Unable to get system hostname. Access denied\n");
    1257           0 :         return ERR_ACCESS_DENIED;
    1258             :     }
    1259           0 :     hostname[HOST_NAME_MAX] = '\0';
    1260             : 
    1261             :     /* FIXME: PADL's pam_ldap also calls gethostbyname() on the hostname
    1262             :      *        in some attempt to get aliases and/or FQDN for the machine.
    1263             :      *        Not sure this is a good idea, but we might want to add it in
    1264             :      *        order to be compatible...
    1265             :      */
    1266             : 
    1267           0 :     ret = ENOENT;
    1268             : 
    1269           0 :     for (i = 0; i < el->num_values; i++) {
    1270           0 :         host = (char *)el->values[i].data;
    1271           0 :         if (host[0] == '!' &&
    1272           0 :                 strcasecmp(hostname, host+1) == 0) {
    1273             :             /* This host is explicitly denied */
    1274           0 :             DEBUG(SSSDBG_CONF_SETTINGS, "Access denied by [%s]\n", host);
    1275             :             /* A denial trumps all. Break here */
    1276           0 :             return ERR_ACCESS_DENIED;
    1277             : 
    1278           0 :         } else if (strcasecmp(hostname, host) == 0) {
    1279             :             /* This host is explicitly allowed */
    1280           0 :             DEBUG(SSSDBG_CONF_SETTINGS, "Access granted for [%s]\n", host);
    1281             :             /* We still need to loop through to make sure
    1282             :              * that it's not also explicitly denied
    1283             :              */
    1284           0 :             ret = EOK;
    1285           0 :         } else if (strcmp("*", host) == 0) {
    1286             :             /* This user has access to all hosts */
    1287           0 :             DEBUG(SSSDBG_CONF_SETTINGS, "Access granted to all hosts\n");
    1288             :             /* We still need to loop through to make sure
    1289             :              * that it's not also explicitly denied
    1290             :              */
    1291           0 :             ret = EOK;
    1292             :         }
    1293             :     }
    1294             : 
    1295           0 :     if (ret == ENOENT) {
    1296           0 :         DEBUG(SSSDBG_CONF_SETTINGS, "No matching host rule found\n");
    1297           0 :         ret = ERR_ACCESS_DENIED;
    1298             :     }
    1299             : 
    1300           0 :     return ret;
    1301             : }
    1302             : 
    1303             : static void sdap_access_ppolicy_get_lockout_done(struct tevent_req *subreq);
    1304             : static int sdap_access_ppolicy_retry(struct tevent_req *req);
    1305             : static errno_t sdap_access_ppolicy_step(struct tevent_req *req);
    1306             : static void sdap_access_ppolicy_step_done(struct tevent_req *subreq);
    1307             : 
    1308             : struct sdap_access_ppolicy_req_ctx {
    1309             :     const char *username;
    1310             :     const char *filter;
    1311             :     struct tevent_context *ev;
    1312             :     struct sdap_access_ctx *access_ctx;
    1313             :     struct sdap_options *opts;
    1314             :     struct sdap_id_conn_ctx *conn;
    1315             :     struct sdap_id_op *sdap_op;
    1316             :     struct sysdb_handle *handle;
    1317             :     struct sss_domain_info *domain;
    1318             :     /* cached results of access control checks */
    1319             :     bool cached_access;
    1320             :     const char *basedn;
    1321             :     /* default DNs to ppolicy */
    1322             :     const char **ppolicy_dns;
    1323             :     unsigned int ppolicy_dns_index;
    1324             :     enum sdap_pwpolicy_mode pwpol_mode;
    1325             : };
    1326             : 
    1327             : static struct tevent_req *
    1328           0 : sdap_access_ppolicy_send(TALLOC_CTX *mem_ctx,
    1329             :                          struct tevent_context *ev,
    1330             :                          struct be_ctx *be_ctx,
    1331             :                          struct sss_domain_info *domain,
    1332             :                          struct sdap_access_ctx *access_ctx,
    1333             :                          struct sdap_id_conn_ctx *conn,
    1334             :                          const char *username,
    1335             :                          struct ldb_message *user_entry,
    1336             :                          enum sdap_pwpolicy_mode pwpol_mode)
    1337             : {
    1338             :     struct sdap_access_ppolicy_req_ctx *state;
    1339             :     struct tevent_req *req;
    1340             :     errno_t ret;
    1341             : 
    1342           0 :     req = tevent_req_create(mem_ctx,
    1343             :                             &state, struct sdap_access_ppolicy_req_ctx);
    1344           0 :     if (req == NULL) {
    1345           0 :         return NULL;
    1346             :     }
    1347             : 
    1348           0 :     state->filter = NULL;
    1349           0 :     state->username = username;
    1350           0 :     state->opts = access_ctx->id_ctx->opts;
    1351           0 :     state->conn = conn;
    1352           0 :     state->ev = ev;
    1353           0 :     state->access_ctx = access_ctx;
    1354           0 :     state->domain = domain;
    1355           0 :     state->ppolicy_dns_index = 0;
    1356           0 :     state->pwpol_mode = pwpol_mode;
    1357             : 
    1358           0 :     DEBUG(SSSDBG_TRACE_FUNC,
    1359             :           "Performing access ppolicy check for user [%s]\n", username);
    1360             : 
    1361           0 :     state->cached_access = ldb_msg_find_attr_as_bool(
    1362             :         user_entry, SYSDB_LDAP_ACCESS_CACHED_LOCKOUT, false);
    1363             : 
    1364             :     /* Ok, we have one result, check if we are online or offline */
    1365           0 :     if (be_is_offline(be_ctx)) {
    1366             :         /* Ok, we're offline. Return from the cache */
    1367           0 :         ret = sdap_access_decide_offline(state->cached_access);
    1368           0 :         goto done;
    1369             :     }
    1370             : 
    1371           0 :     ret = sdap_get_basedn_user_entry(user_entry, state->username,
    1372           0 :                                      &state->basedn);
    1373           0 :     if (ret != EOK) {
    1374           0 :         goto done;
    1375             :     }
    1376             : 
    1377           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Checking ppolicy against LDAP\n");
    1378             : 
    1379           0 :     state->sdap_op = sdap_id_op_create(state,
    1380           0 :                                        state->conn->conn_cache);
    1381           0 :     if (!state->sdap_op) {
    1382           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
    1383           0 :         ret = ENOMEM;
    1384           0 :         goto done;
    1385             :     }
    1386             : 
    1387           0 :     ret = sdap_access_ppolicy_retry(req);
    1388           0 :     if (ret != EOK) {
    1389           0 :         goto done;
    1390             :     }
    1391             : 
    1392           0 :     return req;
    1393             : 
    1394             : done:
    1395           0 :     if (ret == EOK) {
    1396           0 :         tevent_req_done(req);
    1397             :     } else {
    1398           0 :         tevent_req_error(req, ret);
    1399             :     }
    1400           0 :     tevent_req_post(req, ev);
    1401           0 :     return req;
    1402             : }
    1403             : 
    1404           0 : static int sdap_access_ppolicy_retry(struct tevent_req *req)
    1405             : {
    1406             :     struct sdap_access_ppolicy_req_ctx *state;
    1407             :     struct tevent_req *subreq;
    1408             :     int ret;
    1409             : 
    1410           0 :     state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
    1411           0 :     subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
    1412           0 :     if (!subreq) {
    1413           0 :         DEBUG(SSSDBG_OP_FAILURE,
    1414             :               "sdap_id_op_connect_send failed: %d (%s)\n",
    1415             :               ret, sss_strerror(ret));
    1416           0 :         return ret;
    1417             :     }
    1418             : 
    1419           0 :     tevent_req_set_callback(subreq, sdap_access_ppolicy_connect_done, req);
    1420           0 :     return EOK;
    1421             : }
    1422             : 
    1423             : static const char**
    1424           0 : get_default_ppolicy_dns(TALLOC_CTX *mem_ctx, struct sdap_domain *sdom)
    1425             : {
    1426             :     const char **ppolicy_dns;
    1427           0 :     int count = 0;
    1428             :     int i;
    1429             : 
    1430           0 :     while(sdom->search_bases[count] != NULL) {
    1431           0 :         count++;
    1432             :     }
    1433             : 
    1434             :     /* +1 to have space for final NULL */
    1435           0 :     ppolicy_dns = talloc_array(mem_ctx, const char*, count + 1);
    1436             : 
    1437           0 :     for(i = 0; i < count; i++) {
    1438           0 :         ppolicy_dns[i] = talloc_asprintf(mem_ctx, "cn=ppolicy,ou=policies,%s",
    1439           0 :                                          sdom->search_bases[i]->basedn);
    1440             :     }
    1441             : 
    1442           0 :     ppolicy_dns[count] = NULL;
    1443           0 :     return ppolicy_dns;
    1444             : }
    1445             : 
    1446           0 : static void sdap_access_ppolicy_connect_done(struct tevent_req *subreq)
    1447             : {
    1448             :     struct tevent_req *req;
    1449             :     struct sdap_access_ppolicy_req_ctx *state;
    1450             :     int ret, dp_error;
    1451             :     const char *ppolicy_dn;
    1452             : 
    1453           0 :     req = tevent_req_callback_data(subreq, struct tevent_req);
    1454           0 :     state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
    1455             : 
    1456           0 :     ret = sdap_id_op_connect_recv(subreq, &dp_error);
    1457           0 :     talloc_zfree(subreq);
    1458             : 
    1459           0 :     if (ret != EOK) {
    1460           0 :         if (dp_error == DP_ERR_OFFLINE) {
    1461           0 :             ret = sdap_access_decide_offline(state->cached_access);
    1462           0 :             if (ret == EOK) {
    1463           0 :                 tevent_req_done(req);
    1464           0 :                 return;
    1465             :             }
    1466             :         }
    1467             : 
    1468           0 :         tevent_req_error(req, ret);
    1469           0 :         return;
    1470             :     }
    1471             : 
    1472           0 :     ppolicy_dn = dp_opt_get_string(state->opts->basic,
    1473             :                                    SDAP_PWDLOCKOUT_DN);
    1474             : 
    1475             :     /* option was configured */
    1476           0 :     if (ppolicy_dn != NULL) {
    1477           0 :         state->ppolicy_dns = talloc_array(state, const char*, 2);
    1478           0 :         if (state->ppolicy_dns == NULL) {
    1479           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Could not allocate ppolicy_dns.\n");
    1480           0 :             tevent_req_error(req, ERR_INTERNAL);
    1481           0 :             return;
    1482             :         }
    1483             : 
    1484           0 :         state->ppolicy_dns[0] = ppolicy_dn;
    1485           0 :         state->ppolicy_dns[1] = NULL;
    1486             : 
    1487             :     } else {
    1488             :         /* try to determine default value */
    1489           0 :         DEBUG(SSSDBG_CONF_SETTINGS,
    1490             :               "ldap_pwdlockout_dn was not defined in configuration file.\n");
    1491             : 
    1492           0 :         state->ppolicy_dns = get_default_ppolicy_dns(state, state->opts->sdom);
    1493           0 :         if (state->ppolicy_dns == NULL) {
    1494           0 :             tevent_req_error(req, ERR_INTERNAL);
    1495           0 :             return;
    1496             :         }
    1497             :     }
    1498             : 
    1499             :     /* Connection to LDAP succeeded
    1500             :      * Send 'pwdLockout' request
    1501             :      */
    1502           0 :     ret = sdap_access_ppolicy_get_lockout_step(req);
    1503           0 :     if (ret != EOK && ret != EAGAIN) {
    1504           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    1505             :               "sdap_access_ppolicy_get_lockout_step failed: [%d][%s]\n",
    1506             :               ret, sss_strerror(ret));
    1507           0 :         tevent_req_error(req, ERR_INTERNAL);
    1508           0 :         return;
    1509             :     }
    1510             : 
    1511           0 :     if (ret == EOK) {
    1512           0 :         tevent_req_done(req);
    1513             :     }
    1514             : }
    1515             : 
    1516             : static errno_t
    1517           0 : sdap_access_ppolicy_get_lockout_step(struct tevent_req *req)
    1518             : {
    1519           0 :     const char *attrs[] = { SYSDB_LDAP_ACCESS_LOCKOUT, NULL };
    1520             :     struct sdap_access_ppolicy_req_ctx *state;
    1521             :     struct tevent_req *subreq;
    1522             :     errno_t ret;
    1523             : 
    1524           0 :     state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
    1525             : 
    1526             :     /* no more DNs to try */
    1527           0 :     if (state->ppolicy_dns[state->ppolicy_dns_index] == NULL) {
    1528           0 :         DEBUG(SSSDBG_TRACE_FUNC, "No more DNs to try.\n");
    1529           0 :         ret = EOK;
    1530           0 :         goto done;
    1531             :     }
    1532             : 
    1533           0 :     DEBUG(SSSDBG_CONF_SETTINGS,
    1534             :           "Trying to find out if ppolicy is enabled using the DN: %s\n",
    1535             :           state->ppolicy_dns[state->ppolicy_dns_index]);
    1536             : 
    1537           0 :     subreq = sdap_get_generic_send(state,
    1538             :                                    state->ev,
    1539             :                                    state->opts,
    1540             :                                    sdap_id_op_handle(state->sdap_op),
    1541           0 :                                    state->ppolicy_dns[state->ppolicy_dns_index],
    1542             :                                    LDAP_SCOPE_BASE,
    1543             :                                    NULL, attrs,
    1544             :                                    NULL, 0,
    1545           0 :                                    dp_opt_get_int(state->opts->basic,
    1546             :                                                   SDAP_SEARCH_TIMEOUT),
    1547             :                                    false);
    1548           0 :     if (subreq == NULL) {
    1549           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Could not start LDAP communication\n");
    1550           0 :         ret = EIO;
    1551           0 :         goto done;
    1552             :     }
    1553             : 
    1554             :     /* try next basedn */
    1555           0 :     state->ppolicy_dns_index++;
    1556           0 :     tevent_req_set_callback(subreq, sdap_access_ppolicy_get_lockout_done, req);
    1557             : 
    1558           0 :     ret = EAGAIN;
    1559             : 
    1560             : done:
    1561           0 :     return ret;
    1562             : }
    1563             : 
    1564           0 : static void sdap_access_ppolicy_get_lockout_done(struct tevent_req *subreq)
    1565             : {
    1566             :     int ret, tret, dp_error;
    1567             :     size_t num_results;
    1568           0 :     bool pwdLockout = false;
    1569             :     struct sysdb_attrs **results;
    1570             :     struct tevent_req *req;
    1571             :     struct sdap_access_ppolicy_req_ctx *state;
    1572             : 
    1573           0 :     req = tevent_req_callback_data(subreq, struct tevent_req);
    1574           0 :     state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
    1575             : 
    1576           0 :     ret = sdap_get_generic_recv(subreq, state, &num_results, &results);
    1577           0 :     talloc_zfree(subreq);
    1578           0 :     if (ret != EOK) {
    1579           0 :         DEBUG(SSSDBG_OP_FAILURE, "Cannot retrieve ppolicy\n");
    1580           0 :         ret = ERR_NETWORK_IO;
    1581           0 :         goto done;
    1582             :     }
    1583             : 
    1584             :     /* Check the number of responses we got
    1585             :      * If it's exactly 1, we passed the check
    1586             :      * If it's < 1, we failed the check
    1587             :      * Anything else is an error
    1588             :      */
    1589             :     /* Didn't find ppolicy attribute */
    1590           0 :     if (num_results < 1) {
    1591             :         /* Try using next $search_base */
    1592           0 :         ret = sdap_access_ppolicy_get_lockout_step(req);
    1593           0 :         if (ret == EOK) {
    1594             :             /* No more search bases to try */
    1595           0 :             DEBUG(SSSDBG_CONF_SETTINGS,
    1596             :                   "[%s] was not found. Granting access.\n",
    1597             :                   SYSDB_LDAP_ACCESS_LOCKOUT);
    1598             :         } else {
    1599           0 :             if (ret != EAGAIN) {
    1600           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
    1601             :                       "sdap_access_ppolicy_get_lockout_step failed: "
    1602             :                       "[%d][%s]\n",
    1603             :                       ret, sss_strerror(ret));
    1604             :             }
    1605           0 :             goto done;
    1606             :         }
    1607           0 :     } else if (results == NULL) {
    1608           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "num_results > 0, but results is NULL\n");
    1609           0 :         ret = ERR_INTERNAL;
    1610           0 :         goto done;
    1611           0 :     } else if (num_results > 1) {
    1612             :         /* It should not be possible to get more than one reply
    1613             :          * here, since we're doing a base-scoped search
    1614             :          */
    1615           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Received multiple replies\n");
    1616           0 :         ret = ERR_INTERNAL;
    1617           0 :         goto done;
    1618             :     } else { /* Ok, we got a single reply */
    1619           0 :         ret = sysdb_attrs_get_bool(results[0], SYSDB_LDAP_ACCESS_LOCKOUT,
    1620             :                                    &pwdLockout);
    1621           0 :         if (ret != EOK) {
    1622           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
    1623             :                   "Error reading %s: [%s]\n", SYSDB_LDAP_ACCESS_LOCKOUT,
    1624             :                   sss_strerror(ret));
    1625           0 :             ret = ERR_INTERNAL;
    1626           0 :             goto done;
    1627             :         }
    1628             :     }
    1629             : 
    1630           0 :     if (pwdLockout) {
    1631           0 :         DEBUG(SSSDBG_TRACE_FUNC,
    1632             :               "Password policy is enabled on LDAP server.\n");
    1633             : 
    1634             :         /* ppolicy is enabled => find out if account is locked */
    1635           0 :         ret = sdap_access_ppolicy_step(req);
    1636           0 :         if (ret != EOK && ret != EAGAIN) {
    1637           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1638             :                   "sdap_access_ppolicy_step failed: [%d][%s].\n",
    1639             :                   ret, sss_strerror(ret));
    1640             :         }
    1641           0 :         goto done;
    1642             :     } else {
    1643           0 :         DEBUG(SSSDBG_TRACE_FUNC,
    1644             :               "Password policy is disabled on LDAP server "
    1645             :               "- storing 'access granted' in sysdb.\n");
    1646           0 :         tret = sdap_save_user_cache_bool(state->domain, state->username,
    1647             :                                          SYSDB_LDAP_ACCESS_CACHED_LOCKOUT,
    1648             :                                          true);
    1649           0 :         if (tret != EOK) {
    1650             :             /* Failing to save to the cache is non-fatal.
    1651             :              * Just return the result.
    1652             :              */
    1653           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1654             :                   "Failed to set user locked attribute\n");
    1655           0 :             goto done;
    1656             :         }
    1657             : 
    1658           0 :         ret = EOK;
    1659           0 :         goto done;
    1660             :     }
    1661             : 
    1662             : done:
    1663           0 :     if (ret != EAGAIN) {
    1664             :         /* release connection */
    1665           0 :         tret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
    1666           0 :         if (tret != EOK) {
    1667           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1668             :                   "sdap_get_generic_send() returned error [%d][%s]\n",
    1669             :                   ret, sss_strerror(ret));
    1670             :         }
    1671             : 
    1672           0 :         if (ret == EOK) {
    1673           0 :             tevent_req_done(req);
    1674             :         } else {
    1675           0 :             tevent_req_error(req, ret);
    1676             :         }
    1677             :     }
    1678           0 : }
    1679             : 
    1680           0 : errno_t sdap_access_ppolicy_step(struct tevent_req *req)
    1681             : {
    1682             :     errno_t ret;
    1683             :     struct tevent_req *subreq;
    1684             :     struct sdap_access_ppolicy_req_ctx *state;
    1685           0 :     const char *attrs[] = { SYSDB_LDAP_ACCESS_LOCKED_TIME,
    1686             :                             SYSDB_LDAP_ACESS_LOCKOUT_DURATION,
    1687             :                             NULL };
    1688             : 
    1689           0 :     state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
    1690             : 
    1691           0 :     subreq = sdap_get_generic_send(state,
    1692             :                                    state->ev,
    1693             :                                    state->opts,
    1694             :                                    sdap_id_op_handle(state->sdap_op),
    1695             :                                    state->basedn,
    1696             :                                    LDAP_SCOPE_BASE,
    1697             :                                    NULL, attrs,
    1698             :                                    NULL, 0,
    1699           0 :                                    dp_opt_get_int(state->opts->basic,
    1700             :                                                   SDAP_SEARCH_TIMEOUT),
    1701             :                                    false);
    1702             : 
    1703           0 :     if (subreq == NULL) {
    1704           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "sdap_access_ppolicy_send failed.\n");
    1705           0 :         ret = ENOMEM;
    1706           0 :         goto done;
    1707             :     }
    1708             : 
    1709           0 :     tevent_req_set_callback(subreq, sdap_access_ppolicy_step_done, req);
    1710           0 :     ret = EAGAIN;
    1711             : 
    1712             : done:
    1713           0 :     return ret;
    1714             : }
    1715             : 
    1716             : static errno_t
    1717           0 : is_account_locked(const char *pwdAccountLockedTime,
    1718             :                   const char *pwdAccountLockedDurationTime,
    1719             :                   enum sdap_pwpolicy_mode pwpol_mode,
    1720             :                   const char *username,
    1721             :                   bool *_locked)
    1722             : {
    1723             :     errno_t ret;
    1724             :     time_t lock_time;
    1725             :     time_t duration;
    1726             :     time_t now;
    1727             :     bool locked;
    1728             : 
    1729             :     /* Default action is to consider account to be locked. */
    1730           0 :     locked = true;
    1731             : 
    1732             :     /* account is permanently locked */
    1733           0 :     if (strcasecmp(pwdAccountLockedTime,
    1734             :                    PERMANENTLY_LOCKED_ACCOUNT) == 0) {
    1735           0 :         ret = EOK;
    1736           0 :         goto done;
    1737             :     }
    1738             : 
    1739           0 :     switch(pwpol_mode) {
    1740             :     case PWP_LOCKOUT_ONLY:
    1741             :         /* We do *not* care about exact value of account locked time, we
    1742             :          * only *do* care if the value is equal to
    1743             :          * PERMANENTLY_LOCKED_ACCOUNT, which means that account is locked
    1744             :          * permanently.
    1745             :          */
    1746           0 :         DEBUG(SSSDBG_TRACE_FUNC,
    1747             :               "Account of: %s is being blocked by password policy, "
    1748             :               "but value: [%s] value is ignored by SSSD.\n",
    1749             :               username, pwdAccountLockedTime);
    1750           0 :         locked = false;
    1751           0 :         break;
    1752             :     case PWP_LOCKOUT_EXPIRE:
    1753             :         /* Account may be locked out from natural reasons (too many attempts,
    1754             :          * expired password). In this case, pwdAccountLockedTime is also set,
    1755             :          * to the time of lock out.
    1756             :          */
    1757           0 :         ret = sss_utc_to_time_t(pwdAccountLockedTime, "%Y%m%d%H%M%SZ",
    1758             :                                 &lock_time);
    1759           0 :         if (ret != EOK) {
    1760           0 :             DEBUG(SSSDBG_TRACE_FUNC, "sss_utc_to_time_t failed with %d:%s.\n",
    1761             :                   ret, sss_strerror(ret));
    1762           0 :             goto done;
    1763             :         }
    1764             : 
    1765           0 :         now = time(NULL);
    1766             : 
    1767             :         /* Account was NOT locked in past. */
    1768           0 :         if (difftime(lock_time, now) > 0.0) {
    1769           0 :             locked = false;
    1770           0 :         } else if (pwdAccountLockedDurationTime != NULL) {
    1771           0 :             errno = 0;
    1772           0 :             duration = strtouint32(pwdAccountLockedDurationTime, NULL, 0);
    1773           0 :             if (errno) {
    1774           0 :                 ret = errno;
    1775           0 :                 goto done;
    1776             :             }
    1777             :             /* Lockout has expired */
    1778           0 :             if (duration != 0 && difftime(now, lock_time) > duration) {
    1779           0 :                 locked = false;
    1780             :             }
    1781             :         }
    1782           0 :         break;
    1783             :     case PWP_SENTINEL:
    1784             :     default:
    1785           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
    1786             :               "Unexpected value of password policy mode: %d.\n", pwpol_mode);
    1787           0 :         ret = EINVAL;
    1788           0 :         goto done;
    1789             :     }
    1790             : 
    1791           0 :     ret = EOK;
    1792             : 
    1793             : done:
    1794           0 :     if (ret == EOK) {
    1795           0 :         *_locked = locked;
    1796             :     }
    1797             : 
    1798           0 :     return ret;
    1799             : }
    1800             : 
    1801           0 : static void sdap_access_ppolicy_step_done(struct tevent_req *subreq)
    1802             : {
    1803             :     int ret, tret, dp_error;
    1804             :     size_t num_results;
    1805           0 :     bool locked = false;
    1806             :     const char *pwdAccountLockedTime;
    1807             :     const char *pwdAccountLockedDurationTime;
    1808             :     struct sysdb_attrs **results;
    1809             :     struct tevent_req *req;
    1810             :     struct sdap_access_ppolicy_req_ctx *state;
    1811             : 
    1812           0 :     req = tevent_req_callback_data(subreq, struct tevent_req);
    1813           0 :     state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
    1814             : 
    1815           0 :     ret = sdap_get_generic_recv(subreq, state, &num_results, &results);
    1816           0 :     talloc_zfree(subreq);
    1817             : 
    1818           0 :     ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
    1819           0 :     if (ret != EOK) {
    1820           0 :         if (dp_error == DP_ERR_OK) {
    1821             :             /* retry */
    1822           0 :             tret = sdap_access_ppolicy_retry(req);
    1823           0 :             if (tret == EOK) {
    1824           0 :                 return;
    1825             :             }
    1826           0 :         } else if (dp_error == DP_ERR_OFFLINE) {
    1827           0 :             ret = sdap_access_decide_offline(state->cached_access);
    1828             :         } else {
    1829           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1830             :                   "sdap_get_generic_send() returned error [%d][%s]\n",
    1831             :                   ret, sss_strerror(ret));
    1832             :         }
    1833             : 
    1834           0 :         goto done;
    1835             :     }
    1836             : 
    1837             :     /* Check the number of responses we got
    1838             :      * If it's exactly 1, we passed the check
    1839             :      * If it's < 1, we failed the check
    1840             :      * Anything else is an error
    1841             :      */
    1842           0 :     if (num_results < 1) {
    1843           0 :         DEBUG(SSSDBG_CONF_SETTINGS,
    1844             :               "User [%s] was not found with the specified filter. "
    1845             :               "Denying access.\n", state->username);
    1846           0 :     } else if (results == NULL) {
    1847           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "num_results > 0, but results is NULL\n");
    1848           0 :         ret = ERR_INTERNAL;
    1849           0 :         goto done;
    1850           0 :     } else if (num_results > 1) {
    1851             :         /* It should not be possible to get more than one reply
    1852             :          * here, since we're doing a base-scoped search
    1853             :          */
    1854           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Received multiple replies\n");
    1855           0 :         ret = ERR_INTERNAL;
    1856           0 :         goto done;
    1857             :     } else { /* Ok, we got a single reply */
    1858           0 :         ret = sysdb_attrs_get_string(results[0], SYSDB_LDAP_ACESS_LOCKOUT_DURATION,
    1859             :                                      &pwdAccountLockedDurationTime);
    1860           0 :         if (ret != EOK) {
    1861             :             /* This attribute might not be set even if account is locked */
    1862           0 :             pwdAccountLockedDurationTime = NULL;
    1863             :         }
    1864             : 
    1865           0 :         ret = sysdb_attrs_get_string(results[0], SYSDB_LDAP_ACCESS_LOCKED_TIME,
    1866             :                                      &pwdAccountLockedTime);
    1867           0 :         if (ret == EOK) {
    1868             : 
    1869           0 :             ret = is_account_locked(pwdAccountLockedTime,
    1870             :                                     pwdAccountLockedDurationTime,
    1871             :                                     state->pwpol_mode,
    1872             :                                     state->username,
    1873             :                                     &locked);
    1874           0 :             if (ret != EOK) {
    1875           0 :                 if (ret == ERR_TIMESPEC_NOT_SUPPORTED) {
    1876           0 :                     DEBUG(SSSDBG_MINOR_FAILURE,
    1877             :                           "timezone specifier in ppolicy is not supported\n");
    1878             :                 } else {
    1879           0 :                     DEBUG(SSSDBG_MINOR_FAILURE,
    1880             :                           "is_account_locked failed: %d:[%s].\n",
    1881             :                           ret, sss_strerror(ret));
    1882             :                 }
    1883             : 
    1884           0 :                 DEBUG(SSSDBG_MINOR_FAILURE,
    1885             :                       "Account will be considered to be locked.\n");
    1886           0 :                 locked = true;
    1887             :             }
    1888             :         } else {
    1889             :             /* Attribute SYSDB_LDAP_ACCESS_LOCKED_TIME in not be present unless
    1890             :              * user's account is blocked by password policy.
    1891             :              */
    1892           0 :             DEBUG(SSSDBG_TRACE_INTERNAL,
    1893             :                   "Attribute %s failed to be obtained - [%d][%s].\n",
    1894             :                   SYSDB_LDAP_ACCESS_LOCKED_TIME, ret, strerror(ret));
    1895             :         }
    1896             :     }
    1897             : 
    1898           0 :     if (locked) {
    1899           0 :         DEBUG(SSSDBG_TRACE_FUNC,
    1900             :               "Access denied by online lookup - account is locked.\n");
    1901           0 :         ret = ERR_ACCESS_DENIED;
    1902             :     } else {
    1903           0 :         DEBUG(SSSDBG_TRACE_FUNC,
    1904             :               "Access granted by online lookup - account is not locked.\n");
    1905           0 :         ret = EOK;
    1906             :     }
    1907             : 
    1908             :     /* Save '!locked' to the cache for future offline access checks.
    1909             :      * Locked == true => access denied,
    1910             :      * Locked == false => access granted
    1911             :      */
    1912           0 :     tret = sdap_save_user_cache_bool(state->domain, state->username,
    1913             :                                      SYSDB_LDAP_ACCESS_CACHED_LOCKOUT,
    1914           0 :                                      !locked);
    1915             : 
    1916           0 :     if (tret != EOK) {
    1917             :         /* Failing to save to the cache is non-fatal.
    1918             :          * Just return the result.
    1919             :          */
    1920           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set user locked attribute\n");
    1921           0 :         goto done;
    1922             :     }
    1923             : 
    1924             : done:
    1925           0 :     if (ret == EOK) {
    1926           0 :         tevent_req_done(req);
    1927             :     } else {
    1928           0 :         tevent_req_error(req, ret);
    1929             :     }
    1930             : }
    1931             : 
    1932           0 : static errno_t sdap_access_ppolicy_recv(struct tevent_req *req)
    1933             : {
    1934           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
    1935             : 
    1936           0 :     return EOK;
    1937             : }
    1938             : 
    1939           0 : static errno_t sdap_get_basedn_user_entry(struct ldb_message *user_entry,
    1940             :                                           const char *username,
    1941             :                                           const char **_basedn)
    1942             : {
    1943             :     const char *basedn;
    1944             :     errno_t ret;
    1945             : 
    1946           0 :     basedn = ldb_msg_find_attr_as_string(user_entry, SYSDB_ORIG_DN, NULL);
    1947           0 :     if (basedn == NULL) {
    1948           0 :         DEBUG(SSSDBG_CRIT_FAILURE,"Could not find originalDN for user [%s]\n",
    1949             :               username);
    1950           0 :         ret = EINVAL;
    1951           0 :         goto done;
    1952             :     }
    1953             : 
    1954           0 :     *_basedn = basedn;
    1955           0 :     ret = EOK;
    1956             : 
    1957             : done:
    1958           0 :     return ret;
    1959             : }

Generated by: LCOV version 1.10