LCOV - code coverage report
Current view: top level - responder/pam - pamsrv_cmd.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 533 965 55.2 %
Date: 2016-06-29 Functions: 39 48 81.2 %

          Line data    Source code
       1             : /*
       2             :    SSSD
       3             : 
       4             :    PAM Responder
       5             : 
       6             :    Copyright (C) Simo Sorce <ssorce@redhat.com>   2009
       7             :    Copyright (C) Sumit Bose <sbose@redhat.com>    2009
       8             : 
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : #include <time.h>
      24             : #include "util/util.h"
      25             : #include "util/auth_utils.h"
      26             : #include "db/sysdb.h"
      27             : #include "confdb/confdb.h"
      28             : #include "responder/common/responder_packet.h"
      29             : #include "responder/common/responder.h"
      30             : #include "responder/common/negcache.h"
      31             : #include "providers/data_provider.h"
      32             : #include "responder/pam/pamsrv.h"
      33             : #include "responder/pam/pam_helpers.h"
      34             : #include "responder/common/responder_cache_req.h"
      35             : #include "db/sysdb.h"
      36             : 
      37             : enum pam_verbosity {
      38             :     PAM_VERBOSITY_NO_MESSAGES = 0,
      39             :     PAM_VERBOSITY_IMPORTANT,
      40             :     PAM_VERBOSITY_INFO,
      41             :     PAM_VERBOSITY_DEBUG
      42             : };
      43             : 
      44             : #define DEFAULT_PAM_VERBOSITY PAM_VERBOSITY_IMPORTANT
      45             : 
      46             : static errno_t
      47             : pam_null_last_online_auth_with_curr_token(struct sss_domain_info *domain,
      48             :                                           const char *username);
      49             : static errno_t
      50             : pam_get_last_online_auth_with_curr_token(struct sss_domain_info *domain,
      51             :                                          const char *name,
      52             :                                          uint64_t *_value);
      53             : 
      54             : static void pam_reply(struct pam_auth_req *preq);
      55             : 
      56           0 : static errno_t pack_user_info_msg(TALLOC_CTX *mem_ctx,
      57             :                                   const char *user_error_message,
      58             :                                   size_t *resp_len,
      59             :                                   uint8_t **_resp)
      60             : {
      61           0 :     uint32_t resp_type = SSS_PAM_USER_INFO_ACCOUNT_EXPIRED;
      62             :     size_t err_len;
      63             :     uint8_t *resp;
      64             :     size_t p;
      65             : 
      66           0 :     err_len = strlen(user_error_message);
      67           0 :     *resp_len = 2 * sizeof(uint32_t) + err_len;
      68           0 :     resp = talloc_size(mem_ctx, *resp_len);
      69           0 :     if (resp == NULL) {
      70           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
      71           0 :         return ENOMEM;
      72             :     }
      73             : 
      74           0 :     p = 0;
      75           0 :     SAFEALIGN_SET_UINT32(&resp[p], resp_type, &p);
      76           0 :     SAFEALIGN_SET_UINT32(&resp[p], err_len, &p);
      77           0 :     safealign_memcpy(&resp[p], user_error_message, err_len, &p);
      78           0 :     if (p != *resp_len) {
      79           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Size mismatch\n");
      80             :     }
      81             : 
      82           0 :     *_resp = resp;
      83           0 :     return EOK;
      84             : }
      85             : 
      86           0 : static void inform_user(struct pam_data* pd, const char *pam_message)
      87             : {
      88             :     size_t msg_len;
      89             :     uint8_t *msg;
      90             :     errno_t ret;
      91             : 
      92           0 :     ret = pack_user_info_msg(pd, pam_message, &msg_len, &msg);
      93           0 :     if (ret != EOK) {
      94           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
      95             :               "pack_user_info_account_expired failed.\n");
      96             :     } else {
      97           0 :         ret = pam_add_response(pd, SSS_PAM_USER_INFO, msg_len, msg);
      98           0 :         if (ret != EOK) {
      99           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
     100             :         }
     101             :     }
     102           0 : }
     103             : 
     104          38 : static bool is_domain_requested(struct pam_data *pd, const char *domain_name)
     105             : {
     106             :     int i;
     107             : 
     108             :     /* If none specific domains got requested via pam, all domains are allowed.
     109             :      * Which mimics the default/original behaviour.
     110             :      */
     111          38 :     if (!pd->requested_domains) {
     112          38 :         return true;
     113             :     }
     114             : 
     115           0 :     for (i = 0; pd->requested_domains[i]; i++) {
     116           0 :         if (strcasecmp(domain_name, pd->requested_domains[i])) {
     117           0 :             continue;
     118             :         }
     119             : 
     120           0 :         return true;
     121             :     }
     122             : 
     123           0 :     return false;
     124             : }
     125             : 
     126          22 : static int extract_authtok_v2(struct sss_auth_token *tok,
     127             :                               size_t data_size, uint8_t *body, size_t blen,
     128             :                               size_t *c)
     129             : {
     130             :     uint32_t auth_token_type;
     131             :     uint32_t auth_token_length;
     132             :     uint8_t *auth_token_data;
     133          22 :     int ret = EOK;
     134             : 
     135          44 :     if (data_size < sizeof(uint32_t) || *c+data_size > blen ||
     136          22 :         SIZE_T_OVERFLOW(*c, data_size)) return EINVAL;
     137             : 
     138          22 :     SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c);
     139          22 :     auth_token_length = data_size - sizeof(uint32_t);
     140          22 :     auth_token_data = body+(*c);
     141             : 
     142          22 :     switch (auth_token_type) {
     143             :     case SSS_AUTHTOK_TYPE_EMPTY:
     144           0 :         sss_authtok_set_empty(tok);
     145           0 :         break;
     146             :     case SSS_AUTHTOK_TYPE_PASSWORD:
     147          16 :         if (auth_token_length == 0) {
     148           0 :             sss_authtok_set_empty(tok);
     149             :         } else {
     150          16 :             ret = sss_authtok_set_password(tok, (const char *)auth_token_data,
     151             :                                            auth_token_length);
     152             :         }
     153          16 :         break;
     154             :     case SSS_AUTHTOK_TYPE_2FA:
     155           4 :         ret = sss_authtok_set(tok, SSS_AUTHTOK_TYPE_2FA,
     156             :                               auth_token_data, auth_token_length);
     157           4 :         break;
     158             :     case SSS_AUTHTOK_TYPE_SC_PIN:
     159           2 :         ret = sss_authtok_set_sc_pin(tok, (const char *) auth_token_data,
     160             :                                      auth_token_length);
     161           2 :         break;
     162             :     case SSS_AUTHTOK_TYPE_SC_KEYPAD:
     163           0 :         sss_authtok_set_sc_keypad(tok);
     164           0 :         break;
     165             :     default:
     166           0 :         return EINVAL;
     167             :     }
     168             : 
     169          22 :     *c += auth_token_length;
     170             : 
     171          22 :     return ret;
     172             : }
     173             : 
     174         196 : static int extract_string(char **var, size_t size, uint8_t *body, size_t blen,
     175             :                           size_t *c) {
     176             :     uint8_t *str;
     177             : 
     178         196 :     if (*c+size > blen || SIZE_T_OVERFLOW(*c, size)) return EINVAL;
     179             : 
     180         196 :     str = body+(*c);
     181             : 
     182         196 :     if (str[size-1]!='\0') return EINVAL;
     183             : 
     184             :     /* If the string isn't valid UTF-8, fail */
     185         196 :     if (!sss_utf8_check(str, size-1)) {
     186           0 :         return EINVAL;
     187             :     }
     188             : 
     189         196 :     *c += size;
     190             : 
     191         196 :     *var = (char *) str;
     192             : 
     193         196 :     return EOK;
     194             : }
     195             : 
     196          40 : static int extract_uint32_t(uint32_t *var, size_t size, uint8_t *body,
     197             :                             size_t blen, size_t *c) {
     198             : 
     199          40 :     if (size != sizeof(uint32_t) || *c+size > blen || SIZE_T_OVERFLOW(*c, size))
     200           0 :         return EINVAL;
     201             : 
     202          40 :     SAFEALIGN_COPY_UINT32_CHECK(var, &body[*c], blen, c);
     203             : 
     204          40 :     return EOK;
     205             : }
     206             : 
     207          36 : static int pd_set_primary_name(const struct ldb_message *msg,struct pam_data *pd)
     208             : {
     209             :     const char *name;
     210             : 
     211          36 :     name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
     212          36 :     if (!name) {
     213           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "A user with no name?\n");
     214           0 :         return EIO;
     215             :     }
     216             : 
     217          36 :     if (strcmp(pd->user, name)) {
     218           0 :         DEBUG(SSSDBG_TRACE_FUNC, "User's primary name is %s\n", name);
     219           0 :         talloc_free(pd->user);
     220           0 :         pd->user = talloc_strdup(pd, name);
     221           0 :         if (!pd->user) return ENOMEM;
     222             :     }
     223             : 
     224          36 :     return EOK;
     225             : }
     226             : 
     227          40 : static int pam_parse_in_data_v2(struct pam_data *pd,
     228             :                                 uint8_t *body, size_t blen)
     229             : {
     230             :     size_t c;
     231             :     uint32_t type;
     232             :     uint32_t size;
     233             :     int ret;
     234             :     uint32_t start;
     235             :     uint32_t terminator;
     236             :     char *requested_domains;
     237             : 
     238          40 :     if (blen < 4*sizeof(uint32_t)+2) {
     239           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Received data is invalid.\n");
     240           0 :         return EINVAL;
     241             :     }
     242             : 
     243          40 :     SAFEALIGN_COPY_UINT32(&start, body, NULL);
     244          40 :     SAFEALIGN_COPY_UINT32(&terminator, body + blen - sizeof(uint32_t), NULL);
     245             : 
     246          40 :     if (start != SSS_START_OF_PAM_REQUEST
     247          40 :         || terminator != SSS_END_OF_PAM_REQUEST) {
     248           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Received data is invalid.\n");
     249           0 :         return EINVAL;
     250             :     }
     251             : 
     252          40 :     c = sizeof(uint32_t);
     253             :     do {
     254         298 :         SAFEALIGN_COPY_UINT32_CHECK(&type, &body[c], blen, &c);
     255             : 
     256         298 :         if (type == SSS_END_OF_PAM_REQUEST) {
     257          40 :             if (c != blen) return EINVAL;
     258             :         } else {
     259         258 :             SAFEALIGN_COPY_UINT32_CHECK(&size, &body[c], blen, &c);
     260             :             /* the uint32_t end maker SSS_END_OF_PAM_REQUEST does not count to
     261             :              * the remaining buffer */
     262         258 :             if (size > (blen - c - sizeof(uint32_t))) {
     263           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "Invalid data size.\n");
     264           0 :                 return EINVAL;
     265             :             }
     266             : 
     267         258 :             switch(type) {
     268             :                 case SSS_PAM_ITEM_USER:
     269          36 :                     ret = extract_string(&pd->logon_name, size, body, blen, &c);
     270          36 :                     if (ret != EOK) return ret;
     271          36 :                     break;
     272             :                 case SSS_PAM_ITEM_SERVICE:
     273          40 :                     ret = extract_string(&pd->service, size, body, blen, &c);
     274          40 :                     if (ret != EOK) return ret;
     275          40 :                     break;
     276             :                 case SSS_PAM_ITEM_TTY:
     277          40 :                     ret = extract_string(&pd->tty, size, body, blen, &c);
     278          40 :                     if (ret != EOK) return ret;
     279          40 :                     break;
     280             :                 case SSS_PAM_ITEM_RUSER:
     281          40 :                     ret = extract_string(&pd->ruser, size, body, blen, &c);
     282          40 :                     if (ret != EOK) return ret;
     283          40 :                     break;
     284             :                 case SSS_PAM_ITEM_RHOST:
     285          40 :                     ret = extract_string(&pd->rhost, size, body, blen, &c);
     286          40 :                     if (ret != EOK) return ret;
     287          40 :                     break;
     288             :                 case SSS_PAM_ITEM_REQUESTED_DOMAINS:
     289           0 :                     ret = extract_string(&requested_domains, size, body, blen,
     290             :                                          &c);
     291           0 :                     if (ret != EOK) return ret;
     292             : 
     293           0 :                     ret = split_on_separator(pd, requested_domains, ',', true,
     294             :                                              true, &pd->requested_domains,
     295             :                                              NULL);
     296           0 :                     if (ret != EOK) {
     297           0 :                         DEBUG(SSSDBG_CRIT_FAILURE,
     298             :                               "Failed to parse requested_domains list!\n");
     299           0 :                         return ret;
     300             :                     }
     301           0 :                     break;
     302             :                 case SSS_PAM_ITEM_CLI_PID:
     303          40 :                     ret = extract_uint32_t(&pd->cli_pid, size,
     304             :                                            body, blen, &c);
     305          40 :                     if (ret != EOK) return ret;
     306          40 :                     break;
     307             :                 case SSS_PAM_ITEM_AUTHTOK:
     308          22 :                     ret = extract_authtok_v2(pd->authtok,
     309             :                                              size, body, blen, &c);
     310          22 :                     if (ret != EOK) return ret;
     311          22 :                     break;
     312             :                 case SSS_PAM_ITEM_NEWAUTHTOK:
     313           0 :                     ret = extract_authtok_v2(pd->newauthtok,
     314             :                                              size, body, blen, &c);
     315           0 :                     if (ret != EOK) return ret;
     316           0 :                     break;
     317             :                 default:
     318           0 :                     DEBUG(SSSDBG_CRIT_FAILURE,
     319             :                           "Ignoring unknown data type [%d].\n", type);
     320           0 :                     c += size;
     321             :             }
     322             :         }
     323             : 
     324         298 :     } while(c < blen);
     325             : 
     326          40 :     return EOK;
     327             : 
     328             : }
     329             : 
     330          40 : static int pam_parse_in_data_v3(struct pam_data *pd,
     331             :                                 uint8_t *body, size_t blen)
     332             : {
     333             :     int ret;
     334             : 
     335          40 :     ret = pam_parse_in_data_v2(pd, body, blen);
     336          40 :     if (ret != EOK) {
     337           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "pam_parse_in_data_v2 failed.\n");
     338           0 :         return ret;
     339             :     }
     340             : 
     341          40 :     if (pd->cli_pid == 0) {
     342           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Missing client PID.\n");
     343           0 :         return EINVAL;
     344             :     }
     345             : 
     346          40 :     return EOK;
     347             : }
     348             : 
     349           0 : static int extract_authtok_v1(struct sss_auth_token *tok,
     350             :                               uint8_t *body, size_t blen, size_t *c)
     351             : {
     352             :     uint32_t auth_token_type;
     353             :     uint32_t auth_token_length;
     354             :     uint8_t *auth_token_data;
     355           0 :     int ret = EOK;
     356             : 
     357           0 :     SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c);
     358           0 :     SAFEALIGN_COPY_UINT32_CHECK(&auth_token_length, &body[*c], blen, c);
     359           0 :     auth_token_data = body+(*c);
     360             : 
     361           0 :     switch (auth_token_type) {
     362             :     case SSS_AUTHTOK_TYPE_EMPTY:
     363           0 :         sss_authtok_set_empty(tok);
     364           0 :         break;
     365             :     case SSS_AUTHTOK_TYPE_PASSWORD:
     366           0 :         ret = sss_authtok_set_password(tok, (const char *)auth_token_data,
     367             :                                        auth_token_length);
     368           0 :         break;
     369             :     default:
     370           0 :         return EINVAL;
     371             :     }
     372             : 
     373           0 :     *c += auth_token_length;
     374             : 
     375           0 :     return ret;
     376             : }
     377             : 
     378           0 : static int pam_parse_in_data(struct pam_data *pd,
     379             :                              uint8_t *body, size_t blen)
     380             : {
     381             :     size_t start;
     382             :     size_t end;
     383             :     size_t last;
     384             :     int ret;
     385             : 
     386           0 :     last = blen - 1;
     387           0 :     end = 0;
     388             : 
     389             :     /* user name */
     390           0 :     for (start = end; end < last; end++) if (body[end] == '\0') break;
     391           0 :     if (body[end++] != '\0') return EINVAL;
     392           0 :     pd->logon_name = (char *) &body[start];
     393             : 
     394           0 :     for (start = end; end < last; end++) if (body[end] == '\0') break;
     395           0 :     if (body[end++] != '\0') return EINVAL;
     396           0 :     pd->service = (char *) &body[start];
     397             : 
     398           0 :     for (start = end; end < last; end++) if (body[end] == '\0') break;
     399           0 :     if (body[end++] != '\0') return EINVAL;
     400           0 :     pd->tty = (char *) &body[start];
     401             : 
     402           0 :     for (start = end; end < last; end++) if (body[end] == '\0') break;
     403           0 :     if (body[end++] != '\0') return EINVAL;
     404           0 :     pd->ruser = (char *) &body[start];
     405             : 
     406           0 :     for (start = end; end < last; end++) if (body[end] == '\0') break;
     407           0 :     if (body[end++] != '\0') return EINVAL;
     408           0 :     pd->rhost = (char *) &body[start];
     409             : 
     410           0 :     ret = extract_authtok_v1(pd->authtok, body, blen, &end);
     411           0 :     if (ret) {
     412           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid auth token\n");
     413           0 :         return ret;
     414             :     }
     415           0 :     ret = extract_authtok_v1(pd->newauthtok, body, blen, &end);
     416           0 :     if (ret) {
     417           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid new auth token\n");
     418           0 :         return ret;
     419             :     }
     420             : 
     421           0 :     DEBUG_PAM_DATA(SSSDBG_CONF_SETTINGS, pd);
     422             : 
     423           0 :     return EOK;
     424             : }
     425             : 
     426             : /*=Save-Last-Login-State===================================================*/
     427             : 
     428           7 : static errno_t set_last_login(struct pam_auth_req *preq)
     429             : {
     430             :     struct sysdb_attrs *attrs;
     431             :     errno_t ret;
     432             : 
     433           7 :     attrs = sysdb_new_attrs(preq);
     434           7 :     if (!attrs) {
     435           0 :         ret = ENOMEM;
     436           0 :         goto fail;
     437             :     }
     438             : 
     439           7 :     ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_ONLINE_AUTH, time(NULL));
     440           7 :     if (ret != EOK) {
     441           0 :         goto fail;
     442             :     }
     443             : 
     444           7 :     ret = sysdb_attrs_add_time_t(attrs,
     445             :                                  SYSDB_LAST_ONLINE_AUTH_WITH_CURR_TOKEN,
     446             :                                  time(NULL));
     447           7 :     if (ret != EOK) {
     448           0 :         goto fail;
     449             :     }
     450             : 
     451           7 :     ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_LOGIN, time(NULL));
     452           7 :     if (ret != EOK) {
     453           0 :         goto fail;
     454             :     }
     455             : 
     456           7 :     ret = sysdb_set_user_attr(preq->domain, preq->pd->user, attrs,
     457             :                               SYSDB_MOD_REP);
     458           7 :     if (ret != EOK) {
     459           0 :         DEBUG(SSSDBG_OP_FAILURE, "set_last_login failed.\n");
     460           0 :         preq->pd->pam_status = PAM_SYSTEM_ERR;
     461           0 :         goto fail;
     462             :     } else {
     463           7 :         preq->pd->last_auth_saved = true;
     464             :     }
     465           7 :     preq->callback(preq);
     466             : 
     467           7 :     return EOK;
     468             : 
     469             : fail:
     470           0 :     return ret;
     471             : }
     472             : 
     473          40 : static errno_t filter_responses(struct confdb_ctx *cdb,
     474             :                                 struct response_data *resp_list)
     475             : {
     476             :     int ret;
     477             :     struct response_data *resp;
     478             :     uint32_t user_info_type;
     479             :     int64_t expire_date;
     480             :     int pam_verbosity;
     481             : 
     482          40 :     ret = confdb_get_int(cdb, CONFDB_PAM_CONF_ENTRY,
     483             :                          CONFDB_PAM_VERBOSITY, DEFAULT_PAM_VERBOSITY,
     484             :                          &pam_verbosity);
     485          40 :     if (ret != EOK) {
     486           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     487             :               "Failed to read PAM verbosity, not fatal.\n");
     488           0 :         pam_verbosity = DEFAULT_PAM_VERBOSITY;
     489             :     }
     490             : 
     491          40 :     resp = resp_list;
     492          93 :     while(resp != NULL) {
     493          13 :         if (resp->type == SSS_PAM_USER_INFO) {
     494           9 :             if (resp->len < sizeof(uint32_t)) {
     495           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "User info entry is too short.\n");
     496           0 :                 return EINVAL;
     497             :             }
     498             : 
     499           9 :             if (pam_verbosity == PAM_VERBOSITY_NO_MESSAGES) {
     500           0 :                 resp->do_not_send_to_client = true;
     501           0 :                 resp = resp->next;
     502           0 :                 continue;
     503             :             }
     504             : 
     505           9 :             memcpy(&user_info_type, resp->data, sizeof(uint32_t));
     506             : 
     507           9 :             resp->do_not_send_to_client = false;
     508           9 :             switch (user_info_type) {
     509             :                 case SSS_PAM_USER_INFO_OFFLINE_AUTH:
     510           7 :                     if (resp->len != sizeof(uint32_t) + sizeof(int64_t)) {
     511           0 :                         DEBUG(SSSDBG_CRIT_FAILURE,
     512             :                               "User info offline auth entry is "
     513             :                                   "too short.\n");
     514           0 :                         return EINVAL;
     515             :                     }
     516           7 :                     memcpy(&expire_date, resp->data + sizeof(uint32_t),
     517             :                            sizeof(int64_t));
     518          14 :                     if ((expire_date == 0 &&
     519           7 :                          pam_verbosity < PAM_VERBOSITY_INFO) ||
     520           0 :                         (expire_date > 0 &&
     521           0 :                          pam_verbosity < PAM_VERBOSITY_IMPORTANT)) {
     522           7 :                         resp->do_not_send_to_client = true;
     523             :                     }
     524             : 
     525           7 :                     break;
     526             :                 default:
     527           2 :                     DEBUG(SSSDBG_TRACE_LIBS,
     528             :                           "User info type [%d] not filtered.\n",
     529             :                            user_info_type);
     530             :             }
     531           4 :         } else if (resp->type & SSS_SERVER_INFO) {
     532           0 :             resp->do_not_send_to_client = true;
     533             :         }
     534             : 
     535          13 :         resp = resp->next;
     536             :     }
     537             : 
     538          40 :     return EOK;
     539             : }
     540             : 
     541           0 : static void pam_reply_delay(struct tevent_context *ev, struct tevent_timer *te,
     542             :                             struct timeval tv, void *pvt)
     543             : {
     544             :     struct pam_auth_req *preq;
     545             : 
     546           0 :     DEBUG(SSSDBG_CONF_SETTINGS, "pam_reply_delay get called.\n");
     547             : 
     548           0 :     preq = talloc_get_type(pvt, struct pam_auth_req);
     549             : 
     550           0 :     pam_reply(preq);
     551           0 : }
     552             : 
     553          16 : static errno_t get_password_for_cache_auth(struct sss_auth_token *authtok,
     554             :                                            const char **password)
     555             : {
     556             :     int ret;
     557             :     size_t pw_len;
     558             :     const char *fa2;
     559             :     size_t fa2_len;
     560             : 
     561          16 :     switch (sss_authtok_get_type(authtok)) {
     562             :     case SSS_AUTHTOK_TYPE_PASSWORD:
     563          12 :         ret = sss_authtok_get_password(authtok, password, NULL);
     564          12 :         break;
     565             :     case SSS_AUTHTOK_TYPE_2FA:
     566           4 :         ret = sss_authtok_get_2fa(authtok, password, &pw_len, &fa2, &fa2_len);
     567           4 :         break;
     568             :     default:
     569           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Unsupported auth token type [%d].\n",
     570             :               sss_authtok_get_type(authtok));
     571           0 :         ret = EINVAL;
     572             :     }
     573          16 :     if (ret != EOK) {
     574           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to get password.\n");
     575           0 :         return ret;
     576             :     }
     577             : 
     578          16 :     return EOK;
     579             : }
     580             : 
     581             : static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd);
     582             : static void pam_handle_cached_login(struct pam_auth_req *preq, int ret,
     583             :                                     time_t expire_date, time_t delayed_until, bool cached_auth);
     584             : 
     585          63 : static void pam_reply(struct pam_auth_req *preq)
     586             : {
     587             :     struct cli_ctx *cctx;
     588             :     uint8_t *body;
     589             :     size_t blen;
     590             :     int ret;
     591             :     int32_t resp_c;
     592             :     int32_t resp_size;
     593             :     struct response_data *resp;
     594             :     int p;
     595             :     struct timeval tv;
     596             :     struct tevent_timer *te;
     597             :     struct pam_data *pd;
     598             :     struct pam_ctx *pctx;
     599             :     uint32_t user_info_type;
     600          63 :     time_t exp_date = -1;
     601          63 :     time_t delay_until = -1;
     602             :     char* pam_account_expired_message;
     603             :     char* pam_account_locked_message;
     604             :     int pam_verbosity;
     605             : 
     606          63 :     pd = preq->pd;
     607          63 :     cctx = preq->cctx;
     608          63 :     pctx = talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
     609             : 
     610          63 :     ret = confdb_get_int(pctx->rctx->cdb, CONFDB_PAM_CONF_ENTRY,
     611             :                          CONFDB_PAM_VERBOSITY, DEFAULT_PAM_VERBOSITY,
     612             :                          &pam_verbosity);
     613          63 :     if (ret != EOK) {
     614           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     615             :               "Failed to read PAM verbosity, not fatal.\n");
     616           0 :         pam_verbosity = DEFAULT_PAM_VERBOSITY;
     617             :     }
     618             : 
     619          63 :     DEBUG(SSSDBG_FUNC_DATA,
     620             :           "pam_reply called with result [%d]: %s.\n",
     621             :           pd->pam_status, pam_strerror(NULL, pd->pam_status));
     622          63 :     if (pd->pam_status == PAM_AUTHINFO_UNAVAIL || preq->use_cached_auth) {
     623             : 
     624          18 :         switch(pd->cmd) {
     625             :         case SSS_PAM_AUTHENTICATE:
     626          32 :             if ((preq->domain != NULL) &&
     627          32 :                 (preq->domain->cache_credentials == true) &&
     628          16 :                 (pd->offline_auth == false)) {
     629          16 :                 const char *password = NULL;
     630             :                 bool use_cached_auth;
     631             : 
     632             :                 /* backup value of preq->use_cached_auth*/
     633          16 :                 use_cached_auth = preq->use_cached_auth;
     634             :                 /* set to false to avoid entering this branch when pam_reply()
     635             :                  * is recursively called from pam_handle_cached_login() */
     636          16 :                 preq->use_cached_auth = false;
     637             : 
     638             :                 /* do auth with offline credentials */
     639          16 :                 pd->offline_auth = true;
     640             : 
     641          16 :                 if (preq->domain->sysdb == NULL) {
     642           0 :                     DEBUG(SSSDBG_FATAL_FAILURE,
     643             :                           "Fatal: Sysdb CTX not found for domain"
     644             :                               " [%s]!\n", preq->domain->name);
     645           0 :                     goto done;
     646             :                 }
     647             : 
     648          16 :                 ret = get_password_for_cache_auth(pd->authtok, &password);
     649          16 :                 if (ret != EOK) {
     650           0 :                     DEBUG(SSSDBG_FATAL_FAILURE,
     651             :                           "get_password_and_type_for_cache_auth failed.\n");
     652           0 :                     goto done;
     653             :                 }
     654             : 
     655          32 :                 ret = sysdb_cache_auth(preq->domain,
     656          16 :                                        pd->user, password,
     657          16 :                                        pctx->rctx->cdb, false,
     658             :                                        &exp_date, &delay_until);
     659             : 
     660          16 :                 pam_handle_cached_login(preq, ret, exp_date, delay_until,
     661             :                                         use_cached_auth);
     662          16 :                 return;
     663             :             }
     664           0 :             break;
     665             :         case SSS_PAM_CHAUTHTOK_PRELIM:
     666             :         case SSS_PAM_CHAUTHTOK:
     667           2 :             DEBUG(SSSDBG_FUNC_DATA,
     668             :                   "Password change not possible while offline.\n");
     669           2 :             pd->pam_status = PAM_AUTHTOK_ERR;
     670           2 :             user_info_type = SSS_PAM_USER_INFO_OFFLINE_CHPASS;
     671           2 :             ret = pam_add_response(pd, SSS_PAM_USER_INFO, sizeof(uint32_t),
     672             :                                    (const uint8_t *) &user_info_type);
     673           2 :             if (ret != EOK) {
     674           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
     675           0 :                 goto done;
     676             :             }
     677           2 :             break;
     678             : /* TODO: we need the pam session cookie here to make sure that cached
     679             :  * authentication was successful */
     680             :         case SSS_PAM_SETCRED:
     681             :         case SSS_PAM_ACCT_MGMT:
     682             :         case SSS_PAM_OPEN_SESSION:
     683             :         case SSS_PAM_CLOSE_SESSION:
     684           0 :             DEBUG(SSSDBG_OP_FAILURE,
     685             :                   "Assuming offline authentication setting status for "
     686             :                       "pam call %d to PAM_SUCCESS.\n", pd->cmd);
     687           0 :             pd->pam_status = PAM_SUCCESS;
     688           0 :             break;
     689             :         default:
     690           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Unknown PAM call [%d].\n", pd->cmd);
     691           0 :             pd->pam_status = PAM_MODULE_UNKNOWN;
     692             :         }
     693             :     }
     694             : 
     695          47 :     if (pd->pam_status == PAM_SUCCESS && pd->cmd == SSS_PAM_CHAUTHTOK) {
     696           1 :         ret = pam_null_last_online_auth_with_curr_token(preq->domain,
     697           1 :                                                         pd->user);
     698           1 :         if (ret != EOK) {
     699           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     700             :                   "sysdb_null_last_online_auth_with_curr_token failed: "
     701             :                   "%s [%d].\n", sss_strerror(ret), ret);
     702           0 :             goto done;
     703             :         }
     704             :     }
     705             : 
     706          47 :     if (pd->response_delay > 0) {
     707           0 :         ret = gettimeofday(&tv, NULL);
     708           0 :         if (ret != EOK) {
     709           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "gettimeofday failed [%d][%s].\n",
     710             :                   errno, strerror(errno));
     711           0 :             goto done;
     712             :         }
     713           0 :         tv.tv_sec += pd->response_delay;
     714           0 :         tv.tv_usec = 0;
     715           0 :         pd->response_delay = 0;
     716             : 
     717           0 :         te = tevent_add_timer(cctx->ev, cctx, tv, pam_reply_delay, preq);
     718           0 :         if (te == NULL) {
     719           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     720             :                   "Failed to add event pam_reply_delay.\n");
     721           0 :             goto done;
     722             :         }
     723             : 
     724           0 :         return;
     725             :     }
     726             : 
     727             :     /* If this was a successful login, save the lastLogin time */
     728          77 :     if (pd->cmd == SSS_PAM_AUTHENTICATE &&
     729          53 :         pd->pam_status == PAM_SUCCESS &&
     730          46 :         preq->domain->cache_credentials &&
     731          37 :         !pd->offline_auth &&
     732          21 :         !pd->last_auth_saved &&
     733          14 :         NEED_CHECK_PROVIDER(preq->domain->provider)) {
     734           7 :         ret = set_last_login(preq);
     735           7 :         if (ret != EOK) {
     736           0 :             goto done;
     737             :         }
     738           7 :         return;
     739             :     }
     740             : 
     741          40 :     ret = sss_packet_new(cctx->creq, 0, sss_packet_get_cmd(cctx->creq->in),
     742          40 :                          &cctx->creq->out);
     743          40 :     if (ret != EOK) {
     744           0 :         goto done;
     745             :     }
     746             : 
     747             :     /* Account expiration warning is printed for sshd. If pam_verbosity
     748             :      * is equal or above PAM_VERBOSITY_INFO then all services are informed
     749             :      * about account expiration.
     750             :      */
     751          40 :     if (pd->pam_status == PAM_ACCT_EXPIRED &&
     752           0 :         ((pd->service != NULL && strcasecmp(pd->service, "sshd") == 0) ||
     753           0 :          pam_verbosity >= PAM_VERBOSITY_INFO)) {
     754             : 
     755           0 :         ret = confdb_get_string(pctx->rctx->cdb, pd, CONFDB_PAM_CONF_ENTRY,
     756             :                                 CONFDB_PAM_ACCOUNT_EXPIRED_MESSAGE, "",
     757             :                                 &pam_account_expired_message);
     758           0 :         if (ret != EOK) {
     759           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     760             :                   "Failed to get expiration message: %d:[%s].\n",
     761             :                   ret, sss_strerror(ret));
     762           0 :             goto done;
     763             :         }
     764             : 
     765           0 :         inform_user(pd, pam_account_expired_message);
     766             :     }
     767             : 
     768          40 :     if (pd->account_locked) {
     769             : 
     770           0 :         ret = confdb_get_string(pctx->rctx->cdb, pd, CONFDB_PAM_CONF_ENTRY,
     771             :                                 CONFDB_PAM_ACCOUNT_LOCKED_MESSAGE, "",
     772             :                                 &pam_account_locked_message);
     773           0 :         if (ret != EOK) {
     774           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     775             :                   "Failed to get expiration message: %d:[%s].\n",
     776             :                   ret, sss_strerror(ret));
     777           0 :             goto done;
     778             :         }
     779             : 
     780           0 :         inform_user(pd, pam_account_locked_message);
     781             :     }
     782             : 
     783          40 :     ret = filter_responses(pctx->rctx->cdb, pd->resp_list);
     784          40 :     if (ret != EOK) {
     785           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "filter_responses failed, not fatal.\n");
     786             :     }
     787             : 
     788          40 :     if (pd->domain != NULL) {
     789          37 :         ret = pam_add_response(pd, SSS_PAM_DOMAIN_NAME, strlen(pd->domain)+1,
     790          37 :                                (uint8_t *) pd->domain);
     791          37 :         if (ret != EOK) {
     792           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
     793           0 :             goto done;
     794             :         }
     795             :     }
     796             : 
     797          40 :     resp_c = 0;
     798          40 :     resp_size = 0;
     799          40 :     resp = pd->resp_list;
     800         130 :     while(resp != NULL) {
     801          50 :         if (!resp->do_not_send_to_client) {
     802          43 :             resp_c++;
     803          43 :             resp_size += resp->len;
     804             :         }
     805          50 :         resp = resp->next;
     806             :     }
     807             : 
     808          40 :     ret = sss_packet_grow(cctx->creq->out, sizeof(int32_t) +
     809          40 :                                            sizeof(int32_t) +
     810             :                                            resp_c * 2* sizeof(int32_t) +
     811             :                                            resp_size);
     812          40 :     if (ret != EOK) {
     813           0 :         goto done;
     814             :     }
     815             : 
     816          40 :     sss_packet_get_body(cctx->creq->out, &body, &blen);
     817          40 :     DEBUG(SSSDBG_FUNC_DATA, "blen: %zu\n", blen);
     818          40 :     p = 0;
     819             : 
     820          40 :     memcpy(&body[p], &pd->pam_status, sizeof(int32_t));
     821          40 :     p += sizeof(int32_t);
     822             : 
     823          40 :     memcpy(&body[p], &resp_c, sizeof(int32_t));
     824          40 :     p += sizeof(int32_t);
     825             : 
     826          40 :     resp = pd->resp_list;
     827         130 :     while(resp != NULL) {
     828          50 :         if (!resp->do_not_send_to_client) {
     829          43 :             memcpy(&body[p], &resp->type, sizeof(int32_t));
     830          43 :             p += sizeof(int32_t);
     831          43 :             memcpy(&body[p], &resp->len, sizeof(int32_t));
     832          43 :             p += sizeof(int32_t);
     833          43 :             memcpy(&body[p], resp->data, resp->len);
     834          43 :             p += resp->len;
     835             :         }
     836             : 
     837          50 :         resp = resp->next;
     838             :     }
     839             : 
     840             : done:
     841          40 :     sss_cmd_done(cctx, preq);
     842             : }
     843             : 
     844             : static void pam_dom_forwarder(struct pam_auth_req *preq);
     845             : 
     846          16 : static void pam_handle_cached_login(struct pam_auth_req *preq, int ret,
     847             :                                     time_t expire_date, time_t delayed_until,
     848             :                                     bool use_cached_auth)
     849             : {
     850             :     uint32_t resp_type;
     851             :     size_t resp_len;
     852             :     uint8_t *resp;
     853             :     int64_t dummy;
     854             : 
     855          16 :     preq->pd->pam_status = cached_login_pam_status(ret);
     856             : 
     857          16 :     switch (preq->pd->pam_status) {
     858             :         case PAM_SUCCESS:
     859           7 :             resp_type = SSS_PAM_USER_INFO_OFFLINE_AUTH;
     860           7 :             resp_len = sizeof(uint32_t) + sizeof(int64_t);
     861           7 :             resp = talloc_size(preq->pd, resp_len);
     862           7 :             if (resp == NULL) {
     863           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     864             :                       "talloc_size failed, cannot prepare user info.\n");
     865             :             } else {
     866           7 :                 memcpy(resp, &resp_type, sizeof(uint32_t));
     867           7 :                 dummy = (int64_t) expire_date;
     868           7 :                 memcpy(resp+sizeof(uint32_t), &dummy, sizeof(int64_t));
     869           7 :                 ret = pam_add_response(preq->pd, SSS_PAM_USER_INFO, resp_len,
     870             :                                        (const uint8_t *) resp);
     871           7 :                 if (ret != EOK) {
     872           0 :                     DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
     873             :                 }
     874             :             }
     875           7 :             break;
     876             :         case PAM_PERM_DENIED:
     877           1 :             if (delayed_until >= 0) {
     878           0 :                 resp_type = SSS_PAM_USER_INFO_OFFLINE_AUTH_DELAYED;
     879           0 :                 resp_len = sizeof(uint32_t) + sizeof(int64_t);
     880           0 :                 resp = talloc_size(preq->pd, resp_len);
     881           0 :                 if (resp == NULL) {
     882           0 :                     DEBUG(SSSDBG_CRIT_FAILURE,
     883             :                           "talloc_size failed, cannot prepare user info.\n");
     884             :                 } else {
     885           0 :                     memcpy(resp, &resp_type, sizeof(uint32_t));
     886           0 :                     dummy = (int64_t) delayed_until;
     887           0 :                     memcpy(resp+sizeof(uint32_t), &dummy, sizeof(int64_t));
     888           0 :                     ret = pam_add_response(preq->pd, SSS_PAM_USER_INFO, resp_len,
     889             :                                            (const uint8_t *) resp);
     890           0 :                     if (ret != EOK) {
     891           0 :                         DEBUG(SSSDBG_CRIT_FAILURE,
     892             :                               "pam_add_response failed.\n");
     893             :                     }
     894             :                 }
     895             :             }
     896           1 :             break;
     897             :         case PAM_AUTH_ERR:
     898             :             /* Was this attempt to authenticate from cache? */
     899           8 :             if (use_cached_auth) {
     900             :                 /* Don't try cached authentication again, try online check. */
     901           2 :                 DEBUG(SSSDBG_FUNC_DATA,
     902             :                       "Cached authentication failed for: %s\n",
     903             :                       preq->pd->user);
     904           2 :                 preq->cached_auth_failed = true;
     905           2 :                 pam_dom_forwarder(preq);
     906           2 :                 return;
     907             :             }
     908           6 :             break;
     909             :         default:
     910           0 :             DEBUG(SSSDBG_TRACE_LIBS,
     911             :                   "cached login returned: %d\n", preq->pd->pam_status);
     912             :     }
     913             : 
     914          14 :     pam_reply(preq);
     915          14 :     return;
     916             : }
     917             : 
     918             : static void pam_forwarder_cb(struct tevent_req *req);
     919             : static void pam_forwarder_cert_cb(struct tevent_req *req);
     920             : static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min,
     921             :                                        const char *err_msg, void *ptr);
     922             : static int pam_check_user_search(struct pam_auth_req *preq);
     923             : static int pam_check_user_done(struct pam_auth_req *preq, int ret);
     924             : 
     925             : /* TODO: we should probably return some sort of cookie that is set in the
     926             :  * PAM_ENVIRONMENT, so that we can save performing some calls and cache
     927             :  * data. */
     928             : 
     929          40 : static errno_t pam_forwarder_parse_data(struct cli_ctx *cctx, struct pam_data *pd)
     930             : {
     931             :     uint8_t *body;
     932             :     size_t blen;
     933             :     errno_t ret;
     934             :     uint32_t terminator;
     935             : 
     936          40 :     sss_packet_get_body(cctx->creq->in, &body, &blen);
     937          40 :     if (blen >= sizeof(uint32_t)) {
     938          40 :         SAFEALIGN_COPY_UINT32(&terminator,
     939             :                               body + blen - sizeof(uint32_t),
     940             :                               NULL);
     941          40 :         if (terminator != SSS_END_OF_PAM_REQUEST) {
     942           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Received data not terminated.\n");
     943           0 :             ret = EINVAL;
     944           0 :             goto done;
     945             :         }
     946             :     }
     947             : 
     948          40 :     switch (cctx->cli_protocol_version->version) {
     949             :         case 1:
     950           0 :             ret = pam_parse_in_data(pd, body, blen);
     951           0 :             break;
     952             :         case 2:
     953           0 :             ret = pam_parse_in_data_v2(pd, body, blen);
     954           0 :             break;
     955             :         case 3:
     956          40 :             ret = pam_parse_in_data_v3(pd, body, blen);
     957          40 :             break;
     958             :         default:
     959           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Illegal protocol version [%d].\n",
     960             :                       cctx->cli_protocol_version->version);
     961           0 :             ret = EINVAL;
     962             :     }
     963          40 :     if (ret != EOK) {
     964           0 :         goto done;
     965             :     }
     966             : 
     967          40 :     if (pd->logon_name != NULL) {
     968          72 :         ret = sss_parse_name_for_domains(pd, cctx->rctx->domains,
     969          36 :                                          cctx->rctx->default_domain,
     970          36 :                                          pd->logon_name,
     971             :                                          &pd->domain, &pd->user);
     972             :     } else {
     973             :         /* Only SSS_PAM_PREAUTH request may have a missing name, e.g. if the
     974             :          * name is determined with the help of a certificate */
     975           4 :         if (pd->cmd == SSS_PAM_PREAUTH
     976           4 :                 && may_do_cert_auth(talloc_get_type(cctx->rctx->pvt_ctx,
     977             :                                                     struct pam_ctx), pd)) {
     978           3 :             ret = EOK;
     979             :         } else {
     980           1 :             DEBUG(SSSDBG_CRIT_FAILURE, "Missing logon name in PAM request.\n");
     981           1 :             ret = ERR_NO_CREDS;
     982           1 :             goto done;
     983             :         }
     984             :     }
     985             : 
     986          39 :     DEBUG_PAM_DATA(SSSDBG_CONF_SETTINGS, pd);
     987             : 
     988             : done:
     989          40 :     return ret;
     990             : }
     991             : 
     992          40 : static int pam_auth_req_destructor(struct pam_auth_req *preq)
     993             : {
     994          40 :     if (preq && preq->dpreq_spy) {
     995             :         /* If there is still a request pending, tell the spy
     996             :          * the client is going away
     997             :          */
     998           0 :         preq->dpreq_spy->preq = NULL;
     999             :     }
    1000          40 :     return 0;
    1001             : }
    1002             : 
    1003          40 : static bool is_uid_trusted(struct cli_creds *creds,
    1004             :                            size_t trusted_uids_count,
    1005             :                            uid_t *trusted_uids)
    1006             : {
    1007             :     errno_t ret;
    1008             : 
    1009             :     /* root is always trusted */
    1010          40 :     if (client_euid(creds) == 0) {
    1011           0 :         return true;
    1012             :     }
    1013             : 
    1014             :     /* All uids are allowed */
    1015          40 :     if (trusted_uids_count == 0) {
    1016          40 :         return true;
    1017             :     }
    1018             : 
    1019           0 :     ret = check_allowed_uids(client_euid(creds), trusted_uids_count, trusted_uids);
    1020           0 :     if (ret == EOK) return true;
    1021             : 
    1022           0 :     return false;
    1023             : }
    1024             : 
    1025           0 : static bool is_domain_public(char *name,
    1026             :                              char **public_dom_names,
    1027             :                              size_t public_dom_names_count)
    1028             : {
    1029             :     size_t i;
    1030             : 
    1031           0 :     for(i=0; i < public_dom_names_count; i++) {
    1032           0 :         if (strcasecmp(name, public_dom_names[i]) == 0) {
    1033           0 :             return true;
    1034             :         }
    1035             :     }
    1036           0 :     return false;
    1037             : }
    1038             : 
    1039           9 : static errno_t check_cert(TALLOC_CTX *mctx,
    1040             :                           struct tevent_context *ev,
    1041             :                           struct pam_ctx *pctx,
    1042             :                           struct pam_auth_req *preq,
    1043             :                           struct pam_data *pd)
    1044             : {
    1045             :     int p11_child_timeout;
    1046           9 :     const int P11_CHILD_TIMEOUT_DEFAULT = 10;
    1047             :     char *cert_verification_opts;
    1048             :     errno_t ret;
    1049             :     struct tevent_req *req;
    1050             : 
    1051           9 :     ret = confdb_get_int(pctx->rctx->cdb, CONFDB_PAM_CONF_ENTRY,
    1052             :                          CONFDB_PAM_P11_CHILD_TIMEOUT,
    1053             :                          P11_CHILD_TIMEOUT_DEFAULT,
    1054             :                          &p11_child_timeout);
    1055           9 :     if (ret != EOK) {
    1056           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    1057             :               "Failed to read p11_child_timeout from confdb: [%d]: %s\n",
    1058             :               ret, sss_strerror(ret));
    1059           0 :         return ret;
    1060             :     }
    1061             : 
    1062           9 :     ret = confdb_get_string(pctx->rctx->cdb, mctx, CONFDB_MONITOR_CONF_ENTRY,
    1063             :                             CONFDB_MONITOR_CERT_VERIFICATION, NULL,
    1064             :                             &cert_verification_opts);
    1065           9 :     if (ret != EOK) {
    1066           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    1067             :               "Failed to read certificate_verification from confdb: [%d]: %s\n",
    1068             :               ret, sss_strerror(ret));
    1069           0 :         return ret;
    1070             :     }
    1071             : 
    1072          18 :     req = pam_check_cert_send(mctx, ev, pctx->p11_child_debug_fd,
    1073           9 :                               pctx->nss_db, p11_child_timeout,
    1074             :                               cert_verification_opts, pd);
    1075           9 :     if (req == NULL) {
    1076           0 :         DEBUG(SSSDBG_OP_FAILURE, "pam_check_cert_send failed.\n");
    1077           0 :         return ENOMEM;
    1078             :     }
    1079             : 
    1080           9 :     tevent_req_set_callback(req, pam_forwarder_cert_cb, preq);
    1081           9 :     return EAGAIN;
    1082             : }
    1083             : 
    1084          40 : static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
    1085             : {
    1086             :     struct sss_domain_info *dom;
    1087             :     struct pam_auth_req *preq;
    1088             :     struct pam_data *pd;
    1089             :     int ret;
    1090             :     errno_t ncret;
    1091          40 :     struct pam_ctx *pctx =
    1092          40 :             talloc_get_type(cctx->rctx->pvt_ctx, struct pam_ctx);
    1093             :     struct tevent_req *req;
    1094             : 
    1095          40 :     preq = talloc_zero(cctx, struct pam_auth_req);
    1096          40 :     if (!preq) {
    1097           0 :         return ENOMEM;
    1098             :     }
    1099          40 :     talloc_set_destructor(preq, pam_auth_req_destructor);
    1100          40 :     preq->cctx = cctx;
    1101             : 
    1102          40 :     preq->pd = create_pam_data(preq);
    1103          40 :     if (!preq->pd) {
    1104           0 :         talloc_free(preq);
    1105           0 :         return ENOMEM;
    1106             :     }
    1107          40 :     pd = preq->pd;
    1108             : 
    1109          40 :     preq->is_uid_trusted = is_uid_trusted(cctx->creds,
    1110             :                                           pctx->trusted_uids_count,
    1111             :                                           pctx->trusted_uids);
    1112             : 
    1113          40 :     if (!preq->is_uid_trusted) {
    1114           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "uid %"SPRIuid" is not trusted.\n",
    1115             :               client_euid(cctx->creds));
    1116             :     }
    1117             : 
    1118             : 
    1119          40 :     pd->cmd = pam_cmd;
    1120          40 :     pd->priv = cctx->priv;
    1121             : 
    1122          40 :     ret = pam_forwarder_parse_data(cctx, pd);
    1123          40 :     if (ret == EAGAIN) {
    1124           0 :         req = sss_dp_get_domains_send(cctx->rctx, cctx->rctx, true, pd->domain);
    1125           0 :         if (req == NULL) {
    1126           0 :             ret = ENOMEM;
    1127             :         } else {
    1128           0 :             tevent_req_set_callback(req, pam_forwarder_cb, preq);
    1129           0 :             ret = EAGAIN;
    1130             :         }
    1131           0 :         goto done;
    1132          40 :     } else if (ret != EOK) {
    1133           1 :         goto done;
    1134             :     }
    1135             : 
    1136          39 :     if (pd->user != NULL) {
    1137             :         /* now check user is valid */
    1138          36 :         if (pd->domain) {
    1139           0 :             preq->domain = responder_get_domain(cctx->rctx, pd->domain);
    1140           0 :             if (!preq->domain) {
    1141           0 :                 ret = ENOENT;
    1142           0 :                 goto done;
    1143             :             }
    1144             : 
    1145           0 :             ncret = sss_ncache_check_user(pctx->rctx->ncache,
    1146           0 :                                           preq->domain, pd->user);
    1147           0 :             if (ncret == EEXIST) {
    1148             :                 /* User found in the negative cache */
    1149           0 :                 ret = ENOENT;
    1150           0 :                 goto done;
    1151             :             }
    1152             :         } else {
    1153          72 :             for (dom = preq->cctx->rctx->domains;
    1154             :                  dom;
    1155           0 :                  dom = get_next_domain(dom, 0)) {
    1156          36 :                 if (dom->fqnames) continue;
    1157             : 
    1158          36 :                 ncret = sss_ncache_check_user(pctx->rctx->ncache,
    1159          36 :                                               dom, pd->user);
    1160          36 :                 if (ncret == ENOENT) {
    1161             :                     /* User not found in the negative cache
    1162             :                      * Proceed with PAM actions
    1163             :                      */
    1164          36 :                     break;
    1165             :                 }
    1166             : 
    1167             :                 /* Try the next domain */
    1168           0 :                 DEBUG(SSSDBG_TRACE_FUNC,
    1169             :                       "User [%s@%s] filtered out (negative cache). "
    1170             :                        "Trying next domain.\n", pd->user, dom->name);
    1171             :             }
    1172             : 
    1173          36 :             if (!dom) {
    1174           0 :                 ret = ENOENT;
    1175           0 :                 goto done;
    1176             :             }
    1177          36 :             preq->domain = dom;
    1178             :         }
    1179             :     }
    1180             : 
    1181             : 
    1182          39 :     if (may_do_cert_auth(pctx, pd)) {
    1183           9 :         ret = check_cert(cctx, cctx->ev, pctx, preq, pd);
    1184             :         /* Finish here */
    1185           9 :         goto done;
    1186             :     }
    1187             : 
    1188             : 
    1189          30 :     if (preq->domain->provider == NULL) {
    1190           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    1191             :               "Domain [%s] has no auth provider.\n", preq->domain->name);
    1192           0 :         ret = EINVAL;
    1193           0 :         goto done;
    1194             :     }
    1195             : 
    1196          30 :     preq->check_provider = NEED_CHECK_PROVIDER(preq->domain->provider);
    1197             : 
    1198          30 :     ret = pam_check_user_search(preq);
    1199          30 :     if (ret == EOK) {
    1200          30 :         pam_dom_forwarder(preq);
    1201             :     }
    1202             : 
    1203             : done:
    1204          40 :     return pam_check_user_done(preq, ret);
    1205             : }
    1206             : 
    1207             : static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req);
    1208           9 : static void pam_forwarder_cert_cb(struct tevent_req *req)
    1209             : {
    1210           9 :     struct pam_auth_req *preq = tevent_req_callback_data(req,
    1211             :                                                          struct pam_auth_req);
    1212           9 :     struct cli_ctx *cctx = preq->cctx;
    1213             :     struct pam_data *pd;
    1214           9 :     errno_t ret = EOK;
    1215             :     char *cert;
    1216           9 :     struct pam_ctx *pctx =
    1217           9 :             talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
    1218             : 
    1219           9 :     ret = pam_check_cert_recv(req, preq, &cert, &preq->token_name);
    1220           9 :     talloc_free(req);
    1221           9 :     if (ret != EOK) {
    1222           0 :         DEBUG(SSSDBG_OP_FAILURE, "get_cert request failed.\n");
    1223           0 :         goto done;
    1224             :     }
    1225             : 
    1226           9 :     pd = preq->pd;
    1227             : 
    1228           9 :     if (cert == NULL) {
    1229           2 :         if (pd->logon_name == NULL) {
    1230           1 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1231             :                   "No certificate found and no logon name given, " \
    1232             :                   "authentication not possible.\n");;
    1233           1 :             ret = ENOENT;
    1234             :         } else {
    1235           1 :             if (pd->cmd == SSS_PAM_AUTHENTICATE) {
    1236           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
    1237             :                       "No certificate returned, authentication failed.\n");
    1238           0 :                 ret = ENOENT;
    1239             :             } else {
    1240           1 :                 ret = pam_check_user_search(preq);
    1241           1 :                 if (ret == EOK) {
    1242           1 :                     pam_dom_forwarder(preq);
    1243             :                 }
    1244             :             }
    1245             : 
    1246             :         }
    1247           2 :         goto done;
    1248             :     }
    1249             : 
    1250             : 
    1251          14 :     req = cache_req_user_by_cert_send(preq, cctx->ev, cctx->rctx,
    1252           7 :                                       pctx->rctx->ncache, 0, NULL, cert);
    1253           7 :     if (req == NULL) {
    1254           0 :         DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert_send failed.\n");
    1255           0 :         ret = ENOMEM;
    1256           0 :         goto done;
    1257             :     }
    1258           7 :     tevent_req_set_callback(req, pam_forwarder_lookup_by_cert_done, preq);
    1259          16 :     return;
    1260             : 
    1261             : done:
    1262           2 :     pam_check_user_done(preq, ret);
    1263             : }
    1264             : 
    1265           7 : static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
    1266             : {
    1267             :     int ret;
    1268             :     struct ldb_result *res;
    1269             :     struct sss_domain_info *domain;
    1270           7 :     struct pam_auth_req *preq = tevent_req_callback_data(req,
    1271             :                                                          struct pam_auth_req);
    1272             :     const char *cert_user;
    1273             : 
    1274             : 
    1275           7 :     ret = cache_req_user_by_cert_recv(preq, req, &res, &domain, NULL);
    1276           7 :     talloc_zfree(req);
    1277           7 :     if (ret != EOK && ret != ENOENT) {
    1278           0 :         DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert request failed.\n");
    1279           0 :         goto done;
    1280             :     }
    1281             : 
    1282           7 :     if (ret == EOK && res->count > 1) {
    1283           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    1284             :               "Search by certificate returned more than one result.\n");
    1285           0 :         ret = EINVAL;
    1286           0 :         goto done;
    1287             :     }
    1288             : 
    1289           7 :     if (ret == EOK) {
    1290           5 :         if (preq->domain == NULL) {
    1291           1 :             preq->domain = domain;
    1292             :         }
    1293             : 
    1294           5 :         preq->cert_user_obj = talloc_steal(preq, res->msgs[0]);
    1295             : 
    1296           5 :         if (preq->pd->logon_name == NULL) {
    1297           1 :             cert_user = ldb_msg_find_attr_as_string(preq->cert_user_obj,
    1298             :                                                     SYSDB_NAME, NULL);
    1299           1 :             if (cert_user == NULL) {
    1300           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
    1301             :                       "Certificate user object has not name.\n");
    1302           0 :                 ret = ENOENT;
    1303           0 :                 goto done;
    1304             :             }
    1305             : 
    1306           1 :             DEBUG(SSSDBG_FUNC_DATA, "Found certificate user [%s].\n",
    1307             :                                     cert_user);
    1308             : 
    1309           1 :             ret = add_pam_cert_response(preq->pd, cert_user, preq->token_name);
    1310           1 :             if (ret != EOK) {
    1311           0 :                 DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n");
    1312             :             }
    1313             : 
    1314           1 :             preq->pd->domain = talloc_strdup(preq->pd, domain->name);
    1315           1 :             if (preq->pd->domain == NULL) {
    1316           0 :                 DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
    1317           0 :                 ret = ENOMEM;
    1318           0 :                 goto done;
    1319             :             }
    1320           1 :             preq->pd->pam_status = PAM_SUCCESS;
    1321           1 :             pam_reply(preq);
    1322           8 :             return;
    1323             :         }
    1324             :     } else {
    1325           2 :         if (preq->pd->logon_name == NULL) {
    1326           1 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1327             :                   "Missing logon name and no certificate user found.\n");
    1328           1 :             ret = ENOENT;
    1329           1 :             goto done;
    1330             :         }
    1331             :     }
    1332             : 
    1333           5 :     ret = pam_check_user_search(preq);
    1334           5 :     if (ret == EOK) {
    1335           5 :         pam_dom_forwarder(preq);
    1336             :     }
    1337             : 
    1338             : done:
    1339           6 :     pam_check_user_done(preq, ret);
    1340             : }
    1341             : 
    1342           0 : static void pam_forwarder_cb(struct tevent_req *req)
    1343             : {
    1344           0 :     struct pam_auth_req *preq = tevent_req_callback_data(req,
    1345             :                                                          struct pam_auth_req);
    1346           0 :     struct cli_ctx *cctx = preq->cctx;
    1347             :     struct pam_data *pd;
    1348           0 :     errno_t ret = EOK;
    1349           0 :     struct pam_ctx *pctx =
    1350           0 :             talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
    1351             : 
    1352           0 :     ret = sss_dp_get_domains_recv(req);
    1353           0 :     talloc_free(req);
    1354           0 :     if (ret != EOK) {
    1355           0 :         goto done;
    1356             :     }
    1357             : 
    1358           0 :     pd = preq->pd;
    1359             : 
    1360           0 :     ret = pam_forwarder_parse_data(cctx, pd);
    1361           0 :     if (ret == EAGAIN) {
    1362           0 :         if (strchr(preq->pd->logon_name, '@') == NULL) {
    1363           0 :             goto done;
    1364             :         }
    1365             :         /* Assuming Kerberos principal */
    1366           0 :         preq->domain = preq->cctx->rctx->domains;
    1367           0 :         preq->check_provider = NEED_CHECK_PROVIDER(preq->domain->provider);
    1368           0 :         preq->pd->user = talloc_strdup(preq->pd, preq->pd->logon_name);
    1369           0 :         if (preq->pd->user == NULL) {
    1370           0 :             DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
    1371           0 :             ret = ENOMEM;
    1372           0 :             goto done;
    1373             :         }
    1374           0 :         preq->pd->name_is_upn = true;
    1375           0 :         preq->pd->domain = NULL;
    1376           0 :     } else if (ret != EOK) {
    1377           0 :         ret = EINVAL;
    1378           0 :         goto done;
    1379             :     }
    1380             : 
    1381           0 :     if (preq->pd->domain) {
    1382           0 :         preq->domain = responder_get_domain(cctx->rctx, preq->pd->domain);
    1383           0 :         if (preq->domain == NULL) {
    1384           0 :             ret = ENOENT;
    1385           0 :             goto done;
    1386             :         }
    1387             :     }
    1388             : 
    1389           0 :     if (may_do_cert_auth(pctx, pd)) {
    1390           0 :         ret = check_cert(cctx, cctx->ev, pctx, preq, pd);
    1391             :         /* Finish here */
    1392           0 :         goto done;
    1393             :     }
    1394             : 
    1395           0 :     ret = pam_check_user_search(preq);
    1396           0 :     if (ret == EOK) {
    1397           0 :         pam_dom_forwarder(preq);
    1398             :     }
    1399             : 
    1400             : done:
    1401           0 :     pam_check_user_done(preq, ret);
    1402           0 : }
    1403             : 
    1404             : static void pam_dp_send_acct_req_done(struct tevent_req *req);
    1405          36 : static int pam_check_user_search(struct pam_auth_req *preq)
    1406             : {
    1407          36 :     struct sss_domain_info *dom = preq->domain;
    1408          36 :     char *name = NULL;
    1409             :     time_t cacheExpire;
    1410             :     int ret;
    1411             :     struct tevent_req *dpreq;
    1412             :     struct dp_callback_ctx *cb_ctx;
    1413          36 :     struct pam_ctx *pctx =
    1414          36 :             talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
    1415             :     static const char *user_attrs[] = SYSDB_PW_ATTRS;
    1416             :     struct ldb_message *msg;
    1417             :     struct ldb_result *res;
    1418             : 
    1419          36 :     while (dom) {
    1420             :        /* if it is a domainless search, skip domains that require fully
    1421             :         * qualified names instead */
    1422          72 :         while (dom && !preq->pd->domain && !preq->pd->name_is_upn
    1423          36 :                && dom->fqnames) {
    1424           0 :             dom = get_next_domain(dom, 0);
    1425             :         }
    1426             : 
    1427          36 :         if (!dom) break;
    1428             : 
    1429          36 :         if (dom != preq->domain) {
    1430             :             /* make sure we reset the check_provider flag when we check
    1431             :              * a new domain */
    1432           0 :             preq->check_provider = NEED_CHECK_PROVIDER(dom->provider);
    1433             :         }
    1434             : 
    1435             :         /* make sure to update the preq if we changed domain */
    1436          36 :         preq->domain = dom;
    1437             : 
    1438          36 :         talloc_free(name);
    1439          36 :         name = sss_get_cased_name(preq, preq->pd->user,
    1440          36 :                                   dom->case_sensitive);
    1441          36 :         if (!name) {
    1442           0 :             return ENOMEM;
    1443             :         }
    1444             : 
    1445          36 :         name = sss_reverse_replace_space(preq, name,
    1446          36 :                                          pctx->rctx->override_space);
    1447          36 :         if (name == NULL) {
    1448           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1449             :                   "sss_reverse_replace_space failed\n");
    1450           0 :             return ENOMEM;
    1451             :         }
    1452             : 
    1453             :         /* Refresh the user's cache entry on any PAM query
    1454             :          * We put a timeout in the client context so that we limit
    1455             :          * the number of updates within a reasonable timeout
    1456             :          */
    1457          36 :         if (preq->check_provider) {
    1458          30 :             ret = pam_initgr_check_timeout(pctx->id_table,
    1459          30 :                                            preq->pd->logon_name);
    1460          30 :             if (ret != EOK
    1461           0 :                     && ret != ENOENT) {
    1462           0 :                 DEBUG(SSSDBG_OP_FAILURE,
    1463             :                       "Could not look up initgroup timout\n");
    1464           0 :                 return EIO;
    1465          30 :             } else if (ret == ENOENT) {
    1466             :                 /* Call provider first */
    1467           0 :                 break;
    1468             :             }
    1469             :             /* Entry is still valid, get it from the sysdb */
    1470             :         }
    1471             : 
    1472          36 :         DEBUG(SSSDBG_CONF_SETTINGS,
    1473             :               "Requesting info for [%s@%s]\n", name, dom->name);
    1474             : 
    1475          36 :         if (dom->sysdb == NULL) {
    1476           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    1477             :                   "Fatal: Sysdb CTX not found for this domain!\n");
    1478           0 :             preq->pd->pam_status = PAM_SYSTEM_ERR;
    1479           0 :             return EFAULT;
    1480             :         }
    1481             : 
    1482          36 :         if (preq->pd->name_is_upn) {
    1483           0 :             ret = sysdb_search_user_by_upn(preq, dom, name, user_attrs, &msg);
    1484             :         } else {
    1485          36 :             ret = sysdb_getpwnam_with_views(preq, dom, name, &res);
    1486          36 :             if (res->count > 1) {
    1487           0 :                 DEBUG(SSSDBG_FATAL_FAILURE,
    1488             :                       "getpwnam call returned more than one result !?!\n");
    1489           0 :                 sss_log(SSS_LOG_ERR,
    1490             :                         "More users have the same name [%s@%s] in SSSD cache. "
    1491             :                         "SSSD will not work correctly.\n",
    1492             :                         name, dom->name);
    1493           0 :                 return ENOENT;
    1494          36 :             } else if (res->count == 0) {
    1495           0 :                 ret = ENOENT;
    1496             :             } else {
    1497          36 :                 msg = res->msgs[0];
    1498             :             }
    1499             :         }
    1500          36 :         if (ret != EOK && ret != ENOENT) {
    1501           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1502             :                   "Failed to make request to our cache!\n");
    1503           0 :             return EIO;
    1504             :         }
    1505             : 
    1506          36 :         if (ret == ENOENT) {
    1507           0 :             if (preq->check_provider == false) {
    1508             :                 /* set negative cache only if not result of cache check */
    1509           0 :                 ret = sss_ncache_set_user(pctx->rctx->ncache, false, dom, name);
    1510           0 :                 if (ret != EOK) {
    1511             :                     /* Should not be fatal, just slower next time */
    1512           0 :                     DEBUG(SSSDBG_MINOR_FAILURE,
    1513             :                            "Cannot set ncache for [%s@%s]\n", name,
    1514             :                             dom->name);
    1515             :                 }
    1516             :             }
    1517             : 
    1518             :             /* if a multidomain search, try with next */
    1519           0 :             if (!preq->pd->domain) {
    1520           0 :                 dom = get_next_domain(dom, 0);
    1521           0 :                 continue;
    1522             :             }
    1523             : 
    1524           0 :             DEBUG(SSSDBG_OP_FAILURE, "No results for getpwnam call\n");
    1525             : 
    1526             :             /* TODO: store negative cache ? */
    1527             : 
    1528           0 :             return ENOENT;
    1529             :         }
    1530             : 
    1531             :         /* One result found */
    1532             : 
    1533             :         /* if we need to check the remote account go on */
    1534          36 :         if (preq->check_provider) {
    1535          30 :             cacheExpire = ldb_msg_find_attr_as_uint64(msg,
    1536             :                                                       SYSDB_CACHE_EXPIRE, 0);
    1537          30 :             if (cacheExpire < time(NULL)) {
    1538           0 :                 break;
    1539             :             }
    1540             :         }
    1541             : 
    1542          36 :         DEBUG(SSSDBG_TRACE_FUNC,
    1543             :               "Returning info for user [%s@%s]\n", name, dom->name);
    1544             : 
    1545             :         /* We might have searched by alias. Pass on the primary name */
    1546          36 :         ret = pd_set_primary_name(msg, preq->pd);
    1547          36 :         if (ret != EOK) {
    1548           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Could not canonicalize username\n");
    1549           0 :             return ret;
    1550             :         }
    1551             : 
    1552          36 :         return EOK;
    1553             :     }
    1554             : 
    1555           0 :     if (!dom) {
    1556             :         /* Ensure that we don't try to check a provider without a domain,
    1557             :          * since this will cause a NULL-dereference below.
    1558             :          */
    1559           0 :         preq->check_provider = false;
    1560             :     }
    1561             : 
    1562           0 :     if (preq->check_provider) {
    1563             : 
    1564             :         /* dont loop forever :-) */
    1565           0 :         preq->check_provider = false;
    1566             : 
    1567           0 :         dpreq = sss_dp_get_account_send(preq, preq->cctx->rctx,
    1568             :                               dom, false, SSS_DP_INITGROUPS, name, 0,
    1569           0 :                               preq->pd->name_is_upn ? EXTRA_NAME_IS_UPN : NULL);
    1570           0 :         if (!dpreq) {
    1571           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1572             :                   "Out of memory sending data provider request\n");
    1573           0 :             return ENOMEM;
    1574             :         }
    1575             : 
    1576           0 :         cb_ctx = talloc_zero(preq, struct dp_callback_ctx);
    1577           0 :         if(!cb_ctx) {
    1578           0 :             talloc_zfree(dpreq);
    1579           0 :             return ENOMEM;
    1580             :         }
    1581             : 
    1582           0 :         cb_ctx->callback = pam_check_user_dp_callback;
    1583           0 :         cb_ctx->ptr = preq;
    1584           0 :         cb_ctx->cctx = preq->cctx;
    1585           0 :         cb_ctx->mem_ctx = preq;
    1586             : 
    1587           0 :         tevent_req_set_callback(dpreq, pam_dp_send_acct_req_done, cb_ctx);
    1588             : 
    1589             :         /* tell caller we are in an async call */
    1590           0 :         return EAGAIN;
    1591             :     }
    1592             : 
    1593           0 :     DEBUG(SSSDBG_MINOR_FAILURE,
    1594             :           "No matching domain found for [%s], fail!\n", preq->pd->user);
    1595           0 :     return ENOENT;
    1596             : }
    1597             : 
    1598           0 : static void pam_dp_send_acct_req_done(struct tevent_req *req)
    1599             : {
    1600           0 :     struct dp_callback_ctx *cb_ctx =
    1601           0 :             tevent_req_callback_data(req, struct dp_callback_ctx);
    1602             : 
    1603             :     errno_t ret;
    1604             :     dbus_uint16_t err_maj;
    1605             :     dbus_uint32_t err_min;
    1606             :     char *err_msg;
    1607             : 
    1608           0 :     ret = sss_dp_get_account_recv(cb_ctx->mem_ctx, req,
    1609             :                                   &err_maj, &err_min,
    1610             :                                   &err_msg);
    1611           0 :     talloc_zfree(req);
    1612           0 :     if (ret != EOK) {
    1613           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    1614             :               "Fatal error, killing connection!\n");
    1615           0 :         talloc_free(cb_ctx->cctx);
    1616           0 :         return;
    1617             :     }
    1618             : 
    1619           0 :     cb_ctx->callback(err_maj, err_min, err_msg, cb_ctx->ptr);
    1620             : }
    1621             : 
    1622          48 : static int pam_check_user_done(struct pam_auth_req *preq, int ret)
    1623             : {
    1624          48 :     switch (ret) {
    1625             :     case EOK:
    1626          36 :         break;
    1627             : 
    1628             :     case EAGAIN:
    1629             :         /* performing async request, just return */
    1630           9 :         break;
    1631             : 
    1632             :     case ENOENT:
    1633           2 :         preq->pd->pam_status = PAM_USER_UNKNOWN;
    1634           2 :         pam_reply(preq);
    1635           2 :         break;
    1636             : 
    1637             :     case ERR_NO_CREDS:
    1638           1 :         preq->pd->pam_status = PAM_CRED_INSUFFICIENT;
    1639           1 :         pam_reply(preq);
    1640           1 :         break;
    1641             : 
    1642             :     default:
    1643           0 :         preq->pd->pam_status = PAM_SYSTEM_ERR;
    1644           0 :         pam_reply(preq);
    1645           0 :         break;
    1646             :     }
    1647             : 
    1648          48 :     return EOK;
    1649             : }
    1650             : 
    1651           0 : static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min,
    1652             :                                        const char *err_msg, void *ptr)
    1653             : {
    1654           0 :     struct pam_auth_req *preq = talloc_get_type(ptr, struct pam_auth_req);
    1655             :     int ret;
    1656           0 :     struct pam_ctx *pctx =
    1657           0 :             talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
    1658             : 
    1659           0 :     if (err_maj) {
    1660           0 :         DEBUG(SSSDBG_OP_FAILURE,
    1661             :               "Unable to get information from Data Provider\n"
    1662             :                   "Error: %u, %u, %s\n",
    1663             :                   (unsigned int)err_maj, (unsigned int)err_min, err_msg);
    1664             :     }
    1665             : 
    1666           0 :     ret = pam_check_user_search(preq);
    1667           0 :     if (ret == EOK) {
    1668             :         /* Make sure we don't go to the ID provider too often */
    1669           0 :         ret = pam_initgr_cache_set(pctx->rctx->ev, pctx->id_table,
    1670           0 :                                    preq->pd->logon_name, pctx->id_timeout);
    1671           0 :         if (ret != EOK) {
    1672           0 :             DEBUG(SSSDBG_OP_FAILURE,
    1673             :                   "Could not save initgr timestamp. "
    1674             :                    "Proceeding with PAM actions\n");
    1675             :             /* This is non-fatal, we'll just end up going to the
    1676             :              * data provider again next time.
    1677             :              */
    1678             :         }
    1679             : 
    1680           0 :         pam_dom_forwarder(preq);
    1681             :     }
    1682             : 
    1683           0 :     ret = pam_check_user_done(preq, ret);
    1684             : 
    1685           0 :     if (ret) {
    1686           0 :         preq->pd->pam_status = PAM_SYSTEM_ERR;
    1687           0 :         pam_reply(preq);
    1688             :     }
    1689           0 : }
    1690             : 
    1691           8 : static errno_t pam_is_last_online_login_fresh(struct sss_domain_info *domain,
    1692             :                                               const char* user,
    1693             :                                               int cached_auth_timeout,
    1694             :                                               bool *_result)
    1695             : {
    1696             :     errno_t ret;
    1697             :     bool result;
    1698             :     uint64_t last_login;
    1699             : 
    1700           8 :     ret = pam_get_last_online_auth_with_curr_token(domain, user, &last_login);
    1701           8 :     if (ret != EOK) {
    1702           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
    1703             :               "sysdb_get_last_online_auth_with_curr_token failed: %s:[%d]\n",
    1704             :               sss_strerror(ret), ret);
    1705           0 :         goto done;
    1706             :     }
    1707             : 
    1708           8 :     result = time(NULL) < (last_login + cached_auth_timeout);
    1709           8 :     ret = EOK;
    1710             : 
    1711             : done:
    1712           8 :     if (ret == EOK) {
    1713           8 :         *_result = result;
    1714             :     }
    1715           8 :     return ret;
    1716             : }
    1717             : 
    1718           8 : static bool pam_is_cmd_cachable(int cmd)
    1719             : {
    1720             :     bool is_cachable;
    1721             : 
    1722           8 :     switch(cmd) {
    1723             :     case SSS_PAM_AUTHENTICATE:
    1724           8 :         is_cachable = true;
    1725           8 :         break;
    1726             :     default:
    1727           0 :         is_cachable = false;
    1728             :     }
    1729             : 
    1730           8 :     return is_cachable;
    1731             : }
    1732             : 
    1733          14 : static bool pam_is_authtok_cachable(struct sss_auth_token *authtok)
    1734             : {
    1735             :     enum sss_authtok_type type;
    1736          14 :     bool cachable = false;
    1737             : 
    1738          14 :     type = sss_authtok_get_type(authtok);
    1739          14 :     if (type == SSS_AUTHTOK_TYPE_PASSWORD) {
    1740           8 :         cachable = true;
    1741             :     } else {
    1742           6 :         DEBUG(SSSDBG_TRACE_LIBS, "Authentication token can't be cached\n");
    1743             :     }
    1744             : 
    1745          14 :     return cachable;
    1746             : }
    1747             : 
    1748          38 : static bool pam_can_user_cache_auth(struct sss_domain_info *domain,
    1749             :                                     int pam_cmd,
    1750             :                                     struct sss_auth_token *authtok,
    1751             :                                     const char* user,
    1752             :                                     bool cached_auth_failed)
    1753             : {
    1754             :     errno_t ret;
    1755          38 :     bool result = false;
    1756             : 
    1757          38 :     if (!cached_auth_failed /* don't try cached auth again */
    1758          36 :             && domain->cache_credentials
    1759          36 :             && domain->cached_auth_timeout > 0
    1760          14 :             && pam_is_authtok_cachable(authtok)
    1761           8 :             && pam_is_cmd_cachable(pam_cmd)) {
    1762             : 
    1763           8 :         ret = pam_is_last_online_login_fresh(domain, user,
    1764           8 :                                              domain->cached_auth_timeout,
    1765             :                                              &result);
    1766           8 :         if (ret != EOK) {
    1767             :             /* non-critical, consider fail as 'non-fresh value' */
    1768           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
    1769             :                   "pam_is_last_online_login_fresh failed: %s:[%d]\n",
    1770             :                   sss_strerror(ret), ret);
    1771             :         }
    1772             :     }
    1773             : 
    1774          38 :     return result;
    1775             : }
    1776             : 
    1777          38 : static void pam_dom_forwarder(struct pam_auth_req *preq)
    1778             : {
    1779             :     int ret;
    1780          38 :     struct pam_ctx *pctx =
    1781          38 :             talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
    1782             :     const char *cert_user;
    1783             : 
    1784          38 :     if (!preq->pd->domain) {
    1785          36 :         preq->pd->domain = preq->domain->name;
    1786             :     }
    1787             : 
    1788             :     /* Untrusted users can access only public domains. */
    1789          38 :     if (!preq->is_uid_trusted &&
    1790           0 :             !is_domain_public(preq->pd->domain, pctx->public_domains,
    1791           0 :                             pctx->public_domains_count)) {
    1792           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
    1793             :               "Untrusted user %"SPRIuid" cannot access non-public domain %s.\n",
    1794             :               client_euid(preq->cctx->creds), preq->pd->domain);
    1795           0 :         preq->pd->pam_status = PAM_PERM_DENIED;
    1796           0 :         pam_reply(preq);
    1797           0 :         return;
    1798             :     }
    1799             : 
    1800             :     /* skip this domain if not requested and the user is trusted
    1801             :      * as untrusted users can't request a domain */
    1802          76 :     if (preq->is_uid_trusted &&
    1803          38 :             !is_domain_requested(preq->pd, preq->pd->domain)) {
    1804           0 :         preq->pd->pam_status = PAM_USER_UNKNOWN;
    1805           0 :         pam_reply(preq);
    1806           0 :         return;
    1807             :     }
    1808             : 
    1809         114 :     if (pam_can_user_cache_auth(preq->domain,
    1810          38 :                                 preq->pd->cmd,
    1811          38 :                                 preq->pd->authtok,
    1812          38 :                                 preq->pd->user,
    1813          38 :                                 preq->cached_auth_failed)) {
    1814           4 :         preq->use_cached_auth = true;
    1815           4 :         pam_reply(preq);
    1816           4 :         return;
    1817             :     }
    1818             : 
    1819          34 :     if (may_do_cert_auth(pctx, preq->pd) && preq->cert_user_obj != NULL) {
    1820             :         /* Check if user matches certificate user */
    1821           4 :         cert_user = ldb_msg_find_attr_as_string(preq->cert_user_obj, SYSDB_NAME,
    1822             :                                                 NULL);
    1823           4 :         if (cert_user == NULL) {
    1824           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1825             :                   "Certificate user object has not name.\n");
    1826           0 :             preq->pd->pam_status = PAM_USER_UNKNOWN;
    1827           0 :             pam_reply(preq);
    1828           0 :             return;
    1829             :         }
    1830             : 
    1831             :         /* pam_check_user_search() calls pd_set_primary_name() is the search
    1832             :          * was successful, so pd->user contains the canonical name as well */
    1833           4 :         if (strcmp(cert_user, preq->pd->user) == 0) {
    1834             : 
    1835           3 :             preq->pd->pam_status = PAM_SUCCESS;
    1836             : 
    1837           3 :             if (preq->pd->cmd == SSS_PAM_PREAUTH) {
    1838           1 :                 ret = add_pam_cert_response(preq->pd, cert_user,
    1839           1 :                                             preq->token_name);
    1840           1 :                 if (ret != EOK) {
    1841           0 :                     DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n");
    1842           0 :                     preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
    1843             :                 }
    1844             :             }
    1845             : 
    1846           3 :             preq->callback = pam_reply;
    1847           3 :             pam_reply(preq);
    1848           3 :             return;
    1849             :         } else {
    1850           1 :             if (preq->pd->cmd == SSS_PAM_PREAUTH) {
    1851           1 :                 DEBUG(SSSDBG_TRACE_FUNC,
    1852             :                       "User and certificate user do not match, " \
    1853             :                       "continue with other authentication methods.\n");
    1854             :             } else {
    1855           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
    1856             :                       "User and certificate user do not match.\n");
    1857           0 :                 preq->pd->pam_status = PAM_AUTH_ERR;
    1858           0 :                 pam_reply(preq);
    1859           0 :                 return;
    1860             :             }
    1861             :         }
    1862             :     }
    1863             : 
    1864          31 :     if (!NEED_CHECK_PROVIDER(preq->domain->provider) ) {
    1865           0 :         preq->callback = pam_reply;
    1866           0 :         ret = LOCAL_pam_handler(preq);
    1867             :     }
    1868             :     else {
    1869          31 :         preq->callback = pam_reply;
    1870          31 :         ret = pam_dp_send_req(preq, SSS_CLI_SOCKET_TIMEOUT/2);
    1871          31 :         DEBUG(SSSDBG_CONF_SETTINGS, "pam_dp_send_req returned %d\n", ret);
    1872             :     }
    1873             : 
    1874          31 :     if (ret != EOK) {
    1875           0 :         preq->pd->pam_status = PAM_SYSTEM_ERR;
    1876           0 :         pam_reply(preq);
    1877             :     }
    1878             : }
    1879             : 
    1880          23 : static int pam_cmd_authenticate(struct cli_ctx *cctx) {
    1881          23 :     DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_authenticate\n");
    1882          23 :     return pam_forwarder(cctx, SSS_PAM_AUTHENTICATE);
    1883             : }
    1884             : 
    1885           1 : static int pam_cmd_setcred(struct cli_ctx *cctx) {
    1886           1 :     DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_setcred\n");
    1887           1 :     return pam_forwarder(cctx, SSS_PAM_SETCRED);
    1888             : }
    1889             : 
    1890           1 : static int pam_cmd_acct_mgmt(struct cli_ctx *cctx) {
    1891           1 :     DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_acct_mgmt\n");
    1892           1 :     return pam_forwarder(cctx, SSS_PAM_ACCT_MGMT);
    1893             : }
    1894             : 
    1895           1 : static int pam_cmd_open_session(struct cli_ctx *cctx) {
    1896           1 :     DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_open_session\n");
    1897           1 :     return pam_forwarder(cctx, SSS_PAM_OPEN_SESSION);
    1898             : }
    1899             : 
    1900           1 : static int pam_cmd_close_session(struct cli_ctx *cctx) {
    1901           1 :     DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_close_session\n");
    1902           1 :     return pam_forwarder(cctx, SSS_PAM_CLOSE_SESSION);
    1903             : }
    1904             : 
    1905           2 : static int pam_cmd_chauthtok(struct cli_ctx *cctx) {
    1906           2 :     DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_chauthtok\n");
    1907           2 :     return pam_forwarder(cctx, SSS_PAM_CHAUTHTOK);
    1908             : }
    1909             : 
    1910           2 : static int pam_cmd_chauthtok_prelim(struct cli_ctx *cctx) {
    1911           2 :     DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_chauthtok_prelim\n");
    1912           2 :     return pam_forwarder(cctx, SSS_PAM_CHAUTHTOK_PRELIM);
    1913             : }
    1914             : 
    1915           9 : static int pam_cmd_preauth(struct cli_ctx *cctx)
    1916             : {
    1917           9 :     DEBUG(SSSDBG_CONF_SETTINGS, "entering pam_cmd_preauth\n");
    1918           9 :     return pam_forwarder(cctx, SSS_PAM_PREAUTH);
    1919             : }
    1920             : 
    1921          38 : struct cli_protocol_version *register_cli_protocol_version(void)
    1922             : {
    1923             :     static struct cli_protocol_version pam_cli_protocol_version[] = {
    1924             :         {3, "2009-09-14", "make cli_pid mandatory"},
    1925             :         {2, "2009-05-12", "new format <type><size><data>"},
    1926             :         {1, "2008-09-05", "initial version, \\0 terminated strings"},
    1927             :         {0, NULL, NULL}
    1928             :     };
    1929             : 
    1930          38 :     return pam_cli_protocol_version;
    1931             : }
    1932             : 
    1933          38 : struct sss_cmd_table *get_pam_cmds(void)
    1934             : {
    1935             :     static struct sss_cmd_table sss_cmds[] = {
    1936             :         {SSS_GET_VERSION, sss_cmd_get_version},
    1937             :         {SSS_PAM_AUTHENTICATE, pam_cmd_authenticate},
    1938             :         {SSS_PAM_SETCRED, pam_cmd_setcred},
    1939             :         {SSS_PAM_ACCT_MGMT, pam_cmd_acct_mgmt},
    1940             :         {SSS_PAM_OPEN_SESSION, pam_cmd_open_session},
    1941             :         {SSS_PAM_CLOSE_SESSION, pam_cmd_close_session},
    1942             :         {SSS_PAM_CHAUTHTOK, pam_cmd_chauthtok},
    1943             :         {SSS_PAM_CHAUTHTOK_PRELIM, pam_cmd_chauthtok_prelim},
    1944             :         {SSS_PAM_PREAUTH, pam_cmd_preauth},
    1945             :         {SSS_CLI_NULL, NULL}
    1946             :     };
    1947             : 
    1948          38 :     return sss_cmds;
    1949             : }
    1950             : 
    1951             : errno_t
    1952           5 : pam_set_last_online_auth_with_curr_token(struct sss_domain_info *domain,
    1953             :                                          const char *username,
    1954             :                                          uint64_t value)
    1955             : {
    1956             :     TALLOC_CTX *tmp_ctx;
    1957             :     struct sysdb_attrs *attrs;
    1958             :     int ret;
    1959             : 
    1960           5 :     tmp_ctx = talloc_new(NULL);
    1961           5 :     if (tmp_ctx == NULL) {
    1962           0 :         ret = ENOMEM;
    1963           0 :         goto done;
    1964             :     }
    1965             : 
    1966           5 :     attrs = sysdb_new_attrs(tmp_ctx);
    1967           5 :     if (attrs == NULL) {
    1968           0 :         ret = ENOMEM;
    1969           0 :         goto done;
    1970             :     }
    1971             : 
    1972           5 :     ret = sysdb_attrs_add_time_t(attrs,
    1973             :                                  SYSDB_LAST_ONLINE_AUTH_WITH_CURR_TOKEN,
    1974             :                                  value);
    1975           5 :     if (ret != EOK) { goto done; }
    1976             : 
    1977           5 :     ret = sysdb_set_user_attr(domain, username, attrs, SYSDB_MOD_REP);
    1978           5 :     if (ret != EOK) { goto done; }
    1979             : 
    1980             : done:
    1981           5 :     if (ret != EOK) {
    1982           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, sss_strerror(ret));
    1983             :     }
    1984             : 
    1985           5 :     talloc_zfree(tmp_ctx);
    1986           5 :     return ret;
    1987             : }
    1988             : 
    1989             : static errno_t
    1990           1 : pam_null_last_online_auth_with_curr_token(struct sss_domain_info *domain,
    1991             :                                           const char *username)
    1992             : {
    1993           1 :     return pam_set_last_online_auth_with_curr_token(domain, username, 0);
    1994             : }
    1995             : 
    1996             : static errno_t
    1997           8 : pam_get_last_online_auth_with_curr_token(struct sss_domain_info *domain,
    1998             :                                          const char *name,
    1999             :                                          uint64_t *_value)
    2000             : {
    2001           8 :     TALLOC_CTX *tmp_ctx = NULL;
    2002           8 :     const char *attrs[] = { SYSDB_LAST_ONLINE_AUTH_WITH_CURR_TOKEN, NULL };
    2003             :     struct ldb_message *ldb_msg;
    2004             :     uint64_t value;
    2005             :     errno_t ret;
    2006             : 
    2007           8 :     if (name == NULL || *name == '\0') {
    2008           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Missing user name.\n");
    2009           0 :         ret = EINVAL;
    2010           0 :         goto done;
    2011             :     }
    2012             : 
    2013           8 :     if (domain->sysdb == NULL) {
    2014           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Missing sysdb db context.\n");
    2015           0 :         ret = EINVAL;
    2016           0 :         goto done;
    2017             :     }
    2018             : 
    2019           8 :     tmp_ctx = talloc_new(NULL);
    2020           8 :     if (tmp_ctx == NULL) {
    2021           0 :         ret = ENOMEM;
    2022           0 :         goto done;
    2023             :     }
    2024             : 
    2025           8 :     ret = sysdb_search_user_by_name(tmp_ctx, domain, name, attrs, &ldb_msg);
    2026           8 :     if (ret != EOK) {
    2027           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    2028             :               "sysdb_search_user_by_name failed [%d][%s].\n",
    2029             :               ret, strerror(ret));
    2030           0 :         goto done;
    2031             :     }
    2032             : 
    2033             :     /* Check offline_auth_cache_timeout */
    2034           8 :     value = ldb_msg_find_attr_as_uint64(ldb_msg,
    2035             :                                         SYSDB_LAST_ONLINE_AUTH_WITH_CURR_TOKEN,
    2036             :                                         0);
    2037           8 :     ret = EOK;
    2038             : 
    2039             : done:
    2040           8 :     if (ret == EOK) {
    2041           8 :         *_value = value;
    2042             :     }
    2043             : 
    2044           8 :     talloc_free(tmp_ctx);
    2045           8 :     return ret;
    2046             : }

Generated by: LCOV version 1.10