LCOV - code coverage report
Current view: top level - sss_client - pam_sss.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 865 0.0 %
Date: 2016-06-29 Functions: 0 30 0.0 %

          Line data    Source code
       1             : /*
       2             :     Authors:
       3             :         Sumit Bose <sbose@redhat.com>
       4             : 
       5             :     Copyright (C) 2009 Red Hat
       6             :     Copyright (C) 2010, rhafer@suse.de, Novell Inc.
       7             : 
       8             :     This program is free software; you can redistribute it and/or modify
       9             :     it under the terms of the GNU Lesser General Public License as published by
      10             :     the Free Software Foundation; either version 3 of the License, or
      11             :     (at your option) any later version.
      12             : 
      13             :     This program is distributed in the hope that it will be useful,
      14             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :     GNU Lesser General Public License for more details.
      17             : 
      18             :     You should have received a copy of the GNU Lesser General Public License
      19             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "config.h"
      23             : #include <sys/types.h>
      24             : #include <unistd.h>
      25             : #include <stdlib.h>
      26             : #include <stdint.h>
      27             : #include <stdio.h>
      28             : #include <syslog.h>
      29             : #include <time.h>
      30             : #include <sys/stat.h>
      31             : #include <fcntl.h>
      32             : #include <errno.h>
      33             : #include <locale.h>
      34             : #include <stdbool.h>
      35             : 
      36             : #include <security/pam_modules.h>
      37             : #include <security/pam_appl.h>
      38             : 
      39             : #include "sss_pam_compat.h"
      40             : #include "sss_pam_macros.h"
      41             : 
      42             : #include "sss_cli.h"
      43             : #include "pam_message.h"
      44             : #include "util/atomic_io.h"
      45             : #include "util/authtok-utils.h"
      46             : 
      47             : #include <libintl.h>
      48             : #define _(STRING) dgettext (PACKAGE, STRING)
      49             : 
      50             : #define FLAGS_USE_FIRST_PASS (1 << 0)
      51             : #define FLAGS_FORWARD_PASS   (1 << 1)
      52             : #define FLAGS_USE_AUTHTOK    (1 << 2)
      53             : #define FLAGS_IGNORE_UNKNOWN_USER (1 << 3)
      54             : #define FLAGS_IGNORE_AUTHINFO_UNAVAIL (1 << 4)
      55             : #define FLAGS_USE_2FA (1 << 5)
      56             : #define FLAGS_ALLOW_MISSING_NAME (1 << 6)
      57             : 
      58             : #define PWEXP_FLAG "pam_sss:password_expired_flag"
      59             : #define FD_DESTRUCTOR "pam_sss:fd_destructor"
      60             : 
      61             : #define PW_RESET_MSG_FILENAME_TEMPLATE SSSD_CONF_DIR"/customize/%s/pam_sss_pw_reset_message.%s"
      62             : #define PW_RESET_MSG_MAX_SIZE 4096
      63             : 
      64             : #define OPT_RETRY_KEY "retry="
      65             : #define OPT_DOMAINS_KEY "domains="
      66             : 
      67             : #define EXP_ACC_MSG _("Permission denied. ")
      68             : #define SRV_MSG     _("Server message: ")
      69             : 
      70             : #define DEBUG_MGS_LEN 1024
      71             : #define MAX_AUTHTOK_SIZE (1024*1024)
      72             : #define CHECK_AND_RETURN_PI_STRING(s) ((s != NULL && *s != '\0')? s : "(not available)")
      73             : 
      74           0 : static void logger(pam_handle_t *pamh, int level, const char *fmt, ...) {
      75             :     va_list ap;
      76             : 
      77           0 :     va_start(ap, fmt);
      78             : 
      79             : #ifdef DEBUG
      80             :     va_list apd;
      81             :     char debug_msg[DEBUG_MGS_LEN];
      82             :     int ret;
      83             :     va_copy(apd, ap);
      84             : 
      85             :     ret = vsnprintf(debug_msg, DEBUG_MGS_LEN, fmt, apd);
      86             :     if (ret >= DEBUG_MGS_LEN) {
      87             :         D(("the following message is truncated: %s", debug_msg));
      88             :     } else if (ret < 0) {
      89             :         D(("vsnprintf failed to format debug message!"));
      90             :     } else {
      91             :         D((debug_msg));
      92             :     }
      93             : 
      94             :     va_end(apd);
      95             : #endif
      96             : 
      97           0 :     pam_vsyslog(pamh, LOG_AUTHPRIV|level, fmt, ap);
      98             : 
      99           0 :     va_end(ap);
     100           0 : }
     101             : 
     102           0 : static void free_exp_data(pam_handle_t *pamh, void *ptr, int err)
     103             : {
     104           0 :     free(ptr);
     105           0 : }
     106             : 
     107           0 : static void close_fd(pam_handle_t *pamh, void *ptr, int err)
     108             : {
     109             : #ifdef PAM_DATA_REPLACE
     110           0 :     if (err & PAM_DATA_REPLACE) {
     111             :         /* Nothing to do */
     112           0 :         return;
     113             :     }
     114             : #endif /* PAM_DATA_REPLACE */
     115             : 
     116             :     D(("Closing the fd"));
     117           0 :     sss_pam_close_fd();
     118             : }
     119             : 
     120           0 : static void overwrite_and_free_authtoks(struct pam_items *pi)
     121             : {
     122           0 :     if (pi->pam_authtok != NULL) {
     123           0 :         _pam_overwrite_n((void *)pi->pam_authtok, pi->pam_authtok_size);
     124           0 :         free((void *)pi->pam_authtok);
     125           0 :         pi->pam_authtok = NULL;
     126             :     }
     127             : 
     128           0 :     if (pi->pam_newauthtok != NULL) {
     129           0 :         _pam_overwrite_n((void *)pi->pam_newauthtok,  pi->pam_newauthtok_size);
     130           0 :         free((void *)pi->pam_newauthtok);
     131           0 :         pi->pam_newauthtok = NULL;
     132             :     }
     133             : 
     134           0 :     if (pi->first_factor != NULL) {
     135           0 :         _pam_overwrite_n((void *)pi->first_factor, strlen(pi->first_factor));
     136           0 :         free((void *)pi->first_factor);
     137           0 :         pi->first_factor = NULL;
     138             :     }
     139             : 
     140           0 :     pi->pamstack_authtok = NULL;
     141           0 :     pi->pamstack_oldauthtok = NULL;
     142           0 : }
     143             : 
     144           0 : static void overwrite_and_free_pam_items(struct pam_items *pi)
     145             : {
     146           0 :     overwrite_and_free_authtoks(pi);
     147             : 
     148           0 :     free(pi->domain_name);
     149           0 :     pi->domain_name = NULL;
     150             : 
     151           0 :     free(pi->otp_vendor);
     152           0 :     pi->otp_vendor = NULL;
     153             : 
     154           0 :     free(pi->otp_token_id);
     155           0 :     pi->otp_token_id = NULL;
     156             : 
     157           0 :     free(pi->otp_challenge);
     158           0 :     pi->otp_challenge = NULL;
     159             : 
     160           0 :     free(pi->cert_user);
     161           0 :     pi->cert_user = NULL;
     162             : 
     163           0 :     free(pi->token_name);
     164           0 :     pi->token_name = NULL;
     165           0 : }
     166             : 
     167           0 : static int null_strcmp(const char *s1, const char *s2) {
     168           0 :     if (s1 == NULL && s2 == NULL) return 0;
     169           0 :     if (s1 == NULL && s2 != NULL) return -1;
     170           0 :     if (s1 != NULL && s2 == NULL) return 1;
     171           0 :     return strcmp(s1, s2);
     172             : }
     173             : 
     174             : enum {
     175             :     SSS_PAM_CONV_DONE = 0,
     176             :     SSS_PAM_CONV_STD,
     177             :     SSS_PAM_CONV_REENTER,
     178             : };
     179             : 
     180           0 : static int do_pam_conversation(pam_handle_t *pamh, const int msg_style,
     181             :                                const char *msg,
     182             :                                const char *reenter_msg,
     183             :                                char **_answer)
     184             : {
     185             :     int ret;
     186           0 :     int state = SSS_PAM_CONV_STD;
     187             :     const struct pam_conv *conv;
     188             :     const struct pam_message *mesg[1];
     189             :     struct pam_message *pam_msg;
     190           0 :     struct pam_response *resp=NULL;
     191           0 :     char *answer = NULL;
     192             : 
     193           0 :     if ((msg_style == PAM_TEXT_INFO || msg_style == PAM_ERROR_MSG) &&
     194           0 :         msg == NULL) return PAM_SYSTEM_ERR;
     195             : 
     196           0 :     if ((msg_style == PAM_PROMPT_ECHO_OFF ||
     197           0 :          msg_style == PAM_PROMPT_ECHO_ON) &&
     198           0 :         (msg == NULL || _answer == NULL)) return PAM_SYSTEM_ERR;
     199             : 
     200           0 :     if (msg_style == PAM_TEXT_INFO || msg_style == PAM_ERROR_MSG) {
     201           0 :         logger(pamh, LOG_INFO, "User %s message: %s",
     202             :                                msg_style == PAM_TEXT_INFO ? "info" : "error",
     203             :                                msg);
     204             :     }
     205             : 
     206           0 :     ret=pam_get_item(pamh, PAM_CONV, (const void **) &conv);
     207           0 :     if (ret != PAM_SUCCESS) return ret;
     208             : 
     209             :     do {
     210           0 :         pam_msg = malloc(sizeof(struct pam_message));
     211           0 :         if (pam_msg == NULL) {
     212             :             D(("Malloc failed."));
     213           0 :             ret = PAM_SYSTEM_ERR;
     214           0 :             goto failed;
     215             :         }
     216             : 
     217           0 :         pam_msg->msg_style = msg_style;
     218           0 :         if (state == SSS_PAM_CONV_REENTER) {
     219           0 :             pam_msg->msg = reenter_msg;
     220             :         } else {
     221           0 :             pam_msg->msg = msg;
     222             :         }
     223             : 
     224           0 :         mesg[0] = (const struct pam_message *) pam_msg;
     225             : 
     226           0 :         ret=conv->conv(1, mesg, &resp,
     227           0 :                        conv->appdata_ptr);
     228           0 :         free(pam_msg);
     229           0 :         if (ret != PAM_SUCCESS) {
     230             :             D(("Conversation failure: %s.",  pam_strerror(pamh,ret)));
     231           0 :             goto failed;
     232             :         }
     233             : 
     234           0 :         if (msg_style == PAM_PROMPT_ECHO_OFF ||
     235             :             msg_style == PAM_PROMPT_ECHO_ON) {
     236           0 :             if (resp == NULL) {
     237             :                 D(("response expected, but resp==NULL"));
     238           0 :                 ret = PAM_SYSTEM_ERR;
     239           0 :                 goto failed;
     240             :             }
     241             : 
     242           0 :             if (state == SSS_PAM_CONV_REENTER) {
     243           0 :                 if (null_strcmp(answer, resp[0].resp) != 0) {
     244           0 :                     logger(pamh, LOG_NOTICE, "Passwords do not match.");
     245           0 :                     _pam_overwrite((void *)resp[0].resp);
     246           0 :                     free(resp[0].resp);
     247           0 :                     if (answer != NULL) {
     248           0 :                         _pam_overwrite((void *) answer);
     249           0 :                         free(answer);
     250           0 :                         answer = NULL;
     251             :                     }
     252           0 :                     ret = do_pam_conversation(pamh, PAM_ERROR_MSG,
     253           0 :                                               _("Passwords do not match"),
     254             :                                               NULL, NULL);
     255           0 :                     if (ret != PAM_SUCCESS) {
     256             :                         D(("do_pam_conversation failed."));
     257           0 :                         ret = PAM_SYSTEM_ERR;
     258           0 :                         goto failed;
     259             :                     }
     260           0 :                     ret = PAM_CRED_ERR;
     261           0 :                     goto failed;
     262             :                 }
     263           0 :                 _pam_overwrite((void *)resp[0].resp);
     264           0 :                 free(resp[0].resp);
     265             :             } else {
     266           0 :                 if (resp[0].resp == NULL) {
     267             :                     D(("Empty password"));
     268           0 :                     answer = NULL;
     269             :                 } else {
     270           0 :                     answer = strndup(resp[0].resp, MAX_AUTHTOK_SIZE);
     271           0 :                     _pam_overwrite((void *)resp[0].resp);
     272           0 :                     free(resp[0].resp);
     273           0 :                     if(answer == NULL) {
     274             :                         D(("strndup failed"));
     275           0 :                         ret = PAM_BUF_ERR;
     276           0 :                         goto failed;
     277             :                     }
     278             :                 }
     279             :             }
     280           0 :             free(resp);
     281           0 :             resp = NULL;
     282             :         }
     283             : 
     284           0 :         if (reenter_msg != NULL && state == SSS_PAM_CONV_STD) {
     285           0 :             state = SSS_PAM_CONV_REENTER;
     286             :         } else {
     287           0 :             state = SSS_PAM_CONV_DONE;
     288             :         }
     289           0 :     } while (state != SSS_PAM_CONV_DONE);
     290             : 
     291           0 :     if (_answer) *_answer = answer;
     292           0 :     return PAM_SUCCESS;
     293             : 
     294             : failed:
     295           0 :     free(answer);
     296           0 :     return ret;
     297             : 
     298             : }
     299             : 
     300           0 : static errno_t display_pw_reset_message(pam_handle_t *pamh,
     301             :                                         const char *domain_name,
     302             :                                         const char *suffix)
     303             : {
     304             :     int ret;
     305             :     struct stat stat_buf;
     306           0 :     char *msg_buf = NULL;
     307           0 :     int fd = -1;
     308             :     size_t size;
     309             :     size_t total_len;
     310           0 :     char *filename = NULL;
     311             : 
     312           0 :     if (strchr(suffix, '/') != NULL || strchr(domain_name, '/') != NULL) {
     313             :         D(("Suffix [%s] or domain name [%s] contain illegal character.", suffix,
     314             :            domain_name));
     315           0 :         return EINVAL;
     316             :     }
     317             : 
     318           0 :     size = sizeof(PW_RESET_MSG_FILENAME_TEMPLATE) + strlen(domain_name) +
     319           0 :            strlen(suffix);
     320           0 :     filename = malloc(size);
     321           0 :     if (filename == NULL) {
     322             :         D(("malloc failed."));
     323           0 :         ret = ENOMEM;
     324           0 :         goto done;
     325             :     }
     326           0 :     ret = snprintf(filename, size, PW_RESET_MSG_FILENAME_TEMPLATE, domain_name,
     327             :                    suffix);
     328           0 :     if (ret < 0 || ret >= size) {
     329             :         D(("snprintf failed."));
     330           0 :         ret = EFAULT;
     331           0 :         goto done;
     332             :     }
     333             : 
     334           0 :     fd = open(filename, O_RDONLY);
     335           0 :     if (fd == -1) {
     336           0 :         ret = errno;
     337             :         D(("open failed [%d][%s].\n", ret, strerror(ret)));
     338           0 :         goto done;
     339             :     }
     340             : 
     341           0 :     ret = fstat(fd, &stat_buf);
     342           0 :     if (ret == -1) {
     343           0 :         ret = errno;
     344             :         D(("fstat failed [%d][%s].", ret, strerror(ret)));
     345           0 :         goto done;
     346             :     }
     347             : 
     348           0 :     if (!S_ISREG(stat_buf.st_mode)) {
     349           0 :         logger(pamh, LOG_ERR,
     350             :                "Password reset message file is not a regular file.");
     351           0 :         ret = EINVAL;
     352           0 :         goto done;
     353             :     }
     354             : 
     355           0 :     if (stat_buf.st_uid != 0 || stat_buf.st_gid != 0 ||
     356           0 :         (stat_buf.st_mode & ~S_IFMT) != 0644) {
     357           0 :         logger(pamh, LOG_ERR,"Permission error, "
     358             :                "file [%s] must be owned by root with permissions 0644.",
     359             :                filename);
     360           0 :         ret = EPERM;
     361           0 :         goto done;
     362             :     }
     363             : 
     364           0 :     if (stat_buf.st_size > PW_RESET_MSG_MAX_SIZE) {
     365           0 :         logger(pamh, LOG_ERR, "Password reset message file is too large.");
     366           0 :         ret = EFBIG;
     367           0 :         goto done;
     368             :     }
     369             : 
     370           0 :     msg_buf = malloc(stat_buf.st_size + 1);
     371           0 :     if (msg_buf == NULL) {
     372             :         D(("malloc failed."));
     373           0 :         ret = ENOMEM;
     374           0 :         goto done;
     375             :     }
     376             : 
     377           0 :     errno = 0;
     378           0 :     total_len = sss_atomic_read_s(fd, msg_buf, stat_buf.st_size);
     379           0 :     if (total_len == -1) {
     380           0 :         ret = errno;
     381             :         D(("read failed [%d][%s].", ret, strerror(ret)));
     382           0 :         goto done;
     383             :     }
     384             : 
     385           0 :     ret = close(fd);
     386           0 :     fd = -1;
     387           0 :     if (ret == -1) {
     388           0 :         ret = errno;
     389             :         D(("close failed [%d][%s].", ret, strerror(ret)));
     390             :     }
     391             : 
     392           0 :     if (total_len != stat_buf.st_size) {
     393             :         D(("read fewer bytes [%d] than expected [%d].", total_len,
     394             :            stat_buf.st_size));
     395           0 :         ret = EIO;
     396           0 :         goto done;
     397             :     }
     398             : 
     399           0 :     msg_buf[stat_buf.st_size] = '\0';
     400             : 
     401           0 :     ret = do_pam_conversation(pamh, PAM_TEXT_INFO, msg_buf, NULL, NULL);
     402             :     if (ret != PAM_SUCCESS) {
     403             :         D(("do_pam_conversation failed."));
     404             :     }
     405             : 
     406             : done:
     407           0 :     if (fd != -1) {
     408           0 :         close(fd);
     409             :     }
     410           0 :     free(msg_buf);
     411           0 :     free(filename);
     412             : 
     413           0 :     return ret;
     414             : }
     415             : 
     416           0 : static errno_t select_pw_reset_message(pam_handle_t *pamh, struct pam_items *pi)
     417             : {
     418             :     int ret;
     419             :     char *locale;
     420             :     const char *domain_name;
     421             : 
     422           0 :     domain_name = pi->domain_name;
     423           0 :     if (domain_name == NULL || *domain_name == '\0') {
     424             :         D(("Domain name is unknown."));
     425           0 :         return EINVAL;
     426             :     }
     427             : 
     428           0 :     locale = setlocale(LC_MESSAGES, NULL);
     429             : 
     430           0 :     ret = -1;
     431           0 :     if (locale != NULL) {
     432           0 :         ret = display_pw_reset_message(pamh, domain_name, locale);
     433             :     }
     434             : 
     435           0 :     if (ret != 0) {
     436           0 :         ret = display_pw_reset_message(pamh, domain_name, "txt");
     437             :     }
     438             : 
     439           0 :     if (ret != 0) {
     440           0 :         ret = do_pam_conversation(pamh, PAM_TEXT_INFO,
     441           0 :                       _("Password reset by root is not supported."),
     442             :                       NULL, NULL);
     443             :         if (ret != PAM_SUCCESS) {
     444             :             D(("do_pam_conversation failed."));
     445             :         }
     446             :     }
     447             : 
     448           0 :     return ret;
     449             : }
     450             : 
     451           0 : static int user_info_offline_auth(pam_handle_t *pamh, size_t buflen,
     452             :                                   uint8_t *buf)
     453             : {
     454             :     int ret;
     455             :     int64_t expire_date;
     456             :     struct tm tm;
     457             :     char expire_str[128];
     458             :     char user_msg[256];
     459             : 
     460           0 :     expire_str[0] = '\0';
     461             : 
     462           0 :     if (buflen != sizeof(uint32_t) + sizeof(int64_t)) {
     463             :         D(("User info response data has the wrong size"));
     464           0 :         return PAM_BUF_ERR;
     465             :     }
     466             : 
     467           0 :     memcpy(&expire_date, buf + sizeof(uint32_t), sizeof(int64_t));
     468             : 
     469           0 :     if (expire_date > 0) {
     470           0 :         if (localtime_r((time_t *) &expire_date, &tm) != NULL) {
     471           0 :             ret = strftime(expire_str, sizeof(expire_str), "%c", &tm);
     472           0 :             if (ret == 0) {
     473             :                 D(("strftime failed."));
     474           0 :                 expire_str[0] = '\0';
     475             :             }
     476             :         } else {
     477             :             D(("localtime_r failed"));
     478             :         }
     479             :     }
     480             : 
     481           0 :     ret = snprintf(user_msg, sizeof(user_msg), "%s%s%s.",
     482             :                _("Authenticated with cached credentials"),
     483           0 :               expire_str[0] ? _(", your cached password will expire at: ") : "",
     484           0 :               expire_str[0] ? expire_str : "");
     485           0 :     if (ret < 0 || ret >= sizeof(user_msg)) {
     486             :         D(("snprintf failed."));
     487           0 :         return PAM_SYSTEM_ERR;
     488             :     }
     489             : 
     490           0 :     ret = do_pam_conversation(pamh, PAM_TEXT_INFO, user_msg, NULL, NULL);
     491           0 :     if (ret != PAM_SUCCESS) {
     492             :         D(("do_pam_conversation failed."));
     493           0 :         return PAM_SYSTEM_ERR;
     494             :     }
     495             : 
     496           0 :     return PAM_SUCCESS;
     497             : }
     498             : 
     499           0 : static int user_info_grace_login(pam_handle_t *pamh,
     500             :                                  size_t buflen,
     501             :                                  uint8_t *buf)
     502             : {
     503             :     int ret;
     504             :     uint32_t grace;
     505             :     char user_msg[256];
     506             : 
     507           0 :     if (buflen != 2* sizeof(uint32_t)) {
     508             :         D(("User info response data has the wrong size"));
     509           0 :         return PAM_BUF_ERR;
     510             :     }
     511           0 :     memcpy(&grace, buf + sizeof(uint32_t), sizeof(uint32_t));
     512           0 :     ret = snprintf(user_msg, sizeof(user_msg),
     513           0 :                    _("Your password has expired. "
     514             :                      "You have %1$d grace login(s) remaining."),
     515             :                    grace);
     516           0 :     if (ret < 0 || ret >= sizeof(user_msg)) {
     517             :         D(("snprintf failed."));
     518           0 :         return PAM_SYSTEM_ERR;
     519             :     }
     520           0 :     ret = do_pam_conversation(pamh, PAM_TEXT_INFO, user_msg, NULL, NULL);
     521             : 
     522           0 :     if (ret != PAM_SUCCESS) {
     523             :         D(("do_pam_conversation failed."));
     524           0 :         return PAM_SYSTEM_ERR;
     525             :     }
     526             : 
     527           0 :     return PAM_SUCCESS;
     528             : }
     529             : 
     530             : #define MINSEC 60
     531             : #define HOURSEC (60*MINSEC)
     532             : #define DAYSEC (24*HOURSEC)
     533           0 : static int user_info_expire_warn(pam_handle_t *pamh,
     534             :                                  size_t buflen,
     535             :                                  uint8_t *buf)
     536             : {
     537             :     int ret;
     538             :     uint32_t expire;
     539             :     char user_msg[256];
     540           0 :     const char* unit="second(s)";
     541             : 
     542           0 :     if (buflen != 2* sizeof(uint32_t)) {
     543             :         D(("User info response data has the wrong size"));
     544           0 :         return PAM_BUF_ERR;
     545             :     }
     546           0 :     memcpy(&expire, buf + sizeof(uint32_t), sizeof(uint32_t));
     547           0 :     if (expire >= DAYSEC) {
     548           0 :         expire /= DAYSEC;
     549           0 :         unit = "day(s)";
     550           0 :     } else if (expire >= HOURSEC) {
     551           0 :         expire /= HOURSEC;
     552           0 :         unit = "hour(s)";
     553           0 :     } else if (expire >= MINSEC) {
     554           0 :         expire /= MINSEC;
     555           0 :         unit = "minute(s)";
     556             :     }
     557             : 
     558           0 :     ret = snprintf(user_msg, sizeof(user_msg),
     559           0 :                    _("Your password will expire in %1$d %2$s."), expire, unit);
     560           0 :     if (ret < 0 || ret >= sizeof(user_msg)) {
     561             :         D(("snprintf failed."));
     562           0 :         return PAM_SYSTEM_ERR;
     563             :     }
     564           0 :     ret = do_pam_conversation(pamh, PAM_TEXT_INFO, user_msg, NULL, NULL);
     565             : 
     566           0 :     if (ret != PAM_SUCCESS) {
     567             :         D(("do_pam_conversation failed."));
     568           0 :         return PAM_SYSTEM_ERR;
     569             :     }
     570             : 
     571           0 :     return PAM_SUCCESS;
     572             : }
     573             : 
     574           0 : static int user_info_offline_auth_delayed(pam_handle_t *pamh, size_t buflen,
     575             :                                   uint8_t *buf)
     576             : {
     577             :     int ret;
     578             :     int64_t delayed_until;
     579             :     struct tm tm;
     580             :     char delay_str[128];
     581             :     char user_msg[256];
     582             : 
     583           0 :     delay_str[0] = '\0';
     584             : 
     585           0 :     if (buflen != sizeof(uint32_t) + sizeof(int64_t)) {
     586             :         D(("User info response data has the wrong size"));
     587           0 :         return PAM_BUF_ERR;
     588             :     }
     589             : 
     590           0 :     memcpy(&delayed_until, buf + sizeof(uint32_t), sizeof(int64_t));
     591             : 
     592           0 :     if (delayed_until <= 0) {
     593             :         D(("User info response data has an invalid value"));
     594           0 :         return PAM_BUF_ERR;
     595             :     }
     596             : 
     597           0 :     if (localtime_r((time_t *) &delayed_until, &tm) != NULL) {
     598           0 :         ret = strftime(delay_str, sizeof(delay_str), "%c", &tm);
     599           0 :         if (ret == 0) {
     600             :             D(("strftime failed."));
     601           0 :             delay_str[0] = '\0';
     602             :         }
     603             :     } else {
     604             :         D(("localtime_r failed"));
     605             :     }
     606             : 
     607           0 :     ret = snprintf(user_msg, sizeof(user_msg), "%s%s.",
     608             :                    _("Authentication is denied until: "),
     609             :                    delay_str);
     610           0 :     if (ret < 0 || ret >= sizeof(user_msg)) {
     611             :         D(("snprintf failed."));
     612           0 :         return PAM_SYSTEM_ERR;
     613             :     }
     614             : 
     615           0 :     ret = do_pam_conversation(pamh, PAM_TEXT_INFO, user_msg, NULL, NULL);
     616           0 :     if (ret != PAM_SUCCESS) {
     617             :         D(("do_pam_conversation failed."));
     618           0 :         return PAM_SYSTEM_ERR;
     619             :     }
     620             : 
     621           0 :     return PAM_SUCCESS;
     622             : }
     623             : 
     624           0 : static int user_info_offline_chpass(pam_handle_t *pamh)
     625             : {
     626             :     int ret;
     627             : 
     628           0 :     ret = do_pam_conversation(pamh, PAM_TEXT_INFO,
     629           0 :                               _("System is offline, password change not possible"),
     630             :                               NULL, NULL);
     631           0 :     if (ret != PAM_SUCCESS) {
     632             :         D(("do_pam_conversation failed."));
     633           0 :         return PAM_SYSTEM_ERR;
     634             :     }
     635             : 
     636           0 :     return PAM_SUCCESS;
     637             : }
     638             : 
     639           0 : static int user_info_otp_chpass(pam_handle_t *pamh)
     640             : {
     641             :     int ret;
     642             : 
     643           0 :     ret = do_pam_conversation(pamh, PAM_TEXT_INFO,
     644           0 :                               _("After changing the OTP password, you need to "
     645             :                                 "log out and back in order to acquire a ticket"),
     646             :                               NULL, NULL);
     647           0 :     if (ret != PAM_SUCCESS) {
     648             :         D(("do_pam_conversation failed."));
     649           0 :         return PAM_SYSTEM_ERR;
     650             :     }
     651             : 
     652           0 :     return PAM_SUCCESS;
     653             : }
     654             : 
     655           0 : static int user_info_account_expired(pam_handle_t *pamh, size_t buflen,
     656             :                                      uint8_t *buf)
     657             : {
     658             :     int ret;
     659             :     uint32_t msg_len;
     660             :     char *user_msg;
     661           0 :     size_t bufsize = 0;
     662             : 
     663             :     /* resp_type and length of message are expected to be in buf */
     664           0 :     if (buflen < 2* sizeof(uint32_t)) {
     665             :         D(("User info response data is too short"));
     666           0 :         return PAM_BUF_ERR;
     667             :     }
     668             : 
     669             :     /* msg_len = legth of message */
     670           0 :     memcpy(&msg_len, buf + sizeof(uint32_t), sizeof(uint32_t));
     671             : 
     672           0 :     if (buflen != 2* sizeof(uint32_t) + msg_len) {
     673             :         D(("User info response data has the wrong size"));
     674           0 :         return PAM_BUF_ERR;
     675             :     }
     676             : 
     677           0 :     bufsize = strlen(EXP_ACC_MSG) + 1;
     678             : 
     679           0 :     if (msg_len > 0) {
     680           0 :         bufsize += strlen(SRV_MSG) + msg_len;
     681             :     }
     682             : 
     683           0 :     user_msg = (char *)malloc(sizeof(char) * bufsize);
     684           0 :     if (!user_msg) {
     685             :        D(("Out of memory."));
     686           0 :        return PAM_SYSTEM_ERR;
     687             :     }
     688             : 
     689           0 :     ret = snprintf(user_msg, bufsize, "%s%s%.*s",
     690             :                    EXP_ACC_MSG,
     691           0 :                    msg_len > 0 ? SRV_MSG : "",
     692             :                    msg_len,
     693           0 :                    msg_len > 0 ? (char *)(buf + 2 * sizeof(uint32_t)) : "" );
     694           0 :     if (ret < 0 || ret > bufsize) {
     695             :         D(("snprintf failed."));
     696             : 
     697           0 :         free(user_msg);
     698           0 :         return PAM_SYSTEM_ERR;
     699             :     }
     700             : 
     701           0 :     ret = do_pam_conversation(pamh, PAM_TEXT_INFO, user_msg, NULL, NULL);
     702           0 :     free(user_msg);
     703           0 :     if (ret != PAM_SUCCESS) {
     704             :         D(("do_pam_conversation failed."));
     705             : 
     706           0 :         return PAM_SYSTEM_ERR;
     707             :     }
     708             : 
     709           0 :     return PAM_SUCCESS;
     710             : }
     711             : 
     712           0 : static int user_info_chpass_error(pam_handle_t *pamh, size_t buflen,
     713             :                                   uint8_t *buf)
     714             : {
     715             :     int ret;
     716             :     uint32_t msg_len;
     717             :     char *user_msg;
     718           0 :     size_t bufsize = 0;
     719             : 
     720           0 :     if (buflen < 2* sizeof(uint32_t)) {
     721             :         D(("User info response data is too short"));
     722           0 :         return PAM_BUF_ERR;
     723             :     }
     724             : 
     725           0 :     memcpy(&msg_len, buf + sizeof(uint32_t), sizeof(uint32_t));
     726             : 
     727           0 :     if (buflen != 2* sizeof(uint32_t) + msg_len) {
     728             :         D(("User info response data has the wrong size"));
     729           0 :         return PAM_BUF_ERR;
     730             :     }
     731             : 
     732           0 :     bufsize = strlen(_("Password change failed. ")) + 1;
     733             : 
     734           0 :     if (msg_len > 0) {
     735           0 :         bufsize += strlen(_("Server message: ")) + msg_len;
     736             :     }
     737             : 
     738           0 :     user_msg = (char *)malloc(sizeof(char) * bufsize);
     739           0 :     if (!user_msg) {
     740             :        D(("Out of memory."));
     741           0 :        return PAM_SYSTEM_ERR;
     742             :     }
     743             : 
     744           0 :     ret = snprintf(user_msg, bufsize, "%s%s%.*s",
     745             :                    _("Password change failed. "),
     746           0 :                    msg_len > 0 ? _("Server message: ") : "",
     747             :                    msg_len,
     748           0 :                    msg_len > 0 ? (char *)(buf + 2 * sizeof(uint32_t)) : "" );
     749           0 :     if (ret < 0 || ret > bufsize) {
     750             :         D(("snprintf failed."));
     751             : 
     752           0 :         free(user_msg);
     753           0 :         return PAM_SYSTEM_ERR;
     754             :     }
     755             : 
     756           0 :     ret = do_pam_conversation(pamh, PAM_TEXT_INFO, user_msg, NULL, NULL);
     757           0 :     free(user_msg);
     758           0 :     if (ret != PAM_SUCCESS) {
     759             :         D(("do_pam_conversation failed."));
     760             : 
     761           0 :         return PAM_SYSTEM_ERR;
     762             :     }
     763             : 
     764           0 :     return PAM_SUCCESS;
     765             : }
     766             : 
     767           0 : static int eval_user_info_response(pam_handle_t *pamh, size_t buflen,
     768             :                                    uint8_t *buf)
     769             : {
     770             :     int ret;
     771             :     uint32_t type;
     772             : 
     773           0 :     if (buflen < sizeof(uint32_t)) {
     774             :         D(("User info response data is too short"));
     775           0 :         return PAM_BUF_ERR;
     776             :     }
     777             : 
     778           0 :     memcpy(&type, buf, sizeof(uint32_t));
     779             : 
     780           0 :     switch(type) {
     781             :         case SSS_PAM_USER_INFO_OFFLINE_AUTH:
     782           0 :             ret = user_info_offline_auth(pamh, buflen, buf);
     783           0 :             break;
     784             :         case SSS_PAM_USER_INFO_GRACE_LOGIN:
     785           0 :             ret = user_info_grace_login(pamh, buflen, buf);
     786           0 :             break;
     787             :         case SSS_PAM_USER_INFO_EXPIRE_WARN:
     788           0 :             ret = user_info_expire_warn(pamh, buflen, buf);
     789           0 :             break;
     790             :         case SSS_PAM_USER_INFO_OFFLINE_AUTH_DELAYED:
     791           0 :             ret = user_info_offline_auth_delayed(pamh, buflen, buf);
     792           0 :             break;
     793             :         case SSS_PAM_USER_INFO_OFFLINE_CHPASS:
     794           0 :             ret = user_info_offline_chpass(pamh);
     795           0 :             break;
     796             :         case SSS_PAM_USER_INFO_OTP_CHPASS:
     797           0 :             ret = user_info_otp_chpass(pamh);
     798           0 :             break;
     799             :         case SSS_PAM_USER_INFO_CHPASS_ERROR:
     800           0 :             ret = user_info_chpass_error(pamh, buflen, buf);
     801           0 :             break;
     802             :         case SSS_PAM_USER_INFO_ACCOUNT_EXPIRED:
     803           0 :             ret = user_info_account_expired(pamh, buflen, buf);
     804           0 :             break;
     805             :         default:
     806             :             D(("Unknown user info type [%d]", type));
     807           0 :             ret = PAM_SYSTEM_ERR;
     808             :     }
     809             : 
     810           0 :     return ret;
     811             : }
     812             : 
     813           0 : static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf,
     814             :                          struct pam_items *pi)
     815             : {
     816             :     int ret;
     817           0 :     size_t p=0;
     818             :     char *env_item;
     819             :     int32_t c;
     820             :     int32_t type;
     821             :     int32_t len;
     822             :     int32_t pam_status;
     823             :     size_t offset;
     824             : 
     825           0 :     if (buflen < (2*sizeof(int32_t))) {
     826             :         D(("response buffer is too small"));
     827           0 :         return PAM_BUF_ERR;
     828             :     }
     829             : 
     830           0 :     memcpy(&pam_status, buf+p, sizeof(int32_t));
     831           0 :     p += sizeof(int32_t);
     832             : 
     833             : 
     834           0 :     memcpy(&c, buf+p, sizeof(int32_t));
     835           0 :     p += sizeof(int32_t);
     836             : 
     837           0 :     while(c>0) {
     838           0 :         if (buflen < (p+2*sizeof(int32_t))) {
     839             :             D(("response buffer is too small"));
     840           0 :             return PAM_BUF_ERR;
     841             :         }
     842             : 
     843           0 :         memcpy(&type, buf+p, sizeof(int32_t));
     844           0 :         p += sizeof(int32_t);
     845             : 
     846           0 :         memcpy(&len, buf+p, sizeof(int32_t));
     847           0 :         p += sizeof(int32_t);
     848             : 
     849           0 :         if (buflen < (p + len)) {
     850             :             D(("response buffer is too small"));
     851           0 :             return PAM_BUF_ERR;
     852             :         }
     853             : 
     854           0 :         switch(type) {
     855             :             case SSS_PAM_SYSTEM_INFO:
     856           0 :                 if (buf[p + (len -1)] != '\0') {
     857             :                     D(("system info does not end with \\0."));
     858           0 :                     break;
     859             :                 }
     860           0 :                 logger(pamh, LOG_INFO, "system info: [%s]", &buf[p]);
     861           0 :                 break;
     862             :             case SSS_PAM_DOMAIN_NAME:
     863           0 :                 if (buf[p + (len -1)] != '\0') {
     864             :                     D(("domain name does not end with \\0."));
     865           0 :                     break;
     866             :                 }
     867             :                 D(("domain name: [%s]", &buf[p]));
     868           0 :                 pi->domain_name = strdup((char *) &buf[p]);
     869           0 :                 if (pi->domain_name == NULL) {
     870             :                     D(("strdup failed"));
     871             :                 }
     872           0 :                 break;
     873             :             case SSS_ENV_ITEM:
     874             :             case SSS_PAM_ENV_ITEM:
     875             :             case SSS_ALL_ENV_ITEM:
     876           0 :                 if (buf[p + (len -1)] != '\0') {
     877             :                     D(("env item does not end with \\0."));
     878           0 :                     break;
     879             :                 }
     880             : 
     881             :                 D(("env item: [%s]", &buf[p]));
     882           0 :                 if (type == SSS_PAM_ENV_ITEM || type == SSS_ALL_ENV_ITEM) {
     883           0 :                     ret = pam_putenv(pamh, (char *)&buf[p]);
     884           0 :                     if (ret != PAM_SUCCESS) {
     885             :                         D(("pam_putenv failed."));
     886           0 :                         break;
     887             :                     }
     888             :                 }
     889             : 
     890           0 :                 if (type == SSS_ENV_ITEM || type == SSS_ALL_ENV_ITEM) {
     891           0 :                     env_item = strdup((char *)&buf[p]);
     892           0 :                     if (env_item == NULL) {
     893             :                         D(("strdup failed"));
     894           0 :                         break;
     895             :                     }
     896           0 :                     ret = putenv(env_item);
     897           0 :                     if (ret == -1) {
     898             :                         D(("putenv failed."));
     899           0 :                         break;
     900             :                     }
     901             :                 }
     902           0 :                 break;
     903             :             case SSS_PAM_USER_INFO:
     904           0 :                 ret = eval_user_info_response(pamh, len, &buf[p]);
     905             :                 if (ret != PAM_SUCCESS) {
     906             :                     D(("eval_user_info_response failed"));
     907             :                 }
     908           0 :                 break;
     909             :             case SSS_PAM_TEXT_MSG:
     910           0 :                 if (buf[p + (len -1)] != '\0') {
     911             :                     D(("system info does not end with \\0."));
     912           0 :                     break;
     913             :                 }
     914             : 
     915           0 :                 ret = do_pam_conversation(pamh, PAM_TEXT_INFO, (char *) &buf[p],
     916             :                                           NULL, NULL);
     917             :                 if (ret != PAM_SUCCESS) {
     918             :                     D(("do_pam_conversation failed."));
     919             :                 }
     920           0 :                 break;
     921             :             case SSS_OTP:
     922             :                 D(("OTP was used, removing authtokens."));
     923           0 :                 overwrite_and_free_authtoks(pi);
     924           0 :                 ret = pam_set_item(pamh, PAM_AUTHTOK, NULL);
     925             :                 if (ret != PAM_SUCCESS) {
     926             :                     D(("Failed to remove PAM_AUTHTOK after using otp [%s]",
     927             :                        pam_strerror(pamh,ret)));
     928             :                 }
     929           0 :                 break;
     930             :             case SSS_PAM_OTP_INFO:
     931           0 :                 if (buf[p + (len - 1)] != '\0') {
     932             :                     D(("otp info does not end with \\0."));
     933           0 :                     break;
     934             :                 }
     935             : 
     936           0 :                 pi->otp_vendor = strdup((char *) &buf[p]);
     937           0 :                 if (pi->otp_vendor == NULL) {
     938             :                     D(("strdup failed"));
     939           0 :                     break;
     940             :                 }
     941             : 
     942           0 :                 offset = strlen(pi->otp_vendor) + 1;
     943           0 :                 if (offset >= len) {
     944             :                     D(("OTP message size mismatch"));
     945           0 :                     free(pi->otp_vendor);
     946           0 :                     pi->otp_vendor = NULL;
     947           0 :                     break;
     948             :                 }
     949           0 :                 pi->otp_token_id = strdup((char *) &buf[p + offset]);
     950           0 :                 if (pi->otp_token_id == NULL) {
     951             :                     D(("strdup failed"));
     952           0 :                     break;
     953             :                 }
     954             : 
     955           0 :                 offset += strlen(pi->otp_token_id) + 1;
     956           0 :                 if (offset >= len) {
     957             :                     D(("OTP message size mismatch"));
     958           0 :                     free(pi->otp_token_id);
     959           0 :                     pi->otp_token_id = NULL;
     960           0 :                     break;
     961             :                 }
     962           0 :                 pi->otp_challenge = strdup((char *) &buf[p + offset]);
     963           0 :                 if (pi->otp_challenge == NULL) {
     964             :                     D(("strdup failed"));
     965           0 :                     break;
     966             :                 }
     967             : 
     968           0 :                 break;
     969             :             case SSS_PAM_CERT_INFO:
     970           0 :                 if (buf[p + (len - 1)] != '\0') {
     971             :                     D(("cert info does not end with \\0."));
     972           0 :                     break;
     973             :                 }
     974             : 
     975           0 :                 pi->cert_user = strdup((char *) &buf[p]);
     976           0 :                 if (pi->cert_user == NULL) {
     977             :                     D(("strdup failed"));
     978           0 :                     break;
     979             :                 }
     980             : 
     981           0 :                 if (pi->pam_user == NULL || *(pi->pam_user) == '\0') {
     982           0 :                     ret = pam_set_item(pamh, PAM_USER, pi->cert_user);
     983           0 :                     if (ret != PAM_SUCCESS) {
     984             :                         D(("Failed to set PAM_USER during "
     985             :                            "Smartcard authentication [%s]",
     986             :                            pam_strerror(pamh, ret)));
     987           0 :                         break;
     988             :                     }
     989             : 
     990           0 :                     ret = pam_get_item(pamh, PAM_USER,
     991           0 :                                        (const void **)&(pi->pam_user));
     992           0 :                     if (ret != PAM_SUCCESS) {
     993             :                         D(("Failed to get PAM_USER during "
     994             :                            "Smartcard authentication [%s]",
     995             :                            pam_strerror(pamh, ret)));
     996           0 :                         break;
     997             :                     }
     998             : 
     999           0 :                     pi->pam_user_size = strlen(pi->pam_user) + 1;
    1000             :                 }
    1001             : 
    1002           0 :                 offset = strlen(pi->cert_user) + 1;
    1003           0 :                 if (offset >= len) {
    1004             :                     D(("Cert message size mismatch"));
    1005           0 :                     free(pi->cert_user);
    1006           0 :                     pi->cert_user = NULL;
    1007           0 :                     break;
    1008             :                 }
    1009           0 :                 pi->token_name = strdup((char *) &buf[p + offset]);
    1010           0 :                 if (pi->token_name == NULL) {
    1011             :                     D(("strdup failed"));
    1012           0 :                     break;
    1013             :                 }
    1014             :                 D(("cert user: [%s] token name: [%s]", pi->cert_user,
    1015             :                                                        pi->token_name));
    1016           0 :                 break;
    1017             :             default:
    1018             :                 D(("Unknown response type [%d]", type));
    1019             :         }
    1020           0 :         p += len;
    1021             : 
    1022           0 :         --c;
    1023             :     }
    1024             : 
    1025           0 :     return PAM_SUCCESS;
    1026             : }
    1027             : 
    1028           0 : static int get_pam_items(pam_handle_t *pamh, uint32_t flags,
    1029             :                          struct pam_items *pi)
    1030             : {
    1031             :     int ret;
    1032             : 
    1033           0 :     pi->pam_authtok_type = SSS_AUTHTOK_TYPE_EMPTY;
    1034           0 :     pi->pam_authtok = NULL;
    1035           0 :     pi->pam_authtok_size = 0;
    1036           0 :     pi->pam_newauthtok_type = SSS_AUTHTOK_TYPE_EMPTY;
    1037           0 :     pi->pam_newauthtok = NULL;
    1038           0 :     pi->pam_newauthtok_size = 0;
    1039           0 :     pi->first_factor = NULL;
    1040             : 
    1041           0 :     ret = pam_get_item(pamh, PAM_SERVICE, (const void **) &(pi->pam_service));
    1042           0 :     if (ret != PAM_SUCCESS) return ret;
    1043           0 :     if (pi->pam_service == NULL) pi->pam_service="";
    1044           0 :     pi->pam_service_size=strlen(pi->pam_service)+1;
    1045             : 
    1046           0 :     ret = pam_get_item(pamh, PAM_USER, (const void **) &(pi->pam_user));
    1047           0 :     if (ret == PAM_PERM_DENIED && (flags & FLAGS_ALLOW_MISSING_NAME)) {
    1048           0 :         pi->pam_user = "";
    1049           0 :         ret = PAM_SUCCESS;
    1050             :     }
    1051           0 :     if (ret != PAM_SUCCESS) return ret;
    1052           0 :     if (pi->pam_user == NULL) {
    1053           0 :         if (flags & FLAGS_ALLOW_MISSING_NAME) {
    1054           0 :             pi->pam_user = "";
    1055             :         } else {
    1056             :             D(("No user found, aborting."));
    1057           0 :             return PAM_BAD_ITEM;
    1058             :         }
    1059             :     }
    1060           0 :     if (strcmp(pi->pam_user, "root") == 0) {
    1061             :         D(("pam_sss will not handle root."));
    1062           0 :         return PAM_USER_UNKNOWN;
    1063             :     }
    1064           0 :     pi->pam_user_size=strlen(pi->pam_user)+1;
    1065             : 
    1066             : 
    1067           0 :     ret = pam_get_item(pamh, PAM_TTY, (const void **) &(pi->pam_tty));
    1068           0 :     if (ret != PAM_SUCCESS) return ret;
    1069           0 :     if (pi->pam_tty == NULL) pi->pam_tty="";
    1070           0 :     pi->pam_tty_size=strlen(pi->pam_tty)+1;
    1071             : 
    1072           0 :     ret = pam_get_item(pamh, PAM_RUSER, (const void **) &(pi->pam_ruser));
    1073           0 :     if (ret != PAM_SUCCESS) return ret;
    1074           0 :     if (pi->pam_ruser == NULL) pi->pam_ruser="";
    1075           0 :     pi->pam_ruser_size=strlen(pi->pam_ruser)+1;
    1076             : 
    1077           0 :     ret = pam_get_item(pamh, PAM_RHOST, (const void **) &(pi->pam_rhost));
    1078           0 :     if (ret != PAM_SUCCESS) return ret;
    1079           0 :     if (pi->pam_rhost == NULL) pi->pam_rhost="";
    1080           0 :     pi->pam_rhost_size=strlen(pi->pam_rhost)+1;
    1081             : 
    1082           0 :     ret = pam_get_item(pamh, PAM_AUTHTOK,
    1083           0 :                        (const void **) &(pi->pamstack_authtok));
    1084           0 :     if (ret != PAM_SUCCESS) return ret;
    1085           0 :     if (pi->pamstack_authtok == NULL) pi->pamstack_authtok="";
    1086             : 
    1087           0 :     ret = pam_get_item(pamh, PAM_OLDAUTHTOK,
    1088           0 :                        (const void **) &(pi->pamstack_oldauthtok));
    1089           0 :     if (ret != PAM_SUCCESS) return ret;
    1090           0 :     if (pi->pamstack_oldauthtok == NULL) pi->pamstack_oldauthtok="";
    1091             : 
    1092           0 :     pi->cli_pid = getpid();
    1093             : 
    1094           0 :     pi->login_name = pam_modutil_getlogin(pamh);
    1095           0 :     if (pi->login_name == NULL) pi->login_name="";
    1096             : 
    1097           0 :     pi->domain_name = NULL;
    1098             : 
    1099           0 :     if (pi->requested_domains == NULL) pi->requested_domains = "";
    1100           0 :     pi->requested_domains_size = strlen(pi->requested_domains) + 1;
    1101             : 
    1102           0 :     pi->otp_vendor = NULL;
    1103           0 :     pi->otp_token_id = NULL;
    1104           0 :     pi->otp_challenge = NULL;
    1105             : 
    1106           0 :     pi->cert_user = NULL;
    1107           0 :     pi->token_name = NULL;
    1108             : 
    1109           0 :     return PAM_SUCCESS;
    1110             : }
    1111             : 
    1112           0 : static void print_pam_items(struct pam_items *pi)
    1113             : {
    1114           0 :     if (pi == NULL) return;
    1115             : 
    1116             :     D(("Service: %s", CHECK_AND_RETURN_PI_STRING(pi->pam_service)));
    1117             :     D(("User: %s", CHECK_AND_RETURN_PI_STRING(pi->pam_user)));
    1118             :     D(("Tty: %s", CHECK_AND_RETURN_PI_STRING(pi->pam_tty)));
    1119             :     D(("Ruser: %s", CHECK_AND_RETURN_PI_STRING(pi->pam_ruser)));
    1120             :     D(("Rhost: %s", CHECK_AND_RETURN_PI_STRING(pi->pam_rhost)));
    1121             :     D(("Pamstack_Authtok: %s",
    1122             :             CHECK_AND_RETURN_PI_STRING(pi->pamstack_authtok)));
    1123             :     D(("Pamstack_Oldauthtok: %s",
    1124             :             CHECK_AND_RETURN_PI_STRING(pi->pamstack_oldauthtok)));
    1125             :     D(("Authtok: %s", CHECK_AND_RETURN_PI_STRING(pi->pam_authtok)));
    1126             :     D(("Newauthtok: %s", CHECK_AND_RETURN_PI_STRING(pi->pam_newauthtok)));
    1127             :     D(("Cli_PID: %d", pi->cli_pid));
    1128             :     D(("Requested domains: %s", pi->requested_domains));
    1129             : }
    1130             : 
    1131           0 : static int send_and_receive(pam_handle_t *pamh, struct pam_items *pi,
    1132             :                             enum sss_cli_command task, bool quiet_mode)
    1133             : {
    1134             :     int ret;
    1135             :     int sret;
    1136             :     int errnop;
    1137             :     struct sss_cli_req_data rd;
    1138           0 :     uint8_t *buf = NULL;
    1139           0 :     uint8_t *repbuf = NULL;
    1140             :     size_t replen;
    1141           0 :     int pam_status = PAM_SYSTEM_ERR;
    1142             : 
    1143           0 :     print_pam_items(pi);
    1144             : 
    1145           0 :     ret = pack_message_v3(pi, &rd.len, &buf);
    1146           0 :     if (ret != 0) {
    1147             :         D(("pack_message failed."));
    1148           0 :         pam_status = PAM_SYSTEM_ERR;
    1149           0 :         goto done;
    1150             :     }
    1151           0 :     rd.data = buf;
    1152             : 
    1153           0 :     errnop = 0;
    1154           0 :     ret = sss_pam_make_request(task, &rd, &repbuf, &replen, &errnop);
    1155             : 
    1156           0 :     sret = pam_set_data(pamh, FD_DESTRUCTOR, NULL, close_fd);
    1157             :     if (sret != PAM_SUCCESS) {
    1158             :         D(("pam_set_data failed, client might leaks fds"));
    1159             :     }
    1160             : 
    1161           0 :     if (ret != PAM_SUCCESS) {
    1162           0 :         if (errnop != 0) {
    1163           0 :             logger(pamh, LOG_ERR, "Request to sssd failed. %s", ssscli_err2string(errnop));
    1164             :         }
    1165           0 :         pam_status = PAM_AUTHINFO_UNAVAIL;
    1166           0 :         goto done;
    1167             :     }
    1168             : 
    1169             : /* FIXME: add an end signature */
    1170           0 :     if (replen < (2*sizeof(int32_t))) {
    1171             :         D(("response not in expected format."));
    1172           0 :         pam_status = PAM_SYSTEM_ERR;
    1173           0 :         goto done;
    1174             :     }
    1175             : 
    1176           0 :     SAFEALIGN_COPY_UINT32(&pam_status, repbuf, NULL);
    1177           0 :     ret = eval_response(pamh, replen, repbuf, pi);
    1178           0 :     if (ret != PAM_SUCCESS) {
    1179             :         D(("eval_response failed."));
    1180           0 :         pam_status = ret;
    1181           0 :         goto done;
    1182             :     }
    1183             : 
    1184           0 :     switch (task) {
    1185             :         case SSS_PAM_AUTHENTICATE:
    1186           0 :             logger(pamh, (pam_status == PAM_SUCCESS ? LOG_INFO : LOG_NOTICE),
    1187             :                    "authentication %s; logname=%s uid=%lu euid=%d tty=%s "
    1188             :                    "ruser=%s rhost=%s user=%s",
    1189           0 :                    pam_status == PAM_SUCCESS ? "success" : "failure",
    1190           0 :                    pi->login_name, getuid(), (unsigned long) geteuid(),
    1191             :                    pi->pam_tty, pi->pam_ruser, pi->pam_rhost, pi->pam_user);
    1192           0 :             if (pam_status != PAM_SUCCESS) {
    1193             :                 /* don't log if quiet_mode is on and pam_status is
    1194             :                  * User not known to the underlying authentication module
    1195             :                  */
    1196           0 :                 if (!quiet_mode || pam_status != 10) {
    1197           0 :                    logger(pamh, LOG_NOTICE, "received for user %s: %d (%s)",
    1198             :                           pi->pam_user, pam_status,
    1199             :                           pam_strerror(pamh,pam_status));
    1200             :                 }
    1201             :             }
    1202           0 :             break;
    1203             :         case SSS_PAM_CHAUTHTOK_PRELIM:
    1204           0 :             if (pam_status != PAM_SUCCESS) {
    1205             :                 /* don't log if quiet_mode is on and pam_status is
    1206             :                  * User not known to the underlying authentication module
    1207             :                  */
    1208           0 :                 if (!quiet_mode || pam_status != 10) {
    1209           0 :                    logger(pamh, LOG_NOTICE,
    1210             :                           "Authentication failed for user %s: %d (%s)",
    1211             :                           pi->pam_user, pam_status,
    1212             :                           pam_strerror(pamh,pam_status));
    1213             :                 }
    1214             :             }
    1215           0 :             break;
    1216             :         case SSS_PAM_CHAUTHTOK:
    1217           0 :             if (pam_status != PAM_SUCCESS) {
    1218           0 :                    logger(pamh, LOG_NOTICE,
    1219             :                           "Password change failed for user %s: %d (%s)",
    1220             :                           pi->pam_user, pam_status,
    1221             :                           pam_strerror(pamh,pam_status));
    1222             :             }
    1223           0 :             break;
    1224             :         case SSS_PAM_ACCT_MGMT:
    1225           0 :             if (pam_status != PAM_SUCCESS) {
    1226             :                 /* don't log if quiet_mode is on and pam_status is
    1227             :                  * User not known to the underlying authentication module
    1228             :                  */
    1229           0 :                 if (!quiet_mode || pam_status != 10) {
    1230           0 :                    logger(pamh, LOG_NOTICE,
    1231             :                           "Access denied for user %s: %d (%s)",
    1232             :                           pi->pam_user, pam_status,
    1233             :                           pam_strerror(pamh,pam_status));
    1234             :                 }
    1235             :             }
    1236           0 :             break;
    1237             :         case SSS_PAM_OPEN_SESSION:
    1238             :         case SSS_PAM_SETCRED:
    1239             :         case SSS_PAM_CLOSE_SESSION:
    1240             :         case SSS_PAM_PREAUTH:
    1241           0 :             break;
    1242             :         default:
    1243             :             D(("Illegal task [%#x]", task));
    1244           0 :             return PAM_SYSTEM_ERR;
    1245             :     }
    1246             : 
    1247             : done:
    1248           0 :     if (buf != NULL ) {
    1249           0 :         _pam_overwrite_n((void *)buf, rd.len);
    1250           0 :         free(buf);
    1251             :     }
    1252           0 :     free(repbuf);
    1253             : 
    1254           0 :     return pam_status;
    1255             : }
    1256             : 
    1257           0 : static int prompt_password(pam_handle_t *pamh, struct pam_items *pi,
    1258             :                            const char *prompt)
    1259             : {
    1260             :     int ret;
    1261           0 :     char *answer = NULL;
    1262             : 
    1263           0 :     ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_OFF, prompt, NULL, &answer);
    1264           0 :     if (ret != PAM_SUCCESS) {
    1265             :         D(("do_pam_conversation failed."));
    1266           0 :         return ret;
    1267             :     }
    1268             : 
    1269           0 :     if (answer == NULL) {
    1270           0 :         pi->pam_authtok = NULL;
    1271           0 :         pi->pam_authtok_type = SSS_AUTHTOK_TYPE_EMPTY;
    1272           0 :         pi->pam_authtok_size=0;
    1273             :     } else {
    1274           0 :         pi->pam_authtok = strdup(answer);
    1275           0 :         _pam_overwrite((void *)answer);
    1276           0 :         free(answer);
    1277           0 :         answer=NULL;
    1278           0 :         if (pi->pam_authtok == NULL) {
    1279           0 :             return PAM_BUF_ERR;
    1280             :         }
    1281           0 :         pi->pam_authtok_type = SSS_AUTHTOK_TYPE_PASSWORD;
    1282           0 :         pi->pam_authtok_size=strlen(pi->pam_authtok);
    1283             :     }
    1284             : 
    1285           0 :     return PAM_SUCCESS;
    1286             : }
    1287             : 
    1288           0 : static int prompt_2fa(pam_handle_t *pamh, struct pam_items *pi,
    1289             :                       const char *prompt_fa1, const char *prompt_fa2)
    1290             : {
    1291             :     int ret;
    1292             :     const struct pam_conv *conv;
    1293           0 :     const struct pam_message *mesg[2] = { NULL, NULL };
    1294           0 :     struct pam_message m[2] = { {0}, {0} };
    1295           0 :     struct pam_response *resp = NULL;
    1296             :     size_t needed_size;
    1297             : 
    1298           0 :     ret = pam_get_item(pamh, PAM_CONV, (const void **) &conv);
    1299           0 :     if (ret != PAM_SUCCESS) {
    1300           0 :         return ret;
    1301             :     }
    1302             : 
    1303           0 :     m[0].msg_style = PAM_PROMPT_ECHO_OFF;
    1304           0 :     m[0].msg = prompt_fa1;
    1305           0 :     m[1].msg_style = PAM_PROMPT_ECHO_OFF;
    1306           0 :     m[1].msg = prompt_fa2;
    1307             : 
    1308           0 :     mesg[0] = (const struct pam_message *) m;
    1309             :     /* The following assignment might look a bit odd but is recommended in the
    1310             :      * pam_conv man page to make sure that the second argument of the PAM
    1311             :      * conversation function can be interpreted in two different ways.
    1312             :      * Basically it is important that both the actual struct pam_message and
    1313             :      * the pointers to the struct pam_message are arrays. Since the assignment
    1314             :      * makes clear that mesg[] and (*mesg)[] are arrays it should be kept this
    1315             :      * way and not be replaced by other equivalent assignments. */
    1316           0 :     mesg[1] = & (( *mesg )[1]);
    1317             : 
    1318           0 :     ret = conv->conv(2, mesg, &resp, conv->appdata_ptr);
    1319           0 :     if (ret != PAM_SUCCESS) {
    1320             :         D(("Conversation failure: %s.", pam_strerror(pamh, ret)));
    1321           0 :         return ret;
    1322             :     }
    1323             : 
    1324           0 :     if (resp == NULL) {
    1325             :         D(("response expected, but resp==NULL"));
    1326           0 :         return PAM_SYSTEM_ERR;
    1327             :     }
    1328             : 
    1329           0 :     if (resp[0].resp == NULL || *(resp[0].resp) == '\0') {
    1330             :         D(("Missing factor."));
    1331           0 :         ret = PAM_CRED_INSUFFICIENT;
    1332           0 :         goto done;
    1333             :     }
    1334             : 
    1335           0 :     if (resp[1].resp == NULL || *(resp[1].resp) == '\0'
    1336           0 :             || (pi->pam_service != NULL && strcmp(pi->pam_service, "sshd") == 0
    1337           0 :                     && strcmp(resp[0].resp, resp[1].resp) == 0)) {
    1338             :         /* Missing second factor, assume first factor contains combined 2FA
    1339             :          * credentials.
    1340             :          * Special handling for SSH with password authentication. Combined
    1341             :          * 2FA credentials are used but SSH puts them in both responses. */
    1342             : 
    1343           0 :         pi->pam_authtok = strndup(resp[0].resp, MAX_AUTHTOK_SIZE);
    1344           0 :         if (pi->pam_authtok == NULL) {
    1345             :             D(("strndup failed."));
    1346           0 :             ret = PAM_BUF_ERR;
    1347           0 :             goto done;
    1348             :         }
    1349           0 :         pi->pam_authtok_size = strlen(pi->pam_authtok) + 1;
    1350           0 :         pi->pam_authtok_type = SSS_AUTHTOK_TYPE_PASSWORD;
    1351             :     } else {
    1352             : 
    1353           0 :         ret = sss_auth_pack_2fa_blob(resp[0].resp, 0, resp[1].resp, 0, NULL, 0,
    1354             :                                      &needed_size);
    1355           0 :         if (ret != EAGAIN) {
    1356             :             D(("sss_auth_pack_2fa_blob failed."));
    1357           0 :             ret = PAM_BUF_ERR;
    1358           0 :             goto done;
    1359             :         }
    1360             : 
    1361           0 :         pi->pam_authtok = malloc(needed_size);
    1362           0 :         if (pi->pam_authtok == NULL) {
    1363             :             D(("malloc failed."));
    1364           0 :             ret = PAM_BUF_ERR;
    1365           0 :             goto done;
    1366             :         }
    1367             : 
    1368           0 :         ret = sss_auth_pack_2fa_blob(resp[0].resp, 0, resp[1].resp, 0,
    1369           0 :                                      (uint8_t *) pi->pam_authtok, needed_size,
    1370             :                                      &needed_size);
    1371           0 :         if (ret != EOK) {
    1372             :             D(("sss_auth_pack_2fa_blob failed."));
    1373           0 :             ret = PAM_BUF_ERR;
    1374           0 :             goto done;
    1375             :         }
    1376             : 
    1377           0 :         pi->pam_authtok_size = needed_size;
    1378           0 :         pi->pam_authtok_type = SSS_AUTHTOK_TYPE_2FA;
    1379           0 :         pi->first_factor = strndup(resp[0].resp, MAX_AUTHTOK_SIZE);
    1380           0 :         if (pi->first_factor == NULL) {
    1381             :             D(("strndup failed."));
    1382           0 :             ret = PAM_BUF_ERR;
    1383           0 :             goto done;
    1384             :         }
    1385             :     }
    1386             : 
    1387           0 :     ret = PAM_SUCCESS;
    1388             : 
    1389             : done:
    1390           0 :     if (resp != NULL) {
    1391           0 :         if (resp[0].resp != NULL) {
    1392           0 :             _pam_overwrite((void *)resp[0].resp);
    1393           0 :             free(resp[0].resp);
    1394             :         }
    1395           0 :         if (resp[1].resp != NULL) {
    1396           0 :             _pam_overwrite((void *)resp[1].resp);
    1397           0 :             free(resp[1].resp);
    1398             :         }
    1399             : 
    1400           0 :         free(resp);
    1401           0 :         resp = NULL;
    1402             :     }
    1403             : 
    1404           0 :     return ret;
    1405             : }
    1406             : 
    1407             : #define SC_PROMPT_FMT "PIN for %s for user %s"
    1408           0 : static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi)
    1409             : {
    1410             :     int ret;
    1411           0 :     char *answer = NULL;
    1412             :     char *prompt;
    1413             :     size_t size;
    1414             : 
    1415           0 :     if (pi->token_name == NULL || *pi->token_name == '\0'
    1416           0 :             || pi->cert_user == NULL || *pi->cert_user == '\0') {
    1417           0 :         return EINVAL;
    1418             :     }
    1419             : 
    1420           0 :     size = sizeof(SC_PROMPT_FMT) + strlen(pi->token_name) +
    1421           0 :            strlen(pi->cert_user);
    1422           0 :     prompt = malloc(size);
    1423           0 :     if (prompt == NULL) {
    1424             :         D(("malloc failed."));
    1425           0 :         return ENOMEM;
    1426             :     }
    1427             : 
    1428           0 :     ret = snprintf(prompt, size, SC_PROMPT_FMT, pi->token_name, pi->cert_user);
    1429           0 :     if (ret < 0 || ret >= size) {
    1430             :         D(("snprintf failed."));
    1431           0 :         free(prompt);
    1432           0 :         return EFAULT;
    1433             :     }
    1434             : 
    1435           0 :     ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_OFF, prompt, NULL, &answer);
    1436           0 :     free(prompt);
    1437           0 :     if (ret != PAM_SUCCESS) {
    1438             :         D(("do_pam_conversation failed."));
    1439           0 :         return ret;
    1440             :     }
    1441             : 
    1442           0 :     if (answer == NULL) {
    1443           0 :         pi->pam_authtok = NULL;
    1444           0 :         pi->pam_authtok_type = SSS_AUTHTOK_TYPE_EMPTY;
    1445           0 :         pi->pam_authtok_size=0;
    1446             :     } else {
    1447           0 :         pi->pam_authtok = strdup(answer);
    1448           0 :         _pam_overwrite((void *)answer);
    1449           0 :         free(answer);
    1450           0 :         answer=NULL;
    1451           0 :         if (pi->pam_authtok == NULL) {
    1452           0 :             return PAM_BUF_ERR;
    1453             :         }
    1454           0 :         pi->pam_authtok_type = SSS_AUTHTOK_TYPE_SC_PIN;
    1455           0 :         pi->pam_authtok_size=strlen(pi->pam_authtok);
    1456             :     }
    1457             : 
    1458           0 :     return PAM_SUCCESS;
    1459             : }
    1460             : 
    1461           0 : static int prompt_new_password(pam_handle_t *pamh, struct pam_items *pi)
    1462             : {
    1463             :     int ret;
    1464           0 :     char *answer = NULL;
    1465             : 
    1466           0 :     ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_OFF,
    1467           0 :                               _("New Password: "),
    1468           0 :                               _("Reenter new Password: "),
    1469             :                               &answer);
    1470           0 :     if (ret != PAM_SUCCESS) {
    1471             :         D(("do_pam_conversation failed."));
    1472           0 :         return ret;
    1473             :     }
    1474           0 :     if (answer == NULL) {
    1475           0 :         pi->pam_newauthtok = NULL;
    1476           0 :         pi->pam_newauthtok_type = SSS_AUTHTOK_TYPE_EMPTY;
    1477           0 :         pi->pam_newauthtok_size=0;
    1478             :     } else {
    1479           0 :         pi->pam_newauthtok = strdup(answer);
    1480           0 :         _pam_overwrite((void *)answer);
    1481           0 :         free(answer);
    1482           0 :         answer=NULL;
    1483           0 :         if (pi->pam_newauthtok == NULL) {
    1484           0 :             return PAM_BUF_ERR;
    1485             :         }
    1486           0 :         pi->pam_newauthtok_type = SSS_AUTHTOK_TYPE_PASSWORD;
    1487           0 :         pi->pam_newauthtok_size=strlen(pi->pam_newauthtok);
    1488             :     }
    1489             : 
    1490           0 :     return PAM_SUCCESS;
    1491             : }
    1492             : 
    1493           0 : static void eval_argv(pam_handle_t *pamh, int argc, const char **argv,
    1494             :                       uint32_t *flags, int *retries, bool *quiet_mode,
    1495             :                       const char **domains)
    1496             : {
    1497             :     char *ep;
    1498             : 
    1499           0 :     *quiet_mode = false;
    1500             : 
    1501           0 :     for (; argc-- > 0; ++argv) {
    1502           0 :         if (strcmp(*argv, "forward_pass") == 0) {
    1503           0 :             *flags |= FLAGS_FORWARD_PASS;
    1504           0 :         } else if (strcmp(*argv, "use_first_pass") == 0) {
    1505           0 :             *flags |= FLAGS_USE_FIRST_PASS;
    1506           0 :         } else if (strcmp(*argv, "use_authtok") == 0) {
    1507           0 :             *flags |= FLAGS_USE_AUTHTOK;
    1508           0 :         } else if (strncmp(*argv, OPT_DOMAINS_KEY, strlen(OPT_DOMAINS_KEY)) == 0) {
    1509           0 :             if (*(*argv+strlen(OPT_DOMAINS_KEY)) == '\0') {
    1510           0 :                 logger(pamh, LOG_ERR, "Missing argument to option domains.");
    1511           0 :                 *domains = "";
    1512             :             } else {
    1513           0 :                 *domains = *argv+strlen(OPT_DOMAINS_KEY);
    1514             :             }
    1515             : 
    1516           0 :         } else if (strncmp(*argv, OPT_RETRY_KEY, strlen(OPT_RETRY_KEY)) == 0) {
    1517           0 :             if (*(*argv+6) == '\0') {
    1518           0 :                 logger(pamh, LOG_ERR, "Missing argument to option retry.");
    1519           0 :                 *retries = 0;
    1520             :             } else {
    1521           0 :                 errno = 0;
    1522           0 :                 *retries = strtol(*argv+6, &ep, 10);
    1523           0 :                 if (errno != 0) {
    1524             :                     D(("strtol failed [%d][%s]", errno, strerror(errno)));
    1525           0 :                     *retries = 0;
    1526             :                 }
    1527           0 :                 if (*ep != '\0') {
    1528           0 :                     logger(pamh, LOG_ERR, "Argument to option retry contains "
    1529             :                                           "extra characters.");
    1530           0 :                     *retries = 0;
    1531             :                 }
    1532           0 :                 if (*retries < 0) {
    1533           0 :                     logger(pamh, LOG_ERR, "Argument to option retry must not "
    1534             :                                           "be negative.");
    1535           0 :                     *retries = 0;
    1536             :                 }
    1537             :             }
    1538           0 :         } else if (strcmp(*argv, "quiet") == 0) {
    1539           0 :             *quiet_mode = true;
    1540           0 :         } else if (strcmp(*argv, "ignore_unknown_user") == 0) {
    1541           0 :             *flags |= FLAGS_IGNORE_UNKNOWN_USER;
    1542           0 :         } else if (strcmp(*argv, "ignore_authinfo_unavail") == 0) {
    1543           0 :             *flags |= FLAGS_IGNORE_AUTHINFO_UNAVAIL;
    1544           0 :         } else if (strcmp(*argv, "use_2fa") == 0) {
    1545           0 :             *flags |= FLAGS_USE_2FA;
    1546           0 :         } else if (strcmp(*argv, "allow_missing_name") == 0) {
    1547           0 :             *flags |= FLAGS_ALLOW_MISSING_NAME;
    1548             :         } else {
    1549           0 :             logger(pamh, LOG_WARNING, "unknown option: %s", *argv);
    1550             :         }
    1551             :     }
    1552             : 
    1553           0 :     return;
    1554             : }
    1555             : 
    1556           0 : static int get_authtok_for_authentication(pam_handle_t *pamh,
    1557             :                                           struct pam_items *pi,
    1558             :                                           uint32_t flags)
    1559             : {
    1560             :     int ret;
    1561             : 
    1562           0 :     if (flags & FLAGS_USE_FIRST_PASS) {
    1563           0 :         pi->pam_authtok_type = SSS_AUTHTOK_TYPE_PASSWORD;
    1564           0 :         pi->pam_authtok = strdup(pi->pamstack_authtok);
    1565           0 :         if (pi->pam_authtok == NULL) {
    1566             :             D(("option use_first_pass set, but no password found"));
    1567           0 :             return PAM_BUF_ERR;
    1568             :         }
    1569           0 :         pi->pam_authtok_size = strlen(pi->pam_authtok);
    1570             :     } else {
    1571           0 :         if (flags & FLAGS_USE_2FA
    1572           0 :                 || (pi->otp_vendor != NULL && pi->otp_token_id != NULL
    1573           0 :                         && pi->otp_challenge != NULL)) {
    1574           0 :             ret = prompt_2fa(pamh, pi, _("First Factor: "),
    1575           0 :                              _("Second Factor: "));
    1576           0 :         } else if (pi->cert_user != NULL) {
    1577           0 :             ret = prompt_sc_pin(pamh, pi);
    1578             :         } else {
    1579           0 :             ret = prompt_password(pamh, pi, _("Password: "));
    1580             :         }
    1581           0 :         if (ret != PAM_SUCCESS) {
    1582             :             D(("failed to get password from user"));
    1583           0 :             return ret;
    1584             :         }
    1585             : 
    1586           0 :         if (flags & FLAGS_FORWARD_PASS) {
    1587           0 :             if (pi->pam_authtok_type == SSS_AUTHTOK_TYPE_PASSWORD) {
    1588           0 :                 ret = pam_set_item(pamh, PAM_AUTHTOK, pi->pam_authtok);
    1589           0 :             } else if (pi->pam_authtok_type == SSS_AUTHTOK_TYPE_2FA
    1590           0 :                            && pi->first_factor != NULL) {
    1591           0 :                 ret = pam_set_item(pamh, PAM_AUTHTOK, pi->first_factor);
    1592             :             } else {
    1593           0 :                 ret = EINVAL;
    1594             :             }
    1595             :             if (ret != PAM_SUCCESS) {
    1596             :                 D(("Failed to set PAM_AUTHTOK [%s], "
    1597             :                    "authtok may not be available for other modules",
    1598             :                    pam_strerror(pamh,ret)));
    1599             :             }
    1600             :         }
    1601             :     }
    1602             : 
    1603           0 :     return PAM_SUCCESS;
    1604             : }
    1605             : 
    1606           0 : static int get_authtok_for_password_change(pam_handle_t *pamh,
    1607             :                                            struct pam_items *pi,
    1608             :                                            uint32_t flags,
    1609             :                                            int pam_flags)
    1610             : {
    1611             :     int ret;
    1612           0 :     const int *exp_data = NULL;
    1613           0 :     pam_get_data(pamh, PWEXP_FLAG, (const void **) &exp_data);
    1614             : 
    1615             :     /* we query for the old password during PAM_PRELIM_CHECK to make
    1616             :      * pam_sss work e.g. with pam_cracklib */
    1617           0 :     if (pam_flags & PAM_PRELIM_CHECK) {
    1618           0 :         if ( (getuid() != 0 || exp_data ) && !(flags & FLAGS_USE_FIRST_PASS)) {
    1619           0 :             ret = prompt_password(pamh, pi, _("Current Password: "));
    1620           0 :             if (ret != PAM_SUCCESS) {
    1621             :                 D(("failed to get password from user"));
    1622           0 :                 return ret;
    1623             :             }
    1624             : 
    1625           0 :             ret = pam_set_item(pamh, PAM_OLDAUTHTOK, pi->pam_authtok);
    1626           0 :             if (ret != PAM_SUCCESS) {
    1627             :                 D(("Failed to set PAM_OLDAUTHTOK [%s], "
    1628             :                    "oldauthtok may not be available",
    1629             :                    pam_strerror(pamh,ret)));
    1630           0 :                    return ret;
    1631             :             }
    1632             :         }
    1633             : 
    1634           0 :         return PAM_SUCCESS;
    1635             :     }
    1636             : 
    1637           0 :     if (pi->pamstack_oldauthtok == NULL) {
    1638           0 :         if (getuid() != 0) {
    1639             :             D(("no password found for chauthtok"));
    1640           0 :             return PAM_BUF_ERR;
    1641             :         } else {
    1642           0 :             pi->pam_authtok_type = SSS_AUTHTOK_TYPE_EMPTY;
    1643           0 :             pi->pam_authtok = NULL;
    1644           0 :             pi->pam_authtok_size = 0;
    1645             :         }
    1646             :     } else {
    1647           0 :         pi->pam_authtok = strdup(pi->pamstack_oldauthtok);
    1648           0 :         if (pi->pam_authtok == NULL) {
    1649             :             D(("strdup failed"));
    1650           0 :             return PAM_BUF_ERR;
    1651             :         }
    1652           0 :         pi->pam_authtok_type = SSS_AUTHTOK_TYPE_PASSWORD;
    1653           0 :         pi->pam_authtok_size = strlen(pi->pam_authtok);
    1654             :     }
    1655             : 
    1656           0 :     if (flags & FLAGS_USE_AUTHTOK) {
    1657           0 :         pi->pam_newauthtok_type = SSS_AUTHTOK_TYPE_PASSWORD;
    1658           0 :         pi->pam_newauthtok =  strdup(pi->pamstack_authtok);
    1659           0 :         if (pi->pam_newauthtok == NULL) {
    1660             :             D(("option use_authtok set, but no new password found"));
    1661           0 :             return PAM_BUF_ERR;
    1662             :         }
    1663           0 :         pi->pam_newauthtok_size = strlen(pi->pam_newauthtok);
    1664             :     } else {
    1665           0 :         ret = prompt_new_password(pamh, pi);
    1666           0 :         if (ret != PAM_SUCCESS) {
    1667             :             D(("failed to get new password from user"));
    1668           0 :             return ret;
    1669             :         }
    1670             : 
    1671           0 :         if (flags & FLAGS_FORWARD_PASS) {
    1672           0 :             ret = pam_set_item(pamh, PAM_AUTHTOK, pi->pam_newauthtok);
    1673             :             if (ret != PAM_SUCCESS) {
    1674             :                 D(("Failed to set PAM_AUTHTOK [%s], "
    1675             :                    "oldauthtok may not be available",
    1676             :                    pam_strerror(pamh,ret)));
    1677             :             }
    1678             :         }
    1679             :     }
    1680             : 
    1681           0 :     return PAM_SUCCESS;
    1682             : }
    1683             : 
    1684           0 : static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
    1685             :                    int pam_flags, int argc, const char **argv)
    1686             : {
    1687             :     int ret;
    1688             :     int pam_status;
    1689             :     struct pam_items pi;
    1690           0 :     uint32_t flags = 0;
    1691             :     const int *exp_data;
    1692             :     int *pw_exp_data;
    1693           0 :     bool retry = false;
    1694           0 :     bool quiet_mode = false;
    1695           0 :     int retries = 0;
    1696           0 :     const char *domains = NULL;
    1697             : 
    1698           0 :     bindtextdomain(PACKAGE, LOCALEDIR);
    1699             : 
    1700             :     D(("Hello pam_sssd: %#x", task));
    1701             : 
    1702           0 :     eval_argv(pamh, argc, argv, &flags, &retries, &quiet_mode, &domains);
    1703             : 
    1704             :     /* Fail all authentication on misconfigured domains= parameter. The admin
    1705             :      * probably wanted to restrict authentication, so it's safer to fail */
    1706           0 :     if (domains && strcmp(domains, "") == 0) {
    1707           0 :         return PAM_SYSTEM_ERR;
    1708             :     }
    1709             : 
    1710           0 :     pi.requested_domains = domains;
    1711             : 
    1712           0 :     ret = get_pam_items(pamh, flags, &pi);
    1713           0 :     if (ret != PAM_SUCCESS) {
    1714             :         D(("get items returned error: %s", pam_strerror(pamh,ret)));
    1715           0 :         if (flags & FLAGS_IGNORE_UNKNOWN_USER && ret == PAM_USER_UNKNOWN) {
    1716           0 :             ret = PAM_IGNORE;
    1717             :         }
    1718           0 :         if (flags & FLAGS_IGNORE_AUTHINFO_UNAVAIL
    1719           0 :                 && ret == PAM_AUTHINFO_UNAVAIL) {
    1720           0 :             ret = PAM_IGNORE;
    1721             :         }
    1722           0 :         return ret;
    1723             :     }
    1724             : 
    1725             :     do {
    1726           0 :         retry = false;
    1727             : 
    1728           0 :         switch(task) {
    1729             :             case SSS_PAM_AUTHENTICATE:
    1730             :                 /*
    1731             :                  * Only do preauth if
    1732             :                  * - FLAGS_USE_FIRST_PASS is not set
    1733             :                  * - no password is on the stack
    1734             :                  * - preauth indicator file exists.
    1735             :                  */
    1736           0 :                 if ( !(flags & FLAGS_USE_FIRST_PASS) && pi.pam_authtok == NULL
    1737           0 :                         && access(PAM_PREAUTH_INDICATOR, F_OK) == 0) {
    1738           0 :                     pam_status = send_and_receive(pamh, &pi, SSS_PAM_PREAUTH,
    1739             :                                                   quiet_mode);
    1740             :                     if (pam_status != PAM_SUCCESS) {
    1741             :                         D(("send_and_receive returned [%d] during pre-auth",
    1742             :                            pam_status));
    1743             :                         /*
    1744             :                          * Since we are only interested in the result message
    1745             :                          * and will always use password authentication
    1746             :                          * as a fallback, errors can be ignored here.
    1747             :                          */
    1748             :                     }
    1749             :                 }
    1750             : 
    1751           0 :                 ret = get_authtok_for_authentication(pamh, &pi, flags);
    1752           0 :                 if (ret != PAM_SUCCESS) {
    1753             :                     D(("failed to get authentication token: %s",
    1754             :                        pam_strerror(pamh, ret)));
    1755           0 :                     return ret;
    1756             :                 }
    1757           0 :                 break;
    1758             :             case SSS_PAM_CHAUTHTOK:
    1759           0 :                 ret = get_authtok_for_password_change(pamh, &pi, flags, pam_flags);
    1760           0 :                 if (ret != PAM_SUCCESS) {
    1761             :                     D(("failed to get tokens for password change: %s",
    1762             :                        pam_strerror(pamh, ret)));
    1763           0 :                     overwrite_and_free_pam_items(&pi);
    1764           0 :                     return ret;
    1765             :                 }
    1766           0 :                 if (pam_flags & PAM_PRELIM_CHECK) {
    1767           0 :                     task = SSS_PAM_CHAUTHTOK_PRELIM;
    1768             :                 }
    1769           0 :                 break;
    1770             :             case SSS_PAM_ACCT_MGMT:
    1771             :             case SSS_PAM_SETCRED:
    1772             :             case SSS_PAM_OPEN_SESSION:
    1773             :             case SSS_PAM_CLOSE_SESSION:
    1774           0 :                 break;
    1775             :             default:
    1776             :                 D(("Illegal task [%#x]", task));
    1777           0 :                 return PAM_SYSTEM_ERR;
    1778             :         }
    1779             : 
    1780           0 :         pam_status = send_and_receive(pamh, &pi, task, quiet_mode);
    1781             : 
    1782           0 :         if (flags & FLAGS_IGNORE_UNKNOWN_USER
    1783           0 :                 && pam_status == PAM_USER_UNKNOWN) {
    1784           0 :             pam_status = PAM_IGNORE;
    1785             :         }
    1786           0 :         if (flags & FLAGS_IGNORE_AUTHINFO_UNAVAIL
    1787           0 :                 && pam_status == PAM_AUTHINFO_UNAVAIL) {
    1788           0 :             pam_status = PAM_IGNORE;
    1789             :         }
    1790             : 
    1791           0 :         switch (task) {
    1792             :             case SSS_PAM_AUTHENTICATE:
    1793             :                 /* We allow sssd to send the return code PAM_NEW_AUTHTOK_REQD during
    1794             :                  * authentication, see sss_cli.h for details */
    1795           0 :                 if (pam_status == PAM_NEW_AUTHTOK_REQD) {
    1796             :                     D(("Authtoken expired, trying to change it"));
    1797             : 
    1798           0 :                     pw_exp_data = malloc(sizeof(int));
    1799           0 :                     if (pw_exp_data == NULL) {
    1800             :                         D(("malloc failed."));
    1801           0 :                         pam_status = PAM_BUF_ERR;
    1802           0 :                         break;
    1803             :                     }
    1804           0 :                     *pw_exp_data = 1;
    1805             : 
    1806           0 :                     pam_status = pam_set_data(pamh, PWEXP_FLAG, pw_exp_data,
    1807             :                                               free_exp_data);
    1808             :                     if (pam_status != PAM_SUCCESS) {
    1809             :                         D(("pam_set_data failed."));
    1810             :                     }
    1811             :                 }
    1812           0 :                 break;
    1813             :             case SSS_PAM_ACCT_MGMT:
    1814           0 :                 if (pam_status == PAM_SUCCESS &&
    1815           0 :                     pam_get_data(pamh, PWEXP_FLAG, (const void **) &exp_data) ==
    1816             :                                                                       PAM_SUCCESS) {
    1817           0 :                     ret = do_pam_conversation(pamh, PAM_TEXT_INFO,
    1818           0 :                                    _("Password expired. Change your password now."),
    1819             :                                    NULL, NULL);
    1820             :                     if (ret != PAM_SUCCESS) {
    1821             :                         D(("do_pam_conversation failed."));
    1822             :                     }
    1823           0 :                     pam_status = PAM_NEW_AUTHTOK_REQD;
    1824             :                 }
    1825           0 :                 break;
    1826             :             case SSS_PAM_CHAUTHTOK:
    1827           0 :                 if (pam_status != PAM_SUCCESS && pam_status != PAM_USER_UNKNOWN) {
    1828           0 :                     ret = pam_set_item(pamh, PAM_AUTHTOK, NULL);
    1829             :                     if (ret != PAM_SUCCESS) {
    1830             :                         D(("Failed to unset PAM_AUTHTOK [%s]",
    1831             :                            pam_strerror(pamh,ret)));
    1832             :                     }
    1833           0 :                     ret = pam_set_item(pamh, PAM_OLDAUTHTOK, NULL);
    1834             :                     if (ret != PAM_SUCCESS) {
    1835             :                         D(("Failed to unset PAM_OLDAUTHTOK [%s]",
    1836             :                            pam_strerror(pamh,ret)));
    1837             :                     }
    1838             :                 }
    1839           0 :                 break;
    1840             :             case SSS_PAM_CHAUTHTOK_PRELIM:
    1841           0 :                 if (pam_status == PAM_PERM_DENIED && pi.pam_authtok_size == 0 &&
    1842           0 :                     getuid() == 0 &&
    1843           0 :                     pam_get_data(pamh, PWEXP_FLAG, (const void **) &exp_data) !=
    1844             :                                                                       PAM_SUCCESS) {
    1845             : 
    1846           0 :                     ret = select_pw_reset_message(pamh, &pi);
    1847             :                     if (ret != 0) {
    1848             :                         D(("select_pw_reset_message failed.\n"));
    1849             :                     }
    1850             :                 }
    1851             :             default:
    1852             :                 /* nothing to do */
    1853           0 :                 break;
    1854             :         }
    1855             : 
    1856           0 :         overwrite_and_free_pam_items(&pi);
    1857             : 
    1858             :         D(("retries [%d].", retries));
    1859             : 
    1860           0 :         if (pam_status != PAM_SUCCESS &&
    1861           0 :             (task == SSS_PAM_AUTHENTICATE || task == SSS_PAM_CHAUTHTOK_PRELIM) &&
    1862           0 :             retries > 0) {
    1863           0 :             retry = true;
    1864           0 :             retries--;
    1865             : 
    1866           0 :             flags &= ~FLAGS_USE_FIRST_PASS;
    1867           0 :             ret = pam_set_item(pamh, PAM_AUTHTOK, NULL);
    1868             :             if (ret != PAM_SUCCESS) {
    1869             :                 D(("Failed to unset PAM_AUTHTOK [%s]",
    1870             :                    pam_strerror(pamh,ret)));
    1871             :             }
    1872           0 :             ret = pam_set_item(pamh, PAM_OLDAUTHTOK, NULL);
    1873             :             if (ret != PAM_SUCCESS) {
    1874             :                 D(("Failed to unset PAM_OLDAUTHTOK [%s]",
    1875             :                    pam_strerror(pamh,ret)));
    1876             :             }
    1877             :         }
    1878           0 :     } while(retry);
    1879             : 
    1880           0 :     return pam_status;
    1881             : }
    1882             : 
    1883             : PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
    1884             :                                    const char **argv )
    1885             : {
    1886           0 :     return pam_sss(SSS_PAM_AUTHENTICATE, pamh, flags, argc, argv);
    1887             : }
    1888             : 
    1889             : 
    1890             : PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc,
    1891             :                               const char **argv )
    1892             : {
    1893           0 :     return pam_sss(SSS_PAM_SETCRED, pamh, flags, argc, argv);
    1894             : }
    1895             : 
    1896             : PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc,
    1897             :                                 const char **argv )
    1898             : {
    1899           0 :     return pam_sss(SSS_PAM_ACCT_MGMT, pamh, flags, argc, argv);
    1900             : }
    1901             : 
    1902             : PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc,
    1903             :                                 const char **argv )
    1904             : {
    1905           0 :     return pam_sss(SSS_PAM_CHAUTHTOK, pamh, flags, argc, argv);
    1906             : }
    1907             : 
    1908             : PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc,
    1909             :                                    const char **argv )
    1910             : {
    1911           0 :     return pam_sss(SSS_PAM_OPEN_SESSION, pamh, flags, argc, argv);
    1912             : }
    1913             : 
    1914             : PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc,
    1915             :                                     const char **argv )
    1916             : {
    1917           0 :     return pam_sss(SSS_PAM_CLOSE_SESSION, pamh, flags, argc, argv);
    1918             : }
    1919             : 
    1920             : 
    1921             : #ifdef PAM_STATIC
    1922             : 
    1923             : /* static module data */
    1924             : 
    1925             : struct pam_module _pam_sssd_modstruct ={
    1926             :      "pam_sssd",
    1927             :      pam_sm_authenticate,
    1928             :      pam_sm_setcred,
    1929             :      pam_sm_acct_mgmt,
    1930             :      pam_sm_open_session,
    1931             :      pam_sm_close_session,
    1932             :      pam_sm_chauthtok
    1933             : };
    1934             : 
    1935             : #endif

Generated by: LCOV version 1.10