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

Generated by: LCOV version 1.14