LCOV - code coverage report
Current view: top level - nsswitch - pam_winbind.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 657 1408 46.7 %
Date: 2021-09-23 10:06:22 Functions: 45 57 78.9 %

          Line data    Source code
       1             : /* pam_winbind module
       2             : 
       3             :    Copyright Andrew Tridgell <tridge@samba.org> 2000
       4             :    Copyright Tim Potter <tpot@samba.org> 2000
       5             :    Copyright Andrew Bartlett <abartlet@samba.org> 2002
       6             :    Copyright Guenther Deschner <gd@samba.org> 2005-2008
       7             : 
       8             :    largely based on pam_userdb by Cristian Gafton <gafton@redhat.com> also
       9             :    contains large slabs of code from pam_unix by Elliot Lee
      10             :    <sopwith@redhat.com> (see copyright below for full details)
      11             : */
      12             : 
      13             : #include "pam_winbind.h"
      14             : 
      15             : enum pam_winbind_request_type
      16             : {
      17             :         PAM_WINBIND_AUTHENTICATE,
      18             :         PAM_WINBIND_SETCRED,
      19             :         PAM_WINBIND_ACCT_MGMT,
      20             :         PAM_WINBIND_OPEN_SESSION,
      21             :         PAM_WINBIND_CLOSE_SESSION,
      22             :         PAM_WINBIND_CHAUTHTOK,
      23             :         PAM_WINBIND_CLEANUP
      24             : };
      25             : 
      26           0 : static int wbc_error_to_pam_error(wbcErr status)
      27             : {
      28           0 :         switch (status) {
      29           0 :                 case WBC_ERR_SUCCESS:
      30           0 :                         return PAM_SUCCESS;
      31           0 :                 case WBC_ERR_NOT_IMPLEMENTED:
      32           0 :                         return PAM_SERVICE_ERR;
      33           0 :                 case WBC_ERR_UNKNOWN_FAILURE:
      34           0 :                         break;
      35           0 :                 case WBC_ERR_NO_MEMORY:
      36           0 :                         return PAM_BUF_ERR;
      37           0 :                 case WBC_ERR_INVALID_SID:
      38             :                 case WBC_ERR_INVALID_PARAM:
      39           0 :                         break;
      40           0 :                 case WBC_ERR_WINBIND_NOT_AVAILABLE:
      41           0 :                         return PAM_AUTHINFO_UNAVAIL;
      42           0 :                 case WBC_ERR_DOMAIN_NOT_FOUND:
      43           0 :                         return PAM_AUTHINFO_UNAVAIL;
      44           0 :                 case WBC_ERR_INVALID_RESPONSE:
      45           0 :                         return PAM_BUF_ERR;
      46           0 :                 case WBC_ERR_NSS_ERROR:
      47           0 :                         return PAM_USER_UNKNOWN;
      48           0 :                 case WBC_ERR_AUTH_ERROR:
      49           0 :                         return PAM_AUTH_ERR;
      50           0 :                 case WBC_ERR_UNKNOWN_USER:
      51           0 :                         return PAM_USER_UNKNOWN;
      52           0 :                 case WBC_ERR_UNKNOWN_GROUP:
      53           0 :                         return PAM_USER_UNKNOWN;
      54           0 :                 case WBC_ERR_PWD_CHANGE_FAILED:
      55           0 :                         break;
      56             :         }
      57             : 
      58             :         /* be paranoid */
      59           0 :         return PAM_AUTH_ERR;
      60             : }
      61             : 
      62         336 : static const char *_pam_error_code_str(int err)
      63             : {
      64         336 :         switch (err) {
      65         184 :                 case PAM_SUCCESS:
      66         184 :                         return "PAM_SUCCESS";
      67           0 :                 case PAM_OPEN_ERR:
      68           0 :                         return "PAM_OPEN_ERR";
      69           0 :                 case PAM_SYMBOL_ERR:
      70           0 :                         return "PAM_SYMBOL_ERR";
      71           0 :                 case PAM_SERVICE_ERR:
      72           0 :                         return "PAM_SERVICE_ERR";
      73           0 :                 case PAM_SYSTEM_ERR:
      74           0 :                         return "PAM_SYSTEM_ERR";
      75           0 :                 case PAM_BUF_ERR:
      76           0 :                         return "PAM_BUF_ERR";
      77           0 :                 case PAM_PERM_DENIED:
      78           0 :                         return "PAM_PERM_DENIED";
      79         152 :                 case PAM_AUTH_ERR:
      80         152 :                         return "PAM_AUTH_ERR";
      81           0 :                 case PAM_CRED_INSUFFICIENT:
      82           0 :                         return "PAM_CRED_INSUFFICIENT";
      83           0 :                 case PAM_AUTHINFO_UNAVAIL:
      84           0 :                         return "PAM_AUTHINFO_UNAVAIL";
      85           0 :                 case PAM_USER_UNKNOWN:
      86           0 :                         return "PAM_USER_UNKNOWN";
      87           0 :                 case PAM_MAXTRIES:
      88           0 :                         return "PAM_MAXTRIES";
      89           0 :                 case PAM_NEW_AUTHTOK_REQD:
      90           0 :                         return "PAM_NEW_AUTHTOK_REQD";
      91           0 :                 case PAM_ACCT_EXPIRED:
      92           0 :                         return "PAM_ACCT_EXPIRED";
      93           0 :                 case PAM_SESSION_ERR:
      94           0 :                         return "PAM_SESSION_ERR";
      95           0 :                 case PAM_CRED_UNAVAIL:
      96           0 :                         return "PAM_CRED_UNAVAIL";
      97           0 :                 case PAM_CRED_EXPIRED:
      98           0 :                         return "PAM_CRED_EXPIRED";
      99           0 :                 case PAM_CRED_ERR:
     100           0 :                         return "PAM_CRED_ERR";
     101           0 :                 case PAM_NO_MODULE_DATA:
     102           0 :                         return "PAM_NO_MODULE_DATA";
     103           0 :                 case PAM_CONV_ERR:
     104           0 :                         return "PAM_CONV_ERR";
     105           0 :                 case PAM_AUTHTOK_ERR:
     106           0 :                         return "PAM_AUTHTOK_ERR";
     107           0 :                 case PAM_AUTHTOK_RECOVER_ERR:
     108           0 :                         return "PAM_AUTHTOK_RECOVER_ERR";
     109           0 :                 case PAM_AUTHTOK_LOCK_BUSY:
     110           0 :                         return "PAM_AUTHTOK_LOCK_BUSY";
     111           0 :                 case PAM_AUTHTOK_DISABLE_AGING:
     112           0 :                         return "PAM_AUTHTOK_DISABLE_AGING";
     113           0 :                 case PAM_TRY_AGAIN:
     114           0 :                         return "PAM_TRY_AGAIN";
     115           0 :                 case PAM_IGNORE:
     116           0 :                         return "PAM_IGNORE";
     117           0 :                 case PAM_ABORT:
     118           0 :                         return "PAM_ABORT";
     119           0 :                 case PAM_AUTHTOK_EXPIRED:
     120           0 :                         return "PAM_AUTHTOK_EXPIRED";
     121             : #ifdef PAM_MODULE_UNKNOWN
     122           0 :                 case PAM_MODULE_UNKNOWN:
     123           0 :                         return "PAM_MODULE_UNKNOWN";
     124             : #endif
     125             : #ifdef PAM_BAD_ITEM
     126           0 :                 case PAM_BAD_ITEM:
     127           0 :                         return "PAM_BAD_ITEM";
     128             : #endif
     129             : #ifdef PAM_CONV_AGAIN
     130           0 :                 case PAM_CONV_AGAIN:
     131           0 :                         return "PAM_CONV_AGAIN";
     132             : #endif
     133             : #ifdef PAM_INCOMPLETE
     134           0 :                 case PAM_INCOMPLETE:
     135           0 :                         return "PAM_INCOMPLETE";
     136             : #endif
     137           0 :                 default:
     138           0 :                         return NULL;
     139             :         }
     140             : }
     141             : 
     142             : #define _PAM_LOG_FUNCTION_ENTER(function, ctx) \
     143             :         do { \
     144             :                 _pam_log_debug(ctx, LOG_DEBUG, "[pamh: %p] ENTER: " \
     145             :                                function " (flags: 0x%04x)", ctx->pamh, ctx->flags); \
     146             :                 _pam_log_state(ctx); \
     147             :         } while (0)
     148             : 
     149             : #define _PAM_LOG_FUNCTION_LEAVE(function, ctx, retval) \
     150             :         do { \
     151             :                 _pam_log_debug(ctx, LOG_DEBUG, "[pamh: %p] LEAVE: " \
     152             :                                function " returning %d (%s)", ctx ? ctx->pamh : NULL, retval, \
     153             :                                _pam_error_code_str(retval)); \
     154             :                 _pam_log_state(ctx); \
     155             :         } while (0)
     156             : 
     157             : /* data tokens */
     158             : 
     159             : #define MAX_PASSWD_TRIES        3
     160             : 
     161             : #ifdef HAVE_GETTEXT
     162             : static char initialized = 0;
     163             : 
     164             : static inline void textdomain_init(void);
     165         260 : static inline void textdomain_init(void)
     166             : {
     167         260 :         if (!initialized) {
     168         248 :                 bindtextdomain(MODULE_NAME, LOCALEDIR);
     169         248 :                 initialized = 1;
     170             :         }
     171         260 :         return;
     172             : }
     173             : #endif
     174             : 
     175             : 
     176             : /* some syslogging */
     177             : static void _pam_log_int(const pam_handle_t *pamh,
     178             :                          int err,
     179             :                          const char *format,
     180             :                          va_list args) PRINTF_ATTRIBUTE(3, 0);
     181             : 
     182             : #ifdef HAVE_PAM_VSYSLOG
     183        4280 : static void _pam_log_int(const pam_handle_t *pamh,
     184             :                          int err,
     185             :                          const char *format,
     186             :                          va_list args)
     187             : {
     188        4280 :         pam_vsyslog(pamh, err, format, args);
     189        4280 : }
     190             : #else
     191             : static void _pam_log_int(const pam_handle_t *pamh,
     192             :                          int err,
     193             :                          const char *format,
     194             :                          va_list args)
     195             : {
     196             :         char *base = NULL;
     197             :         va_list args2;
     198             :         const char *service;
     199             :         int ret;
     200             : 
     201             :         va_copy(args2, args);
     202             : 
     203             :         pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
     204             : 
     205             :         ret = vasprintf(&base, format, args);
     206             :         if (ret == -1) {
     207             :                 /* what else todo ? */
     208             :                 vsyslog(err, format, args2);
     209             :                 va_end(args2);
     210             :                 return;
     211             :         }
     212             : 
     213             :         syslog(err, "%s(%s): %s", MODULE_NAME, service, base);
     214             :         SAFE_FREE(base);
     215             :         va_end(args2);
     216             : }
     217             : #endif /* HAVE_PAM_VSYSLOG */
     218             : 
     219        4800 : static bool _pam_log_is_silent(int ctrl)
     220             : {
     221        4800 :         return on(ctrl, WINBIND_SILENT);
     222             : }
     223             : 
     224             : static void _pam_log(struct pwb_context *r, int err, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
     225         620 : static void _pam_log(struct pwb_context *r, int err, const char *format, ...)
     226             : {
     227             :         va_list args;
     228             : 
     229         620 :         if (_pam_log_is_silent(r->ctrl)) {
     230           0 :                 return;
     231             :         }
     232             : 
     233         620 :         va_start(args, format);
     234         620 :         _pam_log_int(r->pamh, err, format, args);
     235         620 :         va_end(args);
     236             : }
     237             : static void __pam_log(const pam_handle_t *pamh, int ctrl, int err, const char *format, ...) PRINTF_ATTRIBUTE(4,5);
     238           0 : static void __pam_log(const pam_handle_t *pamh, int ctrl, int err, const char *format, ...)
     239             : {
     240             :         va_list args;
     241             : 
     242           0 :         if (_pam_log_is_silent(ctrl)) {
     243           0 :                 return;
     244             :         }
     245             : 
     246           0 :         va_start(args, format);
     247           0 :         _pam_log_int(pamh, err, format, args);
     248           0 :         va_end(args);
     249             : }
     250             : 
     251        4180 : static bool _pam_log_is_debug_enabled(int ctrl)
     252             : {
     253        4180 :         if (ctrl == -1) {
     254           0 :                 return false;
     255             :         }
     256             : 
     257        4180 :         if (_pam_log_is_silent(ctrl)) {
     258           0 :                 return false;
     259             :         }
     260             : 
     261        4180 :         if (!(ctrl & WINBIND_DEBUG_ARG)) {
     262           0 :                 return false;
     263             :         }
     264             : 
     265        4180 :         return true;
     266             : }
     267             : 
     268         708 : static bool _pam_log_is_debug_state_enabled(int ctrl)
     269             : {
     270         708 :         if (!(ctrl & WINBIND_DEBUG_STATE)) {
     271         188 :                 return false;
     272             :         }
     273             : 
     274         520 :         return _pam_log_is_debug_enabled(ctrl);
     275             : }
     276             : 
     277             : static void _pam_log_debug(struct pwb_context *r, int err, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
     278        3660 : static void _pam_log_debug(struct pwb_context *r, int err, const char *format, ...)
     279             : {
     280             :         va_list args;
     281             : 
     282        3660 :         if (!r || !_pam_log_is_debug_enabled(r->ctrl)) {
     283           0 :                 return;
     284             :         }
     285             : 
     286        3660 :         va_start(args, format);
     287        3660 :         _pam_log_int(r->pamh, err, format, args);
     288        3660 :         va_end(args);
     289             : }
     290             : static void __pam_log_debug(const pam_handle_t *pamh, int ctrl, int err, const char *format, ...) PRINTF_ATTRIBUTE(4,5);
     291           0 : static void __pam_log_debug(const pam_handle_t *pamh, int ctrl, int err, const char *format, ...)
     292             : {
     293             :         va_list args;
     294             : 
     295           0 :         if (!_pam_log_is_debug_enabled(ctrl)) {
     296           0 :                 return;
     297             :         }
     298             : 
     299           0 :         va_start(args, format);
     300           0 :         _pam_log_int(pamh, err, format, args);
     301           0 :         va_end(args);
     302             : }
     303             : 
     304        8840 : static void _pam_log_state_datum(struct pwb_context *ctx,
     305             :                                  int item_type,
     306             :                                  const char *key,
     307             :                                  int is_string)
     308             : {
     309        8840 :         const void *data = NULL;
     310        8840 :         if (item_type != 0) {
     311        5200 :                 pam_get_item(ctx->pamh, item_type, &data);
     312             :         } else {
     313        3640 :                 pam_get_data(ctx->pamh, key, &data);
     314             :         }
     315        8840 :         if (data != NULL) {
     316        2116 :                 const char *type = (item_type != 0) ? "ITEM" : "DATA";
     317        2116 :                 if (is_string != 0) {
     318        1560 :                         _pam_log_debug(ctx, LOG_DEBUG,
     319             :                                        "[pamh: %p] STATE: %s(%s) = \"%s\" (%p)",
     320             :                                        ctx->pamh, type, key, (const char *)data,
     321             :                                        data);
     322             :                 } else {
     323         556 :                         _pam_log_debug(ctx, LOG_DEBUG,
     324             :                                        "[pamh: %p] STATE: %s(%s) = %p",
     325             :                                        ctx->pamh, type, key, data);
     326             :                 }
     327             :         }
     328        8840 : }
     329             : 
     330             : #define _PAM_LOG_STATE_DATA_POINTER(ctx, module_data_name) \
     331             :         _pam_log_state_datum(ctx, 0, module_data_name, 0)
     332             : 
     333             : #define _PAM_LOG_STATE_DATA_STRING(ctx, module_data_name) \
     334             :         _pam_log_state_datum(ctx, 0, module_data_name, 1)
     335             : 
     336             : #define _PAM_LOG_STATE_ITEM_POINTER(ctx, item_type) \
     337             :         _pam_log_state_datum(ctx, item_type, #item_type, 0)
     338             : 
     339             : #define _PAM_LOG_STATE_ITEM_STRING(ctx, item_type) \
     340             :         _pam_log_state_datum(ctx, item_type, #item_type, 1)
     341             : 
     342             : #ifdef DEBUG_PASSWORD
     343             : #define _LOG_PASSWORD_AS_STRING 1
     344             : #else
     345             : #define _LOG_PASSWORD_AS_STRING 0
     346             : #endif
     347             : 
     348             : #define _PAM_LOG_STATE_ITEM_PASSWORD(ctx, item_type) \
     349             :         _pam_log_state_datum(ctx, item_type, #item_type, \
     350             :                              _LOG_PASSWORD_AS_STRING)
     351             : /*
     352             :  * wrapper to preserve old behaviour of iniparser which ignored
     353             :  * key values that had no value assigned like
     354             :  *    key =
     355             :  * for a key like above newer iniparser will return a zero-length
     356             :  * string, previously iniparser would return NULL
     357             :  *
     358             :  * JRA: For compatibility, tiniparser behaves like iniparser.
     359             :  */
     360           0 : static const char *tiniparser_getstring_nonempty(struct tiniparser_dictionary *d,
     361             :                         const char *key,
     362             :                         const char *def)
     363             : {
     364           0 :         const char *ret = tiniparser_getstring(d, key, def);
     365           0 :         if (ret && strlen(ret) == 0) {
     366           0 :                 ret = NULL;
     367             :         }
     368           0 :         return ret;
     369             : }
     370             : 
     371         520 : static void _pam_log_state(struct pwb_context *ctx)
     372             : {
     373         520 :         if (!ctx || !_pam_log_is_debug_state_enabled(ctx->ctrl)) {
     374           0 :                 return;
     375             :         }
     376             : 
     377         520 :         _PAM_LOG_STATE_ITEM_STRING(ctx, PAM_SERVICE);
     378         520 :         _PAM_LOG_STATE_ITEM_STRING(ctx, PAM_USER);
     379         520 :         _PAM_LOG_STATE_ITEM_STRING(ctx, PAM_TTY);
     380         520 :         _PAM_LOG_STATE_ITEM_STRING(ctx, PAM_RHOST);
     381         520 :         _PAM_LOG_STATE_ITEM_STRING(ctx, PAM_RUSER);
     382         520 :         _PAM_LOG_STATE_ITEM_PASSWORD(ctx, PAM_OLDAUTHTOK);
     383         520 :         _PAM_LOG_STATE_ITEM_PASSWORD(ctx, PAM_AUTHTOK);
     384         520 :         _PAM_LOG_STATE_ITEM_STRING(ctx, PAM_USER_PROMPT);
     385         520 :         _PAM_LOG_STATE_ITEM_POINTER(ctx, PAM_CONV);
     386             : #ifdef PAM_FAIL_DELAY
     387         520 :         _PAM_LOG_STATE_ITEM_POINTER(ctx, PAM_FAIL_DELAY);
     388             : #endif
     389             : #ifdef PAM_REPOSITORY
     390             :         _PAM_LOG_STATE_ITEM_POINTER(ctx, PAM_REPOSITORY);
     391             : #endif
     392             : 
     393         520 :         _PAM_LOG_STATE_DATA_STRING(ctx, PAM_WINBIND_HOMEDIR);
     394         520 :         _PAM_LOG_STATE_DATA_STRING(ctx, PAM_WINBIND_LOGONSCRIPT);
     395         520 :         _PAM_LOG_STATE_DATA_STRING(ctx, PAM_WINBIND_LOGONSERVER);
     396         520 :         _PAM_LOG_STATE_DATA_STRING(ctx, PAM_WINBIND_PROFILEPATH);
     397         520 :         _PAM_LOG_STATE_DATA_STRING(ctx,
     398             :                                    PAM_WINBIND_NEW_AUTHTOK_REQD);
     399             :                                    /* Use atoi to get PAM result code */
     400         520 :         _PAM_LOG_STATE_DATA_STRING(ctx,
     401             :                                    PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH);
     402         520 :         _PAM_LOG_STATE_DATA_POINTER(ctx, PAM_WINBIND_PWD_LAST_SET);
     403             : }
     404             : 
     405         448 : static int _pam_parse(const pam_handle_t *pamh,
     406             :                       int flags,
     407             :                       int argc,
     408             :                       const char **argv,
     409             :                       enum pam_winbind_request_type type,
     410             :                       struct tiniparser_dictionary **result_d)
     411             : {
     412         448 :         int ctrl = 0;
     413         448 :         const char *config_file = NULL;
     414             :         int i;
     415             :         const char **v;
     416         448 :         struct tiniparser_dictionary *d = NULL;
     417             : 
     418         448 :         if (flags & PAM_SILENT) {
     419           0 :                 ctrl |= WINBIND_SILENT;
     420             :         }
     421             : 
     422        1252 :         for (i=argc,v=argv; i-- > 0; ++v) {
     423         804 :                 if (!strncasecmp(*v, "config", strlen("config"))) {
     424           0 :                         ctrl |= WINBIND_CONFIG_FILE;
     425           0 :                         config_file = v[i];
     426           0 :                         break;
     427             :                 }
     428             :         }
     429             : 
     430         448 :         if (config_file == NULL) {
     431         448 :                 config_file = PAM_WINBIND_CONFIG_FILE;
     432             :         }
     433             : 
     434         448 :         d = tiniparser_load(config_file);
     435         448 :         if (d == NULL) {
     436         448 :                 goto config_from_pam;
     437             :         }
     438             : 
     439           0 :         if (tiniparser_getboolean(d, "global:debug", false)) {
     440           0 :                 ctrl |= WINBIND_DEBUG_ARG;
     441             :         }
     442             : 
     443           0 :         if (tiniparser_getboolean(d, "global:debug_state", false)) {
     444           0 :                 ctrl |= WINBIND_DEBUG_STATE;
     445             :         }
     446             : 
     447           0 :         if (tiniparser_getboolean(d, "global:cached_login", false)) {
     448           0 :                 ctrl |= WINBIND_CACHED_LOGIN;
     449             :         }
     450             : 
     451           0 :         if (tiniparser_getboolean(d, "global:krb5_auth", false)) {
     452           0 :                 ctrl |= WINBIND_KRB5_AUTH;
     453             :         }
     454             : 
     455           0 :         if (tiniparser_getboolean(d, "global:silent", false)) {
     456           0 :                 ctrl |= WINBIND_SILENT;
     457             :         }
     458             : 
     459           0 :         if (tiniparser_getstring_nonempty(d, "global:krb5_ccache_type", NULL) != NULL) {
     460           0 :                 ctrl |= WINBIND_KRB5_CCACHE_TYPE;
     461             :         }
     462             : 
     463           0 :         if ((tiniparser_getstring_nonempty(d, "global:require-membership-of", NULL)
     464           0 :              != NULL) ||
     465           0 :             (tiniparser_getstring_nonempty(d, "global:require_membership_of", NULL)
     466             :              != NULL)) {
     467           0 :                 ctrl |= WINBIND_REQUIRED_MEMBERSHIP;
     468             :         }
     469             : 
     470           0 :         if (tiniparser_getboolean(d, "global:try_first_pass", false)) {
     471           0 :                 ctrl |= WINBIND_TRY_FIRST_PASS_ARG;
     472             :         }
     473             : 
     474           0 :         if (tiniparser_getint(d, "global:warn_pwd_expire", 0)) {
     475           0 :                 ctrl |= WINBIND_WARN_PWD_EXPIRE;
     476             :         }
     477             : 
     478           0 :         if (tiniparser_getboolean(d, "global:mkhomedir", false)) {
     479           0 :                 ctrl |= WINBIND_MKHOMEDIR;
     480             :         }
     481             : 
     482         224 : config_from_pam:
     483             :         /* step through arguments */
     484        1252 :         for (i=argc,v=argv; i-- > 0; ++v) {
     485             : 
     486             :                 /* generic options */
     487         804 :                 if (!strcmp(*v,"debug"))
     488         260 :                         ctrl |= WINBIND_DEBUG_ARG;
     489         544 :                 else if (!strcasecmp(*v, "debug_state"))
     490         260 :                         ctrl |= WINBIND_DEBUG_STATE;
     491         284 :                 else if (!strcasecmp(*v, "silent"))
     492           0 :                         ctrl |= WINBIND_SILENT;
     493         284 :                 else if (!strcasecmp(*v, "use_authtok"))
     494           8 :                         ctrl |= WINBIND_USE_AUTHTOK_ARG;
     495         276 :                 else if (!strcasecmp(*v, "try_authtok"))
     496           8 :                         ctrl |= WINBIND_TRY_AUTHTOK_ARG;
     497         268 :                 else if (!strcasecmp(*v, "use_first_pass"))
     498           0 :                         ctrl |= WINBIND_USE_FIRST_PASS_ARG;
     499         268 :                 else if (!strcasecmp(*v, "try_first_pass"))
     500           0 :                         ctrl |= WINBIND_TRY_FIRST_PASS_ARG;
     501         268 :                 else if (!strcasecmp(*v, "unknown_ok"))
     502           0 :                         ctrl |= WINBIND_UNKNOWN_OK_ARG;
     503         268 :                 else if ((type == PAM_WINBIND_AUTHENTICATE
     504          24 :                           || type == PAM_WINBIND_SETCRED)
     505         244 :                          && !strncasecmp(*v, "require_membership_of",
     506             :                                          strlen("require_membership_of")))
     507           0 :                         ctrl |= WINBIND_REQUIRED_MEMBERSHIP;
     508         268 :                 else if ((type == PAM_WINBIND_AUTHENTICATE
     509          24 :                           || type == PAM_WINBIND_SETCRED)
     510         244 :                          && !strncasecmp(*v, "require-membership-of",
     511             :                                          strlen("require-membership-of")))
     512           0 :                         ctrl |= WINBIND_REQUIRED_MEMBERSHIP;
     513         268 :                 else if (!strcasecmp(*v, "krb5_auth"))
     514         130 :                         ctrl |= WINBIND_KRB5_AUTH;
     515         138 :                 else if (!strncasecmp(*v, "krb5_ccache_type",
     516             :                                       strlen("krb5_ccache_type")))
     517         130 :                         ctrl |= WINBIND_KRB5_CCACHE_TYPE;
     518           8 :                 else if (!strcasecmp(*v, "cached_login"))
     519           0 :                         ctrl |= WINBIND_CACHED_LOGIN;
     520           8 :                 else if (!strcasecmp(*v, "mkhomedir"))
     521           0 :                         ctrl |= WINBIND_MKHOMEDIR;
     522           8 :                 else if (!strncasecmp(*v, "warn_pwd_expire",
     523             :                         strlen("warn_pwd_expire")))
     524           8 :                         ctrl |= WINBIND_WARN_PWD_EXPIRE;
     525           0 :                 else if (type != PAM_WINBIND_CLEANUP) {
     526           0 :                         __pam_log(pamh, ctrl, LOG_ERR,
     527             :                                  "pam_parse: unknown option: %s", *v);
     528           0 :                         return -1;
     529             :                 }
     530             : 
     531             :         }
     532             : 
     533         448 :         if (result_d) {
     534         260 :                 *result_d = d;
     535             :         } else {
     536         188 :                 if (d) {
     537           0 :                         tiniparser_freedict(d);
     538             :                 }
     539             :         }
     540             : 
     541         448 :         return ctrl;
     542             : };
     543             : 
     544         260 : static int _pam_winbind_free_context(struct pwb_context *ctx)
     545             : {
     546         260 :         if (!ctx) {
     547           0 :                 return 0;
     548             :         }
     549             : 
     550         260 :         if (ctx->dict) {
     551           0 :                 tiniparser_freedict(ctx->dict);
     552             :         }
     553             : 
     554         260 :         wbcCtxFree(ctx->wbc_ctx);
     555             : 
     556         260 :         return 0;
     557             : }
     558             : 
     559         260 : static int _pam_winbind_init_context(pam_handle_t *pamh,
     560             :                                      int flags,
     561             :                                      int argc,
     562             :                                      const char **argv,
     563             :                                      enum pam_winbind_request_type type,
     564             :                                      struct pwb_context **ctx_p)
     565             : {
     566         260 :         struct pwb_context *r = NULL;
     567         260 :         const char *service = NULL;
     568         260 :         char service_name[32] = {0};
     569             :         int ctrl_code;
     570             : 
     571             : #ifdef HAVE_GETTEXT
     572         260 :         textdomain_init();
     573             : #endif
     574             : 
     575         260 :         r = talloc_zero(NULL, struct pwb_context);
     576         260 :         if (!r) {
     577           0 :                 return PAM_BUF_ERR;
     578             :         }
     579             : 
     580         260 :         talloc_set_destructor(r, _pam_winbind_free_context);
     581             : 
     582         260 :         r->pamh = pamh;
     583         260 :         r->flags = flags;
     584         260 :         r->argc = argc;
     585         260 :         r->argv = argv;
     586         260 :         ctrl_code = _pam_parse(pamh, flags, argc, argv, type, &r->dict);
     587         260 :         if (ctrl_code == -1) {
     588           0 :                 TALLOC_FREE(r);
     589           0 :                 return PAM_SYSTEM_ERR;
     590             :         }
     591         260 :         r->ctrl = ctrl_code;
     592             : 
     593         260 :         r->wbc_ctx = wbcCtxCreate();
     594         260 :         if (r->wbc_ctx == NULL) {
     595           0 :                 TALLOC_FREE(r);
     596           0 :                 return PAM_SYSTEM_ERR;
     597             :         }
     598             : 
     599         260 :         pam_get_item(pamh, PAM_SERVICE, (const void **)&service);
     600             : 
     601         260 :         snprintf(service_name, sizeof(service_name), "PAM_WINBIND[%s]", service);
     602             : 
     603         260 :         wbcSetClientProcessName(service_name);
     604             : 
     605         260 :         *ctx_p = r;
     606             : 
     607         260 :         return PAM_SUCCESS;
     608             : }
     609             : 
     610         188 : static void _pam_winbind_cleanup_func(pam_handle_t *pamh,
     611             :                                       void *data,
     612             :                                       int error_status)
     613             : {
     614         188 :         int ctrl = _pam_parse(pamh, 0, 0, NULL, PAM_WINBIND_CLEANUP, NULL);
     615         188 :         if (_pam_log_is_debug_state_enabled(ctrl)) {
     616           0 :                 __pam_log_debug(pamh, ctrl, LOG_DEBUG,
     617             :                                "[pamh: %p] CLEAN: cleaning up PAM data %p "
     618             :                                "(error_status = %d)", pamh, data,
     619             :                                error_status);
     620             :         }
     621         188 :         TALLOC_FREE(data);
     622         188 : }
     623             : 
     624             : 
     625             : static const struct ntstatus_errors {
     626             :         const char *ntstatus_string;
     627             :         const char *error_string;
     628             : } ntstatus_errors[] = {
     629             :         {"NT_STATUS_OK",
     630             :                 N_("Success")},
     631             :         {"NT_STATUS_BACKUP_CONTROLLER",
     632             :                 N_("No primary Domain Controller available")},
     633             :         {"NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND",
     634             :                 N_("No domain controllers found")},
     635             :         {"NT_STATUS_NO_LOGON_SERVERS",
     636             :                 N_("No logon servers")},
     637             :         {"NT_STATUS_PWD_TOO_SHORT",
     638             :                 N_("Password too short")},
     639             :         {"NT_STATUS_PWD_TOO_RECENT",
     640             :                 N_("The password was recently changed and cannot be changed again before %s")},
     641             :         {"NT_STATUS_PWD_HISTORY_CONFLICT",
     642             :                 N_("Password is already in password history")},
     643             :         {"NT_STATUS_PASSWORD_EXPIRED",
     644             :                 N_("Your password has expired")},
     645             :         {"NT_STATUS_PASSWORD_MUST_CHANGE",
     646             :                 N_("You need to change your password now")},
     647             :         {"NT_STATUS_INVALID_WORKSTATION",
     648             :                 N_("You are not allowed to logon from this workstation")},
     649             :         {"NT_STATUS_INVALID_LOGON_HOURS",
     650             :                 N_("You are not allowed to logon at this time")},
     651             :         {"NT_STATUS_ACCOUNT_EXPIRED",
     652             :                 N_("Your account has expired. "
     653             :                    "Please contact your System administrator")}, /* SCNR */
     654             :         {"NT_STATUS_ACCOUNT_DISABLED",
     655             :                 N_("Your account is disabled. "
     656             :                    "Please contact your System administrator")}, /* SCNR */
     657             :         {"NT_STATUS_ACCOUNT_LOCKED_OUT",
     658             :                 N_("Your account has been locked. "
     659             :                    "Please contact your System administrator")}, /* SCNR */
     660             :         {"NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT",
     661             :                 N_("Invalid Trust Account")},
     662             :         {"NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT",
     663             :                 N_("Invalid Trust Account")},
     664             :         {"NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT",
     665             :                 N_("Invalid Trust Account")},
     666             :         {"NT_STATUS_ACCESS_DENIED",
     667             :                 N_("Access is denied")},
     668             :         {NULL, NULL}
     669             : };
     670             : 
     671          52 : static const char *_get_ntstatus_error_string(const char *nt_status_string)
     672             : {
     673             :         int i;
     674         988 :         for (i=0; ntstatus_errors[i].ntstatus_string != NULL; i++) {
     675         936 :                 if (!strcasecmp(ntstatus_errors[i].ntstatus_string,
     676             :                                 nt_status_string)) {
     677           0 :                         return _(ntstatus_errors[i].error_string);
     678             :                 }
     679             :         }
     680          52 :         return NULL;
     681             : }
     682             : 
     683             : /* --- authentication management functions --- */
     684             : 
     685             : /* Attempt a conversation */
     686             : 
     687         312 : static int converse(const pam_handle_t *pamh,
     688             :                     int nargs,
     689             :                     const struct pam_message **message,
     690             :                     struct pam_response **response)
     691             : {
     692             :         int retval;
     693             :         const struct pam_conv *conv;
     694             : 
     695         312 :         retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv);
     696         312 :         if (retval == PAM_SUCCESS) {
     697         468 :                 retval = conv->conv(nargs,
     698             :                                     discard_const_p(const struct pam_message *, message),
     699         312 :                                     response, conv->appdata_ptr);
     700             :         }
     701             : 
     702         312 :         return retval; /* propagate error status */
     703             : }
     704             : 
     705             : 
     706          56 : static int _make_remark(struct pwb_context *ctx,
     707             :                         int type,
     708             :                         const char *text)
     709             : {
     710          56 :         int retval = PAM_SUCCESS;
     711             : 
     712             :         const struct pam_message *pmsg[1];
     713             :         struct pam_message msg[1];
     714             :         struct pam_response *resp;
     715             : 
     716          56 :         if (ctx->flags & WINBIND_SILENT) {
     717           0 :                 return PAM_SUCCESS;
     718             :         }
     719             : 
     720          56 :         pmsg[0] = &msg[0];
     721          56 :         msg[0].msg = discard_const_p(char, text);
     722          56 :         msg[0].msg_style = type;
     723             : 
     724          56 :         resp = NULL;
     725          56 :         retval = converse(ctx->pamh, 1, pmsg, &resp);
     726             : 
     727          56 :         if (resp) {
     728        3436 :                 _pam_drop_reply(resp, 1);
     729             :         }
     730          56 :         return retval;
     731             : }
     732             : 
     733             : static int _make_remark_v(struct pwb_context *ctx,
     734             :                           int type,
     735             :                           const char *format,
     736             :                           va_list args) PRINTF_ATTRIBUTE(3, 0);
     737             : 
     738           4 : static int _make_remark_v(struct pwb_context *ctx,
     739             :                           int type,
     740             :                           const char *format,
     741             :                           va_list args)
     742             : {
     743             :         char *var;
     744             :         int ret;
     745             : 
     746           4 :         ret = vasprintf(&var, format, args);
     747           4 :         if (ret < 0) {
     748           0 :                 _pam_log(ctx, LOG_ERR, "memory allocation failure");
     749           0 :                 return ret;
     750             :         }
     751             : 
     752           4 :         ret = _make_remark(ctx, type, var);
     753           4 :         SAFE_FREE(var);
     754           4 :         return ret;
     755             : }
     756             : 
     757             : static int _make_remark_format(struct pwb_context *ctx, int type, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
     758           4 : static int _make_remark_format(struct pwb_context *ctx, int type, const char *format, ...)
     759             : {
     760             :         int ret;
     761             :         va_list args;
     762             : 
     763           4 :         va_start(args, format);
     764           4 :         ret = _make_remark_v(ctx, type, format, args);
     765           4 :         va_end(args);
     766           4 :         return ret;
     767             : }
     768             : 
     769         260 : static int pam_winbind_request_log(struct pwb_context *ctx,
     770             :                                    int retval,
     771             :                                    const char *user,
     772             :                                    const char *fn)
     773             : {
     774         260 :         switch (retval) {
     775          76 :         case PAM_AUTH_ERR:
     776             :                 /* incorrect password */
     777          76 :                 _pam_log(ctx, LOG_WARNING, "user '%s' denied access "
     778             :                          "(incorrect password or invalid membership)", user);
     779          76 :                 return retval;
     780           0 :         case PAM_ACCT_EXPIRED:
     781             :                 /* account expired */
     782           0 :                 _pam_log(ctx, LOG_WARNING, "user '%s' account expired",
     783             :                          user);
     784           0 :                 return retval;
     785           0 :         case PAM_AUTHTOK_EXPIRED:
     786             :                 /* password expired */
     787           0 :                 _pam_log(ctx, LOG_WARNING, "user '%s' password expired",
     788             :                          user);
     789           0 :                 return retval;
     790           0 :         case PAM_NEW_AUTHTOK_REQD:
     791             :                 /* new password required */
     792           0 :                 _pam_log(ctx, LOG_WARNING, "user '%s' new password "
     793             :                          "required", user);
     794           0 :                 return retval;
     795           0 :         case PAM_USER_UNKNOWN:
     796             :                 /* the user does not exist */
     797           0 :                 _pam_log_debug(ctx, LOG_NOTICE, "user '%s' not found",
     798             :                                user);
     799           0 :                 if (ctx->ctrl & WINBIND_UNKNOWN_OK_ARG) {
     800           0 :                         return PAM_IGNORE;
     801             :                 }
     802           0 :                 return retval;
     803           0 :         case PAM_AUTHTOK_ERR:
     804             :                 /* Authentication token manipulation error */
     805           0 :                 _pam_log(ctx, LOG_WARNING, "user `%s' authentication token change failed "
     806             :                         "(pwd complexity/history/min_age not met?)", user);
     807           0 :                 return retval;
     808         184 :         case PAM_SUCCESS:
     809             :                 /* Otherwise, the authentication looked good */
     810         184 :                 if (strcmp(fn, "wbcLogonUser") == 0) {
     811         172 :                         _pam_log(ctx, LOG_NOTICE,
     812             :                                  "user '%s' granted access", user);
     813             :                 } else {
     814          12 :                         _pam_log(ctx, LOG_NOTICE,
     815             :                                  "user '%s' OK", user);
     816             :                 }
     817         184 :                 return retval;
     818           0 :         default:
     819             :                 /* we don't know anything about this return value */
     820           0 :                 _pam_log(ctx, LOG_ERR,
     821             :                          "internal module error (retval = %s(%d), user = '%s')",
     822             :                         _pam_error_code_str(retval), retval, user);
     823           0 :                 return retval;
     824             :         }
     825             : }
     826             : 
     827         260 : static int wbc_auth_error_to_pam_error(struct pwb_context *ctx,
     828             :                                        struct wbcAuthErrorInfo *e,
     829             :                                        wbcErr status,
     830             :                                        const char *username,
     831             :                                        const char *fn)
     832             : {
     833         260 :         int ret = PAM_AUTH_ERR;
     834             : 
     835         260 :         if (WBC_ERROR_IS_OK(status)) {
     836         184 :                 _pam_log_debug(ctx, LOG_DEBUG, "request %s succeeded",
     837             :                         fn);
     838         184 :                 ret = PAM_SUCCESS;
     839         184 :                 return pam_winbind_request_log(ctx, ret, username, fn);
     840             :         }
     841             : 
     842          76 :         if (e) {
     843          76 :                 if (e->pam_error != PAM_SUCCESS) {
     844          76 :                         _pam_log(ctx, LOG_ERR,
     845             :                                  "request %s failed: %s, "
     846             :                                  "PAM error: %s (%d), NTSTATUS: %s, "
     847             :                                  "Error message was: %s",
     848             :                                  fn,
     849             :                                  wbcErrorString(status),
     850             :                                  _pam_error_code_str(e->pam_error),
     851             :                                  e->pam_error,
     852             :                                  e->nt_string,
     853             :                                  e->display_string);
     854          76 :                         ret = e->pam_error;
     855          76 :                         return pam_winbind_request_log(ctx, ret, username, fn);
     856             :                 }
     857             : 
     858           0 :                 _pam_log(ctx, LOG_ERR, "request %s failed, but PAM error 0!", fn);
     859             : 
     860           0 :                 ret = PAM_SERVICE_ERR;
     861           0 :                 return pam_winbind_request_log(ctx, ret, username, fn);
     862             :         }
     863             : 
     864           0 :         ret = wbc_error_to_pam_error(status);
     865           0 :         _pam_log(ctx, LOG_ERR,
     866             :                  "request %s failed: %s, PAM error: %s (%d)!",
     867             :                  fn, wbcErrorString(status),
     868             :                  _pam_error_code_str(ret), ret);
     869           0 :         return pam_winbind_request_log(ctx, ret, username, fn);
     870             : }
     871             : 
     872             : #if defined(HAVE_PAM_RADIO_TYPE)
     873           4 : static bool _pam_winbind_change_pwd(struct pwb_context *ctx)
     874             : {
     875             :         struct pam_message msg;
     876             :         const struct pam_message *pmsg;
     877           4 :         struct pam_response *resp = NULL;
     878             :         int ret;
     879           4 :         bool retval = false;
     880           4 :         pmsg = &msg;
     881           4 :         msg.msg_style = PAM_RADIO_TYPE;
     882           4 :         msg.msg = _("Do you want to change your password now?");
     883           4 :         ret = converse(ctx->pamh, 1, &pmsg, &resp);
     884           4 :         if (resp == NULL) {
     885           0 :                 if (ret == PAM_SUCCESS) {
     886           0 :                         _pam_log(ctx, LOG_CRIT, "pam_winbind: system error!\n");
     887           0 :                         return false;
     888             :                 }
     889             :         }
     890           4 :         if (ret != PAM_SUCCESS) {
     891           0 :                 return false;
     892             :         }
     893           4 :         _pam_log(ctx, LOG_CRIT, "Received [%s] reply from application.\n", resp->resp);
     894             : 
     895           4 :         if ((resp->resp != NULL) && (strcasecmp(resp->resp, "yes") == 0)) {
     896           0 :                 retval = true;
     897             :         }
     898             : 
     899           6 :         _pam_drop_reply(resp, 1);
     900           4 :         return retval;
     901             : }
     902             : #else
     903             : static bool _pam_winbind_change_pwd(struct pwb_context *ctx)
     904             : {
     905             :         return false;
     906             : }
     907             : #endif
     908             : 
     909             : /**
     910             :  * send a password expiry message if required
     911             :  *
     912             :  * @param ctx PAM winbind context.
     913             :  * @param next_change expected (calculated) next expiry date.
     914             :  * @param already_expired pointer to a boolean to indicate if the password is
     915             :  *        already expired.
     916             :  *
     917             :  * @return boolean Returns true if message has been sent, false if not.
     918             :  */
     919             : 
     920         172 : static bool _pam_send_password_expiry_message(struct pwb_context *ctx,
     921             :                                               time_t next_change,
     922             :                                               time_t now,
     923             :                                               int warn_pwd_expire,
     924             :                                               bool *already_expired,
     925             :                                               bool *change_pwd)
     926             : {
     927         172 :         int days = 0;
     928             :         struct tm tm_now, tm_next_change;
     929         172 :         bool retval = false;
     930             :         int ret;
     931             : 
     932         172 :         if (already_expired) {
     933         172 :                 *already_expired = false;
     934             :         }
     935             : 
     936         172 :         if (change_pwd) {
     937         172 :                 *change_pwd = false;
     938             :         }
     939             : 
     940         172 :         if (next_change <= now) {
     941           0 :                 PAM_WB_REMARK_DIRECT(ctx, "NT_STATUS_PASSWORD_EXPIRED");
     942           0 :                 if (already_expired) {
     943           0 :                         *already_expired = true;
     944             :                 }
     945           0 :                 return true;
     946             :         }
     947             : 
     948         258 :         if ((next_change < 0) ||
     949         172 :             (next_change > now + warn_pwd_expire * SECONDS_PER_DAY)) {
     950         168 :                 return false;
     951             :         }
     952             : 
     953           8 :         if ((localtime_r(&now, &tm_now) == NULL) ||
     954           4 :             (localtime_r(&next_change, &tm_next_change) == NULL)) {
     955           0 :                 return false;
     956             :         }
     957             : 
     958           6 :         days = (tm_next_change.tm_yday+tm_next_change.tm_year*365) -
     959           4 :                (tm_now.tm_yday+tm_now.tm_year*365);
     960             : 
     961           4 :         if (days == 0) {
     962           0 :                 ret = _make_remark(ctx, PAM_TEXT_INFO,
     963           0 :                                 _("Your password expires today.\n"));
     964             : 
     965             :                 /*
     966             :                  * If change_pwd and already_expired is null.
     967             :                  * We are just sending a notification message.
     968             :                  * We don't expect any response in this case.
     969             :                  */
     970             : 
     971           0 :                 if (!change_pwd && !already_expired) {
     972           0 :                         return true;
     973             :                 }
     974             : 
     975             :                 /*
     976             :                  * successfully sent the warning message.
     977             :                  * Give the user a chance to change pwd.
     978             :                  */
     979           0 :                 if (ret == PAM_SUCCESS) {
     980           0 :                         if (change_pwd) {
     981           0 :                                 retval = _pam_winbind_change_pwd(ctx);
     982           0 :                                 if (retval) {
     983           0 :                                         *change_pwd = true;
     984             :                                 }
     985             :                         }
     986             :                 }
     987           0 :                 return true;
     988             :         }
     989             : 
     990           4 :         if (days > 0 && days < warn_pwd_expire) {
     991             : 
     992           6 :                 ret = _make_remark_format(ctx, PAM_TEXT_INFO,
     993           4 :                                         _("Your password will expire in %d %s.\n"),
     994           2 :                                         days, (days > 1) ? _("days"):_("day"));
     995             :                 /*
     996             :                  * If change_pwd and already_expired is null.
     997             :                  * We are just sending a notification message.
     998             :                  * We don't expect any response in this case.
     999             :                  */
    1000             : 
    1001           4 :                 if (!change_pwd && !already_expired) {
    1002           0 :                         return true;
    1003             :                 }
    1004             : 
    1005             :                 /*
    1006             :                  * successfully sent the warning message.
    1007             :                  * Give the user a chance to change pwd.
    1008             :                  */
    1009           4 :                 if (ret == PAM_SUCCESS) {
    1010           4 :                         if (change_pwd) {
    1011           4 :                                 retval = _pam_winbind_change_pwd(ctx);
    1012           4 :                                 if (retval) {
    1013           0 :                                         *change_pwd = true;
    1014             :                                 }
    1015             :                         }
    1016             :                 }
    1017           4 :                 return true;
    1018             :         }
    1019             : 
    1020           0 :         return false;
    1021             : }
    1022             : 
    1023             : /**
    1024             :  * Send a warning if the password expires in the near future
    1025             :  *
    1026             :  * @param ctx PAM winbind context.
    1027             :  * @param response The full authentication response structure.
    1028             :  * @param already_expired boolean, is the pwd already expired?
    1029             :  *
    1030             :  * @return void.
    1031             :  */
    1032             : 
    1033         172 : static void _pam_warn_password_expiry(struct pwb_context *ctx,
    1034             :                                       const struct wbcAuthUserInfo *info,
    1035             :                                       int warn_pwd_expire,
    1036             :                                       bool *already_expired,
    1037             :                                       bool *change_pwd)
    1038             : {
    1039         172 :         time_t now = time(NULL);
    1040         172 :         time_t next_change = 0;
    1041             : 
    1042         172 :         if (info == NULL) {
    1043           0 :                 return;
    1044             :         }
    1045             : 
    1046         172 :         if (already_expired) {
    1047         172 :                 *already_expired = false;
    1048             :         }
    1049             : 
    1050         172 :         if (change_pwd) {
    1051         172 :                 *change_pwd = false;
    1052             :         }
    1053             : 
    1054             :         /* accounts with WBC_ACB_PWNOEXP set never receive a warning */
    1055         172 :         if (info->acct_flags & WBC_ACB_PWNOEXP) {
    1056           0 :                 return;
    1057             :         }
    1058             : 
    1059             :         /* no point in sending a warning if this is a grace logon */
    1060         172 :         if (PAM_WB_GRACE_LOGON(info->user_flags)) {
    1061           0 :                 return;
    1062             :         }
    1063             : 
    1064             :         /* check if the info3 must change timestamp has been set */
    1065         172 :         next_change = info->pass_must_change_time;
    1066             : 
    1067         172 :         if (_pam_send_password_expiry_message(ctx, next_change, now,
    1068             :                                               warn_pwd_expire,
    1069             :                                               already_expired,
    1070             :                                               change_pwd)) {
    1071           4 :                 return;
    1072             :         }
    1073             : 
    1074             :         /* no warning sent */
    1075             : }
    1076             : 
    1077             : #define IS_SID_STRING(name) (strncmp("S-", name, 2) == 0)
    1078             : 
    1079             : /**
    1080             :  * Append a string, making sure not to overflow and to always return a
    1081             :  * NULL-terminated string.
    1082             :  *
    1083             :  * @param dest Destination string buffer (must already be NULL-terminated).
    1084             :  * @param src Source string buffer.
    1085             :  * @param dest_buffer_size Size of dest buffer in bytes.
    1086             :  *
    1087             :  * @return false if dest buffer is not big enough (no bytes copied), true on
    1088             :  * success.
    1089             :  */
    1090             : 
    1091           0 : static bool safe_append_string(char *dest,
    1092             :                                const char *src,
    1093             :                                int dest_buffer_size)
    1094             : {
    1095             :         size_t len;
    1096           0 :         len = strlcat(dest, src, dest_buffer_size);
    1097           0 :         return (len < dest_buffer_size);
    1098             : }
    1099             : 
    1100             : /**
    1101             :  * Convert a names into a SID string, appending it to a buffer.
    1102             :  *
    1103             :  * @param ctx PAM winbind context.
    1104             :  * @param user User in PAM request.
    1105             :  * @param name Name to convert.
    1106             :  * @param sid_list_buffer Where to append the string sid.
    1107             :  * @param sid_list_buffer Size of sid_list_buffer (in bytes).
    1108             :  *
    1109             :  * @return false on failure, true on success.
    1110             :  */
    1111           0 : static bool winbind_name_to_sid_string(struct pwb_context *ctx,
    1112             :                                        const char *user,
    1113             :                                        const char *name,
    1114             :                                        char *sid_list_buffer,
    1115             :                                        int sid_list_buffer_size)
    1116             : {
    1117             :         char sid_string[WBC_SID_STRING_BUFLEN];
    1118             : 
    1119             :         /* lookup name? */
    1120           0 :         if (IS_SID_STRING(name)) {
    1121           0 :                 strlcpy(sid_string, name, sizeof(sid_string));
    1122             :         } else {
    1123             :                 wbcErr wbc_status;
    1124             :                 struct wbcDomainSid sid;
    1125             :                 enum wbcSidType type;
    1126             : 
    1127           0 :                 _pam_log_debug(ctx, LOG_DEBUG,
    1128             :                                "no sid given, looking up: %s\n", name);
    1129             : 
    1130           0 :                 wbc_status = wbcCtxLookupName(ctx->wbc_ctx,
    1131             :                                               "",
    1132             :                                               name,
    1133             :                                               &sid,
    1134             :                                               &type);
    1135           0 :                 if (!WBC_ERROR_IS_OK(wbc_status)) {
    1136           0 :                         _pam_log(ctx, LOG_INFO,
    1137             :                                  "could not lookup name: %s\n", name);
    1138           0 :                         return false;
    1139             :                 }
    1140             : 
    1141           0 :                 wbcSidToStringBuf(&sid, sid_string, sizeof(sid_string));
    1142             :         }
    1143             : 
    1144           0 :         if (!safe_append_string(sid_list_buffer, sid_string,
    1145             :                                 sid_list_buffer_size)) {
    1146           0 :                 return false;
    1147             :         }
    1148           0 :         return true;
    1149             : }
    1150             : 
    1151             : /**
    1152             :  * Convert a list of names into a list of sids.
    1153             :  *
    1154             :  * @param ctx PAM winbind context.
    1155             :  * @param user User in PAM request.
    1156             :  * @param name_list List of names or string sids, separated by commas.
    1157             :  * @param sid_list_buffer Where to put the list of string sids.
    1158             :  * @param sid_list_buffer Size of sid_list_buffer (in bytes).
    1159             :  *
    1160             :  * @return false on failure, true on success.
    1161             :  */
    1162           0 : static bool winbind_name_list_to_sid_string_list(struct pwb_context *ctx,
    1163             :                                                  const char *user,
    1164             :                                                  const char *name_list,
    1165             :                                                  char *sid_list_buffer,
    1166             :                                                  int sid_list_buffer_size)
    1167             : {
    1168           0 :         bool result = false;
    1169           0 :         char *current_name = NULL;
    1170             :         const char *search_location;
    1171             :         const char *comma;
    1172             :         int len;
    1173             : 
    1174           0 :         if (sid_list_buffer_size > 0) {
    1175           0 :                 sid_list_buffer[0] = 0;
    1176             :         }
    1177             : 
    1178           0 :         search_location = name_list;
    1179           0 :         while ((comma = strchr(search_location, ',')) != NULL) {
    1180           0 :                 current_name = strndup(search_location,
    1181           0 :                                        comma - search_location);
    1182           0 :                 if (NULL == current_name) {
    1183           0 :                         goto out;
    1184             :                 }
    1185             : 
    1186           0 :                 if (!winbind_name_to_sid_string(ctx, user,
    1187             :                                                 current_name,
    1188             :                                                 sid_list_buffer,
    1189             :                                                 sid_list_buffer_size)) {
    1190             :                         /*
    1191             :                          * If one group name failed, we must not fail
    1192             :                          * the authentication totally, continue with
    1193             :                          * the following group names. If user belongs to
    1194             :                          * one of the valid groups, we must allow it
    1195             :                          * login. -- BoYang
    1196             :                          */
    1197             : 
    1198           0 :                         _pam_log(ctx, LOG_INFO, "cannot convert group %s to sid, "
    1199             :                                  "check if group %s is valid group.", current_name,
    1200             :                                  current_name);
    1201           0 :                         _make_remark_format(ctx, PAM_TEXT_INFO, _("Cannot convert group %s "
    1202             :                                         "to sid, please contact your administrator to see "
    1203             :                                         "if group %s is valid."), current_name, current_name);
    1204           0 :                         SAFE_FREE(current_name);
    1205           0 :                         search_location = comma + 1;
    1206           0 :                         continue;
    1207             :                 }
    1208             : 
    1209           0 :                 SAFE_FREE(current_name);
    1210             : 
    1211           0 :                 if (!safe_append_string(sid_list_buffer, ",",
    1212             :                                         sid_list_buffer_size)) {
    1213           0 :                         goto out;
    1214             :                 }
    1215             : 
    1216           0 :                 search_location = comma + 1;
    1217             :         }
    1218             : 
    1219           0 :         if (!winbind_name_to_sid_string(ctx, user, search_location,
    1220             :                                         sid_list_buffer,
    1221             :                                         sid_list_buffer_size)) {
    1222           0 :                 _pam_log(ctx, LOG_INFO, "cannot convert group %s to sid, "
    1223             :                          "check if group %s is valid group.", search_location,
    1224             :                          search_location);
    1225           0 :                 _make_remark_format(ctx, PAM_TEXT_INFO, _("Cannot convert group %s "
    1226             :                                 "to sid, please contact your administrator to see "
    1227             :                                 "if group %s is valid."), search_location, search_location);
    1228             : 
    1229             :                 /* If no valid groups were converted we should fail outright */
    1230           0 :                 if (name_list != NULL && strlen(sid_list_buffer) == 0) {
    1231           0 :                         result = false;
    1232           0 :                         goto out;
    1233             :                 }
    1234             :                 /*
    1235             :                  * The lookup of the last name failed..
    1236             :                  * It results in require_member_of_sid ends with ','
    1237             :                  * It is malformatted parameter here, overwrite the last ','.
    1238             :                  */
    1239           0 :                 len = strlen(sid_list_buffer);
    1240           0 :                 if ((len != 0) && (sid_list_buffer[len - 1] == ',')) {
    1241           0 :                         sid_list_buffer[len - 1] = '\0';
    1242             :                 }
    1243             :         }
    1244             : 
    1245           0 :         result = true;
    1246             : 
    1247           0 : out:
    1248           0 :         SAFE_FREE(current_name);
    1249           0 :         return result;
    1250             : }
    1251             : 
    1252             : /**
    1253             :  * put krb5ccname variable into environment
    1254             :  *
    1255             :  * @param ctx PAM winbind context.
    1256             :  * @param krb5ccname env variable retrieved from winbindd.
    1257             :  *
    1258             :  * @return void.
    1259             :  */
    1260             : 
    1261         172 : static void _pam_setup_krb5_env(struct pwb_context *ctx,
    1262             :                                 struct wbcLogonUserInfo *info)
    1263             : {
    1264         172 :         char *var = NULL;
    1265             :         int ret;
    1266             :         uint32_t i;
    1267         172 :         const char *krb5ccname = NULL;
    1268             : 
    1269         172 :         if (off(ctx->ctrl, WINBIND_KRB5_AUTH)) {
    1270         163 :                 return;
    1271             :         }
    1272             : 
    1273          86 :         if (!info) {
    1274           0 :                 return;
    1275             :         }
    1276             : 
    1277         114 :         for (i=0; i < info->num_blobs; i++) {
    1278          80 :                 if (strcasecmp(info->blobs[i].name, "krb5ccname") == 0) {
    1279          52 :                         krb5ccname = (const char *)info->blobs[i].blob.data;
    1280          52 :                         break;
    1281             :                 }
    1282             :         }
    1283             : 
    1284          86 :         if (!krb5ccname || (strlen(krb5ccname) == 0)) {
    1285          34 :                 return;
    1286             :         }
    1287             : 
    1288          52 :         _pam_log_debug(ctx, LOG_DEBUG,
    1289             :                        "request returned KRB5CCNAME: %s", krb5ccname);
    1290             : 
    1291          52 :         if (asprintf(&var, "KRB5CCNAME=%s", krb5ccname) == -1) {
    1292           0 :                 return;
    1293             :         }
    1294             : 
    1295          52 :         ret = pam_putenv(ctx->pamh, var);
    1296          52 :         if (ret != PAM_SUCCESS) {
    1297           0 :                 _pam_log(ctx, LOG_ERR,
    1298             :                          "failed to set KRB5CCNAME to %s: %s",
    1299             :                          var, pam_strerror(ctx->pamh, ret));
    1300             :         }
    1301          52 :         free(var);
    1302             : }
    1303             : 
    1304             : /**
    1305             :  * Copy unix username if available (further processed in PAM).
    1306             :  *
    1307             :  * @param ctx PAM winbind context
    1308             :  * @param user_ret A pointer that holds a pointer to a string
    1309             :  * @param unix_username A username
    1310             :  *
    1311             :  * @return void.
    1312             :  */
    1313             : 
    1314         172 : static void _pam_setup_unix_username(struct pwb_context *ctx,
    1315             :                                      char **user_ret,
    1316             :                                      struct wbcLogonUserInfo *info)
    1317             : {
    1318         172 :         const char *unix_username = NULL;
    1319             :         uint32_t i;
    1320             : 
    1321         172 :         if (!user_ret || !info) {
    1322          12 :                 return;
    1323             :         }
    1324             : 
    1325         212 :         for (i=0; i < info->num_blobs; i++) {
    1326         212 :                 if (strcasecmp(info->blobs[i].name, "unix_username") == 0) {
    1327         160 :                         unix_username = (const char *)info->blobs[i].blob.data;
    1328         160 :                         break;
    1329             :                 }
    1330             :         }
    1331             : 
    1332         160 :         if (!unix_username || !unix_username[0]) {
    1333           0 :                 return;
    1334             :         }
    1335             : 
    1336         160 :         *user_ret = strdup(unix_username);
    1337             : }
    1338             : 
    1339             : /**
    1340             :  * Set string into the PAM stack.
    1341             :  *
    1342             :  * @param ctx PAM winbind context.
    1343             :  * @param data_name Key name for pam_set_data.
    1344             :  * @param value String value.
    1345             :  *
    1346             :  * @return void.
    1347             :  */
    1348             : 
    1349         688 : static void _pam_set_data_string(struct pwb_context *ctx,
    1350             :                                  const char *data_name,
    1351             :                                  const char *value)
    1352             : {
    1353             :         int ret;
    1354             : 
    1355        1032 :         if (!data_name || !value || (strlen(data_name) == 0) ||
    1356         688 :              (strlen(value) == 0)) {
    1357         500 :                 return;
    1358             :         }
    1359             : 
    1360         188 :         ret = pam_set_data(ctx->pamh, data_name, talloc_strdup(NULL, value),
    1361             :                            _pam_winbind_cleanup_func);
    1362         188 :         if (ret != PAM_SUCCESS) {
    1363           0 :                 _pam_log_debug(ctx, LOG_DEBUG,
    1364             :                                "Could not set data %s: %s\n",
    1365             :                                data_name, pam_strerror(ctx->pamh, ret));
    1366             :         }
    1367             : }
    1368             : 
    1369             : /**
    1370             :  * Set info3 strings into the PAM stack.
    1371             :  *
    1372             :  * @param ctx PAM winbind context.
    1373             :  * @param data_name Key name for pam_set_data.
    1374             :  * @param value String value.
    1375             :  *
    1376             :  * @return void.
    1377             :  */
    1378             : 
    1379         172 : static void _pam_set_data_info3(struct pwb_context *ctx,
    1380             :                                 const struct wbcAuthUserInfo *info)
    1381             : {
    1382         172 :         if (info != NULL) {
    1383         172 :                 _pam_set_data_string(ctx, PAM_WINBIND_HOMEDIR,
    1384         172 :                              info->home_directory);
    1385         172 :                 _pam_set_data_string(ctx, PAM_WINBIND_LOGONSCRIPT,
    1386         172 :                              info->logon_script);
    1387         172 :                 _pam_set_data_string(ctx, PAM_WINBIND_LOGONSERVER,
    1388         172 :                              info->logon_server);
    1389         172 :                 _pam_set_data_string(ctx, PAM_WINBIND_PROFILEPATH,
    1390         172 :                              info->profile_path);
    1391             :         }
    1392         172 : }
    1393             : 
    1394             : /**
    1395             :  * Free info3 strings in the PAM stack.
    1396             :  *
    1397             :  * @param pamh PAM handle
    1398             :  *
    1399             :  * @return void.
    1400             :  */
    1401             : 
    1402          76 : static void _pam_free_data_info3(pam_handle_t *pamh)
    1403             : {
    1404          76 :         pam_set_data(pamh, PAM_WINBIND_HOMEDIR, NULL, NULL);
    1405          76 :         pam_set_data(pamh, PAM_WINBIND_LOGONSCRIPT, NULL, NULL);
    1406          76 :         pam_set_data(pamh, PAM_WINBIND_LOGONSERVER, NULL, NULL);
    1407          76 :         pam_set_data(pamh, PAM_WINBIND_PROFILEPATH, NULL, NULL);
    1408          76 : }
    1409             : 
    1410             : /**
    1411             :  * Send PAM_ERROR_MSG for cached or grace logons.
    1412             :  *
    1413             :  * @param ctx PAM winbind context.
    1414             :  * @param username User in PAM request.
    1415             :  * @param info3_user_flgs Info3 flags containing logon type bits.
    1416             :  *
    1417             :  * @return void.
    1418             :  */
    1419             : 
    1420         172 : static void _pam_warn_logon_type(struct pwb_context *ctx,
    1421             :                                  const char *username,
    1422             :                                  uint32_t info3_user_flgs)
    1423             : {
    1424             :         /* inform about logon type */
    1425         172 :         if (PAM_WB_GRACE_LOGON(info3_user_flgs)) {
    1426             : 
    1427           0 :                 _make_remark(ctx, PAM_ERROR_MSG,
    1428           0 :                              _("Grace login. "
    1429             :                                "Please change your password as soon you're "
    1430             :                                "online again"));
    1431           0 :                 _pam_log_debug(ctx, LOG_DEBUG,
    1432             :                                "User %s logged on using grace logon\n",
    1433             :                                username);
    1434             : 
    1435         172 :         } else if (PAM_WB_CACHED_LOGON(info3_user_flgs)) {
    1436             : 
    1437           0 :                 _make_remark(ctx, PAM_ERROR_MSG,
    1438           0 :                              _("Domain Controller unreachable, "
    1439             :                                "using cached credentials instead. "
    1440             :                                "Network resources may be unavailable"));
    1441           0 :                 _pam_log_debug(ctx, LOG_DEBUG,
    1442             :                                "User %s logged on using cached credentials\n",
    1443             :                                username);
    1444             :         }
    1445         172 : }
    1446             : 
    1447             : /**
    1448             :  * Send PAM_ERROR_MSG for krb5 errors.
    1449             :  *
    1450             :  * @param ctx PAM winbind context.
    1451             :  * @param username User in PAM request.
    1452             :  * @param info3_user_flgs Info3 flags containing logon type bits.
    1453             :  *
    1454             :  * @return void.
    1455             :  */
    1456             : 
    1457         172 : static void _pam_warn_krb5_failure(struct pwb_context *ctx,
    1458             :                                    const char *username,
    1459             :                                    uint32_t info3_user_flgs)
    1460             : {
    1461         172 :         if (PAM_WB_KRB5_CLOCK_SKEW(info3_user_flgs)) {
    1462           0 :                 _make_remark(ctx, PAM_ERROR_MSG,
    1463           0 :                              _("Failed to establish your Kerberos Ticket cache "
    1464             :                                "due time differences\n"
    1465             :                                "with the domain controller.  "
    1466             :                                "Please verify the system time.\n"));
    1467           0 :                 _pam_log_debug(ctx, LOG_DEBUG,
    1468             :                                "User %s: Clock skew when getting Krb5 TGT\n",
    1469             :                                username);
    1470             :         }
    1471         172 : }
    1472             : 
    1473        3492 : static bool _pam_check_remark_auth_err(struct pwb_context *ctx,
    1474             :                                        const struct wbcAuthErrorInfo *e,
    1475             :                                        const char *nt_status_string,
    1476             :                                        int *pam_err)
    1477             : {
    1478        3492 :         const char *ntstatus = NULL;
    1479        3492 :         const char *error_string = NULL;
    1480             : 
    1481        3492 :         if (!e || !pam_err) {
    1482        2480 :                 return false;
    1483             :         }
    1484             : 
    1485        1012 :         ntstatus = e->nt_string;
    1486        1012 :         if (!ntstatus) {
    1487           0 :                 return false;
    1488             :         }
    1489             : 
    1490        1012 :         if (strcasecmp(ntstatus, nt_status_string) == 0) {
    1491             : 
    1492          52 :                 error_string = _get_ntstatus_error_string(nt_status_string);
    1493          52 :                 if (error_string) {
    1494           0 :                         _make_remark(ctx, PAM_ERROR_MSG, error_string);
    1495           0 :                         *pam_err = e->pam_error;
    1496           0 :                         return true;
    1497             :                 }
    1498             : 
    1499          52 :                 if (e->display_string) {
    1500          52 :                         _make_remark(ctx, PAM_ERROR_MSG, _(e->display_string));
    1501          52 :                         *pam_err = e->pam_error;
    1502          52 :                         return true;
    1503             :                 }
    1504             : 
    1505           0 :                 _make_remark(ctx, PAM_ERROR_MSG, nt_status_string);
    1506           0 :                 *pam_err = e->pam_error;
    1507             : 
    1508           0 :                 return true;
    1509             :         }
    1510             : 
    1511         960 :         return false;
    1512             : };
    1513             : 
    1514             : /**
    1515             :  * Compose Password Restriction String for a PAM_ERROR_MSG conversation.
    1516             :  *
    1517             :  * @param i The wbcUserPasswordPolicyInfo struct.
    1518             :  *
    1519             :  * @return string (caller needs to talloc_free).
    1520             :  */
    1521             : 
    1522           0 : static char *_pam_compose_pwd_restriction_string(struct pwb_context *ctx,
    1523             :                                                  struct wbcUserPasswordPolicyInfo *i)
    1524             : {
    1525           0 :         char *str = NULL;
    1526             : 
    1527           0 :         if (!i) {
    1528           0 :                 goto failed;
    1529             :         }
    1530             : 
    1531           0 :         str = talloc_asprintf(ctx, _("Your password "));
    1532           0 :         if (!str) {
    1533           0 :                 goto failed;
    1534             :         }
    1535             : 
    1536           0 :         if (i->min_length_password > 0) {
    1537           0 :                 str = talloc_asprintf_append(str,
    1538           0 :                                _("must be at least %d characters; "),
    1539             :                                i->min_length_password);
    1540           0 :                 if (!str) {
    1541           0 :                         goto failed;
    1542             :                 }
    1543             :         }
    1544             : 
    1545           0 :         if (i->password_history > 0) {
    1546           0 :                 str = talloc_asprintf_append(str,
    1547           0 :                                _("cannot repeat any of your previous %d "
    1548             :                                 "passwords; "),
    1549             :                                i->password_history);
    1550           0 :                 if (!str) {
    1551           0 :                         goto failed;
    1552             :                 }
    1553             :         }
    1554             : 
    1555           0 :         if (i->password_properties & WBC_DOMAIN_PASSWORD_COMPLEX) {
    1556           0 :                 str = talloc_asprintf_append(str,
    1557           0 :                                _("must contain capitals, numerals "
    1558             :                                  "or punctuation; "
    1559             :                                  "and cannot contain your account "
    1560             :                                  "or full name; "));
    1561           0 :                 if (!str) {
    1562           0 :                         goto failed;
    1563             :                 }
    1564             :         }
    1565             : 
    1566           0 :         str = talloc_asprintf_append(str,
    1567           0 :                        _("Please type a different password. "
    1568             :                          "Type a password which meets these requirements in "
    1569             :                          "both text boxes."));
    1570           0 :         if (!str) {
    1571           0 :                 goto failed;
    1572             :         }
    1573             : 
    1574           0 :         return str;
    1575             : 
    1576           0 :  failed:
    1577           0 :         TALLOC_FREE(str);
    1578           0 :         return NULL;
    1579             : }
    1580             : 
    1581           0 : static int _pam_create_homedir(struct pwb_context *ctx,
    1582             :                                const char *dirname,
    1583             :                                mode_t mode)
    1584             : {
    1585             :         int ret;
    1586             : 
    1587           0 :         ret = mkdir(dirname, mode);
    1588           0 :         if (ret != 0 && errno == EEXIST) {
    1589             :                 struct stat sbuf;
    1590             : 
    1591           0 :                 ret = stat(dirname, &sbuf);
    1592           0 :                 if (ret != 0) {
    1593           0 :                         return PAM_PERM_DENIED;
    1594             :                 }
    1595             : 
    1596           0 :                 if (!S_ISDIR(sbuf.st_mode)) {
    1597           0 :                         return PAM_PERM_DENIED;
    1598             :                 }
    1599             :         }
    1600             : 
    1601           0 :         if (ret != 0) {
    1602           0 :                 _make_remark_format(ctx, PAM_TEXT_INFO,
    1603           0 :                                     _("Creating directory: %s failed: %s"),
    1604           0 :                                     dirname, strerror(errno));
    1605           0 :                 _pam_log(ctx, LOG_ERR, "could not create dir: %s (%s)",
    1606           0 :                  dirname, strerror(errno));
    1607           0 :                  return PAM_PERM_DENIED;
    1608             :         }
    1609             : 
    1610           0 :         return PAM_SUCCESS;
    1611             : }
    1612             : 
    1613           0 : static int _pam_chown_homedir(struct pwb_context *ctx,
    1614             :                               const char *dirname,
    1615             :                               uid_t uid,
    1616             :                               gid_t gid)
    1617             : {
    1618           0 :         if (chown(dirname, uid, gid) != 0) {
    1619           0 :                 _pam_log(ctx, LOG_ERR, "failed to chown user homedir: %s (%s)",
    1620           0 :                          dirname, strerror(errno));
    1621           0 :                 return PAM_PERM_DENIED;
    1622             :         }
    1623             : 
    1624           0 :         return PAM_SUCCESS;
    1625             : }
    1626             : 
    1627           0 : static int _pam_mkhomedir(struct pwb_context *ctx)
    1628             : {
    1629           0 :         struct passwd *pwd = NULL;
    1630           0 :         char *token = NULL;
    1631           0 :         char *create_dir = NULL;
    1632           0 :         char *user_dir = NULL;
    1633             :         int ret;
    1634             :         const char *username;
    1635           0 :         mode_t mode = 0700;
    1636           0 :         char *safe_ptr = NULL;
    1637           0 :         char *p = NULL;
    1638             : 
    1639             :         /* Get the username */
    1640           0 :         ret = pam_get_user(ctx->pamh, &username, NULL);
    1641           0 :         if ((ret != PAM_SUCCESS) || (!username)) {
    1642           0 :                 _pam_log_debug(ctx, LOG_DEBUG, "can not get the username");
    1643           0 :                 return PAM_SERVICE_ERR;
    1644             :         }
    1645             : 
    1646           0 :         pwd = getpwnam(username);
    1647           0 :         if (pwd == NULL) {
    1648           0 :                 _pam_log_debug(ctx, LOG_DEBUG, "can not get the username");
    1649           0 :                 return PAM_USER_UNKNOWN;
    1650             :         }
    1651           0 :         _pam_log_debug(ctx, LOG_DEBUG, "homedir is: %s", pwd->pw_dir);
    1652             : 
    1653           0 :         ret = _pam_create_homedir(ctx, pwd->pw_dir, 0700);
    1654           0 :         if (ret == PAM_SUCCESS) {
    1655           0 :                 ret = _pam_chown_homedir(ctx, pwd->pw_dir,
    1656             :                                          pwd->pw_uid,
    1657             :                                          pwd->pw_gid);
    1658             :         }
    1659             : 
    1660           0 :         if (ret == PAM_SUCCESS) {
    1661           0 :                 return ret;
    1662             :         }
    1663             : 
    1664             :         /* maybe we need to create parent dirs */
    1665           0 :         create_dir = talloc_strdup(ctx, "/");
    1666           0 :         if (!create_dir) {
    1667           0 :                 return PAM_BUF_ERR;
    1668             :         }
    1669             : 
    1670             :         /* find final directory */
    1671           0 :         user_dir = strrchr(pwd->pw_dir, '/');
    1672           0 :         if (!user_dir) {
    1673           0 :                 return PAM_BUF_ERR;
    1674             :         }
    1675           0 :         user_dir++;
    1676             : 
    1677           0 :         _pam_log(ctx, LOG_DEBUG, "final directory: %s", user_dir);
    1678             : 
    1679           0 :         p = pwd->pw_dir;
    1680             : 
    1681           0 :         while ((token = strtok_r(p, "/", &safe_ptr)) != NULL) {
    1682             : 
    1683           0 :                 mode = 0755;
    1684             : 
    1685           0 :                 p = NULL;
    1686             : 
    1687           0 :                 _pam_log_debug(ctx, LOG_DEBUG, "token is %s", token);
    1688             : 
    1689           0 :                 create_dir = talloc_asprintf_append(create_dir, "%s/", token);
    1690           0 :                 if (!create_dir) {
    1691           0 :                         return PAM_BUF_ERR;
    1692             :                 }
    1693           0 :                 _pam_log_debug(ctx, LOG_DEBUG, "current_dir is %s", create_dir);
    1694             : 
    1695           0 :                 if (strcmp(token, user_dir) == 0) {
    1696           0 :                         _pam_log_debug(ctx, LOG_DEBUG, "assuming last directory: %s", token);
    1697           0 :                         mode = 0700;
    1698             :                 }
    1699             : 
    1700           0 :                 ret = _pam_create_homedir(ctx, create_dir, mode);
    1701           0 :                 if (ret != PAM_SUCCESS) {
    1702           0 :                         return ret;
    1703             :                 }
    1704             :         }
    1705             : 
    1706           0 :         return _pam_chown_homedir(ctx, create_dir,
    1707             :                                   pwd->pw_uid,
    1708             :                                   pwd->pw_gid);
    1709             : }
    1710             : 
    1711             : /* talk to winbindd */
    1712         248 : static int winbind_auth_request(struct pwb_context *ctx,
    1713             :                                 const char *user,
    1714             :                                 const char *pass,
    1715             :                                 const char *member,
    1716             :                                 const char *cctype,
    1717             :                                 const int warn_pwd_expire,
    1718             :                                 struct wbcAuthErrorInfo **p_error,
    1719             :                                 struct wbcLogonUserInfo **p_info,
    1720             :                                 time_t *pwd_last_set,
    1721             :                                 char **user_ret)
    1722             : {
    1723             :         wbcErr wbc_status;
    1724             :         struct wbcLogonUserParams logon;
    1725             :         char membership_of[1024];
    1726         248 :         uid_t user_uid = -1;
    1727         248 :         uint32_t flags = WBFLAG_PAM_INFO3_TEXT;
    1728         248 :         struct wbcLogonUserInfo *info = NULL;
    1729         248 :         struct wbcAuthUserInfo *user_info = NULL;
    1730         248 :         struct wbcAuthErrorInfo *error = NULL;
    1731         248 :         int ret = PAM_AUTH_ERR;
    1732             :         int i;
    1733         248 :         const char *codes[] = {
    1734             :                 "NT_STATUS_PASSWORD_EXPIRED",
    1735             :                 "NT_STATUS_PASSWORD_MUST_CHANGE",
    1736             :                 "NT_STATUS_INVALID_WORKSTATION",
    1737             :                 "NT_STATUS_INVALID_LOGON_HOURS",
    1738             :                 "NT_STATUS_ACCOUNT_EXPIRED",
    1739             :                 "NT_STATUS_ACCOUNT_DISABLED",
    1740             :                 "NT_STATUS_ACCOUNT_LOCKED_OUT",
    1741             :                 "NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT",
    1742             :                 "NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT",
    1743             :                 "NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT",
    1744             :                 "NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND",
    1745             :                 "NT_STATUS_NO_LOGON_SERVERS",
    1746             :                 "NT_STATUS_WRONG_PASSWORD",
    1747             :                 "NT_STATUS_ACCESS_DENIED"
    1748             :         };
    1749             : 
    1750         248 :         if (pwd_last_set) {
    1751          12 :                 *pwd_last_set = 0;
    1752             :         }
    1753             : 
    1754             :         /* Krb5 auth always has to go against the KDC of the user's realm */
    1755             : 
    1756         248 :         if (ctx->ctrl & WINBIND_KRB5_AUTH) {
    1757         124 :                 flags           |= WBFLAG_PAM_CONTACT_TRUSTDOM;
    1758             :         }
    1759             : 
    1760         248 :         if (ctx->ctrl & (WINBIND_KRB5_AUTH|WINBIND_CACHED_LOGIN)) {
    1761         124 :                 struct passwd *pwd = NULL;
    1762             : 
    1763         124 :                 pwd = getpwnam(user);
    1764         124 :                 if (pwd == NULL) {
    1765           0 :                         return PAM_USER_UNKNOWN;
    1766             :                 }
    1767         124 :                 user_uid        = pwd->pw_uid;
    1768             :         }
    1769             : 
    1770         248 :         if (ctx->ctrl & WINBIND_KRB5_AUTH) {
    1771             : 
    1772         124 :                 _pam_log_debug(ctx, LOG_DEBUG,
    1773             :                                "enabling krb5 login flag\n");
    1774             : 
    1775         124 :                 flags           |= WBFLAG_PAM_KRB5 |
    1776             :                                    WBFLAG_PAM_FALLBACK_AFTER_KRB5;
    1777             :         }
    1778             : 
    1779         248 :         if (ctx->ctrl & WINBIND_CACHED_LOGIN) {
    1780           0 :                 _pam_log_debug(ctx, LOG_DEBUG,
    1781             :                                "enabling cached login flag\n");
    1782           0 :                 flags           |= WBFLAG_PAM_CACHED_LOGIN;
    1783             :         }
    1784             : 
    1785         248 :         if (user_ret) {
    1786         236 :                 *user_ret = NULL;
    1787         236 :                 flags           |= WBFLAG_PAM_UNIX_NAME;
    1788             :         }
    1789             : 
    1790         248 :         if (cctype != NULL) {
    1791         118 :                 _pam_log_debug(ctx, LOG_DEBUG,
    1792             :                                "enabling request for a %s krb5 ccache\n",
    1793             :                                cctype);
    1794             :         }
    1795             : 
    1796         248 :         if (member != NULL) {
    1797             : 
    1798           0 :                 ZERO_STRUCT(membership_of);
    1799             : 
    1800           0 :                 if (!winbind_name_list_to_sid_string_list(ctx, user, member,
    1801             :                                                           membership_of,
    1802             :                                                           sizeof(membership_of))) {
    1803           0 :                         _pam_log_debug(ctx, LOG_ERR,
    1804             :                                        "failed to serialize membership of sid "
    1805             :                                        "\"%s\"\n", member);
    1806           0 :                         return PAM_AUTH_ERR;
    1807             :                 }
    1808             :         }
    1809             : 
    1810         248 :         ZERO_STRUCT(logon);
    1811             : 
    1812         248 :         logon.username                  = user;
    1813         248 :         logon.password                  = pass;
    1814             : 
    1815         248 :         if (cctype) {
    1816         118 :                 wbc_status = wbcAddNamedBlob(&logon.num_blobs,
    1817             :                                              &logon.blobs,
    1818             :                                              "krb5_cc_type",
    1819             :                                              0,
    1820             :                                              discard_const_p(uint8_t, cctype),
    1821         118 :                                              strlen(cctype)+1);
    1822         118 :                 if (!WBC_ERROR_IS_OK(wbc_status)) {
    1823           0 :                         goto done;
    1824             :                 }
    1825             :         }
    1826             : 
    1827         248 :         wbc_status = wbcAddNamedBlob(&logon.num_blobs,
    1828             :                                      &logon.blobs,
    1829             :                                      "flags",
    1830             :                                      0,
    1831             :                                      (uint8_t *)&flags,
    1832             :                                      sizeof(flags));
    1833         248 :         if (!WBC_ERROR_IS_OK(wbc_status)) {
    1834           0 :                 goto done;
    1835             :         }
    1836             : 
    1837         248 :         wbc_status = wbcAddNamedBlob(&logon.num_blobs,
    1838             :                                      &logon.blobs,
    1839             :                                      "user_uid",
    1840             :                                      0,
    1841             :                                      (uint8_t *)&user_uid,
    1842             :                                      sizeof(user_uid));
    1843         248 :         if (!WBC_ERROR_IS_OK(wbc_status)) {
    1844           0 :                 goto done;
    1845             :         }
    1846             : 
    1847         248 :         if (member) {
    1848           0 :                 wbc_status = wbcAddNamedBlob(&logon.num_blobs,
    1849             :                                              &logon.blobs,
    1850             :                                              "membership_of",
    1851             :                                              0,
    1852             :                                              (uint8_t *)membership_of,
    1853             :                                              sizeof(membership_of));
    1854           0 :                 if (!WBC_ERROR_IS_OK(wbc_status)) {
    1855           0 :                         goto done;
    1856             :                 }
    1857             :         }
    1858             : 
    1859         248 :         wbc_status = wbcCtxLogonUser(ctx->wbc_ctx,
    1860             :                                      &logon,
    1861             :                                      &info,
    1862             :                                      &error,
    1863             :                                      NULL);
    1864         248 :         ret = wbc_auth_error_to_pam_error(ctx, error, wbc_status,
    1865             :                                           user, "wbcLogonUser");
    1866         248 :         wbcFreeMemory(logon.blobs);
    1867         248 :         logon.blobs = NULL;
    1868             : 
    1869         248 :         if (info && info->info) {
    1870         172 :                 user_info = info->info;
    1871             :         }
    1872             : 
    1873         248 :         if (pwd_last_set && user_info) {
    1874          12 :                 *pwd_last_set = user_info->pass_last_set_time;
    1875             :         }
    1876             : 
    1877         248 :         if (p_info && info) {
    1878           0 :                 *p_info = info;
    1879             :         }
    1880             : 
    1881         248 :         if (p_error && error) {
    1882             :                 /* We want to process the error in the caller. */
    1883           0 :                 *p_error = error;
    1884           0 :                 return ret;
    1885             :         }
    1886             : 
    1887        3616 :         for (i=0; i<ARRAY_SIZE(codes); i++) {
    1888        3420 :                 int _ret = ret;
    1889        3420 :                 if (_pam_check_remark_auth_err(ctx, error, codes[i], &_ret)) {
    1890          52 :                         ret = _ret;
    1891          52 :                         goto done;
    1892             :                 }
    1893             :         }
    1894             : 
    1895         368 :         if ((ret == PAM_SUCCESS) && user_info && info) {
    1896             : 
    1897         172 :                 bool already_expired = false;
    1898         172 :                 bool change_pwd = false;
    1899             : 
    1900             :                 /* warn a user if the password is about to expire soon */
    1901         172 :                 _pam_warn_password_expiry(ctx, user_info,
    1902             :                                           warn_pwd_expire,
    1903             :                                           &already_expired,
    1904             :                                           &change_pwd);
    1905             : 
    1906         172 :                 if (already_expired == true) {
    1907             : 
    1908           0 :                         SMB_TIME_T last_set = user_info->pass_last_set_time;
    1909           0 :                         SMB_TIME_T must_set = user_info->pass_must_change_time;
    1910             : 
    1911           0 :                         _pam_log_debug(ctx, LOG_DEBUG,
    1912             :                                        "Password has expired "
    1913             :                                        "(Password was last set: %lld, "
    1914             :                                        "it must be changed here "
    1915             :                                        "%lld (now it's: %ld))\n",
    1916             :                                        (long long int)last_set,
    1917             :                                        (long long int)must_set,
    1918           0 :                                        (long)time(NULL));
    1919             : 
    1920           0 :                         return PAM_AUTHTOK_EXPIRED;
    1921             :                 }
    1922             : 
    1923         172 :                 if (change_pwd) {
    1924           0 :                         ret = PAM_NEW_AUTHTOK_REQD;
    1925           0 :                         goto done;
    1926             :                 }
    1927             : 
    1928             :                 /* inform about logon type */
    1929         172 :                 _pam_warn_logon_type(ctx, user, user_info->user_flags);
    1930             : 
    1931             :                 /* inform about krb5 failures */
    1932         172 :                 _pam_warn_krb5_failure(ctx, user, user_info->user_flags);
    1933             : 
    1934             :                 /* set some info3 info for other modules in the stack */
    1935         172 :                 _pam_set_data_info3(ctx, user_info);
    1936             : 
    1937             :                 /* put krb5ccname into env */
    1938         172 :                 _pam_setup_krb5_env(ctx, info);
    1939             : 
    1940             :                 /* If winbindd returned a username, return the pointer to it
    1941             :                  * here. */
    1942         172 :                 _pam_setup_unix_username(ctx, user_ret, info);
    1943             :         }
    1944             : 
    1945         148 :  done:
    1946         248 :         wbcFreeMemory(logon.blobs);
    1947         248 :         if (info && info->blobs && !p_info) {
    1948         160 :                 wbcFreeMemory(info->blobs);
    1949             :                 /*
    1950             :                  * We set blobs to NULL to prevent a use after free in the
    1951             :                  * in the wbcLogonUserInfoDestructor
    1952             :                  */
    1953         160 :                 info->blobs = NULL;
    1954             :         }
    1955         248 :         if (error && !p_error) {
    1956          76 :                 wbcFreeMemory(error);
    1957             :         }
    1958         248 :         if (info && !p_info) {
    1959         172 :                 wbcFreeMemory(info);
    1960             :         }
    1961             : 
    1962         248 :         return ret;
    1963             : }
    1964             : 
    1965             : /* talk to winbindd */
    1966          12 : static int winbind_chauthtok_request(struct pwb_context *ctx,
    1967             :                                      const char *user,
    1968             :                                      const char *oldpass,
    1969             :                                      const char *newpass,
    1970             :                                      time_t pwd_last_set)
    1971             : {
    1972             :         wbcErr wbc_status;
    1973             :         struct wbcChangePasswordParams params;
    1974          12 :         struct wbcAuthErrorInfo *error = NULL;
    1975          12 :         struct wbcUserPasswordPolicyInfo *policy = NULL;
    1976          12 :         enum wbcPasswordChangeRejectReason reject_reason = -1;
    1977          12 :         uint32_t flags = 0;
    1978             : 
    1979             :         int i;
    1980          12 :         const char *codes[] = {
    1981             :                 "NT_STATUS_BACKUP_CONTROLLER",
    1982             :                 "NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND",
    1983             :                 "NT_STATUS_NO_LOGON_SERVERS",
    1984             :                 "NT_STATUS_ACCESS_DENIED",
    1985             :                 "NT_STATUS_PWD_TOO_SHORT", /* TODO: tell the min pwd length ? */
    1986             :                 "NT_STATUS_PWD_TOO_RECENT", /* TODO: tell the minage ? */
    1987             :                 "NT_STATUS_PWD_HISTORY_CONFLICT" /* TODO: tell the history length ? */
    1988             :         };
    1989          12 :         int ret = PAM_AUTH_ERR;
    1990             : 
    1991          12 :         ZERO_STRUCT(params);
    1992             : 
    1993          12 :         if (ctx->ctrl & WINBIND_KRB5_AUTH) {
    1994           6 :                 flags |= WBFLAG_PAM_KRB5 |
    1995             :                          WBFLAG_PAM_CONTACT_TRUSTDOM;
    1996             :         }
    1997             : 
    1998          12 :         if (ctx->ctrl & WINBIND_CACHED_LOGIN) {
    1999           0 :                 flags |= WBFLAG_PAM_CACHED_LOGIN;
    2000             :         }
    2001             : 
    2002          12 :         params.account_name             = user;
    2003          12 :         params.level                    = WBC_CHANGE_PASSWORD_LEVEL_PLAIN;
    2004          12 :         params.old_password.plaintext   = oldpass;
    2005          12 :         params.new_password.plaintext   = newpass;
    2006          12 :         params.flags                    = flags;
    2007             : 
    2008          12 :         wbc_status = wbcCtxChangeUserPasswordEx(ctx->wbc_ctx,
    2009             :                                                 &params,
    2010             :                                                 &error,
    2011             :                                                 &reject_reason,
    2012             :                                                 &policy);
    2013          12 :         ret = wbc_auth_error_to_pam_error(ctx, error, wbc_status,
    2014             :                                           user, "wbcChangeUserPasswordEx");
    2015             : 
    2016          12 :         if (WBC_ERROR_IS_OK(wbc_status)) {
    2017          12 :                 _pam_log(ctx, LOG_NOTICE,
    2018             :                          "user '%s' password changed", user);
    2019          12 :                 return PAM_SUCCESS;
    2020             :         }
    2021             : 
    2022           0 :         if (!error) {
    2023           0 :                 wbcFreeMemory(policy);
    2024           0 :                 return ret;
    2025             :         }
    2026             : 
    2027           0 :         for (i=0; i<ARRAY_SIZE(codes); i++) {
    2028           0 :                 int _ret = ret;
    2029           0 :                 if (_pam_check_remark_auth_err(ctx, error, codes[i], &_ret)) {
    2030           0 :                         ret = _ret;
    2031           0 :                         goto done;
    2032             :                 }
    2033             :         }
    2034             : 
    2035           0 :         if (!strcasecmp(error->nt_string,
    2036             :                         "NT_STATUS_PASSWORD_RESTRICTION")) {
    2037             : 
    2038           0 :                 char *pwd_restriction_string = NULL;
    2039           0 :                 SMB_TIME_T min_pwd_age = 0;
    2040             : 
    2041           0 :                 if (policy) {
    2042           0 :                         min_pwd_age     = policy->min_passwordage;
    2043             :                 }
    2044             : 
    2045             :                 /* FIXME: avoid to send multiple PAM messages after another */
    2046           0 :                 switch ((int)reject_reason) {
    2047           0 :                         case -1:
    2048           0 :                                 break;
    2049           0 :                         case WBC_PWD_CHANGE_NO_ERROR:
    2050           0 :                                 if ((min_pwd_age > 0) &&
    2051           0 :                                     (pwd_last_set + min_pwd_age > time(NULL))) {
    2052           0 :                                         time_t next_change = pwd_last_set + min_pwd_age;
    2053             : #if defined(__clang__)
    2054             : #pragma clang diagnostic push
    2055             : #pragma clang diagnostic ignored "-Wformat-nonliteral"
    2056             : #endif
    2057           0 :                                         _make_remark_format(ctx, PAM_ERROR_MSG,
    2058             :                                                 _get_ntstatus_error_string("NT_STATUS_PWD_TOO_RECENT"),
    2059             :                                                 ctime(&next_change));
    2060             : #if defined(__clang__)
    2061             : #pragma clang diagnostic pop
    2062             : #endif
    2063           0 :                                         goto done;
    2064             :                                 }
    2065           0 :                                 break;
    2066           0 :                         case WBC_PWD_CHANGE_PASSWORD_TOO_SHORT:
    2067           0 :                                 PAM_WB_REMARK_DIRECT(ctx,
    2068             :                                         "NT_STATUS_PWD_TOO_SHORT");
    2069           0 :                                 break;
    2070           0 :                         case WBC_PWD_CHANGE_PWD_IN_HISTORY:
    2071           0 :                                 PAM_WB_REMARK_DIRECT(ctx,
    2072             :                                         "NT_STATUS_PWD_HISTORY_CONFLICT");
    2073           0 :                                 break;
    2074           0 :                         case WBC_PWD_CHANGE_NOT_COMPLEX:
    2075           0 :                                 _make_remark(ctx, PAM_ERROR_MSG,
    2076           0 :                                              _("Password does not meet "
    2077             :                                                "complexity requirements"));
    2078           0 :                                 break;
    2079           0 :                         default:
    2080           0 :                                 _pam_log_debug(ctx, LOG_DEBUG,
    2081             :                                                "unknown password change "
    2082             :                                                "reject reason: %d",
    2083             :                                                reject_reason);
    2084           0 :                                 break;
    2085             :                 }
    2086             : 
    2087           0 :                 pwd_restriction_string =
    2088           0 :                         _pam_compose_pwd_restriction_string(ctx, policy);
    2089           0 :                 if (pwd_restriction_string) {
    2090           0 :                         _make_remark(ctx, PAM_ERROR_MSG,
    2091             :                                      pwd_restriction_string);
    2092           0 :                         TALLOC_FREE(pwd_restriction_string);
    2093             :                 }
    2094             :         }
    2095           0 :  done:
    2096           0 :         wbcFreeMemory(error);
    2097           0 :         wbcFreeMemory(policy);
    2098             : 
    2099           0 :         return ret;
    2100             : }
    2101             : 
    2102             : /*
    2103             :  * Checks if a user has an account
    2104             :  *
    2105             :  * return values:
    2106             :  *       1  = User not found
    2107             :  *       0  = OK
    2108             :  *      -1  = System error
    2109             :  */
    2110          24 : static int valid_user(struct pwb_context *ctx,
    2111             :                       const char *user)
    2112             : {
    2113             :         /* check not only if the user is available over NSS calls, also make
    2114             :          * sure it's really a winbind user, this is important when stacking PAM
    2115             :          * modules in the 'account' or 'password' facility. */
    2116             : 
    2117             :         wbcErr wbc_status;
    2118          24 :         struct passwd *pwd = NULL;
    2119          24 :         struct passwd *wb_pwd = NULL;
    2120             : 
    2121          24 :         pwd = getpwnam(user);
    2122          24 :         if (pwd == NULL) {
    2123           0 :                 return 1;
    2124             :         }
    2125             : 
    2126          24 :         wbc_status = wbcCtxGetpwnam(ctx->wbc_ctx, user, &wb_pwd);
    2127          24 :         wbcFreeMemory(wb_pwd);
    2128          24 :         if (!WBC_ERROR_IS_OK(wbc_status)) {
    2129           0 :                 _pam_log(ctx, LOG_DEBUG, "valid_user: wbcGetpwnam gave %s\n",
    2130             :                         wbcErrorString(wbc_status));
    2131             :         }
    2132             : 
    2133          24 :         switch (wbc_status) {
    2134           0 :                 case WBC_ERR_UNKNOWN_USER:
    2135             :                 /* match other insane libwbclient return codes */
    2136             :                 case WBC_ERR_WINBIND_NOT_AVAILABLE:
    2137             :                 case WBC_ERR_DOMAIN_NOT_FOUND:
    2138           0 :                         return 1;
    2139          24 :                 case WBC_ERR_SUCCESS:
    2140          24 :                         return 0;
    2141           0 :                 default:
    2142           0 :                         break;
    2143             :         }
    2144           0 :         return -1;
    2145             : }
    2146             : 
    2147         252 : static char *_pam_delete(register char *xx)
    2148             : {
    2149        1658 :         _pam_overwrite(xx);
    2150         252 :         _pam_drop(xx);
    2151         252 :         return NULL;
    2152             : }
    2153             : 
    2154             : /*
    2155             :  * obtain a password from the user
    2156             :  */
    2157             : 
    2158         260 : static int _winbind_read_password(struct pwb_context *ctx,
    2159             :                                   unsigned int ctrl,
    2160             :                                   const char *comment,
    2161             :                                   const char *prompt1,
    2162             :                                   const char *prompt2,
    2163             :                                   const char **pass)
    2164             : {
    2165             :         int authtok_flag;
    2166             :         int retval;
    2167             :         const char *item;
    2168             :         char *token;
    2169             : 
    2170         260 :         _pam_log(ctx, LOG_DEBUG, "getting password (0x%08x)", ctrl);
    2171             : 
    2172             :         /*
    2173             :          * make sure nothing inappropriate gets returned
    2174             :          */
    2175             : 
    2176         260 :         *pass = token = NULL;
    2177             : 
    2178             :         /*
    2179             :          * which authentication token are we getting?
    2180             :          */
    2181             : 
    2182         260 :         if (on(WINBIND__OLD_PASSWORD, ctrl)) {
    2183          12 :                 authtok_flag = PAM_OLDAUTHTOK;
    2184             :         } else {
    2185         248 :                 authtok_flag = PAM_AUTHTOK;
    2186             :         }
    2187             : 
    2188             :         /*
    2189             :          * should we obtain the password from a PAM item ?
    2190             :          */
    2191             : 
    2192         388 :         if (on(WINBIND_TRY_FIRST_PASS_ARG, ctrl) ||
    2193         256 :             on(WINBIND_USE_FIRST_PASS_ARG, ctrl)) {
    2194           8 :                 retval = pam_get_item(ctx->pamh,
    2195             :                                       authtok_flag,
    2196             :                                       (const void **) &item);
    2197           8 :                 if (retval != PAM_SUCCESS) {
    2198             :                         /* very strange. */
    2199           0 :                         _pam_log(ctx, LOG_ALERT,
    2200             :                                  "pam_get_item returned error "
    2201             :                                  "to unix-read-password");
    2202           0 :                         return retval;
    2203           8 :                 } else if (item != NULL) {      /* we have a password! */
    2204           8 :                         *pass = item;
    2205           8 :                         item = NULL;
    2206           8 :                         _pam_log(ctx, LOG_DEBUG,
    2207             :                                  "pam_get_item returned a password");
    2208           8 :                         return PAM_SUCCESS;
    2209           0 :                 } else if (on(WINBIND_USE_FIRST_PASS_ARG, ctrl)) {
    2210           0 :                         return PAM_AUTHTOK_RECOVER_ERR; /* didn't work */
    2211           0 :                 } else if (on(WINBIND_USE_AUTHTOK_ARG, ctrl)
    2212           0 :                            && off(WINBIND__OLD_PASSWORD, ctrl)) {
    2213           0 :                         return PAM_AUTHTOK_RECOVER_ERR;
    2214             :                 }
    2215             :         }
    2216             :         /*
    2217             :          * getting here implies we will have to get the password from the
    2218             :          * user directly.
    2219             :          */
    2220             : 
    2221             :         {
    2222             :                 struct pam_message msg[3];
    2223             :                 const struct pam_message *pmsg[3];
    2224             :                 struct pam_response *resp;
    2225             :                 int i, replies;
    2226             : 
    2227             :                 /* prepare to converse */
    2228             : 
    2229         252 :                 if (comment != NULL && off(ctrl, WINBIND_SILENT)) {
    2230          12 :                         pmsg[0] = &msg[0];
    2231          12 :                         msg[0].msg_style = PAM_TEXT_INFO;
    2232          12 :                         msg[0].msg = discard_const_p(char, comment);
    2233          12 :                         i = 1;
    2234             :                 } else {
    2235         240 :                         i = 0;
    2236             :                 }
    2237             : 
    2238         252 :                 pmsg[i] = &msg[i];
    2239         252 :                 msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
    2240         252 :                 msg[i++].msg = discard_const_p(char, prompt1);
    2241         252 :                 replies = 1;
    2242             : 
    2243         252 :                 if (prompt2 != NULL) {
    2244           4 :                         pmsg[i] = &msg[i];
    2245           4 :                         msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
    2246           4 :                         msg[i++].msg = discard_const_p(char, prompt2);
    2247           4 :                         ++replies;
    2248             :                 }
    2249             :                 /* so call the conversation expecting i responses */
    2250         252 :                 resp = NULL;
    2251         252 :                 retval = converse(ctx->pamh, i, pmsg, &resp);
    2252         252 :                 if (resp == NULL) {
    2253           0 :                         if (retval == PAM_SUCCESS) {
    2254           0 :                                 retval = PAM_AUTHTOK_RECOVER_ERR;
    2255             :                         }
    2256           0 :                         goto done;
    2257             :                 }
    2258         252 :                 if (retval != PAM_SUCCESS) {
    2259           0 :                         _pam_drop_reply(resp, i);
    2260           0 :                         goto done;
    2261             :                 }
    2262             : 
    2263             :                 /* interpret the response */
    2264             : 
    2265         252 :                 token = x_strdup(resp[i - replies].resp);
    2266         252 :                 if (!token) {
    2267           0 :                         _pam_log(ctx, LOG_NOTICE,
    2268             :                                  "could not recover "
    2269             :                                  "authentication token");
    2270           0 :                         retval = PAM_AUTHTOK_RECOVER_ERR;
    2271           0 :                         goto done;
    2272             :                 }
    2273             : 
    2274         252 :                 if (replies == 2) {
    2275             :                         /* verify that password entered correctly */
    2276           6 :                         if (!resp[i - 1].resp ||
    2277           4 :                             strcmp(token, resp[i - 1].resp)) {
    2278           0 :                                 _pam_delete(token);     /* mistyped */
    2279           0 :                                 retval = PAM_AUTHTOK_RECOVER_ERR;
    2280           0 :                                 _make_remark(ctx, PAM_ERROR_MSG,
    2281           0 :                                              MISTYPED_PASS);
    2282             :                         }
    2283             :                 }
    2284             : 
    2285             :                 /*
    2286             :                  * tidy up the conversation (resp_retcode) is ignored
    2287             :                  * -- what is it for anyway? AGM
    2288             :                  */
    2289        2110 :                 _pam_drop_reply(resp, i);
    2290             :         }
    2291             : 
    2292         252 :  done:
    2293         252 :         if (retval != PAM_SUCCESS) {
    2294           0 :                 _pam_log_debug(ctx, LOG_DEBUG,
    2295             :                                "unable to obtain a password");
    2296           0 :                 return retval;
    2297             :         }
    2298             :         /* 'token' is the entered password */
    2299             : 
    2300             :         /* we store this password as an item */
    2301             : 
    2302         252 :         retval = pam_set_item(ctx->pamh, authtok_flag, token);
    2303         252 :         _pam_delete(token);     /* clean it up */
    2304         504 :         if (retval != PAM_SUCCESS ||
    2305         252 :             (retval = pam_get_item(ctx->pamh, authtok_flag, (const void **) &item)) != PAM_SUCCESS) {
    2306             : 
    2307           0 :                 _pam_log(ctx, LOG_CRIT, "error manipulating password");
    2308           0 :                 return retval;
    2309             : 
    2310             :         }
    2311             : 
    2312         252 :         *pass = item;
    2313         252 :         item = NULL;            /* break link to password */
    2314             : 
    2315         252 :         return PAM_SUCCESS;
    2316             : }
    2317             : 
    2318         708 : static const char *get_conf_item_string(struct pwb_context *ctx,
    2319             :                                         const char *item,
    2320             :                                         int config_flag)
    2321             : {
    2322         708 :         int i = 0;
    2323         708 :         const char *parm_opt = NULL;
    2324             : 
    2325         708 :         if (!(ctx->ctrl & config_flag)) {
    2326         590 :                 goto out;
    2327             :         }
    2328             : 
    2329             :         /* let the pam opt take precedence over the pam_winbind.conf option */
    2330         476 :         for (i=0; i<ctx->argc; i++) {
    2331             : 
    2332         476 :                 if ((strncmp(ctx->argv[i], item, strlen(item)) == 0)) {
    2333             :                         char *p;
    2334             : 
    2335         118 :                         if ((p = strchr(ctx->argv[i], '=')) == NULL) {
    2336           0 :                                 _pam_log(ctx, LOG_INFO,
    2337             :                                          "no \"=\" delimiter for \"%s\" found\n",
    2338             :                                          item);
    2339           0 :                                 goto out;
    2340             :                         }
    2341         118 :                         _pam_log_debug(ctx, LOG_INFO,
    2342             :                                        "PAM config: %s '%s'\n", item, p+1);
    2343         118 :                         return p + 1;
    2344             :                 }
    2345             :         }
    2346             : 
    2347           0 :         if (ctx->dict) {
    2348           0 :                 char *key = NULL;
    2349             : 
    2350           0 :                 key = talloc_asprintf(ctx, "global:%s", item);
    2351           0 :                 if (!key) {
    2352           0 :                         goto out;
    2353             :                 }
    2354             : 
    2355           0 :                 parm_opt = tiniparser_getstring_nonempty(ctx->dict, key, NULL);
    2356           0 :                 TALLOC_FREE(key);
    2357             : 
    2358           0 :                 _pam_log_debug(ctx, LOG_INFO, "CONFIG file: %s '%s'\n",
    2359             :                                item, parm_opt);
    2360             :         }
    2361         295 : out:
    2362         590 :         return parm_opt;
    2363             : }
    2364             : 
    2365         236 : static int get_config_item_int(struct pwb_context *ctx,
    2366             :                                const char *item,
    2367             :                                int config_flag)
    2368             : {
    2369         236 :         int i, parm_opt = -1;
    2370             : 
    2371         236 :         if (!(ctx->ctrl & config_flag)) {
    2372         228 :                 goto out;
    2373             :         }
    2374             : 
    2375             :         /* let the pam opt take precedence over the pam_winbind.conf option */
    2376          24 :         for (i = 0; i < ctx->argc; i++) {
    2377             : 
    2378          24 :                 if ((strncmp(ctx->argv[i], item, strlen(item)) == 0)) {
    2379             :                         char *p;
    2380             : 
    2381           8 :                         if ((p = strchr(ctx->argv[i], '=')) == NULL) {
    2382           0 :                                 _pam_log(ctx, LOG_INFO,
    2383             :                                          "no \"=\" delimiter for \"%s\" found\n",
    2384             :                                          item);
    2385           0 :                                 goto out;
    2386             :                         }
    2387           8 :                         parm_opt = atoi(p + 1);
    2388           8 :                         _pam_log_debug(ctx, LOG_INFO,
    2389             :                                        "PAM config: %s '%d'\n",
    2390             :                                        item, parm_opt);
    2391           8 :                         return parm_opt;
    2392             :                 }
    2393             :         }
    2394             : 
    2395           0 :         if (ctx->dict) {
    2396           0 :                 char *key = NULL;
    2397             : 
    2398           0 :                 key = talloc_asprintf(ctx, "global:%s", item);
    2399           0 :                 if (!key) {
    2400           0 :                         goto out;
    2401             :                 }
    2402             : 
    2403           0 :                 parm_opt = tiniparser_getint(ctx->dict, key, -1);
    2404           0 :                 TALLOC_FREE(key);
    2405             : 
    2406           0 :                 _pam_log_debug(ctx, LOG_INFO,
    2407             :                                "CONFIG file: %s '%d'\n",
    2408             :                                item, parm_opt);
    2409             :         }
    2410         114 : out:
    2411         228 :         return parm_opt;
    2412             : }
    2413             : 
    2414         236 : static const char *get_krb5_cc_type_from_config(struct pwb_context *ctx)
    2415             : {
    2416         236 :         return get_conf_item_string(ctx, "krb5_ccache_type",
    2417             :                                     WINBIND_KRB5_CCACHE_TYPE);
    2418             : }
    2419             : 
    2420         236 : static const char *get_member_from_config(struct pwb_context *ctx)
    2421             : {
    2422         236 :         const char *ret = NULL;
    2423         236 :         ret = get_conf_item_string(ctx, "require_membership_of",
    2424             :                                    WINBIND_REQUIRED_MEMBERSHIP);
    2425         236 :         if (ret != NULL) {
    2426           0 :                 return ret;
    2427             :         }
    2428         236 :         return get_conf_item_string(ctx, "require-membership-of",
    2429             :                                     WINBIND_REQUIRED_MEMBERSHIP);
    2430             : }
    2431             : 
    2432         236 : static int get_warn_pwd_expire_from_config(struct pwb_context *ctx)
    2433             : {
    2434             :         int ret;
    2435         236 :         ret = get_config_item_int(ctx, "warn_pwd_expire",
    2436             :                                   WINBIND_WARN_PWD_EXPIRE);
    2437             :         /* no or broken setting */
    2438         236 :         if (ret < 0) {
    2439         228 :                 return DEFAULT_DAYS_TO_WARN_BEFORE_PWD_EXPIRES;
    2440             :         }
    2441           8 :         return ret;
    2442             : }
    2443             : 
    2444             : /**
    2445             :  * Retrieve the winbind separator.
    2446             :  *
    2447             :  * @param ctx PAM winbind context.
    2448             :  *
    2449             :  * @return string separator character. NULL on failure.
    2450             :  */
    2451             : 
    2452         144 : static char winbind_get_separator(struct pwb_context *ctx)
    2453             : {
    2454             :         wbcErr wbc_status;
    2455             :         static struct wbcInterfaceDetails *details = NULL;
    2456             : 
    2457         144 :         wbc_status = wbcCtxInterfaceDetails(ctx->wbc_ctx, &details);
    2458         144 :         if (!WBC_ERROR_IS_OK(wbc_status)) {
    2459           0 :                 _pam_log(ctx, LOG_ERR,
    2460             :                          "Could not retrieve winbind interface details: %s",
    2461             :                          wbcErrorString(wbc_status));
    2462           0 :                 return '\0';
    2463             :         }
    2464             : 
    2465         144 :         if (!details) {
    2466           0 :                 return '\0';
    2467             :         }
    2468             : 
    2469         144 :         return details->winbind_separator;
    2470             : }
    2471             : 
    2472             : 
    2473             : /**
    2474             :  * Convert a upn to a name.
    2475             :  *
    2476             :  * @param ctx PAM winbind context.
    2477             :  * @param upn  User UPN to be translated.
    2478             :  *
    2479             :  * @return converted name. NULL pointer on failure. Caller needs to free.
    2480             :  */
    2481             : 
    2482         144 : static char* winbind_upn_to_username(struct pwb_context *ctx,
    2483             :                                      const char *upn)
    2484             : {
    2485             :         char sep;
    2486         144 :         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
    2487             :         struct wbcDomainSid sid;
    2488             :         enum wbcSidType type;
    2489         144 :         char *domain = NULL;
    2490             :         char *name;
    2491             :         char *p;
    2492             :         char *result;
    2493             : 
    2494             :         /* This cannot work when the winbind separator = @ */
    2495             : 
    2496         144 :         sep = winbind_get_separator(ctx);
    2497         144 :         if (!sep || sep == '@') {
    2498           0 :                 return NULL;
    2499             :         }
    2500             : 
    2501         144 :         name = talloc_strdup(ctx, upn);
    2502         144 :         if (!name) {
    2503           0 :                 return NULL;
    2504             :         }
    2505             : 
    2506         144 :         p = strchr(name, '@');
    2507         144 :         if (p == NULL) {
    2508           0 :                 TALLOC_FREE(name);
    2509           0 :                 return NULL;
    2510             :         }
    2511         144 :         *p = '\0';
    2512         144 :         domain = p + 1;
    2513             : 
    2514             :         /* Convert the UPN to a SID */
    2515             : 
    2516         144 :         wbc_status = wbcCtxLookupName(ctx->wbc_ctx, domain, name, &sid, &type);
    2517         144 :         if (!WBC_ERROR_IS_OK(wbc_status)) {
    2518          72 :                 return NULL;
    2519             :         }
    2520             : 
    2521             :         /* Convert the the SID back to the sAMAccountName */
    2522             : 
    2523          72 :         wbc_status = wbcCtxLookupSid(ctx->wbc_ctx, &sid, &domain, &name, &type);
    2524          72 :         if (!WBC_ERROR_IS_OK(wbc_status)) {
    2525           0 :                 return NULL;
    2526             :         }
    2527             : 
    2528          72 :         result = talloc_asprintf(ctx, "%s%c%s", domain, sep, name);
    2529          72 :         wbcFreeMemory(domain);
    2530          72 :         wbcFreeMemory(name);
    2531          72 :         return result;
    2532             : }
    2533             : 
    2534           0 : static int _pam_delete_cred(pam_handle_t *pamh, int flags,
    2535             :                             int argc, enum pam_winbind_request_type type,
    2536             :                             const char **argv)
    2537             : {
    2538           0 :         int retval = PAM_SUCCESS;
    2539           0 :         struct pwb_context *ctx = NULL;
    2540             :         struct wbcLogoffUserParams logoff;
    2541           0 :         struct wbcAuthErrorInfo *error = NULL;
    2542             :         const char *user;
    2543           0 :         wbcErr wbc_status = WBC_ERR_SUCCESS;
    2544             : 
    2545           0 :         ZERO_STRUCT(logoff);
    2546             : 
    2547           0 :         retval = _pam_winbind_init_context(pamh, flags, argc, argv, type, &ctx);
    2548           0 :         if (retval != PAM_SUCCESS) {
    2549           0 :                 return retval;
    2550             :         }
    2551             : 
    2552           0 :         _PAM_LOG_FUNCTION_ENTER("_pam_delete_cred", ctx);
    2553             : 
    2554           0 :         if (ctx->ctrl & WINBIND_KRB5_AUTH) {
    2555             : 
    2556             :                 /* destroy the ccache here */
    2557             : 
    2558           0 :                 uint32_t wbc_flags = 0;
    2559           0 :                 const char *ccname = NULL;
    2560           0 :                 struct passwd *pwd = NULL;
    2561             : 
    2562           0 :                 retval = pam_get_user(pamh, &user, _("Username: "));
    2563           0 :                 if (retval != PAM_SUCCESS) {
    2564           0 :                         _pam_log(ctx, LOG_ERR,
    2565             :                                  "could not identify user");
    2566           0 :                         goto out;
    2567             :                 }
    2568             : 
    2569           0 :                 if (user == NULL) {
    2570           0 :                         _pam_log(ctx, LOG_ERR,
    2571             :                                  "username was NULL!");
    2572           0 :                         retval = PAM_USER_UNKNOWN;
    2573           0 :                         goto out;
    2574             :                 }
    2575             : 
    2576           0 :                 _pam_log_debug(ctx, LOG_DEBUG,
    2577             :                                "username [%s] obtained", user);
    2578             : 
    2579           0 :                 ccname = pam_getenv(pamh, "KRB5CCNAME");
    2580           0 :                 if (ccname == NULL) {
    2581           0 :                         _pam_log_debug(ctx, LOG_DEBUG,
    2582             :                                        "user has no KRB5CCNAME environment");
    2583             :                 }
    2584             : 
    2585           0 :                 pwd = getpwnam(user);
    2586           0 :                 if (pwd == NULL) {
    2587           0 :                         retval = PAM_USER_UNKNOWN;
    2588           0 :                         goto out;
    2589             :                 }
    2590             : 
    2591           0 :                 wbc_flags = WBFLAG_PAM_KRB5 |
    2592             :                         WBFLAG_PAM_CONTACT_TRUSTDOM;
    2593             : 
    2594           0 :                 logoff.username         = user;
    2595             : 
    2596           0 :                 if (ccname) {
    2597           0 :                         wbc_status = wbcAddNamedBlob(&logoff.num_blobs,
    2598             :                                                      &logoff.blobs,
    2599             :                                                      "ccfilename",
    2600             :                                                      0,
    2601             :                                                      discard_const_p(uint8_t, ccname),
    2602           0 :                                                      strlen(ccname)+1);
    2603           0 :                         if (!WBC_ERROR_IS_OK(wbc_status)) {
    2604           0 :                                 goto out;
    2605             :                         }
    2606             :                 }
    2607             : 
    2608           0 :                 wbc_status = wbcAddNamedBlob(&logoff.num_blobs,
    2609             :                                              &logoff.blobs,
    2610             :                                              "flags",
    2611             :                                              0,
    2612             :                                              (uint8_t *)&wbc_flags,
    2613             :                                              sizeof(wbc_flags));
    2614           0 :                 if (!WBC_ERROR_IS_OK(wbc_status)) {
    2615           0 :                         goto out;
    2616             :                 }
    2617             : 
    2618           0 :                 wbc_status = wbcAddNamedBlob(&logoff.num_blobs,
    2619             :                                              &logoff.blobs,
    2620             :                                              "user_uid",
    2621             :                                              0,
    2622           0 :                                              (uint8_t *)&pwd->pw_uid,
    2623             :                                              sizeof(pwd->pw_uid));
    2624           0 :                 if (!WBC_ERROR_IS_OK(wbc_status)) {
    2625           0 :                         goto out;
    2626             :                 }
    2627             : 
    2628           0 :                 wbc_status = wbcCtxLogoffUserEx(ctx->wbc_ctx, &logoff, &error);
    2629           0 :                 retval = wbc_auth_error_to_pam_error(ctx, error, wbc_status,
    2630             :                                                      user, "wbcLogoffUser");
    2631           0 :                 wbcFreeMemory(logoff.blobs);
    2632           0 :                 logoff.blobs = NULL;
    2633             : 
    2634           0 :                 if (!WBC_ERROR_IS_OK(wbc_status)) {
    2635           0 :                         _pam_log(ctx, LOG_INFO,
    2636             :                                  "failed to logoff user %s: %s\n",
    2637             :                                          user, wbcErrorString(wbc_status));
    2638             :                 }
    2639             :         }
    2640             : 
    2641           0 : out:
    2642           0 :         if (logoff.blobs) {
    2643           0 :                 wbcFreeMemory(logoff.blobs);
    2644             :         }
    2645             : 
    2646           0 :         if (!WBC_ERROR_IS_OK(wbc_status)) {
    2647           0 :                 retval = wbc_auth_error_to_pam_error(ctx, error, wbc_status,
    2648             :                      user, "wbcLogoffUser");
    2649             :         }
    2650           0 :         wbcFreeMemory(error);
    2651             : 
    2652             :         /*
    2653             :          * Delete the krb5 ccname variable from the PAM environment
    2654             :          * if it was set by winbind.
    2655             :          */
    2656           0 :         if ((ctx->ctrl & WINBIND_KRB5_AUTH) && pam_getenv(pamh, "KRB5CCNAME")) {
    2657           0 :                 pam_putenv(pamh, "KRB5CCNAME");
    2658             :         }
    2659             : 
    2660           0 :         _PAM_LOG_FUNCTION_LEAVE("_pam_delete_cred", ctx, retval);
    2661             : 
    2662           0 :         TALLOC_FREE(ctx);
    2663             : 
    2664           0 :         return retval;
    2665             : }
    2666             : 
    2667             : #ifdef SECURITY_OPENPAM_H_INCLUDED
    2668             : /*
    2669             :  * Logic below is copied from openpam_check_error_code() in
    2670             :  *./contrib/openpam/lib/libpam/openpam_dispatch.c on FreeBSD.
    2671             :  */
    2672             : static int openpam_convert_error_code(struct pwb_context *ctx,
    2673             :                                       enum pam_winbind_request_type req,
    2674             :                                       int r)
    2675             : {
    2676             :         if (r == PAM_SUCCESS ||
    2677             :             r == PAM_SYSTEM_ERR ||
    2678             :             r == PAM_SERVICE_ERR ||
    2679             :             r == PAM_BUF_ERR ||
    2680             :             r == PAM_CONV_ERR ||
    2681             :             r == PAM_PERM_DENIED ||
    2682             :             r == PAM_ABORT) {
    2683             :                 return r;
    2684             :         }
    2685             : 
    2686             :         /* specific winbind request types */
    2687             :         switch (req) {
    2688             :         case PAM_WINBIND_AUTHENTICATE:
    2689             :                 if (r == PAM_AUTH_ERR ||
    2690             :                     r == PAM_CRED_INSUFFICIENT ||
    2691             :                     r == PAM_AUTHINFO_UNAVAIL ||
    2692             :                     r == PAM_USER_UNKNOWN ||
    2693             :                     r == PAM_MAXTRIES) {
    2694             :                         return r;
    2695             :                 }
    2696             :                 break;
    2697             :         case PAM_WINBIND_SETCRED:
    2698             :                 if (r == PAM_CRED_UNAVAIL ||
    2699             :                     r == PAM_CRED_EXPIRED ||
    2700             :                     r == PAM_USER_UNKNOWN ||
    2701             :                     r == PAM_CRED_ERR) {
    2702             :                         return r;
    2703             :                 }
    2704             :                 break;
    2705             :         case PAM_WINBIND_ACCT_MGMT:
    2706             :                 if (r == PAM_USER_UNKNOWN ||
    2707             :                     r == PAM_AUTH_ERR ||
    2708             :                     r == PAM_NEW_AUTHTOK_REQD ||
    2709             :                     r == PAM_ACCT_EXPIRED) {
    2710             :                         return r;
    2711             :                 }
    2712             :                 break;
    2713             :         case PAM_WINBIND_OPEN_SESSION:
    2714             :         case PAM_WINBIND_CLOSE_SESSION:
    2715             :                 if (r == PAM_SESSION_ERR) {
    2716             :                         return r;
    2717             :                 }
    2718             :                 break;
    2719             :         case PAM_WINBIND_CHAUTHTOK:
    2720             :                 if (r == PAM_PERM_DENIED ||
    2721             :                     r == PAM_AUTHTOK_ERR ||
    2722             :                     r == PAM_AUTHTOK_RECOVERY_ERR ||
    2723             :                     r == PAM_AUTHTOK_LOCK_BUSY ||
    2724             :                     r == PAM_AUTHTOK_DISABLE_AGING ||
    2725             :                     r == PAM_TRY_AGAIN) {
    2726             :                         return r;
    2727             :                 }
    2728             :                 break;
    2729             :         default:
    2730             :                 break;
    2731             :         }
    2732             :         _pam_log(ctx, LOG_INFO,
    2733             :                  "Converting PAM error [%d] to PAM_SERVICE_ERR.\n", r);
    2734             :         return PAM_SERVICE_ERR;
    2735             : };
    2736             : #define pam_error_code(a, b, c) openpam_convert_error_code(a, b, c)
    2737             : #else
    2738             : #define pam_error_code(a, b, c) (c)
    2739             : #endif
    2740             : 
    2741             : PAM_EXTERN
    2742             : int pam_sm_authenticate(pam_handle_t *pamh, int flags,
    2743             :                         int argc, const char **argv)
    2744             : {
    2745             :         const char *username;
    2746             :         const char *password;
    2747         236 :         const char *member = NULL;
    2748         236 :         const char *cctype = NULL;
    2749             :         int warn_pwd_expire;
    2750         236 :         int retval = PAM_AUTH_ERR;
    2751         236 :         char *username_ret = NULL;
    2752         236 :         char *new_authtok_required = NULL;
    2753         236 :         char *real_username = NULL;
    2754         236 :         struct pwb_context *ctx = NULL;
    2755             : 
    2756         236 :         retval = _pam_winbind_init_context(pamh, flags, argc, argv,
    2757             :                                            PAM_WINBIND_AUTHENTICATE, &ctx);
    2758         236 :         if (retval != PAM_SUCCESS) {
    2759           0 :                 return retval;
    2760             :         }
    2761             : 
    2762         236 :         _PAM_LOG_FUNCTION_ENTER("pam_sm_authenticate", ctx);
    2763             : 
    2764             :         /* Get the username */
    2765         236 :         retval = pam_get_user(pamh, &username, NULL);
    2766         236 :         if ((retval != PAM_SUCCESS) || (!username)) {
    2767           0 :                 _pam_log_debug(ctx, LOG_DEBUG,
    2768             :                                "can not get the username");
    2769           0 :                 retval = PAM_SERVICE_ERR;
    2770           0 :                 goto out;
    2771             :         }
    2772             : 
    2773             : 
    2774             : #if defined(AIX)
    2775             :         /* Decode the user name since AIX does not support logn user
    2776             :            names by default.  The name is encoded as _#uid.  */
    2777             : 
    2778             :         if (username[0] == '_') {
    2779             :                 uid_t id = atoi(&username[1]);
    2780             :                 struct passwd *pw = NULL;
    2781             : 
    2782             :                 if ((id!=0) && ((pw = getpwuid(id)) != NULL)) {
    2783             :                         real_username = strdup(pw->pw_name);
    2784             :                 }
    2785             :         }
    2786             : #endif
    2787             : 
    2788         236 :         if (!real_username) {
    2789             :                 /* Just making a copy of the username we got from PAM */
    2790         236 :                 if ((real_username = strdup(username)) == NULL) {
    2791           0 :                         _pam_log_debug(ctx, LOG_DEBUG,
    2792             :                                        "memory allocation failure when copying "
    2793             :                                        "username");
    2794           0 :                         retval = PAM_SERVICE_ERR;
    2795           0 :                         goto out;
    2796             :                 }
    2797             :         }
    2798             : 
    2799             :         /* Maybe this was a UPN */
    2800             : 
    2801         236 :         if (strchr(real_username, '@') != NULL) {
    2802         144 :                 char *samaccountname = NULL;
    2803             : 
    2804         144 :                 samaccountname = winbind_upn_to_username(ctx,
    2805             :                                                          real_username);
    2806         144 :                 if (samaccountname) {
    2807          72 :                         free(real_username);
    2808          72 :                         real_username = strdup(samaccountname);
    2809             :                 }
    2810             :         }
    2811             : 
    2812         236 :         retval = _winbind_read_password(ctx, ctx->ctrl, NULL,
    2813         236 :                                         _("Password: "), NULL,
    2814             :                                         &password);
    2815             : 
    2816         236 :         if (retval != PAM_SUCCESS) {
    2817           0 :                 _pam_log(ctx, LOG_ERR,
    2818             :                          "Could not retrieve user's password");
    2819           0 :                 retval = PAM_AUTHTOK_ERR;
    2820           0 :                 goto out;
    2821             :         }
    2822             : 
    2823             :         /* Let's not give too much away in the log file */
    2824             : 
    2825             : #ifdef DEBUG_PASSWORD
    2826         236 :         _pam_log_debug(ctx, LOG_INFO,
    2827             :                        "Verify user '%s' with password '%s'",
    2828             :                        real_username, password);
    2829             : #else
    2830             :         _pam_log_debug(ctx, LOG_INFO,
    2831             :                        "Verify user '%s'", real_username);
    2832             : #endif
    2833             : 
    2834         236 :         member = get_member_from_config(ctx);
    2835         236 :         cctype = get_krb5_cc_type_from_config(ctx);
    2836         236 :         warn_pwd_expire = get_warn_pwd_expire_from_config(ctx);
    2837             : 
    2838             :         /* Now use the username to look up password */
    2839         236 :         retval = winbind_auth_request(ctx, real_username, password,
    2840             :                                       member, cctype, warn_pwd_expire,
    2841             :                                       NULL, NULL, NULL, &username_ret);
    2842             : 
    2843         236 :         if (retval == PAM_NEW_AUTHTOK_REQD ||
    2844             :             retval == PAM_AUTHTOK_EXPIRED) {
    2845             : 
    2846           0 :                 char *new_authtok_required_during_auth = NULL;
    2847             : 
    2848           0 :                 new_authtok_required = talloc_asprintf(NULL, "%d", retval);
    2849           0 :                 if (!new_authtok_required) {
    2850           0 :                         retval = PAM_BUF_ERR;
    2851           0 :                         goto out;
    2852             :                 }
    2853             : 
    2854           0 :                 pam_set_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD,
    2855             :                              new_authtok_required,
    2856             :                              _pam_winbind_cleanup_func);
    2857             : 
    2858           0 :                 retval = PAM_SUCCESS;
    2859             : 
    2860           0 :                 new_authtok_required_during_auth = talloc_asprintf(NULL, "%d", true);
    2861           0 :                 if (!new_authtok_required_during_auth) {
    2862           0 :                         retval = PAM_BUF_ERR;
    2863           0 :                         goto out;
    2864             :                 }
    2865             : 
    2866           0 :                 pam_set_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH,
    2867             :                              new_authtok_required_during_auth,
    2868             :                              _pam_winbind_cleanup_func);
    2869             : 
    2870           0 :                 goto out;
    2871             :         }
    2872             : 
    2873         354 : out:
    2874         236 :         if (username_ret) {
    2875         160 :                 pam_set_item (pamh, PAM_USER, username_ret);
    2876         160 :                 _pam_log_debug(ctx, LOG_INFO,
    2877             :                                "Returned user was '%s'", username_ret);
    2878         160 :                 free(username_ret);
    2879             :         }
    2880             : 
    2881         236 :         if (real_username) {
    2882         236 :                 free(real_username);
    2883             :         }
    2884             : 
    2885         236 :         if (!new_authtok_required) {
    2886         236 :                 pam_set_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD, NULL, NULL);
    2887             :         }
    2888             : 
    2889         236 :         if (retval != PAM_SUCCESS) {
    2890          76 :                 _pam_free_data_info3(pamh);
    2891             :         }
    2892             : 
    2893         236 :         _PAM_LOG_FUNCTION_LEAVE("pam_sm_authenticate", ctx, retval);
    2894             : 
    2895         236 :         TALLOC_FREE(ctx);
    2896             : 
    2897         236 :         return retval;
    2898             : }
    2899             : 
    2900             : PAM_EXTERN
    2901             : int pam_sm_setcred(pam_handle_t *pamh, int flags,
    2902             :                    int argc, const char **argv)
    2903             : {
    2904           0 :         int ret = PAM_SYSTEM_ERR;
    2905           0 :         struct pwb_context *ctx = NULL;
    2906             : 
    2907           0 :         ret = _pam_winbind_init_context(pamh, flags, argc, argv,
    2908             :                                         PAM_WINBIND_SETCRED, &ctx);
    2909           0 :         if (ret != PAM_SUCCESS) {
    2910           0 :                 return ret;
    2911             :         }
    2912             : 
    2913           0 :         _PAM_LOG_FUNCTION_ENTER("pam_sm_setcred", ctx);
    2914             : 
    2915           0 :         switch (flags & ~PAM_SILENT) {
    2916             : 
    2917           0 :                 case PAM_DELETE_CRED:
    2918           0 :                         ret = _pam_delete_cred(pamh, flags, argc,
    2919             :                                                PAM_WINBIND_SETCRED, argv);
    2920           0 :                         break;
    2921           0 :                 case PAM_REFRESH_CRED:
    2922           0 :                         _pam_log_debug(ctx, LOG_WARNING,
    2923             :                                        "PAM_REFRESH_CRED not implemented");
    2924           0 :                         ret = PAM_SUCCESS;
    2925           0 :                         break;
    2926           0 :                 case PAM_REINITIALIZE_CRED:
    2927           0 :                         _pam_log_debug(ctx, LOG_WARNING,
    2928             :                                        "PAM_REINITIALIZE_CRED not implemented");
    2929           0 :                         ret = PAM_SUCCESS;
    2930           0 :                         break;
    2931           0 :                 case PAM_ESTABLISH_CRED:
    2932           0 :                         _pam_log_debug(ctx, LOG_WARNING,
    2933             :                                        "PAM_ESTABLISH_CRED not implemented");
    2934           0 :                         ret = PAM_SUCCESS;
    2935           0 :                         break;
    2936           0 :                 default:
    2937           0 :                         ret = PAM_SYSTEM_ERR;
    2938           0 :                         break;
    2939             :         }
    2940             : 
    2941           0 :         _PAM_LOG_FUNCTION_LEAVE("pam_sm_setcred", ctx, ret);
    2942             : 
    2943           0 :         TALLOC_FREE(ctx);
    2944             : 
    2945           0 :         return pam_error_code(ctx, PAM_WINBIND_SETCRED, ret);
    2946             : }
    2947             : 
    2948             : /*
    2949             :  * Account management. We want to verify that the account exists
    2950             :  * before returning PAM_SUCCESS
    2951             :  */
    2952             : PAM_EXTERN
    2953             : int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
    2954             :                    int argc, const char **argv)
    2955             : {
    2956             :         const char *username;
    2957           0 :         int ret = PAM_USER_UNKNOWN;
    2958           0 :         const char *tmp = NULL;
    2959           0 :         struct pwb_context *ctx = NULL;
    2960             : 
    2961           0 :         ret = _pam_winbind_init_context(pamh, flags, argc, argv,
    2962             :                                         PAM_WINBIND_ACCT_MGMT, &ctx);
    2963           0 :         if (ret != PAM_SUCCESS) {
    2964           0 :                 return ret;
    2965             :         }
    2966             : 
    2967           0 :         _PAM_LOG_FUNCTION_ENTER("pam_sm_acct_mgmt", ctx);
    2968             : 
    2969             : 
    2970             :         /* Get the username */
    2971           0 :         ret = pam_get_user(pamh, &username, NULL);
    2972           0 :         if ((ret != PAM_SUCCESS) || (!username)) {
    2973           0 :                 _pam_log_debug(ctx, LOG_DEBUG,
    2974             :                                "can not get the username");
    2975           0 :                 ret = PAM_SERVICE_ERR;
    2976           0 :                 goto out;
    2977             :         }
    2978             : 
    2979             :         /* Verify the username */
    2980           0 :         ret = valid_user(ctx, username);
    2981           0 :         switch (ret) {
    2982           0 :         case -1:
    2983             :                 /* some sort of system error. The log was already printed */
    2984           0 :                 ret = PAM_SERVICE_ERR;
    2985           0 :                 goto out;
    2986           0 :         case 1:
    2987             :                 /* the user does not exist */
    2988           0 :                 _pam_log_debug(ctx, LOG_NOTICE, "user '%s' not found",
    2989             :                                username);
    2990           0 :                 if (ctx->ctrl & WINBIND_UNKNOWN_OK_ARG) {
    2991           0 :                         ret = PAM_IGNORE;
    2992           0 :                         goto out;
    2993             :                 }
    2994           0 :                 ret = PAM_USER_UNKNOWN;
    2995           0 :                 goto out;
    2996           0 :         case 0:
    2997           0 :                 pam_get_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD,
    2998             :                              (const void **)&tmp);
    2999           0 :                 if (tmp != NULL) {
    3000           0 :                         ret = atoi(tmp);
    3001           0 :                         switch (ret) {
    3002           0 :                         case PAM_AUTHTOK_EXPIRED:
    3003             :                                 /* Since new token is required in this case */
    3004             :                                 FALL_THROUGH;
    3005             :                         case PAM_NEW_AUTHTOK_REQD:
    3006           0 :                                 _pam_log(ctx, LOG_WARNING,
    3007             :                                          "pam_sm_acct_mgmt success but %s is set",
    3008             :                                          PAM_WINBIND_NEW_AUTHTOK_REQD);
    3009           0 :                                 _pam_log(ctx, LOG_NOTICE,
    3010             :                                          "user '%s' needs new password",
    3011             :                                          username);
    3012             :                                 /* PAM_AUTHTOKEN_REQD does not exist, but is documented in the manpage */
    3013           0 :                                 ret = PAM_NEW_AUTHTOK_REQD;
    3014           0 :                                 goto out;
    3015           0 :                         default:
    3016           0 :                                 _pam_log(ctx, LOG_WARNING,
    3017             :                                          "pam_sm_acct_mgmt success");
    3018           0 :                                 _pam_log(ctx, LOG_NOTICE,
    3019             :                                          "user '%s' granted access", username);
    3020           0 :                                 ret = PAM_SUCCESS;
    3021           0 :                                 goto out;
    3022             :                         }
    3023             :                 }
    3024             : 
    3025             :                 /* Otherwise, the authentication looked good */
    3026           0 :                 _pam_log(ctx, LOG_NOTICE,
    3027             :                          "user '%s' granted access", username);
    3028           0 :                 ret = PAM_SUCCESS;
    3029           0 :                 goto out;
    3030           0 :         default:
    3031             :                 /* we don't know anything about this return value */
    3032           0 :                 _pam_log(ctx, LOG_ERR,
    3033             :                          "internal module error (ret = %d, user = '%s')",
    3034             :                          ret, username);
    3035           0 :                 ret = PAM_SERVICE_ERR;
    3036           0 :                 goto out;
    3037             :         }
    3038             : 
    3039             :         /* should not be reached */
    3040             :         ret = PAM_IGNORE;
    3041             : 
    3042           0 :  out:
    3043             : 
    3044           0 :         _PAM_LOG_FUNCTION_LEAVE("pam_sm_acct_mgmt", ctx, ret);
    3045             : 
    3046           0 :         TALLOC_FREE(ctx);
    3047             : 
    3048           0 :         return pam_error_code(ctx, PAM_WINBIND_ACCT_MGMT, ret);
    3049             : }
    3050             : 
    3051             : PAM_EXTERN
    3052             : int pam_sm_open_session(pam_handle_t *pamh, int flags,
    3053             :                         int argc, const char **argv)
    3054             : {
    3055           0 :         int ret = PAM_SUCCESS;
    3056           0 :         struct pwb_context *ctx = NULL;
    3057             : 
    3058           0 :         ret = _pam_winbind_init_context(pamh, flags, argc, argv,
    3059             :                                         PAM_WINBIND_OPEN_SESSION, &ctx);
    3060           0 :         if (ret != PAM_SUCCESS) {
    3061           0 :                 return ret;
    3062             :         }
    3063             : 
    3064           0 :         _PAM_LOG_FUNCTION_ENTER("pam_sm_open_session", ctx);
    3065             : 
    3066           0 :         if (ctx->ctrl & WINBIND_MKHOMEDIR) {
    3067             :                 /* check and create homedir */
    3068           0 :                 ret = _pam_mkhomedir(ctx);
    3069             :         }
    3070             : 
    3071           0 :         _PAM_LOG_FUNCTION_LEAVE("pam_sm_open_session", ctx, ret);
    3072             : 
    3073           0 :         TALLOC_FREE(ctx);
    3074             : 
    3075           0 :         return pam_error_code(ctx, PAM_WINBIND_OPEN_SESSION, ret);
    3076             : }
    3077             : 
    3078             : PAM_EXTERN
    3079             : int pam_sm_close_session(pam_handle_t *pamh, int flags,
    3080             :                          int argc, const char **argv)
    3081             : {
    3082           0 :         int ret = PAM_SUCCESS;
    3083           0 :         struct pwb_context *ctx = NULL;
    3084             : 
    3085           0 :         ret = _pam_winbind_init_context(pamh, flags, argc, argv,
    3086             :                                         PAM_WINBIND_CLOSE_SESSION, &ctx);
    3087           0 :         if (ret != PAM_SUCCESS) {
    3088           0 :                 return ret;
    3089             :         }
    3090             : 
    3091           0 :         _PAM_LOG_FUNCTION_ENTER("pam_sm_close_session", ctx);
    3092             : 
    3093           0 :         _PAM_LOG_FUNCTION_LEAVE("pam_sm_close_session", ctx, ret);
    3094             : 
    3095           0 :         TALLOC_FREE(ctx);
    3096             : 
    3097           0 :         return pam_error_code(ctx, PAM_WINBIND_CLOSE_SESSION, ret);
    3098             : }
    3099             : 
    3100             : /**
    3101             :  * evaluate whether we need to re-authenticate with kerberos after a
    3102             :  * password change
    3103             :  *
    3104             :  * @param ctx PAM winbind context.
    3105             :  * @param user The username
    3106             :  *
    3107             :  * @return boolean Returns true if required, false if not.
    3108             :  */
    3109             : 
    3110          12 : static bool _pam_require_krb5_auth_after_chauthtok(struct pwb_context *ctx,
    3111             :                                                    const char *user)
    3112             : {
    3113             : 
    3114             :         /* Make sure that we only do this if a) the chauthtok got initiated
    3115             :          * during a logon attempt (authenticate->acct_mgmt->chauthtok) b) any
    3116             :          * later password change via the "passwd" command if done by the user
    3117             :          * itself
    3118             :          * NB. If we login from gdm or xdm and the password expires,
    3119             :          * we change the password, but there is no memory cache.
    3120             :          * Thus, even for passthrough login, we should do the
    3121             :          * authentication again to update memory cache.
    3122             :          * --- BoYang
    3123             :          * */
    3124             : 
    3125          12 :         const char *new_authtok_reqd_during_auth = NULL;
    3126          12 :         struct passwd *pwd = NULL;
    3127             : 
    3128          12 :         pam_get_data(ctx->pamh, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH,
    3129             :                       (const void **) &new_authtok_reqd_during_auth);
    3130          12 :         pam_set_data(ctx->pamh, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH,
    3131             :                      NULL, NULL);
    3132             : 
    3133          12 :         if (new_authtok_reqd_during_auth) {
    3134           0 :                 return true;
    3135             :         }
    3136             : 
    3137          12 :         pwd = getpwnam(user);
    3138          12 :         if (!pwd) {
    3139           0 :                 return false;
    3140             :         }
    3141             : 
    3142          12 :         if (getuid() == pwd->pw_uid) {
    3143           0 :                 return true;
    3144             :         }
    3145             : 
    3146          12 :         return false;
    3147             : }
    3148             : 
    3149             : 
    3150             : PAM_EXTERN
    3151             : int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
    3152             :                      int argc, const char **argv)
    3153             : {
    3154             :         unsigned int lctrl;
    3155             :         int ret;
    3156          24 :         bool cached_login = false;
    3157             : 
    3158             :         /* <DO NOT free() THESE> */
    3159             :         const char *user;
    3160             :         const char *pass_old;
    3161             :         const char *pass_new;
    3162             :         /* </DO NOT free() THESE> */
    3163             : 
    3164             :         char *Announce;
    3165             : 
    3166          24 :         int retry = 0;
    3167          24 :         char *username_ret = NULL;
    3168          24 :         struct wbcAuthErrorInfo *error = NULL;
    3169          24 :         struct pwb_context *ctx = NULL;
    3170             : 
    3171          24 :         ret = _pam_winbind_init_context(pamh, flags, argc, argv,
    3172             :                                         PAM_WINBIND_CHAUTHTOK, &ctx);
    3173          24 :         if (ret != PAM_SUCCESS) {
    3174           0 :                 return ret;
    3175             :         }
    3176             : 
    3177          24 :         _PAM_LOG_FUNCTION_ENTER("pam_sm_chauthtok", ctx);
    3178             : 
    3179          24 :         cached_login = (ctx->ctrl & WINBIND_CACHED_LOGIN);
    3180             : 
    3181             :         /* clearing offline bit for auth */
    3182          24 :         ctx->ctrl &= ~WINBIND_CACHED_LOGIN;
    3183             : 
    3184             :         /*
    3185             :          * First get the name of a user
    3186             :          */
    3187          24 :         ret = pam_get_user(pamh, &user, _("Username: "));
    3188          24 :         if (ret != PAM_SUCCESS) {
    3189           0 :                 _pam_log(ctx, LOG_ERR,
    3190             :                          "password - could not identify user");
    3191           0 :                 goto out;
    3192             :         }
    3193             : 
    3194          24 :         if (user == NULL) {
    3195           0 :                 _pam_log(ctx, LOG_ERR, "username was NULL!");
    3196           0 :                 ret = PAM_USER_UNKNOWN;
    3197           0 :                 goto out;
    3198             :         }
    3199             : 
    3200          24 :         _pam_log_debug(ctx, LOG_DEBUG, "username [%s] obtained", user);
    3201             : 
    3202             :         /* check if this is really a user in winbindd, not only in NSS */
    3203          24 :         ret = valid_user(ctx, user);
    3204          24 :         switch (ret) {
    3205           0 :                 case 1:
    3206           0 :                         ret = PAM_USER_UNKNOWN;
    3207           0 :                         goto out;
    3208           0 :                 case -1:
    3209           0 :                         ret = PAM_SYSTEM_ERR;
    3210           0 :                         goto out;
    3211          24 :                 default:
    3212          24 :                         break;
    3213             :         }
    3214             : 
    3215             :         /*
    3216             :          * obtain and verify the current password (OLDAUTHTOK) for
    3217             :          * the user.
    3218             :          */
    3219             : 
    3220          24 :         if (flags & PAM_PRELIM_CHECK) {
    3221          12 :                 time_t pwdlastset_prelim = 0;
    3222             : 
    3223             :                 /* instruct user what is happening */
    3224             : 
    3225             : #define greeting _("Changing password for")
    3226          12 :                 Announce = talloc_asprintf(ctx, "%s %s", greeting, user);
    3227          12 :                 if (!Announce) {
    3228           0 :                         _pam_log(ctx, LOG_CRIT,
    3229             :                                  "password - out of memory");
    3230           0 :                         ret = PAM_BUF_ERR;
    3231           0 :                         goto out;
    3232             :                 }
    3233             : #undef greeting
    3234             : 
    3235          12 :                 lctrl = ctx->ctrl | WINBIND__OLD_PASSWORD;
    3236          12 :                 ret = _winbind_read_password(ctx, lctrl,
    3237             :                                                 Announce,
    3238          12 :                                                 _("(current) NT password: "),
    3239             :                                                 NULL,
    3240             :                                                 (const char **) &pass_old);
    3241          12 :                 TALLOC_FREE(Announce);
    3242          12 :                 if (ret != PAM_SUCCESS) {
    3243           0 :                         _pam_log(ctx, LOG_NOTICE,
    3244             :                                  "password - (old) token not obtained");
    3245           0 :                         goto out;
    3246             :                 }
    3247             : 
    3248             :                 /* verify that this is the password for this user */
    3249             : 
    3250          12 :                 ret = winbind_auth_request(ctx, user, pass_old,
    3251             :                                            NULL, NULL, 0,
    3252             :                                            &error, NULL,
    3253             :                                            &pwdlastset_prelim, NULL);
    3254             : 
    3255          12 :                 if (ret != PAM_ACCT_EXPIRED &&
    3256          12 :                     ret != PAM_AUTHTOK_EXPIRED &&
    3257          12 :                     ret != PAM_NEW_AUTHTOK_REQD &&
    3258             :                     ret != PAM_SUCCESS) {
    3259           0 :                         pass_old = NULL;
    3260           0 :                         goto out;
    3261             :                 }
    3262             : 
    3263          12 :                 pam_set_data(pamh, PAM_WINBIND_PWD_LAST_SET,
    3264             :                              (void *)pwdlastset_prelim, NULL);
    3265             : 
    3266          12 :                 ret = pam_set_item(pamh, PAM_OLDAUTHTOK,
    3267             :                                    (const void *) pass_old);
    3268          12 :                 pass_old = NULL;
    3269          12 :                 if (ret != PAM_SUCCESS) {
    3270           0 :                         _pam_log(ctx, LOG_CRIT,
    3271             :                                  "failed to set PAM_OLDAUTHTOK");
    3272             :                 }
    3273          12 :         } else if (flags & PAM_UPDATE_AUTHTOK) {
    3274             : 
    3275          12 :                 time_t pwdlastset_update = 0;
    3276             : 
    3277             :                 /*
    3278             :                  * obtain the proposed password
    3279             :                  */
    3280             : 
    3281             :                 /*
    3282             :                  * get the old token back.
    3283             :                  */
    3284             : 
    3285          12 :                 ret = pam_get_item(pamh, PAM_OLDAUTHTOK, (const void **) &pass_old);
    3286             : 
    3287          12 :                 if (ret != PAM_SUCCESS) {
    3288           0 :                         _pam_log(ctx, LOG_NOTICE,
    3289             :                                  "user not authenticated");
    3290           0 :                         goto out;
    3291             :                 }
    3292             : 
    3293          12 :                 lctrl = ctx->ctrl & ~WINBIND_TRY_FIRST_PASS_ARG;
    3294             : 
    3295          12 :                 if (on(WINBIND_USE_AUTHTOK_ARG, lctrl)) {
    3296           4 :                         lctrl |= WINBIND_USE_FIRST_PASS_ARG;
    3297             :                 }
    3298          12 :                 if (on(WINBIND_TRY_AUTHTOK_ARG, lctrl)) {
    3299           4 :                         lctrl |= WINBIND_TRY_FIRST_PASS_ARG;
    3300             :                 }
    3301          12 :                 retry = 0;
    3302          12 :                 ret = PAM_AUTHTOK_ERR;
    3303          30 :                 while ((ret != PAM_SUCCESS) && (retry++ < MAX_PASSWD_TRIES)) {
    3304             :                         /*
    3305             :                          * use_authtok is to force the use of a previously entered
    3306             :                          * password -- needed for pluggable password strength checking
    3307             :                          */
    3308             : 
    3309          12 :                         ret = _winbind_read_password(ctx, lctrl,
    3310             :                                                      NULL,
    3311          12 :                                                      _("Enter new NT password: "),
    3312          12 :                                                      _("Retype new NT password: "),
    3313             :                                                      (const char **)&pass_new);
    3314             : 
    3315          12 :                         if (ret != PAM_SUCCESS) {
    3316           0 :                                 _pam_log_debug(ctx, LOG_ALERT,
    3317             :                                                "password - "
    3318             :                                                "new password not obtained");
    3319           0 :                                 pass_old = NULL;/* tidy up */
    3320           0 :                                 goto out;
    3321             :                         }
    3322             : 
    3323             :                         /*
    3324             :                          * At this point we know who the user is and what they
    3325             :                          * propose as their new password. Verify that the new
    3326             :                          * password is acceptable.
    3327             :                          */
    3328             : 
    3329          12 :                         if (pass_new[0] == '\0') {/* "\0" password = NULL */
    3330           0 :                                 pass_new = NULL;
    3331             :                         }
    3332             :                 }
    3333             : 
    3334             :                 /*
    3335             :                  * By reaching here we have approved the passwords and must now
    3336             :                  * rebuild the password database file.
    3337             :                  */
    3338          12 :                 pam_get_data(pamh, PAM_WINBIND_PWD_LAST_SET,
    3339             :                              (const void **) &pwdlastset_update);
    3340             : 
    3341             :                 /*
    3342             :                  * if cached creds were enabled, make sure to set the
    3343             :                  * WINBIND_CACHED_LOGIN bit here in order to have winbindd
    3344             :                  * update the cached creds storage - gd
    3345             :                  */
    3346          12 :                 if (cached_login) {
    3347           0 :                         ctx->ctrl |= WINBIND_CACHED_LOGIN;
    3348             :                 }
    3349             : 
    3350          12 :                 ret = winbind_chauthtok_request(ctx, user, pass_old,
    3351             :                                                 pass_new, pwdlastset_update);
    3352          12 :                 if (ret != PAM_SUCCESS) {
    3353           0 :                         pass_old = pass_new = NULL;
    3354           0 :                         goto out;
    3355             :                 }
    3356             : 
    3357          12 :                 if (_pam_require_krb5_auth_after_chauthtok(ctx, user)) {
    3358             : 
    3359           0 :                         const char *member = NULL;
    3360           0 :                         const char *cctype = NULL;
    3361             :                         int warn_pwd_expire;
    3362           0 :                         struct wbcLogonUserInfo *info = NULL;
    3363             : 
    3364           0 :                         member = get_member_from_config(ctx);
    3365           0 :                         cctype = get_krb5_cc_type_from_config(ctx);
    3366           0 :                         warn_pwd_expire = get_warn_pwd_expire_from_config(ctx);
    3367             : 
    3368             :                         /* Keep WINBIND_CACHED_LOGIN bit for
    3369             :                          * authentication after changing the password.
    3370             :                          * This will update the cached credentials in case
    3371             :                          * that winbindd_dual_pam_chauthtok() fails
    3372             :                          * to update them.
    3373             :                          * --- BoYang
    3374             :                          * */
    3375             : 
    3376           0 :                         ret = winbind_auth_request(ctx, user, pass_new,
    3377             :                                                    member, cctype, 0,
    3378             :                                                    &error, &info,
    3379             :                                                    NULL, &username_ret);
    3380           0 :                         pass_old = pass_new = NULL;
    3381             : 
    3382           0 :                         if (ret == PAM_SUCCESS) {
    3383             : 
    3384           0 :                                 struct wbcAuthUserInfo *user_info = NULL;
    3385             : 
    3386           0 :                                 if (info && info->info) {
    3387           0 :                                         user_info = info->info;
    3388             :                                 }
    3389             : 
    3390             :                                 /* warn a user if the password is about to
    3391             :                                  * expire soon */
    3392           0 :                                 _pam_warn_password_expiry(ctx, user_info,
    3393             :                                                           warn_pwd_expire,
    3394             :                                                           NULL, NULL);
    3395             : 
    3396             :                                 /* set some info3 info for other modules in the
    3397             :                                  * stack */
    3398           0 :                                 _pam_set_data_info3(ctx, user_info);
    3399             : 
    3400             :                                 /* put krb5ccname into env */
    3401           0 :                                 _pam_setup_krb5_env(ctx, info);
    3402             : 
    3403           0 :                                 if (username_ret) {
    3404           0 :                                         pam_set_item(pamh, PAM_USER,
    3405             :                                                      username_ret);
    3406           0 :                                         _pam_log_debug(ctx, LOG_INFO,
    3407             :                                                        "Returned user was '%s'",
    3408             :                                                        username_ret);
    3409           0 :                                         free(username_ret);
    3410             :                                 }
    3411             : 
    3412             :                         }
    3413             : 
    3414           0 :                         if (info && info->blobs) {
    3415           0 :                                 wbcFreeMemory(info->blobs);
    3416             :                         }
    3417           0 :                         wbcFreeMemory(info);
    3418             : 
    3419           0 :                         goto out;
    3420             :                 }
    3421             :         } else {
    3422           0 :                 ret = PAM_SERVICE_ERR;
    3423             :         }
    3424             : 
    3425          24 : out:
    3426             :         {
    3427             :                 /* Deal with offline errors. */
    3428             :                 int i;
    3429          24 :                 const char *codes[] = {
    3430             :                         "NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND",
    3431             :                         "NT_STATUS_NO_LOGON_SERVERS",
    3432             :                         "NT_STATUS_ACCESS_DENIED"
    3433             :                 };
    3434             : 
    3435          96 :                 for (i=0; i<ARRAY_SIZE(codes); i++) {
    3436             :                         int _ret;
    3437          72 :                         if (_pam_check_remark_auth_err(ctx, error, codes[i], &_ret)) {
    3438           0 :                                 break;
    3439             :                         }
    3440             :                 }
    3441             :         }
    3442             : 
    3443          24 :         wbcFreeMemory(error);
    3444             : 
    3445          24 :         _PAM_LOG_FUNCTION_LEAVE("pam_sm_chauthtok", ctx, ret);
    3446             : 
    3447          24 :         TALLOC_FREE(ctx);
    3448             : 
    3449          24 :         return pam_error_code(ctx, PAM_WINBIND_CHAUTHTOK, ret);
    3450             : }
    3451             : 
    3452             : #ifdef PAM_STATIC
    3453             : 
    3454             : /* static module data */
    3455             : 
    3456             : struct pam_module _pam_winbind_modstruct = {
    3457             :         MODULE_NAME,
    3458             :         pam_sm_authenticate,
    3459             :         pam_sm_setcred,
    3460             :         pam_sm_acct_mgmt,
    3461             :         pam_sm_open_session,
    3462             :         pam_sm_close_session,
    3463             :         pam_sm_chauthtok
    3464             : };
    3465             : 
    3466             : #endif
    3467             : 
    3468             : /*
    3469             :  * Copyright (c) Andrew Tridgell  <tridge@samba.org>   2000
    3470             :  * Copyright (c) Tim Potter       <tpot@samba.org>     2000
    3471             :  * Copyright (c) Andrew Bartlettt <abartlet@samba.org> 2002
    3472             :  * Copyright (c) Guenther Deschner <gd@samba.org>      2005-2008
    3473             :  * Copyright (c) Jan Rêkorajski 1999.
    3474             :  * Copyright (c) Andrew G. Morgan 1996-8.
    3475             :  * Copyright (c) Alex O. Yuriev, 1996.
    3476             :  * Copyright (c) Cristian Gafton 1996.
    3477             :  * Copyright (C) Elliot Lee <sopwith@redhat.com> 1996, Red Hat Software.
    3478             :  *
    3479             :  * Redistribution and use in source and binary forms, with or without
    3480             :  * modification, are permitted provided that the following conditions
    3481             :  * are met:
    3482             :  * 1. Redistributions of source code must retain the above copyright
    3483             :  *    notice, and the entire permission notice in its entirety,
    3484             :  *    including the disclaimer of warranties.
    3485             :  * 2. Redistributions in binary form must reproduce the above copyright
    3486             :  *    notice, this list of conditions and the following disclaimer in the
    3487             :  *    documentation and/or other materials provided with the distribution.
    3488             :  * 3. The name of the author may not be used to endorse or promote
    3489             :  *    products derived from this software without specific prior
    3490             :  *    written permission.
    3491             :  *
    3492             :  * ALTERNATIVELY, this product may be distributed under the terms of
    3493             :  * the GNU Public License, in which case the provisions of the GPL are
    3494             :  * required INSTEAD OF the above restrictions.  (This clause is
    3495             :  * necessary due to a potential bad interaction between the GPL and
    3496             :  * the restrictions contained in a BSD-style copyright.)
    3497             :  *
    3498             :  * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED
    3499             :  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    3500             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    3501             :  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
    3502             :  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    3503             :  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    3504             :  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    3505             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    3506             :  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    3507             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
    3508             :  * OF THE POSSIBILITY OF SUCH DAMAGE.
    3509             :  */

Generated by: LCOV version 1.13