2000-05-09 15:43:00 +04:00
/* pam_winbind module
Copyright Andrew Tridgell < tridge @ samba . org > 2000
2002-01-30 06:14:20 +03:00
Copyright Tim Potter < tpot @ samba . org > 2000
2002-03-13 04:26:59 +03:00
Copyright Andrew Bartlett < abartlet @ samba . org > 2002
2008-04-03 19:23:22 +04:00
Copyright Guenther Deschner < gd @ samba . org > 2005 - 2008
2000-05-09 15:43:00 +04:00
2007-09-14 12:21:20 +04:00
largely based on pam_userdb by Cristian Gafton < gafton @ redhat . com > also
contains large slabs of code from pam_unix by Elliot Lee
< sopwith @ redhat . com > ( see copyright below for full details )
2000-05-09 15:43:00 +04:00
*/
2001-05-04 04:43:20 +04:00
# include "pam_winbind.h"
2000-05-09 15:43:00 +04:00
2008-08-15 05:13:18 +04:00
static int wbc_error_to_pam_error ( wbcErr status )
{
switch ( status ) {
case WBC_ERR_SUCCESS :
return PAM_SUCCESS ;
case WBC_ERR_NOT_IMPLEMENTED :
return PAM_SERVICE_ERR ;
case WBC_ERR_UNKNOWN_FAILURE :
break ;
case WBC_ERR_NO_MEMORY :
return PAM_BUF_ERR ;
case WBC_ERR_INVALID_SID :
case WBC_ERR_INVALID_PARAM :
break ;
case WBC_ERR_WINBIND_NOT_AVAILABLE :
return PAM_AUTHINFO_UNAVAIL ;
case WBC_ERR_DOMAIN_NOT_FOUND :
return PAM_AUTHINFO_UNAVAIL ;
case WBC_ERR_INVALID_RESPONSE :
return PAM_BUF_ERR ;
case WBC_ERR_NSS_ERROR :
return PAM_USER_UNKNOWN ;
case WBC_ERR_AUTH_ERROR :
return PAM_AUTH_ERR ;
case WBC_ERR_UNKNOWN_USER :
return PAM_USER_UNKNOWN ;
case WBC_ERR_UNKNOWN_GROUP :
return PAM_USER_UNKNOWN ;
case WBC_ERR_PWD_CHANGE_FAILED :
break ;
}
/* be paranoid */
return PAM_AUTH_ERR ;
}
2008-08-14 19:40:26 +04:00
static const char * _pam_error_code_str ( int err )
{
switch ( err ) {
case PAM_SUCCESS :
return " PAM_SUCCESS " ;
case PAM_OPEN_ERR :
return " PAM_OPEN_ERR " ;
case PAM_SYMBOL_ERR :
return " PAM_SYMBOL_ERR " ;
case PAM_SERVICE_ERR :
return " PAM_SERVICE_ERR " ;
case PAM_SYSTEM_ERR :
return " PAM_SYSTEM_ERR " ;
case PAM_BUF_ERR :
return " PAM_BUF_ERR " ;
case PAM_PERM_DENIED :
return " PAM_PERM_DENIED " ;
case PAM_AUTH_ERR :
return " PAM_AUTH_ERR " ;
case PAM_CRED_INSUFFICIENT :
return " PAM_CRED_INSUFFICIENT " ;
case PAM_AUTHINFO_UNAVAIL :
return " PAM_AUTHINFO_UNAVAIL " ;
case PAM_USER_UNKNOWN :
return " PAM_USER_UNKNOWN " ;
case PAM_MAXTRIES :
return " PAM_MAXTRIES " ;
case PAM_NEW_AUTHTOK_REQD :
return " PAM_NEW_AUTHTOK_REQD " ;
case PAM_ACCT_EXPIRED :
return " PAM_ACCT_EXPIRED " ;
case PAM_SESSION_ERR :
return " PAM_SESSION_ERR " ;
case PAM_CRED_UNAVAIL :
return " PAM_CRED_UNAVAIL " ;
case PAM_CRED_EXPIRED :
return " PAM_CRED_EXPIRED " ;
case PAM_CRED_ERR :
return " PAM_CRED_ERR " ;
case PAM_NO_MODULE_DATA :
return " PAM_NO_MODULE_DATA " ;
case PAM_CONV_ERR :
return " PAM_CONV_ERR " ;
case PAM_AUTHTOK_ERR :
return " PAM_AUTHTOK_ERR " ;
2008-12-15 13:32:45 +03:00
case PAM_AUTHTOK_RECOVER_ERR :
return " PAM_AUTHTOK_RECOVER_ERR " ;
2008-08-14 19:40:26 +04:00
case PAM_AUTHTOK_LOCK_BUSY :
return " PAM_AUTHTOK_LOCK_BUSY " ;
case PAM_AUTHTOK_DISABLE_AGING :
return " PAM_AUTHTOK_DISABLE_AGING " ;
case PAM_TRY_AGAIN :
return " PAM_TRY_AGAIN " ;
case PAM_IGNORE :
return " PAM_IGNORE " ;
case PAM_ABORT :
return " PAM_ABORT " ;
case PAM_AUTHTOK_EXPIRED :
return " PAM_AUTHTOK_EXPIRED " ;
2008-09-24 01:41:39 +04:00
# ifdef PAM_MODULE_UNKNOWN
2008-08-14 19:40:26 +04:00
case PAM_MODULE_UNKNOWN :
return " PAM_MODULE_UNKNOWN " ;
2008-09-24 01:41:39 +04:00
# endif
# ifdef PAM_BAD_ITEM
2008-08-14 19:40:26 +04:00
case PAM_BAD_ITEM :
return " PAM_BAD_ITEM " ;
2008-09-24 01:41:39 +04:00
# endif
# ifdef PAM_CONV_AGAIN
2008-08-14 19:40:26 +04:00
case PAM_CONV_AGAIN :
return " PAM_CONV_AGAIN " ;
2008-09-24 01:41:39 +04:00
# endif
# ifdef PAM_INCOMPLETE
2008-08-14 19:40:26 +04:00
case PAM_INCOMPLETE :
return " PAM_INCOMPLETE " ;
2008-09-24 01:41:39 +04:00
# endif
2008-08-14 19:40:26 +04:00
default :
return NULL ;
}
}
2008-04-03 17:41:26 +04:00
# define _PAM_LOG_FUNCTION_ENTER(function, ctx) \
2007-01-25 04:56:34 +03:00
do { \
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_DEBUG , " [pamh: %p] ENTER: " \
function " (flags: 0x%04x) " , ctx - > pamh , ctx - > flags ) ; \
_pam_log_state ( ctx ) ; \
2007-01-25 04:56:34 +03:00
} while ( 0 )
2008-04-03 17:41:26 +04:00
# define _PAM_LOG_FUNCTION_LEAVE(function, ctx, retval) \
2007-01-25 04:56:34 +03:00
do { \
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_DEBUG , " [pamh: %p] LEAVE: " \
2008-08-14 22:56:47 +04:00
function " returning %d (%s) " , ctx - > pamh , retval , \
_pam_error_code_str ( retval ) ) ; \
2008-04-03 17:41:26 +04:00
_pam_log_state ( ctx ) ; \
2007-01-25 04:56:34 +03:00
} while ( 0 )
2002-02-05 12:40:36 +03:00
/* data tokens */
# define MAX_PASSWD_TRIES 3
2008-10-30 12:53:52 +03:00
# ifdef HAVE_GETTEXT
static char initialized = 0 ;
static inline void textdomain_init ( void ) ;
static inline void textdomain_init ( void )
{
if ( ! initialized ) {
bindtextdomain ( MODULE_NAME , dyn_LOCALEDIR ) ;
initialized = 1 ;
}
return ;
}
# endif
2006-09-13 20:39:52 +04:00
/*
2007-09-14 12:21:20 +04:00
* Work around the pam API that has functions with void * * as parameters
2006-09-13 20:39:52 +04:00
* These lead to strict aliasing warnings with gcc .
*/
2007-09-14 12:21:20 +04:00
static int _pam_get_item ( const pam_handle_t * pamh ,
int item_type ,
2006-09-13 20:39:52 +04:00
const void * _item )
{
const void * * item = ( const void * * ) _item ;
return pam_get_item ( pamh , item_type , item ) ;
}
static int _pam_get_data ( const pam_handle_t * pamh ,
2007-09-14 12:21:20 +04:00
const char * module_data_name ,
const void * _data )
2006-09-13 20:39:52 +04:00
{
const void * * data = ( const void * * ) _data ;
return pam_get_data ( pamh , module_data_name , data ) ;
}
2000-05-09 15:43:00 +04:00
/* some syslogging */
2006-09-13 20:39:52 +04:00
2006-12-18 18:35:52 +03:00
# ifdef HAVE_PAM_VSYSLOG
2007-09-14 12:21:20 +04:00
static void _pam_log_int ( const pam_handle_t * pamh ,
int err ,
const char * format ,
va_list args )
2006-09-13 20:39:52 +04:00
{
pam_vsyslog ( pamh , err , format , args ) ;
2006-12-18 18:35:52 +03:00
}
2006-09-13 20:39:52 +04:00
# else
2007-09-14 12:21:20 +04:00
static void _pam_log_int ( const pam_handle_t * pamh ,
int err ,
const char * format ,
va_list args )
2006-12-18 18:35:52 +03:00
{
2006-09-13 20:39:52 +04:00
char * format2 = NULL ;
const char * service ;
_pam_get_item ( pamh , PAM_SERVICE , & service ) ;
2007-09-29 12:25:44 +04:00
format2 = ( char * ) malloc ( strlen ( MODULE_NAME ) + strlen ( format ) + strlen ( service ) + 5 ) ;
2006-09-13 20:39:52 +04:00
if ( format2 = = NULL ) {
/* what else todo ? */
vsyslog ( err , format , args ) ;
return ;
}
sprintf ( format2 , " %s(%s): %s " , MODULE_NAME , service , format ) ;
vsyslog ( err , format2 , args ) ;
SAFE_FREE ( format2 ) ;
}
2006-12-18 18:35:52 +03:00
# endif /* HAVE_PAM_VSYSLOG */
2006-09-13 20:39:52 +04:00
2007-09-13 18:14:02 +04:00
static bool _pam_log_is_silent ( int ctrl )
2007-01-25 04:56:34 +03:00
{
2007-01-25 18:05:23 +03:00
return on ( ctrl , WINBIND_SILENT ) ;
2007-01-25 04:56:34 +03:00
}
2008-04-03 17:41:26 +04:00
static void _pam_log ( struct pwb_context * r , int err , const char * format , . . . ) PRINTF_ATTRIBUTE ( 3 , 4 ) ;
static void _pam_log ( struct pwb_context * r , int err , const char * format , . . . )
{
va_list args ;
if ( _pam_log_is_silent ( r - > ctrl ) ) {
return ;
}
va_start ( args , format ) ;
_pam_log_int ( r - > pamh , err , format , args ) ;
va_end ( args ) ;
}
static void __pam_log ( const pam_handle_t * pamh , int ctrl , int err , const char * format , . . . ) PRINTF_ATTRIBUTE ( 4 , 5 ) ;
static void __pam_log ( const pam_handle_t * pamh , int ctrl , int err , const char * format , . . . )
2000-05-09 15:43:00 +04:00
{
va_list args ;
2007-01-25 04:56:34 +03:00
if ( _pam_log_is_silent ( ctrl ) ) {
2006-09-13 20:39:52 +04:00
return ;
}
2000-05-09 15:43:00 +04:00
va_start ( args , format ) ;
2006-09-13 20:39:52 +04:00
_pam_log_int ( pamh , err , format , args ) ;
2000-05-09 15:43:00 +04:00
va_end ( args ) ;
}
2007-09-13 18:14:02 +04:00
static bool _pam_log_is_debug_enabled ( int ctrl )
2006-02-04 01:19:41 +03:00
{
2007-01-25 04:56:34 +03:00
if ( ctrl = = - 1 ) {
2007-09-13 18:14:02 +04:00
return false ;
2007-01-25 04:56:34 +03:00
}
2006-02-04 01:19:41 +03:00
2007-01-25 04:56:34 +03:00
if ( _pam_log_is_silent ( ctrl ) ) {
2007-09-13 18:14:02 +04:00
return false ;
2006-09-13 20:39:52 +04:00
}
2006-02-04 01:19:41 +03:00
if ( ! ( ctrl & WINBIND_DEBUG_ARG ) ) {
2007-09-13 18:14:02 +04:00
return false ;
2007-01-25 04:56:34 +03:00
}
2007-09-13 18:14:02 +04:00
return true ;
2007-01-25 04:56:34 +03:00
}
2007-09-13 18:14:02 +04:00
static bool _pam_log_is_debug_state_enabled ( int ctrl )
2007-01-25 04:56:34 +03:00
{
if ( ! ( ctrl & WINBIND_DEBUG_STATE ) ) {
2007-09-13 18:14:02 +04:00
return false ;
2007-01-25 04:56:34 +03:00
}
return _pam_log_is_debug_enabled ( ctrl ) ;
}
2008-04-03 17:41:26 +04:00
static void _pam_log_debug ( struct pwb_context * r , int err , const char * format , . . . ) PRINTF_ATTRIBUTE ( 3 , 4 ) ;
static void _pam_log_debug ( struct pwb_context * r , int err , const char * format , . . . )
{
va_list args ;
if ( ! _pam_log_is_debug_enabled ( r - > ctrl ) ) {
return ;
}
va_start ( args , format ) ;
_pam_log_int ( r - > pamh , err , format , args ) ;
va_end ( args ) ;
}
static void __pam_log_debug ( const pam_handle_t * pamh , int ctrl , int err , const char * format , . . . ) PRINTF_ATTRIBUTE ( 4 , 5 ) ;
static void __pam_log_debug ( const pam_handle_t * pamh , int ctrl , int err , const char * format , . . . )
2007-01-25 04:56:34 +03:00
{
va_list args ;
if ( ! _pam_log_is_debug_enabled ( ctrl ) ) {
2006-02-04 01:19:41 +03:00
return ;
}
va_start ( args , format ) ;
2006-09-13 20:39:52 +04:00
_pam_log_int ( pamh , err , format , args ) ;
2006-02-04 01:19:41 +03:00
va_end ( args ) ;
}
2008-04-03 17:41:26 +04:00
static void _pam_log_state_datum ( struct pwb_context * ctx ,
2007-09-14 12:21:20 +04:00
int item_type ,
const char * key ,
int is_string )
2007-01-25 04:56:34 +03:00
{
const void * data = NULL ;
if ( item_type ! = 0 ) {
2008-04-03 17:41:26 +04:00
pam_get_item ( ctx - > pamh , item_type , & data ) ;
2007-01-25 04:56:34 +03:00
} else {
2008-04-03 17:41:26 +04:00
pam_get_data ( ctx - > pamh , key , & data ) ;
2007-01-25 04:56:34 +03:00
}
if ( data ! = NULL ) {
const char * type = ( item_type ! = 0 ) ? " ITEM " : " DATA " ;
if ( is_string ! = 0 ) {
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_DEBUG ,
2007-09-14 12:21:20 +04:00
" [pamh: %p] STATE: %s(%s) = \" %s \" (%p) " ,
2008-04-03 17:41:26 +04:00
ctx - > pamh , type , key , ( const char * ) data ,
2007-09-14 12:21:20 +04:00
data ) ;
2007-01-25 04:56:34 +03:00
} else {
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_DEBUG ,
2007-09-14 12:21:20 +04:00
" [pamh: %p] STATE: %s(%s) = %p " ,
2008-04-03 17:41:26 +04:00
ctx - > pamh , type , key , data ) ;
2007-01-25 04:56:34 +03:00
}
}
}
2008-04-03 17:41:26 +04:00
# define _PAM_LOG_STATE_DATA_POINTER(ctx, module_data_name) \
_pam_log_state_datum ( ctx , 0 , module_data_name , 0 )
2007-01-25 04:56:34 +03:00
2008-04-03 17:41:26 +04:00
# define _PAM_LOG_STATE_DATA_STRING(ctx, module_data_name) \
_pam_log_state_datum ( ctx , 0 , module_data_name , 1 )
2007-01-25 04:56:34 +03:00
2008-04-03 17:41:26 +04:00
# define _PAM_LOG_STATE_ITEM_POINTER(ctx, item_type) \
_pam_log_state_datum ( ctx , item_type , # item_type , 0 )
2007-01-25 04:56:34 +03:00
2008-04-03 17:41:26 +04:00
# define _PAM_LOG_STATE_ITEM_STRING(ctx, item_type) \
_pam_log_state_datum ( ctx , item_type , # item_type , 1 )
2007-01-25 04:56:34 +03:00
# ifdef DEBUG_PASSWORD
# define _LOG_PASSWORD_AS_STRING 1
# else
# define _LOG_PASSWORD_AS_STRING 0
# endif
2008-04-03 17:41:26 +04:00
# define _PAM_LOG_STATE_ITEM_PASSWORD(ctx, item_type) \
_pam_log_state_datum ( ctx , item_type , # item_type , \
2007-09-14 12:21:20 +04:00
_LOG_PASSWORD_AS_STRING )
2007-01-25 04:56:34 +03:00
2008-04-03 17:41:26 +04:00
static void _pam_log_state ( struct pwb_context * ctx )
2007-01-25 04:56:34 +03:00
{
2008-04-03 17:41:26 +04:00
if ( ! _pam_log_is_debug_state_enabled ( ctx - > ctrl ) ) {
2007-01-25 04:56:34 +03:00
return ;
}
2008-04-03 17:41:26 +04:00
_PAM_LOG_STATE_ITEM_STRING ( ctx , PAM_SERVICE ) ;
_PAM_LOG_STATE_ITEM_STRING ( ctx , PAM_USER ) ;
_PAM_LOG_STATE_ITEM_STRING ( ctx , PAM_TTY ) ;
_PAM_LOG_STATE_ITEM_STRING ( ctx , PAM_RHOST ) ;
_PAM_LOG_STATE_ITEM_STRING ( ctx , PAM_RUSER ) ;
_PAM_LOG_STATE_ITEM_PASSWORD ( ctx , PAM_OLDAUTHTOK ) ;
_PAM_LOG_STATE_ITEM_PASSWORD ( ctx , PAM_AUTHTOK ) ;
_PAM_LOG_STATE_ITEM_STRING ( ctx , PAM_USER_PROMPT ) ;
_PAM_LOG_STATE_ITEM_POINTER ( ctx , PAM_CONV ) ;
2007-01-25 04:56:34 +03:00
# ifdef PAM_FAIL_DELAY
2008-04-03 17:41:26 +04:00
_PAM_LOG_STATE_ITEM_POINTER ( ctx , PAM_FAIL_DELAY ) ;
2007-01-25 04:56:34 +03:00
# endif
# ifdef PAM_REPOSITORY
2008-04-03 17:41:26 +04:00
_PAM_LOG_STATE_ITEM_POINTER ( ctx , PAM_REPOSITORY ) ;
2007-01-25 04:56:34 +03:00
# endif
2008-04-03 17:41:26 +04:00
_PAM_LOG_STATE_DATA_STRING ( ctx , PAM_WINBIND_HOMEDIR ) ;
_PAM_LOG_STATE_DATA_STRING ( ctx , PAM_WINBIND_LOGONSCRIPT ) ;
_PAM_LOG_STATE_DATA_STRING ( ctx , PAM_WINBIND_LOGONSERVER ) ;
_PAM_LOG_STATE_DATA_STRING ( ctx , PAM_WINBIND_PROFILEPATH ) ;
_PAM_LOG_STATE_DATA_STRING ( ctx ,
2007-09-14 12:21:20 +04:00
PAM_WINBIND_NEW_AUTHTOK_REQD ) ;
/* Use atoi to get PAM result code */
2008-04-03 17:41:26 +04:00
_PAM_LOG_STATE_DATA_STRING ( ctx ,
2007-09-14 12:21:20 +04:00
PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH ) ;
2008-04-03 17:41:26 +04:00
_PAM_LOG_STATE_DATA_POINTER ( ctx , PAM_WINBIND_PWD_LAST_SET ) ;
2007-01-25 04:56:34 +03:00
}
2007-09-14 12:21:20 +04:00
static int _pam_parse ( const pam_handle_t * pamh ,
int flags ,
int argc ,
const char * * argv ,
dictionary * * result_d )
2000-05-09 15:43:00 +04:00
{
2006-02-04 01:19:41 +03:00
int ctrl = 0 ;
2006-04-11 18:40:53 +04:00
const char * config_file = NULL ;
2006-07-13 20:31:26 +04:00
int i ;
const char * * v ;
2007-01-25 03:47:27 +03:00
dictionary * d = NULL ;
2006-02-04 01:19:41 +03:00
2006-09-13 20:39:52 +04:00
if ( flags & PAM_SILENT ) {
ctrl | = WINBIND_SILENT ;
}
2006-07-13 20:31:26 +04:00
for ( i = argc , v = argv ; i - - > 0 ; + + v ) {
if ( ! strncasecmp ( * v , " config " , strlen ( " config " ) ) ) {
2006-04-11 18:40:53 +04:00
ctrl | = WINBIND_CONFIG_FILE ;
2006-07-13 20:31:26 +04:00
config_file = v [ i ] ;
2006-04-11 18:40:53 +04:00
break ;
}
}
if ( config_file = = NULL ) {
2006-04-11 19:18:46 +04:00
config_file = PAM_WINBIND_CONFIG_FILE ;
2006-04-11 18:40:53 +04:00
}
2007-01-25 03:47:27 +03:00
d = iniparser_load ( config_file ) ;
if ( d = = NULL ) {
2006-05-11 01:12:10 +04:00
goto config_from_pam ;
2006-02-04 01:19:41 +03:00
}
2007-09-13 18:14:02 +04:00
if ( iniparser_getboolean ( d , " global:debug " , false ) ) {
2006-04-11 18:40:53 +04:00
ctrl | = WINBIND_DEBUG_ARG ;
}
2007-09-13 18:14:02 +04:00
if ( iniparser_getboolean ( d , " global:debug_state " , false ) ) {
2007-01-25 04:56:34 +03:00
ctrl | = WINBIND_DEBUG_STATE ;
}
2007-09-13 18:14:02 +04:00
if ( iniparser_getboolean ( d , " global:cached_login " , false ) ) {
2006-02-04 01:19:41 +03:00
ctrl | = WINBIND_CACHED_LOGIN ;
}
2006-04-11 18:40:53 +04:00
2007-09-13 18:14:02 +04:00
if ( iniparser_getboolean ( d , " global:krb5_auth " , false ) ) {
2006-02-04 01:19:41 +03:00
ctrl | = WINBIND_KRB5_AUTH ;
}
2006-04-11 18:40:53 +04:00
2007-09-13 18:14:02 +04:00
if ( iniparser_getboolean ( d , " global:silent " , false ) ) {
2006-09-13 20:39:52 +04:00
ctrl | = WINBIND_SILENT ;
}
2007-01-25 03:47:27 +03:00
if ( iniparser_getstr ( d , " global:krb5_ccache_type " ) ! = NULL ) {
2006-02-04 01:19:41 +03:00
ctrl | = WINBIND_KRB5_CCACHE_TYPE ;
}
2007-01-25 04:56:34 +03:00
2007-01-25 03:47:27 +03:00
if ( ( iniparser_getstr ( d , " global:require-membership-of " ) ! = NULL ) | |
( iniparser_getstr ( d , " global:require_membership_of " ) ! = NULL ) ) {
2006-02-04 01:19:41 +03:00
ctrl | = WINBIND_REQUIRED_MEMBERSHIP ;
}
2007-09-13 18:14:02 +04:00
if ( iniparser_getboolean ( d , " global:try_first_pass " , false ) ) {
2007-01-25 03:47:27 +03:00
ctrl | = WINBIND_TRY_FIRST_PASS_ARG ;
}
2007-07-05 00:25:29 +04:00
if ( iniparser_getint ( d , " global:warn_pwd_expire " , 0 ) ) {
ctrl | = WINBIND_WARN_PWD_EXPIRE ;
}
2008-08-14 16:39:52 +04:00
if ( iniparser_getboolean ( d , " global:mkhomedir " , false ) ) {
ctrl | = WINBIND_MKHOMEDIR ;
}
2006-04-11 18:40:53 +04:00
config_from_pam :
2002-02-05 12:40:36 +03:00
/* step through arguments */
2006-07-13 20:31:26 +04:00
for ( i = argc , v = argv ; i - - > 0 ; + + v ) {
2002-02-05 12:40:36 +03:00
/* generic options */
2006-07-13 20:31:26 +04:00
if ( ! strcmp ( * v , " debug " ) )
2002-02-05 12:40:36 +03:00
ctrl | = WINBIND_DEBUG_ARG ;
2007-01-25 18:05:23 +03:00
else if ( ! strcasecmp ( * v , " debug_state " ) )
ctrl | = WINBIND_DEBUG_STATE ;
2007-05-11 15:54:41 +04:00
else if ( ! strcasecmp ( * v , " silent " ) )
ctrl | = WINBIND_SILENT ;
2006-07-13 20:31:26 +04:00
else if ( ! strcasecmp ( * v , " use_authtok " ) )
2002-02-05 12:40:36 +03:00
ctrl | = WINBIND_USE_AUTHTOK_ARG ;
2006-07-13 20:31:26 +04:00
else if ( ! strcasecmp ( * v , " use_first_pass " ) )
2002-02-05 12:40:36 +03:00
ctrl | = WINBIND_USE_FIRST_PASS_ARG ;
2006-07-13 20:31:26 +04:00
else if ( ! strcasecmp ( * v , " try_first_pass " ) )
2002-03-23 11:28:19 +03:00
ctrl | = WINBIND_TRY_FIRST_PASS_ARG ;
2006-07-13 20:31:26 +04:00
else if ( ! strcasecmp ( * v , " unknown_ok " ) )
2002-02-05 12:40:36 +03:00
ctrl | = WINBIND_UNKNOWN_OK_ARG ;
2007-09-14 12:21:20 +04:00
else if ( ! strncasecmp ( * v , " require_membership_of " ,
strlen ( " require_membership_of " ) ) )
2004-10-01 07:28:39 +04:00
ctrl | = WINBIND_REQUIRED_MEMBERSHIP ;
2007-09-14 12:21:20 +04:00
else if ( ! strncasecmp ( * v , " require-membership-of " ,
strlen ( " require-membership-of " ) ) )
2004-08-18 20:25:41 +04:00
ctrl | = WINBIND_REQUIRED_MEMBERSHIP ;
2006-07-13 20:31:26 +04:00
else if ( ! strcasecmp ( * v , " krb5_auth " ) )
2006-02-04 01:19:41 +03:00
ctrl | = WINBIND_KRB5_AUTH ;
2007-09-14 12:21:20 +04:00
else if ( ! strncasecmp ( * v , " krb5_ccache_type " ,
strlen ( " krb5_ccache_type " ) ) )
2006-02-04 01:19:41 +03:00
ctrl | = WINBIND_KRB5_CCACHE_TYPE ;
2006-07-13 20:31:26 +04:00
else if ( ! strcasecmp ( * v , " cached_login " ) )
2006-02-04 01:19:41 +03:00
ctrl | = WINBIND_CACHED_LOGIN ;
2008-08-14 16:39:52 +04:00
else if ( ! strcasecmp ( * v , " mkhomedir " ) )
ctrl | = WINBIND_MKHOMEDIR ;
2002-02-05 12:40:36 +03:00
else {
2008-04-03 17:41:26 +04:00
__pam_log ( pamh , ctrl , LOG_ERR ,
2007-09-14 12:21:20 +04:00
" pam_parse: unknown option: %s " , * v ) ;
2006-12-19 01:10:09 +03:00
return - 1 ;
2002-02-05 12:40:36 +03:00
}
2006-02-04 01:19:41 +03:00
2002-02-05 12:40:36 +03:00
}
2007-01-25 03:47:27 +03:00
if ( result_d ) {
* result_d = d ;
} else {
if ( d ) {
iniparser_freedict ( d ) ;
}
}
2002-02-05 12:40:36 +03:00
return ctrl ;
2006-02-04 01:19:41 +03:00
} ;
2002-02-05 12:40:36 +03:00
2008-08-14 18:53:51 +04:00
static int _pam_winbind_free_context ( struct pwb_context * ctx )
2008-04-03 15:23:34 +04:00
{
2008-08-14 18:53:51 +04:00
if ( ! ctx ) {
return 0 ;
}
2008-04-03 15:23:34 +04:00
if ( ctx - > dict ) {
iniparser_freedict ( ctx - > dict ) ;
}
2008-08-14 18:53:51 +04:00
return 0 ;
2008-04-03 15:23:34 +04:00
}
2008-04-03 17:41:26 +04:00
static int _pam_winbind_init_context ( pam_handle_t * pamh ,
2008-04-03 15:23:34 +04:00
int flags ,
int argc ,
const char * * argv ,
struct pwb_context * * ctx_p )
{
struct pwb_context * r = NULL ;
2008-10-30 12:53:52 +03:00
# ifdef HAVE_GETTEXT
textdomain_init ( ) ;
# endif
2008-08-14 18:53:51 +04:00
r = TALLOC_ZERO_P ( NULL , struct pwb_context ) ;
2008-04-03 15:23:34 +04:00
if ( ! r ) {
return PAM_BUF_ERR ;
}
2008-08-14 18:53:51 +04:00
talloc_set_destructor ( r , _pam_winbind_free_context ) ;
2008-04-03 15:23:34 +04:00
r - > pamh = pamh ;
r - > flags = flags ;
r - > argc = argc ;
r - > argv = argv ;
r - > ctrl = _pam_parse ( pamh , flags , argc , argv , & r - > dict ) ;
if ( r - > ctrl = = - 1 ) {
2008-08-14 18:53:51 +04:00
TALLOC_FREE ( r ) ;
2008-04-03 15:23:34 +04:00
return PAM_SYSTEM_ERR ;
}
* ctx_p = r ;
return PAM_SUCCESS ;
}
2007-09-14 12:21:20 +04:00
static void _pam_winbind_cleanup_func ( pam_handle_t * pamh ,
void * data ,
int error_status )
2006-01-13 14:11:23 +03:00
{
2007-01-25 04:56:34 +03:00
int ctrl = _pam_parse ( pamh , 0 , 0 , NULL , NULL ) ;
if ( _pam_log_is_debug_state_enabled ( ctrl ) ) {
2008-04-03 17:41:26 +04:00
__pam_log_debug ( pamh , ctrl , LOG_DEBUG ,
2007-09-14 12:21:20 +04:00
" [pamh: %p] CLEAN: cleaning up PAM data %p "
" (error_status = %d) " , pamh , data ,
error_status ) ;
2007-01-25 04:56:34 +03:00
}
2008-08-14 18:53:51 +04:00
TALLOC_FREE ( data ) ;
2006-01-13 14:11:23 +03:00
}
2006-07-11 22:01:26 +04:00
2006-02-04 01:19:41 +03:00
static const struct ntstatus_errors {
const char * ntstatus_string ;
const char * error_string ;
} ntstatus_errors [ ] = {
2007-09-14 12:21:20 +04:00
{ " NT_STATUS_OK " ,
2008-10-30 12:53:52 +03:00
N_ ( " Success " ) } ,
2007-09-14 12:21:20 +04:00
{ " NT_STATUS_BACKUP_CONTROLLER " ,
2008-10-30 12:53:52 +03:00
N_ ( " No primary Domain Controler available " ) } ,
2007-09-14 12:21:20 +04:00
{ " NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND " ,
2008-10-30 12:53:52 +03:00
N_ ( " No domain controllers found " ) } ,
2007-09-14 12:21:20 +04:00
{ " NT_STATUS_NO_LOGON_SERVERS " ,
2008-10-30 12:53:52 +03:00
N_ ( " No logon servers " ) } ,
2007-09-14 12:21:20 +04:00
{ " NT_STATUS_PWD_TOO_SHORT " ,
2008-10-30 12:53:52 +03:00
N_ ( " Password too short " ) } ,
2007-09-14 12:21:20 +04:00
{ " NT_STATUS_PWD_TOO_RECENT " ,
2008-10-30 12:53:52 +03:00
N_ ( " The password of this user is too recent to change " ) } ,
2007-09-14 12:21:20 +04:00
{ " NT_STATUS_PWD_HISTORY_CONFLICT " ,
2008-10-30 12:53:52 +03:00
N_ ( " Password is already in password history " ) } ,
2007-09-14 12:21:20 +04:00
{ " NT_STATUS_PASSWORD_EXPIRED " ,
2008-10-30 12:53:52 +03:00
N_ ( " Your password has expired " ) } ,
2007-09-14 12:21:20 +04:00
{ " NT_STATUS_PASSWORD_MUST_CHANGE " ,
2008-10-30 12:53:52 +03:00
N_ ( " You need to change your password now " ) } ,
2007-09-14 12:21:20 +04:00
{ " NT_STATUS_INVALID_WORKSTATION " ,
2008-10-30 12:53:52 +03:00
N_ ( " You are not allowed to logon from this workstation " ) } ,
2007-09-14 12:21:20 +04:00
{ " NT_STATUS_INVALID_LOGON_HOURS " ,
2008-10-30 12:53:52 +03:00
N_ ( " You are not allowed to logon at this time " ) } ,
2007-09-14 12:21:20 +04:00
{ " NT_STATUS_ACCOUNT_EXPIRED " ,
2008-11-16 11:31:31 +03:00
N_ ( " Your account has expired. "
" Please contact your System administrator " ) } , /* SCNR */
2007-09-14 12:21:20 +04:00
{ " NT_STATUS_ACCOUNT_DISABLED " ,
2008-11-16 11:31:31 +03:00
N_ ( " Your account is disabled. "
" Please contact your System administrator " ) } , /* SCNR */
2007-09-14 12:21:20 +04:00
{ " NT_STATUS_ACCOUNT_LOCKED_OUT " ,
2008-11-16 11:31:31 +03:00
N_ ( " Your account has been locked. "
" Please contact your System administrator " ) } , /* SCNR */
2007-09-14 12:21:20 +04:00
{ " NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT " ,
2008-10-30 12:53:52 +03:00
N_ ( " Invalid Trust Account " ) } ,
2007-09-14 12:21:20 +04:00
{ " NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT " ,
2008-10-30 12:53:52 +03:00
N_ ( " Invalid Trust Account " ) } ,
2007-09-14 12:21:20 +04:00
{ " NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT " ,
2008-10-30 12:53:52 +03:00
N_ ( " Invalid Trust Account " ) } ,
2007-09-14 12:21:20 +04:00
{ " NT_STATUS_ACCESS_DENIED " ,
2008-10-30 12:53:52 +03:00
N_ ( " Access is denied " ) } ,
2006-02-04 01:19:41 +03:00
{ NULL , NULL }
} ;
2008-04-03 15:06:14 +04:00
static const char * _get_ntstatus_error_string ( const char * nt_status_string )
2006-02-04 01:19:41 +03:00
{
int i ;
for ( i = 0 ; ntstatus_errors [ i ] . ntstatus_string ! = NULL ; i + + ) {
2007-09-14 12:21:20 +04:00
if ( ! strcasecmp ( ntstatus_errors [ i ] . ntstatus_string ,
nt_status_string ) ) {
2008-10-30 12:53:52 +03:00
return _ ( ntstatus_errors [ i ] . error_string ) ;
2006-02-04 01:19:41 +03:00
}
}
return NULL ;
}
2002-02-05 12:40:36 +03:00
/* --- authentication management functions --- */
/* Attempt a conversation */
2000-05-09 15:43:00 +04:00
2008-04-03 17:41:26 +04:00
static int converse ( const pam_handle_t * pamh ,
2007-09-14 12:21:20 +04:00
int nargs ,
2002-02-05 12:40:36 +03:00
struct pam_message * * message ,
struct pam_response * * response )
{
2006-02-04 01:19:41 +03:00
int retval ;
struct pam_conv * conv ;
2007-09-14 12:21:20 +04:00
retval = _pam_get_item ( pamh , PAM_CONV , & conv ) ;
2006-02-04 01:19:41 +03:00
if ( retval = = PAM_SUCCESS ) {
2007-09-14 12:21:20 +04:00
retval = conv - > conv ( nargs ,
( const struct pam_message * * ) message ,
2006-02-04 01:19:41 +03:00
response , conv - > appdata_ptr ) ;
}
2007-09-14 12:21:20 +04:00
2006-02-04 01:19:41 +03:00
return retval ; /* propagate error status */
2002-02-05 12:40:36 +03:00
}
2008-04-03 17:41:26 +04:00
static int _make_remark ( struct pwb_context * ctx ,
2007-09-14 12:21:20 +04:00
int type ,
const char * text )
2002-02-05 12:40:36 +03:00
{
int retval = PAM_SUCCESS ;
struct pam_message * pmsg [ 1 ] , msg [ 1 ] ;
struct pam_response * resp ;
2007-09-14 12:21:20 +04:00
2008-04-03 17:41:26 +04:00
if ( ctx - > flags & WINBIND_SILENT ) {
2007-02-05 18:25:31 +03:00
return PAM_SUCCESS ;
}
2002-02-05 12:40:36 +03:00
pmsg [ 0 ] = & msg [ 0 ] ;
2007-09-13 18:14:02 +04:00
msg [ 0 ] . msg = discard_const_p ( char , text ) ;
2002-02-05 12:40:36 +03:00
msg [ 0 ] . msg_style = type ;
2007-09-14 12:21:20 +04:00
2002-02-05 12:40:36 +03:00
resp = NULL ;
2008-04-03 17:41:26 +04:00
retval = converse ( ctx - > pamh , 1 , pmsg , & resp ) ;
2007-09-14 12:21:20 +04:00
2002-02-05 12:40:36 +03:00
if ( resp ) {
_pam_drop_reply ( resp , 1 ) ;
}
return retval ;
2000-05-09 15:43:00 +04:00
}
2008-04-03 17:41:26 +04:00
static int _make_remark_v ( struct pwb_context * ctx ,
2007-09-14 12:21:20 +04:00
int type ,
const char * format ,
va_list args )
2006-02-04 01:19:41 +03:00
{
char * var ;
2006-08-01 19:17:18 +04:00
int ret ;
2006-02-04 01:19:41 +03:00
2007-01-25 04:56:34 +03:00
ret = vasprintf ( & var , format , args ) ;
if ( ret < 0 ) {
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_ERR , " memory allocation failure " ) ;
2007-01-25 04:56:34 +03:00
return ret ;
}
2006-02-04 01:19:41 +03:00
2008-04-03 17:41:26 +04:00
ret = _make_remark ( ctx , type , var ) ;
2006-08-01 19:17:18 +04:00
SAFE_FREE ( var ) ;
return ret ;
2006-02-04 01:19:41 +03:00
}
2008-04-03 17:41:26 +04:00
static int _make_remark_format ( struct pwb_context * ctx , int type , const char * format , . . . ) PRINTF_ATTRIBUTE ( 3 , 4 ) ;
static int _make_remark_format ( struct pwb_context * ctx , int type , const char * format , . . . )
2007-01-25 04:56:34 +03:00
{
int ret ;
va_list args ;
va_start ( args , format ) ;
2008-04-03 17:41:26 +04:00
ret = _make_remark_v ( ctx , type , format , args ) ;
2007-01-25 04:56:34 +03:00
va_end ( args ) ;
return ret ;
}
2008-04-03 17:41:26 +04:00
static int pam_winbind_request_log ( struct pwb_context * ctx ,
2008-08-19 12:59:18 +04:00
int retval ,
2008-08-19 16:52:24 +04:00
const char * user ,
const char * fn )
2001-05-04 04:43:20 +04:00
{
2002-02-05 12:40:36 +03:00
switch ( retval ) {
case PAM_AUTH_ERR :
/* incorrect password */
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_WARNING , " user '%s' denied access "
2007-09-14 12:21:20 +04:00
" (incorrect password or invalid membership) " , user ) ;
2002-02-05 12:40:36 +03:00
return retval ;
2002-07-15 14:35:28 +04:00
case PAM_ACCT_EXPIRED :
/* account expired */
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_WARNING , " user '%s' account expired " ,
2007-09-14 12:21:20 +04:00
user ) ;
2002-07-15 14:35:28 +04:00
return retval ;
case PAM_AUTHTOK_EXPIRED :
/* password expired */
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_WARNING , " user '%s' password expired " ,
2007-09-14 12:21:20 +04:00
user ) ;
2002-07-15 14:35:28 +04:00
return retval ;
2002-08-17 21:00:51 +04:00
case PAM_NEW_AUTHTOK_REQD :
2006-02-04 01:19:41 +03:00
/* new password required */
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_WARNING , " user '%s' new password "
2007-09-14 12:21:20 +04:00
" required " , user ) ;
2002-08-17 21:00:51 +04:00
return retval ;
2002-02-05 12:40:36 +03:00
case PAM_USER_UNKNOWN :
/* the user does not exist */
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_NOTICE , " user '%s' not found " ,
2007-09-14 12:21:20 +04:00
user ) ;
2008-04-03 17:41:26 +04:00
if ( ctx - > ctrl & WINBIND_UNKNOWN_OK_ARG ) {
2002-02-05 12:40:36 +03:00
return PAM_IGNORE ;
2007-09-14 12:21:20 +04:00
}
2002-02-05 12:40:36 +03:00
return retval ;
case PAM_SUCCESS :
2007-02-13 14:04:10 +03:00
/* Otherwise, the authentication looked good */
2008-08-19 16:52:24 +04:00
if ( strcmp ( fn , " wbcLogonUser " ) = = 0 ) {
_pam_log ( ctx , LOG_NOTICE ,
" user '%s' granted access " , user ) ;
} else {
_pam_log ( ctx , LOG_NOTICE ,
" user '%s' OK " , user ) ;
2002-10-26 06:20:59 +04:00
}
2002-02-05 12:40:36 +03:00
return retval ;
default :
/* we don't know anything about this return value */
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_ERR ,
2008-08-19 16:52:24 +04:00
" internal module error (retval = %s(%d), user = '%s') " ,
_pam_error_code_str ( retval ) , retval , user ) ;
2002-02-05 12:40:36 +03:00
return retval ;
}
2002-10-26 06:20:59 +04:00
}
2008-08-19 12:59:18 +04:00
static int wbc_auth_error_to_pam_error ( struct pwb_context * ctx ,
struct wbcAuthErrorInfo * e ,
wbcErr status ,
const char * username ,
const char * fn )
{
int ret = PAM_AUTH_ERR ;
if ( WBC_ERROR_IS_OK ( status ) ) {
_pam_log_debug ( ctx , LOG_DEBUG , " request %s succeeded " ,
fn ) ;
ret = PAM_SUCCESS ;
2008-08-19 16:52:24 +04:00
return pam_winbind_request_log ( ctx , ret , username , fn ) ;
2008-08-19 12:59:18 +04:00
}
if ( e ) {
if ( e - > pam_error ! = PAM_SUCCESS ) {
_pam_log ( ctx , LOG_ERR ,
" request %s failed: %s, "
" PAM error: %s (%d), NTSTATUS: %s, "
" Error message was: %s " ,
fn ,
wbcErrorString ( status ) ,
_pam_error_code_str ( e - > pam_error ) ,
e - > pam_error ,
e - > nt_string ,
e - > display_string ) ;
ret = e - > pam_error ;
2008-08-19 16:52:24 +04:00
return pam_winbind_request_log ( ctx , ret , username , fn ) ;
2008-08-19 12:59:18 +04:00
}
_pam_log ( ctx , LOG_ERR , " request %s failed, but PAM error 0! " , fn ) ;
ret = PAM_SERVICE_ERR ;
2008-08-19 16:52:24 +04:00
return pam_winbind_request_log ( ctx , ret , username , fn ) ;
2008-08-19 12:59:18 +04:00
}
ret = wbc_error_to_pam_error ( status ) ;
2008-08-19 16:52:24 +04:00
return pam_winbind_request_log ( ctx , ret , username , fn ) ;
2008-08-19 12:59:18 +04:00
}
2007-02-05 21:04:28 +03:00
/**
* send a password expiry message if required
2007-09-14 12:21:20 +04:00
*
2008-08-19 18:19:54 +04:00
* @ param ctx PAM winbind context .
2007-02-05 21:04:28 +03:00
* @ param next_change expected ( calculated ) next expiry date .
* @ param already_expired pointer to a boolean to indicate if the password is
* already expired .
*
2007-09-13 18:14:02 +04:00
* @ return boolean Returns true if message has been sent , false if not .
2007-02-05 21:04:28 +03:00
*/
2008-04-03 17:41:26 +04:00
static bool _pam_send_password_expiry_message ( struct pwb_context * ctx ,
2007-07-04 18:03:10 +04:00
time_t next_change ,
time_t now ,
int warn_pwd_expire ,
2007-09-13 18:14:02 +04:00
bool * already_expired )
2007-01-10 15:34:24 +03:00
{
int days = 0 ;
struct tm tm_now , tm_next_change ;
2007-02-05 21:04:28 +03:00
if ( already_expired ) {
2007-09-13 18:14:02 +04:00
* already_expired = false ;
2007-02-05 21:04:28 +03:00
}
if ( next_change < = now ) {
2008-04-03 17:41:26 +04:00
PAM_WB_REMARK_DIRECT ( ctx , " NT_STATUS_PASSWORD_EXPIRED " ) ;
2007-02-05 21:04:28 +03:00
if ( already_expired ) {
2007-09-13 18:14:02 +04:00
* already_expired = true ;
2007-02-05 21:04:28 +03:00
}
2007-09-13 18:14:02 +04:00
return true ;
2007-02-05 21:04:28 +03:00
}
2007-01-10 15:34:24 +03:00
if ( ( next_change < 0 ) | |
2007-07-04 18:03:10 +04:00
( next_change > now + warn_pwd_expire * SECONDS_PER_DAY ) ) {
2007-09-13 18:14:02 +04:00
return false ;
2007-01-10 15:34:24 +03:00
}
2007-09-14 12:21:20 +04:00
if ( ( localtime_r ( & now , & tm_now ) = = NULL ) | |
2007-01-10 15:34:24 +03:00
( localtime_r ( & next_change , & tm_next_change ) = = NULL ) ) {
2007-09-13 18:14:02 +04:00
return false ;
2007-01-10 15:34:24 +03:00
}
2007-09-14 12:21:20 +04:00
days = ( tm_next_change . tm_yday + tm_next_change . tm_year * 365 ) -
( tm_now . tm_yday + tm_now . tm_year * 365 ) ;
2007-01-10 15:34:24 +03:00
if ( days = = 0 ) {
2008-04-03 17:41:26 +04:00
_make_remark ( ctx , PAM_TEXT_INFO ,
2008-10-30 12:53:52 +03:00
_ ( " Your password expires today " ) ) ;
2007-09-13 18:14:02 +04:00
return true ;
2007-09-14 12:21:20 +04:00
}
2007-07-04 18:03:10 +04:00
if ( days > 0 & & days < warn_pwd_expire ) {
2008-04-03 17:41:26 +04:00
_make_remark_format ( ctx , PAM_TEXT_INFO ,
2008-10-30 12:53:52 +03:00
_ ( " Your password will expire in %d %s " ) ,
days , ( days > 1 ) ? _ ( " days " ) : _ ( " day " ) ) ;
2007-09-13 18:14:02 +04:00
return true ;
2007-01-10 15:34:24 +03:00
}
2007-09-13 18:14:02 +04:00
return false ;
2007-01-10 15:34:24 +03:00
}
2007-02-05 21:04:28 +03:00
/**
* Send a warning if the password expires in the near future
*
2008-08-19 18:19:54 +04:00
* @ param ctx PAM winbind context .
2007-02-05 21:04:28 +03:00
* @ param response The full authentication response structure .
* @ param already_expired boolean , is the pwd already expired ?
*
* @ return void .
*/
2008-04-03 17:41:26 +04:00
static void _pam_warn_password_expiry ( struct pwb_context * ctx ,
2008-08-19 13:07:59 +04:00
const struct wbcAuthUserInfo * info ,
const struct wbcUserPasswordPolicyInfo * policy ,
2007-07-04 18:03:10 +04:00
int warn_pwd_expire ,
2007-09-13 18:14:02 +04:00
bool * already_expired )
2007-01-10 15:34:24 +03:00
{
time_t now = time ( NULL ) ;
time_t next_change = 0 ;
2008-08-19 13:07:59 +04:00
if ( ! info | | ! policy ) {
return ;
}
2007-02-05 21:04:28 +03:00
if ( already_expired ) {
2007-09-13 18:14:02 +04:00
* already_expired = false ;
2007-02-05 21:04:28 +03:00
}
2008-08-19 16:48:23 +04:00
/* accounts with WBC_ACB_PWNOEXP set never receive a warning */
if ( info - > acct_flags & WBC_ACB_PWNOEXP ) {
2007-01-10 15:34:24 +03:00
return ;
}
2007-01-11 18:41:02 +03:00
/* no point in sending a warning if this is a grace logon */
2008-08-19 13:07:59 +04:00
if ( PAM_WB_GRACE_LOGON ( info - > user_flags ) ) {
2007-01-11 18:41:02 +03:00
return ;
}
2007-01-10 15:34:24 +03:00
/* check if the info3 must change timestamp has been set */
2008-08-19 13:07:59 +04:00
next_change = info - > pass_must_change_time ;
2007-01-10 15:34:24 +03:00
2008-04-03 17:41:26 +04:00
if ( _pam_send_password_expiry_message ( ctx , next_change , now ,
2007-07-04 18:03:10 +04:00
warn_pwd_expire ,
2007-02-05 21:04:28 +03:00
already_expired ) ) {
2007-01-10 15:34:24 +03:00
return ;
}
/* now check for the global password policy */
2007-02-05 21:04:28 +03:00
/* good catch from Ralf Haferkamp: an expiry of "never" is translated
* to - 1 */
2009-05-05 14:54:21 +04:00
if ( policy - > expire = = - 1 ) {
2007-01-10 15:34:24 +03:00
return ;
}
2008-08-19 13:07:59 +04:00
next_change = info - > pass_last_set_time + policy - > expire ;
2007-01-10 15:34:24 +03:00
2008-04-03 17:41:26 +04:00
if ( _pam_send_password_expiry_message ( ctx , next_change , now ,
2007-07-04 18:03:10 +04:00
warn_pwd_expire ,
2007-02-05 21:04:28 +03:00
already_expired ) ) {
2007-01-10 15:34:24 +03:00
return ;
}
/* no warning sent */
}
2007-01-25 03:47:27 +03:00
# define IS_SID_STRING(name) (strncmp("S-", name, 2) == 0)
/**
2007-09-14 12:21:20 +04:00
* Append a string , making sure not to overflow and to always return a
* NULL - terminated string .
2007-01-25 03:47:27 +03:00
*
* @ param dest Destination string buffer ( must already be NULL - terminated ) .
* @ param src Source string buffer .
* @ param dest_buffer_size Size of dest buffer in bytes .
*
2007-09-14 12:21:20 +04:00
* @ return false if dest buffer is not big enough ( no bytes copied ) , true on
* success .
2007-01-25 03:47:27 +03:00
*/
2007-09-14 12:21:20 +04:00
static bool safe_append_string ( char * dest ,
const char * src ,
int dest_buffer_size )
2007-01-25 03:47:27 +03:00
{
int dest_length = strlen ( dest ) ;
int src_length = strlen ( src ) ;
2007-09-14 12:21:20 +04:00
if ( dest_length + src_length + 1 > dest_buffer_size ) {
2007-09-13 18:14:02 +04:00
return false ;
2007-01-25 03:47:27 +03:00
}
memcpy ( dest + dest_length , src , src_length + 1 ) ;
2007-09-13 18:14:02 +04:00
return true ;
2007-01-25 03:47:27 +03:00
}
/**
* Convert a names into a SID string , appending it to a buffer .
*
2008-08-19 18:19:54 +04:00
* @ param ctx PAM winbind context .
2007-01-25 03:47:27 +03:00
* @ param user User in PAM request .
* @ param name Name to convert .
* @ param sid_list_buffer Where to append the string sid .
* @ param sid_list_buffer Size of sid_list_buffer ( in bytes ) .
*
2007-09-13 18:14:02 +04:00
* @ return false on failure , true on success .
2007-01-25 03:47:27 +03:00
*/
2008-04-03 17:41:26 +04:00
static bool winbind_name_to_sid_string ( struct pwb_context * ctx ,
2007-09-14 12:21:20 +04:00
const char * user ,
const char * name ,
char * sid_list_buffer ,
int sid_list_buffer_size )
2007-01-25 03:47:27 +03:00
{
const char * sid_string ;
2007-09-14 12:21:20 +04:00
/* lookup name? */
2007-01-25 03:47:27 +03:00
if ( IS_SID_STRING ( name ) ) {
sid_string = name ;
} else {
2008-08-15 01:33:12 +04:00
wbcErr wbc_status ;
struct wbcDomainSid sid ;
enum wbcSidType type ;
char * sid_str ;
2007-01-25 03:47:27 +03:00
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_DEBUG ,
2007-09-14 12:21:20 +04:00
" no sid given, looking up: %s \n " , name ) ;
2007-01-25 03:47:27 +03:00
2008-08-15 01:33:12 +04:00
wbc_status = wbcLookupName ( " " , name , & sid , & type ) ;
if ( ! WBC_ERROR_IS_OK ( wbc_status ) ) {
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_INFO ,
2007-09-14 12:21:20 +04:00
" could not lookup name: %s \n " , name ) ;
2007-09-13 18:14:02 +04:00
return false ;
2007-01-25 03:47:27 +03:00
}
2008-08-15 01:33:12 +04:00
wbc_status = wbcSidToString ( & sid , & sid_str ) ;
if ( ! WBC_ERROR_IS_OK ( wbc_status ) ) {
return false ;
}
wbcFreeMemory ( sid_str ) ;
sid_string = sid_str ;
2007-01-25 03:47:27 +03:00
}
2007-09-14 12:21:20 +04:00
if ( ! safe_append_string ( sid_list_buffer , sid_string ,
sid_list_buffer_size ) ) {
2007-09-13 18:14:02 +04:00
return false ;
2007-01-25 03:47:27 +03:00
}
2007-09-13 18:14:02 +04:00
return true ;
2007-01-25 03:47:27 +03:00
}
/**
* Convert a list of names into a list of sids .
*
2008-08-19 18:19:54 +04:00
* @ param ctx PAM winbind context .
2007-01-25 03:47:27 +03:00
* @ param user User in PAM request .
* @ param name_list List of names or string sids , separated by commas .
* @ param sid_list_buffer Where to put the list of string sids .
* @ param sid_list_buffer Size of sid_list_buffer ( in bytes ) .
*
2007-09-13 18:14:02 +04:00
* @ return false on failure , true on success .
2007-01-25 03:47:27 +03:00
*/
2008-04-03 17:41:26 +04:00
static bool winbind_name_list_to_sid_string_list ( struct pwb_context * ctx ,
2007-09-14 12:21:20 +04:00
const char * user ,
const char * name_list ,
char * sid_list_buffer ,
int sid_list_buffer_size )
2007-01-25 03:47:27 +03:00
{
2007-09-13 18:14:02 +04:00
bool result = false ;
2007-01-25 03:47:27 +03:00
char * current_name = NULL ;
const char * search_location ;
const char * comma ;
2007-09-14 12:21:20 +04:00
if ( sid_list_buffer_size > 0 ) {
2007-01-25 03:47:27 +03:00
sid_list_buffer [ 0 ] = 0 ;
}
search_location = name_list ;
2007-09-14 12:21:20 +04:00
while ( ( comma = strstr ( search_location , " , " ) ) ! = NULL ) {
current_name = strndup ( search_location ,
comma - search_location ) ;
2007-01-25 03:47:27 +03:00
if ( NULL = = current_name ) {
goto out ;
}
2008-04-03 17:41:26 +04:00
if ( ! winbind_name_to_sid_string ( ctx , user ,
2007-09-14 12:21:20 +04:00
current_name ,
sid_list_buffer ,
sid_list_buffer_size ) ) {
2007-01-25 03:47:27 +03:00
goto out ;
}
2007-01-25 18:05:23 +03:00
SAFE_FREE ( current_name ) ;
2007-01-25 03:47:27 +03:00
2007-09-14 12:21:20 +04:00
if ( ! safe_append_string ( sid_list_buffer , " , " ,
sid_list_buffer_size ) ) {
2007-01-25 03:47:27 +03:00
goto out ;
}
search_location = comma + 1 ;
}
2008-04-03 17:41:26 +04:00
if ( ! winbind_name_to_sid_string ( ctx , user , search_location ,
2007-09-14 12:21:20 +04:00
sid_list_buffer ,
sid_list_buffer_size ) ) {
2007-01-25 03:47:27 +03:00
goto out ;
}
2007-09-13 18:14:02 +04:00
result = true ;
2007-01-25 03:47:27 +03:00
out :
2007-01-25 18:05:23 +03:00
SAFE_FREE ( current_name ) ;
2007-01-25 03:47:27 +03:00
return result ;
}
2007-02-05 20:28:55 +03:00
/**
* put krb5ccname variable into environment
*
2008-08-19 18:19:54 +04:00
* @ param ctx PAM winbind context .
2007-02-05 20:28:55 +03:00
* @ param krb5ccname env variable retrieved from winbindd .
*
* @ return void .
*/
2008-04-03 17:41:26 +04:00
static void _pam_setup_krb5_env ( struct pwb_context * ctx ,
2008-08-19 13:07:59 +04:00
struct wbcLogonUserInfo * info )
2007-02-05 20:28:55 +03:00
{
char var [ PATH_MAX ] ;
int ret ;
2008-08-19 13:07:59 +04:00
uint32_t i ;
const char * krb5ccname = NULL ;
2007-02-05 20:28:55 +03:00
2008-04-03 17:41:26 +04:00
if ( off ( ctx - > ctrl , WINBIND_KRB5_AUTH ) ) {
2007-02-05 20:28:55 +03:00
return ;
}
2008-08-19 13:07:59 +04:00
if ( ! info ) {
return ;
}
for ( i = 0 ; i < info - > num_blobs ; i + + ) {
if ( strcasecmp ( info - > blobs [ i ] . name , " krb5ccname " ) = = 0 ) {
krb5ccname = ( const char * ) info - > blobs [ i ] . blob . data ;
break ;
}
}
2007-02-05 20:28:55 +03:00
if ( ! krb5ccname | | ( strlen ( krb5ccname ) = = 0 ) ) {
return ;
}
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_DEBUG ,
2007-09-14 12:21:20 +04:00
" request returned KRB5CCNAME: %s " , krb5ccname ) ;
2007-02-05 20:28:55 +03:00
if ( snprintf ( var , sizeof ( var ) , " KRB5CCNAME=%s " , krb5ccname ) = = - 1 ) {
return ;
}
2007-09-14 12:21:20 +04:00
2008-04-03 17:41:26 +04:00
ret = pam_putenv ( ctx - > pamh , var ) ;
2007-02-05 20:28:55 +03:00
if ( ret ) {
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_ERR ,
2007-09-14 12:21:20 +04:00
" failed to set KRB5CCNAME to %s: %s " ,
2008-04-03 17:41:26 +04:00
var , pam_strerror ( ctx - > pamh , ret ) ) ;
2007-02-05 20:28:55 +03:00
}
2007-09-14 12:21:20 +04:00
}
2007-02-05 20:28:55 +03:00
2008-08-19 13:07:59 +04:00
/**
* Copy unix username if available ( further processed in PAM ) .
*
* @ param ctx PAM winbind context
* @ param user_ret A pointer that holds a pointer to a string
* @ param unix_username A username
*
* @ return void .
*/
static void _pam_setup_unix_username ( struct pwb_context * ctx ,
char * * user_ret ,
struct wbcLogonUserInfo * info )
{
const char * unix_username = NULL ;
uint32_t i ;
if ( ! user_ret | | ! info ) {
return ;
}
for ( i = 0 ; i < info - > num_blobs ; i + + ) {
if ( strcasecmp ( info - > blobs [ i ] . name , " unix_username " ) = = 0 ) {
unix_username = ( const char * ) info - > blobs [ i ] . blob . data ;
break ;
}
}
if ( ! unix_username | | ! unix_username [ 0 ] ) {
return ;
}
* user_ret = strdup ( unix_username ) ;
}
2007-02-05 20:12:13 +03:00
/**
* Set string into the PAM stack .
*
2008-08-19 18:19:54 +04:00
* @ param ctx PAM winbind context .
2007-02-05 20:12:13 +03:00
* @ param data_name Key name for pam_set_data .
* @ param value String value .
*
* @ return void .
*/
2008-04-03 17:41:26 +04:00
static void _pam_set_data_string ( struct pwb_context * ctx ,
2007-09-14 12:21:20 +04:00
const char * data_name ,
const char * value )
2007-02-05 20:12:13 +03:00
{
int ret ;
2007-09-14 12:21:20 +04:00
if ( ! data_name | | ! value | | ( strlen ( data_name ) = = 0 ) | |
( strlen ( value ) = = 0 ) ) {
2007-02-05 20:12:13 +03:00
return ;
}
2008-08-14 18:53:51 +04:00
ret = pam_set_data ( ctx - > pamh , data_name , talloc_strdup ( NULL , value ) ,
2007-09-14 12:21:20 +04:00
_pam_winbind_cleanup_func ) ;
2007-02-05 20:12:13 +03:00
if ( ret ) {
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_DEBUG ,
2007-09-14 12:21:20 +04:00
" Could not set data %s: %s \n " ,
2008-04-03 17:41:26 +04:00
data_name , pam_strerror ( ctx - > pamh , ret ) ) ;
2007-02-05 20:12:13 +03:00
}
}
/**
* Set info3 strings into the PAM stack .
*
2008-08-19 18:19:54 +04:00
* @ param ctx PAM winbind context .
2007-02-05 20:12:13 +03:00
* @ param data_name Key name for pam_set_data .
* @ param value String value .
*
* @ return void .
*/
2008-04-03 17:41:26 +04:00
static void _pam_set_data_info3 ( struct pwb_context * ctx ,
2008-08-19 13:07:59 +04:00
const struct wbcAuthUserInfo * info )
2007-02-05 20:12:13 +03:00
{
2008-04-03 17:41:26 +04:00
_pam_set_data_string ( ctx , PAM_WINBIND_HOMEDIR ,
2008-08-19 13:07:59 +04:00
info - > home_directory ) ;
2008-04-03 17:41:26 +04:00
_pam_set_data_string ( ctx , PAM_WINBIND_LOGONSCRIPT ,
2008-08-19 13:07:59 +04:00
info - > logon_script ) ;
2008-04-03 17:41:26 +04:00
_pam_set_data_string ( ctx , PAM_WINBIND_LOGONSERVER ,
2008-08-19 13:07:59 +04:00
info - > logon_server ) ;
2008-04-03 17:41:26 +04:00
_pam_set_data_string ( ctx , PAM_WINBIND_PROFILEPATH ,
2008-08-19 13:07:59 +04:00
info - > profile_path ) ;
2007-02-05 20:12:13 +03:00
}
/**
* Free info3 strings in the PAM stack .
*
* @ param pamh PAM handle
*
* @ return void .
*/
static void _pam_free_data_info3 ( pam_handle_t * pamh )
{
pam_set_data ( pamh , PAM_WINBIND_HOMEDIR , NULL , NULL ) ;
pam_set_data ( pamh , PAM_WINBIND_LOGONSCRIPT , NULL , NULL ) ;
pam_set_data ( pamh , PAM_WINBIND_LOGONSERVER , NULL , NULL ) ;
pam_set_data ( pamh , PAM_WINBIND_PROFILEPATH , NULL , NULL ) ;
}
2007-02-05 20:28:55 +03:00
/**
* Send PAM_ERROR_MSG for cached or grace logons .
*
2008-08-19 18:19:54 +04:00
* @ param ctx PAM winbind context .
2007-02-05 20:28:55 +03:00
* @ param username User in PAM request .
* @ param info3_user_flgs Info3 flags containing logon type bits .
*
* @ return void .
*/
2008-04-03 17:41:26 +04:00
static void _pam_warn_logon_type ( struct pwb_context * ctx ,
2007-09-14 12:21:20 +04:00
const char * username ,
uint32_t info3_user_flgs )
2007-02-05 20:28:55 +03:00
{
/* inform about logon type */
if ( PAM_WB_GRACE_LOGON ( info3_user_flgs ) ) {
2008-04-03 17:41:26 +04:00
_make_remark ( ctx , PAM_ERROR_MSG ,
2008-10-30 12:53:52 +03:00
_ ( " Grace login. "
" Please change your password as soon you're "
" online again " ) ) ;
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_DEBUG ,
2007-09-14 12:21:20 +04:00
" User %s logged on using grace logon \n " ,
username ) ;
2007-02-05 20:28:55 +03:00
} else if ( PAM_WB_CACHED_LOGON ( info3_user_flgs ) ) {
2008-04-03 17:41:26 +04:00
_make_remark ( ctx , PAM_ERROR_MSG ,
2008-10-30 12:53:52 +03:00
_ ( " Domain Controller unreachable, "
" using cached credentials instead. "
" Network resources may be unavailable " ) ) ;
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_DEBUG ,
2007-09-14 12:21:20 +04:00
" User %s logged on using cached credentials \n " ,
username ) ;
2007-02-05 20:28:55 +03:00
}
}
2007-05-07 00:33:33 +04:00
/**
* Send PAM_ERROR_MSG for krb5 errors .
*
2008-08-19 18:19:54 +04:00
* @ param ctx PAM winbind context .
2007-05-07 00:33:33 +04:00
* @ param username User in PAM request .
* @ param info3_user_flgs Info3 flags containing logon type bits .
*
* @ return void .
*/
2008-04-03 17:41:26 +04:00
static void _pam_warn_krb5_failure ( struct pwb_context * ctx ,
2007-09-14 12:21:20 +04:00
const char * username ,
uint32_t info3_user_flgs )
2007-05-07 00:33:33 +04:00
{
if ( PAM_WB_KRB5_CLOCK_SKEW ( info3_user_flgs ) ) {
2008-04-03 17:41:26 +04:00
_make_remark ( ctx , PAM_ERROR_MSG ,
2008-10-30 12:53:52 +03:00
_ ( " Failed to establish your Kerberos Ticket cache "
" due time differences \n "
" with the domain controller. "
" Please verify the system time. \n " ) ) ;
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_DEBUG ,
2007-09-14 12:21:20 +04:00
" User %s: Clock skew when getting Krb5 TGT \n " ,
username ) ;
2007-05-07 00:33:33 +04:00
}
}
2008-08-19 15:36:39 +04:00
static bool _pam_check_remark_auth_err ( struct pwb_context * ctx ,
const struct wbcAuthErrorInfo * e ,
const char * nt_status_string ,
int * pam_error )
{
const char * ntstatus = NULL ;
const char * error_string = NULL ;
if ( ! e | | ! pam_error ) {
return false ;
}
ntstatus = e - > nt_string ;
if ( ! ntstatus ) {
return false ;
}
if ( strcasecmp ( ntstatus , nt_status_string ) = = 0 ) {
error_string = _get_ntstatus_error_string ( nt_status_string ) ;
if ( error_string ) {
_make_remark ( ctx , PAM_ERROR_MSG , error_string ) ;
* pam_error = e - > pam_error ;
return true ;
}
if ( e - > display_string ) {
_make_remark ( ctx , PAM_ERROR_MSG , e - > display_string ) ;
* pam_error = e - > pam_error ;
return true ;
}
_make_remark ( ctx , PAM_ERROR_MSG , nt_status_string ) ;
* pam_error = e - > pam_error ;
return true ;
}
return false ;
} ;
2007-02-05 17:43:06 +03:00
/**
* Compose Password Restriction String for a PAM_ERROR_MSG conversation .
*
2008-08-15 04:34:22 +04:00
* @ param i The wbcUserPasswordPolicyInfo struct .
2007-02-05 17:43:06 +03:00
*
2008-08-15 04:34:22 +04:00
* @ return string ( caller needs to talloc_free ) .
2007-02-05 17:43:06 +03:00
*/
2008-08-14 18:53:51 +04:00
static char * _pam_compose_pwd_restriction_string ( struct pwb_context * ctx ,
2008-08-15 04:34:22 +04:00
struct wbcUserPasswordPolicyInfo * i )
2007-02-05 17:43:06 +03:00
{
char * str = NULL ;
2008-08-15 04:34:22 +04:00
if ( ! i ) {
goto failed ;
}
2008-10-30 12:53:52 +03:00
str = talloc_asprintf ( ctx , _ ( " Your password " ) ) ;
2007-02-05 17:43:06 +03:00
if ( ! str ) {
goto failed ;
}
2008-08-15 04:34:22 +04:00
if ( i - > min_length_password > 0 ) {
2008-08-14 18:53:51 +04:00
str = talloc_asprintf_append ( str ,
2008-11-13 16:44:14 +03:00
_ ( " must be at least %d characters; " ) ,
2008-08-15 04:34:22 +04:00
i - > min_length_password ) ;
2008-08-14 18:53:51 +04:00
if ( ! str ) {
2007-02-05 17:43:06 +03:00
goto failed ;
}
}
2007-09-14 12:21:20 +04:00
2008-08-15 04:34:22 +04:00
if ( i - > password_history > 0 ) {
2008-08-14 18:53:51 +04:00
str = talloc_asprintf_append ( str ,
2008-10-30 12:53:52 +03:00
_ ( " cannot repeat any of your previous %d "
" passwords; " ) ,
2008-08-15 04:34:22 +04:00
i - > password_history ) ;
2008-08-14 18:53:51 +04:00
if ( ! str ) {
2007-02-05 17:43:06 +03:00
goto failed ;
}
}
2007-09-14 12:21:20 +04:00
2008-08-15 04:34:22 +04:00
if ( i - > password_properties & WBC_DOMAIN_PASSWORD_COMPLEX ) {
2008-08-14 18:53:51 +04:00
str = talloc_asprintf_append ( str ,
2008-10-30 12:53:52 +03:00
_ ( " must contain capitals, numerals "
" or punctuation; "
" and cannot contain your account "
" or full name; " ) ) ;
2008-08-14 18:53:51 +04:00
if ( ! str ) {
2007-02-05 17:43:06 +03:00
goto failed ;
}
}
2008-08-14 18:53:51 +04:00
str = talloc_asprintf_append ( str ,
2008-10-30 12:53:52 +03:00
_ ( " Please type a different password. "
" Type a password which meets these requirements in "
" both text boxes. " ) ) ;
2008-08-14 18:53:51 +04:00
if ( ! str ) {
2007-02-05 17:43:06 +03:00
goto failed ;
}
return str ;
failed :
2008-08-14 18:53:51 +04:00
TALLOC_FREE ( str ) ;
2007-02-05 17:43:06 +03:00
return NULL ;
}
2008-08-14 16:39:52 +04:00
static int _pam_create_homedir ( struct pwb_context * ctx ,
const char * dirname ,
mode_t mode )
{
struct stat sbuf ;
if ( stat ( dirname , & sbuf ) = = 0 ) {
return PAM_SUCCESS ;
}
if ( mkdir ( dirname , mode ) ! = 0 ) {
_make_remark_format ( ctx , PAM_TEXT_INFO ,
2008-11-13 16:44:14 +03:00
_ ( " Creating directory: %s failed: %s " ) ,
2008-08-14 16:39:52 +04:00
dirname , strerror ( errno ) ) ;
_pam_log ( ctx , LOG_ERR , " could not create dir: %s (%s) " ,
dirname , strerror ( errno ) ) ;
return PAM_PERM_DENIED ;
}
return PAM_SUCCESS ;
}
static int _pam_chown_homedir ( struct pwb_context * ctx ,
const char * dirname ,
uid_t uid ,
gid_t gid )
{
if ( chown ( dirname , uid , gid ) ! = 0 ) {
_pam_log ( ctx , LOG_ERR , " failed to chown user homedir: %s (%s) " ,
dirname , strerror ( errno ) ) ;
return PAM_PERM_DENIED ;
}
return PAM_SUCCESS ;
}
static int _pam_mkhomedir ( struct pwb_context * ctx )
{
struct passwd * pwd = NULL ;
char * token = NULL ;
char * create_dir = NULL ;
char * user_dir = NULL ;
int ret ;
const char * username ;
mode_t mode = 0700 ;
char * safe_ptr = NULL ;
char * p = NULL ;
/* Get the username */
ret = pam_get_user ( ctx - > pamh , & username , NULL ) ;
if ( ( ret ! = PAM_SUCCESS ) | | ( ! username ) ) {
_pam_log_debug ( ctx , LOG_DEBUG , " can not get the username " ) ;
return PAM_SERVICE_ERR ;
}
pwd = getpwnam ( username ) ;
if ( pwd = = NULL ) {
_pam_log_debug ( ctx , LOG_DEBUG , " can not get the username " ) ;
return PAM_USER_UNKNOWN ;
}
_pam_log_debug ( ctx , LOG_DEBUG , " homedir is: %s " , pwd - > pw_dir ) ;
ret = _pam_create_homedir ( ctx , pwd - > pw_dir , 0700 ) ;
if ( ret = = PAM_SUCCESS ) {
ret = _pam_chown_homedir ( ctx , pwd - > pw_dir ,
pwd - > pw_uid ,
pwd - > pw_gid ) ;
}
if ( ret = = PAM_SUCCESS ) {
return ret ;
}
/* maybe we need to create parent dirs */
create_dir = talloc_strdup ( ctx , " / " ) ;
if ( ! create_dir ) {
return PAM_BUF_ERR ;
}
/* find final directory */
user_dir = strrchr ( pwd - > pw_dir , ' / ' ) ;
if ( ! user_dir ) {
return PAM_BUF_ERR ;
}
user_dir + + ;
_pam_log ( ctx , LOG_DEBUG , " final directory: %s " , user_dir ) ;
p = pwd - > pw_dir ;
while ( ( token = strtok_r ( p , " / " , & safe_ptr ) ) ! = NULL ) {
mode = 0755 ;
p = NULL ;
_pam_log_debug ( ctx , LOG_DEBUG , " token is %s " , token ) ;
create_dir = talloc_asprintf_append ( create_dir , " %s/ " , token ) ;
if ( ! create_dir ) {
return PAM_BUF_ERR ;
}
_pam_log_debug ( ctx , LOG_DEBUG , " current_dir is %s " , create_dir ) ;
if ( strcmp ( token , user_dir ) = = 0 ) {
_pam_log_debug ( ctx , LOG_DEBUG , " assuming last directory: %s " , token ) ;
mode = 0700 ;
}
ret = _pam_create_homedir ( ctx , create_dir , mode ) ;
if ( ret ) {
return ret ;
}
}
return _pam_chown_homedir ( ctx , create_dir ,
pwd - > pw_uid ,
pwd - > pw_gid ) ;
}
2002-10-26 06:20:59 +04:00
/* talk to winbindd */
2008-04-03 17:41:26 +04:00
static int winbind_auth_request ( struct pwb_context * ctx ,
2007-09-14 12:21:20 +04:00
const char * user ,
const char * pass ,
const char * member ,
2006-02-04 01:19:41 +03:00
const char * cctype ,
2007-07-04 18:03:10 +04:00
const int warn_pwd_expire ,
2008-08-19 13:07:59 +04:00
struct wbcAuthErrorInfo * * p_error ,
struct wbcLogonUserInfo * * p_info ,
struct wbcUserPasswordPolicyInfo * * p_policy ,
2006-09-05 09:28:31 +04:00
time_t * pwd_last_set ,
char * * user_ret )
2002-10-26 06:20:59 +04:00
{
2008-08-19 13:07:59 +04:00
wbcErr wbc_status ;
struct wbcLogonUserParams logon ;
char membership_of [ 1024 ] ;
uid_t user_uid = - 1 ;
uint32_t flags = WBFLAG_PAM_INFO3_TEXT |
WBFLAG_PAM_GET_PWD_POLICY ;
2002-10-26 06:20:59 +04:00
2008-08-19 13:07:59 +04:00
struct wbcLogonUserInfo * info = NULL ;
struct wbcAuthUserInfo * user_info = NULL ;
struct wbcAuthErrorInfo * error = NULL ;
struct wbcUserPasswordPolicyInfo * policy = NULL ;
int ret = PAM_AUTH_ERR ;
int i ;
const char * codes [ ] = {
" NT_STATUS_PASSWORD_EXPIRED " ,
" NT_STATUS_PASSWORD_MUST_CHANGE " ,
" NT_STATUS_INVALID_WORKSTATION " ,
" NT_STATUS_INVALID_LOGON_HOURS " ,
" NT_STATUS_ACCOUNT_EXPIRED " ,
" NT_STATUS_ACCOUNT_DISABLED " ,
" NT_STATUS_ACCOUNT_LOCKED_OUT " ,
" NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT " ,
" NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT " ,
" NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT " ,
" NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND " ,
" NT_STATUS_NO_LOGON_SERVERS " ,
" NT_STATUS_WRONG_PASSWORD " ,
" NT_STATUS_ACCESS_DENIED "
} ;
2002-10-26 06:20:59 +04:00
2006-05-02 23:22:39 +04:00
if ( pwd_last_set ) {
* pwd_last_set = 0 ;
}
2008-03-27 19:57:26 +03:00
/* Krb5 auth always has to go against the KDC of the user's realm */
2008-04-03 17:41:26 +04:00
if ( ctx - > ctrl & WINBIND_KRB5_AUTH ) {
2008-08-19 13:07:59 +04:00
flags | = WBFLAG_PAM_CONTACT_TRUSTDOM ;
2008-03-27 19:57:26 +03:00
}
2006-02-04 01:19:41 +03:00
2008-04-03 17:41:26 +04:00
if ( ctx - > ctrl & ( WINBIND_KRB5_AUTH | WINBIND_CACHED_LOGIN ) ) {
2006-02-04 01:19:41 +03:00
struct passwd * pwd = NULL ;
pwd = getpwnam ( user ) ;
if ( pwd = = NULL ) {
return PAM_USER_UNKNOWN ;
}
2008-08-19 13:07:59 +04:00
user_uid = pwd - > pw_uid ;
2006-02-04 01:19:41 +03:00
}
2004-08-18 20:25:41 +04:00
2008-04-03 17:41:26 +04:00
if ( ctx - > ctrl & WINBIND_KRB5_AUTH ) {
2007-02-13 18:56:09 +03:00
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_DEBUG ,
2007-09-14 12:21:20 +04:00
" enabling krb5 login flag \n " ) ;
2007-02-13 18:56:09 +03:00
2008-08-19 13:07:59 +04:00
flags | = WBFLAG_PAM_KRB5 |
WBFLAG_PAM_FALLBACK_AFTER_KRB5 ;
2007-02-13 18:56:09 +03:00
}
2008-04-03 17:41:26 +04:00
if ( ctx - > ctrl & WINBIND_CACHED_LOGIN ) {
_pam_log_debug ( ctx , LOG_DEBUG ,
2007-09-14 12:21:20 +04:00
" enabling cached login flag \n " ) ;
2008-08-19 13:07:59 +04:00
flags | = WBFLAG_PAM_CACHED_LOGIN ;
2006-02-04 01:19:41 +03:00
}
2006-09-05 09:28:31 +04:00
if ( user_ret ) {
* user_ret = NULL ;
2008-08-19 13:07:59 +04:00
flags | = WBFLAG_PAM_UNIX_NAME ;
2006-09-05 09:28:31 +04:00
}
2006-02-04 01:19:41 +03:00
if ( cctype ! = NULL ) {
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_DEBUG ,
2007-09-14 12:21:20 +04:00
" enabling request for a %s krb5 ccache \n " ,
cctype ) ;
2006-02-04 01:19:41 +03:00
}
if ( member ! = NULL ) {
2004-08-18 20:25:41 +04:00
2008-08-19 13:07:59 +04:00
ZERO_STRUCT ( membership_of ) ;
2004-08-18 20:25:41 +04:00
2008-08-19 13:07:59 +04:00
if ( ! winbind_name_list_to_sid_string_list ( ctx , user , member ,
membership_of ,
sizeof ( membership_of ) ) ) {
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_ERR ,
2007-09-14 12:21:20 +04:00
" failed to serialize membership of sid "
" \" %s \" \n " , member ) ;
2004-08-18 20:25:41 +04:00
return PAM_AUTH_ERR ;
}
}
2007-01-25 03:47:27 +03:00
2008-08-19 13:07:59 +04:00
ZERO_STRUCT ( logon ) ;
2004-08-18 20:25:41 +04:00
2008-08-19 13:07:59 +04:00
logon . username = user ;
logon . password = pass ;
2008-11-12 16:27:51 +03:00
if ( cctype ) {
wbc_status = wbcAddNamedBlob ( & logon . num_blobs ,
& logon . blobs ,
" krb5_cc_type " ,
0 ,
( uint8_t * ) cctype ,
strlen ( cctype ) + 1 ) ;
if ( ! WBC_ERROR_IS_OK ( wbc_status ) ) {
goto done ;
}
2006-05-02 23:22:39 +04:00
}
2008-08-19 13:07:59 +04:00
wbc_status = wbcAddNamedBlob ( & logon . num_blobs ,
& logon . blobs ,
" flags " ,
0 ,
( uint8_t * ) & flags ,
sizeof ( flags ) ) ;
if ( ! WBC_ERROR_IS_OK ( wbc_status ) ) {
goto done ;
}
wbc_status = wbcAddNamedBlob ( & logon . num_blobs ,
& logon . blobs ,
" user_uid " ,
0 ,
( uint8_t * ) & user_uid ,
sizeof ( user_uid ) ) ;
if ( ! WBC_ERROR_IS_OK ( wbc_status ) ) {
goto done ;
}
2008-11-12 16:27:51 +03:00
if ( member ) {
wbc_status = wbcAddNamedBlob ( & logon . num_blobs ,
& logon . blobs ,
" membership_of " ,
0 ,
( uint8_t * ) membership_of ,
sizeof ( membership_of ) ) ;
if ( ! WBC_ERROR_IS_OK ( wbc_status ) ) {
goto done ;
}
2008-08-19 13:07:59 +04:00
}
wbc_status = wbcLogonUser ( & logon , & info , & error , & policy ) ;
ret = wbc_auth_error_to_pam_error ( ctx , error , wbc_status ,
user , " wbcLogonUser " ) ;
wbcFreeMemory ( logon . blobs ) ;
logon . blobs = NULL ;
if ( info & & info - > info ) {
user_info = info - > info ;
}
if ( pwd_last_set & & user_info ) {
* pwd_last_set = user_info - > pass_last_set_time ;
}
if ( p_info & & info ) {
* p_info = info ;
}
if ( p_policy & & policy ) {
* p_policy = policy ;
}
if ( p_error & & error ) {
/* We want to process the error in the caller. */
* p_error = error ;
2006-02-04 01:19:41 +03:00
return ret ;
}
2008-08-19 13:07:59 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( codes ) ; i + + ) {
int _ret = ret ;
if ( _pam_check_remark_auth_err ( ctx , error , codes [ i ] , & _ret ) ) {
ret = _ret ;
goto done ;
}
}
if ( ( ret = = PAM_SUCCESS ) & & user_info & & policy & & info ) {
bool already_expired = false ;
2006-02-04 01:19:41 +03:00
2007-02-05 21:11:41 +03:00
/* warn a user if the password is about to expire soon */
2008-08-19 13:07:59 +04:00
_pam_warn_password_expiry ( ctx , user_info , policy ,
2007-07-04 18:03:10 +04:00
warn_pwd_expire ,
& already_expired ) ;
2006-02-04 01:19:41 +03:00
2007-09-13 18:14:02 +04:00
if ( already_expired = = true ) {
2008-08-19 13:07:59 +04:00
SMB_TIME_T last_set = user_info - > pass_last_set_time ;
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_DEBUG ,
2007-09-14 12:21:20 +04:00
" Password has expired "
" (Password was last set: %lld, "
" the policy says it should expire here "
" %lld (now it's: %lu)) \n " ,
( long long int ) last_set ,
( long long int ) last_set +
2008-08-19 13:07:59 +04:00
policy - > expire ,
2007-02-05 21:11:41 +03:00
time ( NULL ) ) ;
return PAM_AUTHTOK_EXPIRED ;
}
2006-02-04 01:19:41 +03:00
2007-02-05 21:04:28 +03:00
/* inform about logon type */
2008-08-19 13:07:59 +04:00
_pam_warn_logon_type ( ctx , user , user_info - > user_flags ) ;
2007-05-07 00:33:33 +04:00
/* inform about krb5 failures */
2008-08-19 13:07:59 +04:00
_pam_warn_krb5_failure ( ctx , user , user_info - > user_flags ) ;
2006-02-04 01:19:41 +03:00
2007-02-05 21:04:28 +03:00
/* set some info3 info for other modules in the stack */
2008-08-19 13:07:59 +04:00
_pam_set_data_info3 ( ctx , user_info ) ;
2006-10-17 03:13:56 +04:00
2007-02-05 21:04:28 +03:00
/* put krb5ccname into env */
2008-08-19 13:07:59 +04:00
_pam_setup_krb5_env ( ctx , info ) ;
2007-02-05 20:28:55 +03:00
2007-09-14 12:21:20 +04:00
/* If winbindd returned a username, return the pointer to it
* here . */
2008-08-19 13:07:59 +04:00
_pam_setup_unix_username ( ctx , user_ret , info ) ;
}
done :
if ( logon . blobs ) {
wbcFreeMemory ( logon . blobs ) ;
}
if ( info & & info - > blobs ) {
wbcFreeMemory ( info - > blobs ) ;
}
if ( error & & ! p_error ) {
wbcFreeMemory ( error ) ;
}
if ( info & & ! p_info ) {
wbcFreeMemory ( info ) ;
}
if ( policy & & ! p_policy ) {
wbcFreeMemory ( policy ) ;
2006-09-05 09:28:31 +04:00
}
2006-02-04 01:19:41 +03:00
return ret ;
2001-05-04 04:43:20 +04:00
}
/* talk to winbindd */
2008-04-03 17:41:26 +04:00
static int winbind_chauthtok_request ( struct pwb_context * ctx ,
2007-09-14 12:21:20 +04:00
const char * user ,
2006-02-04 01:19:41 +03:00
const char * oldpass ,
2006-05-02 23:22:39 +04:00
const char * newpass ,
2007-09-14 12:21:20 +04:00
time_t pwd_last_set )
2001-05-04 04:43:20 +04:00
{
2008-08-15 04:34:22 +04:00
wbcErr wbc_status ;
struct wbcChangePasswordParams params ;
struct wbcAuthErrorInfo * error = NULL ;
struct wbcUserPasswordPolicyInfo * policy = NULL ;
enum wbcPasswordChangeRejectReason reject_reason = - 1 ;
uint32_t flags = 0 ;
2006-02-04 01:19:41 +03:00
2008-08-15 04:34:22 +04:00
int i ;
const char * codes [ ] = {
" NT_STATUS_BACKUP_CONTROLLER " ,
" NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND " ,
" NT_STATUS_NO_LOGON_SERVERS " ,
" NT_STATUS_ACCESS_DENIED " ,
" NT_STATUS_PWD_TOO_SHORT " , /* TODO: tell the min pwd length ? */
" NT_STATUS_PWD_TOO_RECENT " , /* TODO: tell the minage ? */
" NT_STATUS_PWD_HISTORY_CONFLICT " /* TODO: tell the history length ? */
} ;
int ret = PAM_AUTH_ERR ;
2007-09-14 12:21:20 +04:00
2008-08-15 04:34:22 +04:00
ZERO_STRUCT ( params ) ;
2006-02-04 01:19:41 +03:00
2008-04-03 17:41:26 +04:00
if ( ctx - > ctrl & WINBIND_KRB5_AUTH ) {
2008-08-15 04:34:22 +04:00
flags | = WBFLAG_PAM_KRB5 |
WBFLAG_PAM_CONTACT_TRUSTDOM ;
2006-02-04 01:19:41 +03:00
}
2008-06-11 11:52:56 +04:00
if ( ctx - > ctrl & WINBIND_CACHED_LOGIN ) {
2008-08-15 04:34:22 +04:00
flags | = WBFLAG_PAM_CACHED_LOGIN ;
2008-06-11 11:52:56 +04:00
}
2008-08-15 04:34:22 +04:00
params . account_name = user ;
params . level = WBC_AUTH_USER_LEVEL_PLAIN ;
params . old_password . plaintext = oldpass ;
params . new_password . plaintext = newpass ;
params . flags = flags ;
2006-02-04 01:19:41 +03:00
2008-08-15 04:34:22 +04:00
wbc_status = wbcChangeUserPasswordEx ( & params , & error , & reject_reason , & policy ) ;
ret = wbc_auth_error_to_pam_error ( ctx , error , wbc_status ,
user , " wbcChangeUserPasswordEx " ) ;
2006-02-04 01:19:41 +03:00
2008-08-15 04:34:22 +04:00
if ( WBC_ERROR_IS_OK ( wbc_status ) ) {
_pam_log ( ctx , LOG_NOTICE ,
" user '%s' password changed " , user ) ;
return PAM_SUCCESS ;
}
2006-02-04 01:19:41 +03:00
2008-08-15 04:34:22 +04:00
if ( ! error ) {
wbcFreeMemory ( policy ) ;
return ret ;
}
2006-02-04 01:19:41 +03:00
2008-08-15 04:34:22 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( codes ) ; i + + ) {
int _ret = ret ;
if ( _pam_check_remark_auth_err ( ctx , error , codes [ i ] , & _ret ) ) {
ret = _ret ;
goto done ;
}
}
2006-02-04 01:19:41 +03:00
2008-08-15 04:34:22 +04:00
if ( ! strcasecmp ( error - > nt_string ,
2007-09-14 12:21:20 +04:00
" NT_STATUS_PASSWORD_RESTRICTION " ) ) {
2006-02-04 01:19:41 +03:00
2007-02-05 17:43:06 +03:00
char * pwd_restriction_string = NULL ;
2008-08-15 04:34:22 +04:00
SMB_TIME_T min_pwd_age = 0 ;
if ( policy ) {
min_pwd_age = policy - > min_passwordage ;
}
2007-02-05 17:43:06 +03:00
2006-02-04 01:19:41 +03:00
/* FIXME: avoid to send multiple PAM messages after another */
2007-09-14 12:21:20 +04:00
switch ( reject_reason ) {
2006-05-02 23:22:39 +04:00
case - 1 :
break ;
2008-08-15 04:34:22 +04:00
case WBC_PWD_CHANGE_REJECT_OTHER :
2007-09-14 12:21:20 +04:00
if ( ( min_pwd_age > 0 ) & &
( pwd_last_set + min_pwd_age > time ( NULL ) ) ) {
2008-04-03 17:41:26 +04:00
PAM_WB_REMARK_DIRECT ( ctx ,
2007-09-14 12:21:20 +04:00
" NT_STATUS_PWD_TOO_RECENT " ) ;
2006-05-02 23:22:39 +04:00
}
2006-02-04 01:19:41 +03:00
break ;
2008-08-15 04:34:22 +04:00
case WBC_PWD_CHANGE_REJECT_TOO_SHORT :
2008-04-03 17:41:26 +04:00
PAM_WB_REMARK_DIRECT ( ctx ,
2007-09-14 12:21:20 +04:00
" NT_STATUS_PWD_TOO_SHORT " ) ;
2006-02-04 01:19:41 +03:00
break ;
2008-08-15 04:34:22 +04:00
case WBC_PWD_CHANGE_REJECT_IN_HISTORY :
2008-04-03 17:41:26 +04:00
PAM_WB_REMARK_DIRECT ( ctx ,
2007-09-14 12:21:20 +04:00
" NT_STATUS_PWD_HISTORY_CONFLICT " ) ;
2006-02-04 01:19:41 +03:00
break ;
2008-08-15 04:34:22 +04:00
case WBC_PWD_CHANGE_REJECT_COMPLEXITY :
2008-04-03 17:41:26 +04:00
_make_remark ( ctx , PAM_ERROR_MSG ,
2008-10-30 12:53:52 +03:00
_ ( " Password does not meet "
" complexity requirements " ) ) ;
2006-02-04 01:19:41 +03:00
break ;
default :
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_DEBUG ,
2007-09-14 12:21:20 +04:00
" unknown password change "
" reject reason: %d " ,
reject_reason ) ;
2006-02-04 01:19:41 +03:00
break ;
}
2007-09-14 12:21:20 +04:00
pwd_restriction_string =
2008-08-15 04:34:22 +04:00
_pam_compose_pwd_restriction_string ( ctx , policy ) ;
2007-02-05 17:43:06 +03:00
if ( pwd_restriction_string ) {
2008-04-03 17:41:26 +04:00
_make_remark ( ctx , PAM_ERROR_MSG ,
2007-09-14 12:21:20 +04:00
pwd_restriction_string ) ;
2008-08-14 18:53:51 +04:00
TALLOC_FREE ( pwd_restriction_string ) ;
2007-02-05 17:43:06 +03:00
}
2006-02-04 01:19:41 +03:00
}
2008-08-15 04:34:22 +04:00
done :
wbcFreeMemory ( error ) ;
wbcFreeMemory ( policy ) ;
2006-02-04 01:19:41 +03:00
return ret ;
2001-05-04 04:43:20 +04:00
}
2000-05-09 15:43:00 +04:00
/*
* Checks if a user has an account
*
* return values :
* 1 = User not found
* 0 = OK
* - 1 = System error
*/
2008-04-03 17:41:26 +04:00
static int valid_user ( struct pwb_context * ctx ,
2007-09-14 12:21:20 +04:00
const char * user )
2000-05-09 15:43:00 +04:00
{
2006-02-13 18:12:22 +03:00
/* check not only if the user is available over NSS calls, also make
* sure it ' s really a winbind user , this is important when stacking PAM
* modules in the ' account ' or ' password ' facility . */
2008-08-14 20:15:29 +04:00
wbcErr wbc_status ;
2006-02-13 18:12:22 +03:00
struct passwd * pwd = NULL ;
2008-08-14 20:15:29 +04:00
struct passwd * wb_pwd = NULL ;
2006-02-13 18:12:22 +03:00
pwd = getpwnam ( user ) ;
if ( pwd = = NULL ) {
return 1 ;
}
2008-08-14 20:15:29 +04:00
wbc_status = wbcGetpwnam ( user , & wb_pwd ) ;
wbcFreeMemory ( wb_pwd ) ;
if ( ! WBC_ERROR_IS_OK ( wbc_status ) ) {
_pam_log ( ctx , LOG_DEBUG , " valid_user: wbcGetpwnam gave %s \n " ,
wbcErrorString ( wbc_status ) ) ;
}
2006-02-13 18:12:22 +03:00
2008-08-14 20:15:29 +04:00
switch ( wbc_status ) {
case WBC_ERR_UNKNOWN_USER :
2006-02-13 18:12:22 +03:00
return 1 ;
2008-08-14 20:15:29 +04:00
case WBC_ERR_SUCCESS :
2006-02-13 18:12:22 +03:00
return 0 ;
default :
break ;
}
return - 1 ;
2000-05-09 15:43:00 +04:00
}
static char * _pam_delete ( register char * xx )
{
2006-02-04 01:19:41 +03:00
_pam_overwrite ( xx ) ;
_pam_drop ( xx ) ;
return NULL ;
2000-05-09 15:43:00 +04:00
}
/*
2002-02-05 12:40:36 +03:00
* obtain a password from the user
2000-05-09 15:43:00 +04:00
*/
2002-02-05 12:40:36 +03:00
2008-04-03 17:41:26 +04:00
static int _winbind_read_password ( struct pwb_context * ctx ,
2006-02-04 01:19:41 +03:00
unsigned int ctrl ,
const char * comment ,
const char * prompt1 ,
const char * prompt2 ,
const char * * pass )
2000-05-09 15:43:00 +04:00
{
2002-02-05 12:40:36 +03:00
int authtok_flag ;
int retval ;
const char * item ;
char * token ;
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_DEBUG , " getting password (0x%08x) " , ctrl ) ;
2007-01-25 04:56:34 +03:00
2002-02-05 12:40:36 +03:00
/*
* make sure nothing inappropriate gets returned
*/
* pass = token = NULL ;
/*
* which authentication token are we getting ?
*/
2007-09-14 12:21:20 +04:00
if ( on ( WINBIND__OLD_PASSWORD , ctrl ) ) {
authtok_flag = PAM_OLDAUTHTOK ;
} else {
authtok_flag = PAM_AUTHTOK ;
}
2002-02-05 12:40:36 +03:00
/*
* should we obtain the password from a PAM item ?
*/
2007-09-14 12:21:20 +04:00
if ( on ( WINBIND_TRY_FIRST_PASS_ARG , ctrl ) | |
on ( WINBIND_USE_FIRST_PASS_ARG , ctrl ) ) {
2008-04-03 17:41:26 +04:00
retval = _pam_get_item ( ctx - > pamh , authtok_flag , & item ) ;
2002-02-05 12:40:36 +03:00
if ( retval ! = PAM_SUCCESS ) {
/* very strange. */
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_ALERT ,
2007-09-14 12:21:20 +04:00
" pam_get_item returned error "
" to unix-read-password " ) ;
2002-02-05 12:40:36 +03:00
return retval ;
} else if ( item ! = NULL ) { /* we have a password! */
* pass = item ;
item = NULL ;
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_DEBUG ,
2007-01-25 04:56:34 +03:00
" pam_get_item returned a password " ) ;
2002-02-05 12:40:36 +03:00
return PAM_SUCCESS ;
} else if ( on ( WINBIND_USE_FIRST_PASS_ARG , ctrl ) ) {
2007-09-14 12:21:20 +04:00
return PAM_AUTHTOK_RECOVER_ERR ; /* didn't work */
2002-02-05 12:40:36 +03:00
} else if ( on ( WINBIND_USE_AUTHTOK_ARG , ctrl )
& & off ( WINBIND__OLD_PASSWORD , ctrl ) ) {
return PAM_AUTHTOK_RECOVER_ERR ;
}
}
/*
* getting here implies we will have to get the password from the
* user directly .
*/
{
struct pam_message msg [ 3 ] , * pmsg [ 3 ] ;
struct pam_response * resp ;
int i , replies ;
/* prepare to converse */
2007-02-05 18:25:31 +03:00
if ( comment ! = NULL & & off ( ctrl , WINBIND_SILENT ) ) {
2002-02-05 12:40:36 +03:00
pmsg [ 0 ] = & msg [ 0 ] ;
msg [ 0 ] . msg_style = PAM_TEXT_INFO ;
2007-09-13 18:14:02 +04:00
msg [ 0 ] . msg = discard_const_p ( char , comment ) ;
2002-02-05 12:40:36 +03:00
i = 1 ;
} else {
i = 0 ;
}
pmsg [ i ] = & msg [ i ] ;
msg [ i ] . msg_style = PAM_PROMPT_ECHO_OFF ;
2007-09-13 18:14:02 +04:00
msg [ i + + ] . msg = discard_const_p ( char , prompt1 ) ;
2002-02-05 12:40:36 +03:00
replies = 1 ;
if ( prompt2 ! = NULL ) {
pmsg [ i ] = & msg [ i ] ;
msg [ i ] . msg_style = PAM_PROMPT_ECHO_OFF ;
2007-09-13 18:14:02 +04:00
msg [ i + + ] . msg = discard_const_p ( char , prompt2 ) ;
2002-02-05 12:40:36 +03:00
+ + replies ;
}
/* so call the conversation expecting i responses */
resp = NULL ;
2008-04-03 17:41:26 +04:00
retval = converse ( ctx - > pamh , i , pmsg , & resp ) ;
2007-09-14 12:21:20 +04:00
if ( resp = = NULL ) {
if ( retval = = PAM_SUCCESS ) {
retval = PAM_AUTHTOK_RECOVER_ERR ;
2002-02-05 12:40:36 +03:00
}
2007-09-14 12:21:20 +04:00
goto done ;
}
if ( retval ! = PAM_SUCCESS ) {
2002-02-05 12:40:36 +03:00
_pam_drop_reply ( resp , i ) ;
2007-09-14 12:21:20 +04:00
goto done ;
}
2002-02-05 12:40:36 +03:00
2007-09-14 12:21:20 +04:00
/* interpret the response */
token = x_strdup ( resp [ i - replies ] . resp ) ;
if ( ! token ) {
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_NOTICE ,
2007-09-14 12:21:20 +04:00
" could not recover "
" authentication token " ) ;
retval = PAM_AUTHTOK_RECOVER_ERR ;
goto done ;
}
if ( replies = = 2 ) {
/* verify that password entered correctly */
if ( ! resp [ i - 1 ] . resp | |
strcmp ( token , resp [ i - 1 ] . resp ) ) {
_pam_delete ( token ) ; /* mistyped */
retval = PAM_AUTHTOK_RECOVER_ERR ;
2008-04-03 17:41:26 +04:00
_make_remark ( ctx , PAM_ERROR_MSG ,
2007-09-14 12:21:20 +04:00
MISTYPED_PASS ) ;
}
2002-02-05 12:40:36 +03:00
}
2007-09-14 12:21:20 +04:00
/*
* tidy up the conversation ( resp_retcode ) is ignored
* - - what is it for anyway ? AGM
*/
_pam_drop_reply ( resp , i ) ;
2000-05-09 15:43:00 +04:00
}
2007-09-14 12:21:20 +04:00
done :
2002-02-05 12:40:36 +03:00
if ( retval ! = PAM_SUCCESS ) {
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_DEBUG ,
2007-09-14 12:21:20 +04:00
" unable to obtain a password " ) ;
2002-02-05 12:40:36 +03:00
return retval ;
2000-05-09 15:43:00 +04:00
}
2002-02-05 12:40:36 +03:00
/* 'token' is the entered password */
/* we store this password as an item */
2007-09-14 12:21:20 +04:00
2008-04-03 17:41:26 +04:00
retval = pam_set_item ( ctx - > pamh , authtok_flag , token ) ;
2002-02-05 12:40:36 +03:00
_pam_delete ( token ) ; /* clean it up */
2007-09-14 12:21:20 +04:00
if ( retval ! = PAM_SUCCESS | |
2008-04-03 17:41:26 +04:00
( retval = _pam_get_item ( ctx - > pamh , authtok_flag , & item ) ) ! = PAM_SUCCESS ) {
2007-09-14 12:21:20 +04:00
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_CRIT , " error manipulating password " ) ;
2002-02-05 12:40:36 +03:00
return retval ;
2007-09-14 12:21:20 +04:00
2002-02-05 12:40:36 +03:00
}
2000-05-09 15:43:00 +04:00
2002-02-05 12:40:36 +03:00
* pass = item ;
item = NULL ; /* break link to password */
return PAM_SUCCESS ;
2000-05-09 15:43:00 +04:00
}
2008-04-03 17:41:26 +04:00
static const char * get_conf_item_string ( struct pwb_context * ctx ,
2008-04-03 15:06:14 +04:00
const char * item ,
int config_flag )
2006-02-04 01:19:41 +03:00
{
int i = 0 ;
const char * parm_opt = NULL ;
2008-04-03 17:41:26 +04:00
if ( ! ( ctx - > ctrl & config_flag ) ) {
2006-02-04 01:19:41 +03:00
goto out ;
}
2006-05-11 01:12:10 +04:00
/* let the pam opt take precedence over the pam_winbind.conf option */
2008-04-03 17:41:26 +04:00
for ( i = 0 ; i < ctx - > argc ; i + + ) {
2006-02-04 01:19:41 +03:00
2008-04-03 17:41:26 +04:00
if ( ( strncmp ( ctx - > argv [ i ] , item , strlen ( item ) ) = = 0 ) ) {
2006-02-04 01:19:41 +03:00
char * p ;
2008-04-03 17:41:26 +04:00
if ( ( p = strchr ( ctx - > argv [ i ] , ' = ' ) ) = = NULL ) {
_pam_log ( ctx , LOG_INFO ,
2007-09-14 12:21:20 +04:00
" no \" = \" delimiter for \" %s \" found \n " ,
item ) ;
2006-02-04 01:19:41 +03:00
goto out ;
}
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_INFO ,
2007-09-14 12:21:20 +04:00
" PAM config: %s '%s' \n " , item , p + 1 ) ;
2006-02-04 01:19:41 +03:00
return p + 1 ;
}
}
2008-04-03 17:41:26 +04:00
if ( ctx - > dict ) {
2007-07-04 23:52:51 +04:00
char * key = NULL ;
2008-08-14 18:53:51 +04:00
key = talloc_asprintf ( ctx , " global:%s " , item ) ;
if ( ! key ) {
2007-07-04 23:52:51 +04:00
goto out ;
}
2008-04-03 17:41:26 +04:00
parm_opt = iniparser_getstr ( ctx - > dict , key ) ;
2008-08-14 18:53:51 +04:00
TALLOC_FREE ( key ) ;
2007-07-04 23:52:51 +04:00
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_INFO , " CONFIG file: %s '%s' \n " ,
2007-09-14 12:21:20 +04:00
item , parm_opt ) ;
2006-05-11 01:12:10 +04:00
}
2006-02-04 01:19:41 +03:00
out :
return parm_opt ;
}
2008-04-03 17:41:26 +04:00
static int get_config_item_int ( struct pwb_context * ctx ,
2008-04-03 15:06:14 +04:00
const char * item ,
int config_flag )
2007-07-04 18:03:10 +04:00
{
2007-07-04 23:52:51 +04:00
int i , parm_opt = - 1 ;
2007-07-04 18:03:10 +04:00
2008-04-03 17:41:26 +04:00
if ( ! ( ctx - > ctrl & config_flag ) ) {
2007-07-05 00:25:29 +04:00
goto out ;
}
2007-07-04 18:03:10 +04:00
/* let the pam opt take precedence over the pam_winbind.conf option */
2008-04-03 17:41:26 +04:00
for ( i = 0 ; i < ctx - > argc ; i + + ) {
2007-07-04 18:03:10 +04:00
2008-04-03 17:41:26 +04:00
if ( ( strncmp ( ctx - > argv [ i ] , item , strlen ( item ) ) = = 0 ) ) {
2007-07-04 18:03:10 +04:00
char * p ;
2008-04-03 17:41:26 +04:00
if ( ( p = strchr ( ctx - > argv [ i ] , ' = ' ) ) = = NULL ) {
_pam_log ( ctx , LOG_INFO ,
2007-07-04 18:03:10 +04:00
" no \" = \" delimiter for \" %s \" found \n " ,
item ) ;
goto out ;
}
parm_opt = atoi ( p + 1 ) ;
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_INFO ,
2007-07-04 18:03:10 +04:00
" PAM config: %s '%d' \n " ,
item , parm_opt ) ;
return parm_opt ;
}
}
2008-04-03 17:41:26 +04:00
if ( ctx - > dict ) {
2007-07-04 23:52:51 +04:00
char * key = NULL ;
2008-08-14 18:53:51 +04:00
key = talloc_asprintf ( ctx , " global:%s " , item ) ;
if ( ! key ) {
2007-07-04 18:03:10 +04:00
goto out ;
}
2008-04-03 17:41:26 +04:00
parm_opt = iniparser_getint ( ctx - > dict , key , - 1 ) ;
2008-08-14 18:53:51 +04:00
TALLOC_FREE ( key ) ;
2007-07-04 18:03:10 +04:00
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_INFO ,
2007-07-04 18:03:10 +04:00
" CONFIG file: %s '%d' \n " ,
item , parm_opt ) ;
}
out :
return parm_opt ;
}
2008-04-03 17:41:26 +04:00
static const char * get_krb5_cc_type_from_config ( struct pwb_context * ctx )
2006-02-04 01:19:41 +03:00
{
2008-04-03 17:41:26 +04:00
return get_conf_item_string ( ctx , " krb5_ccache_type " ,
2007-09-14 12:21:20 +04:00
WINBIND_KRB5_CCACHE_TYPE ) ;
2006-02-04 01:19:41 +03:00
}
2008-04-03 17:41:26 +04:00
static const char * get_member_from_config ( struct pwb_context * ctx )
2006-02-04 01:19:41 +03:00
{
const char * ret = NULL ;
2008-04-03 17:41:26 +04:00
ret = get_conf_item_string ( ctx , " require_membership_of " ,
2007-09-14 12:21:20 +04:00
WINBIND_REQUIRED_MEMBERSHIP ) ;
2006-02-04 01:19:41 +03:00
if ( ret ) {
return ret ;
}
2008-04-03 17:41:26 +04:00
return get_conf_item_string ( ctx , " require-membership-of " ,
2007-09-14 12:21:20 +04:00
WINBIND_REQUIRED_MEMBERSHIP ) ;
2006-02-04 01:19:41 +03:00
}
2008-04-03 17:41:26 +04:00
static int get_warn_pwd_expire_from_config ( struct pwb_context * ctx )
2007-07-04 18:03:10 +04:00
{
int ret ;
2008-04-03 17:41:26 +04:00
ret = get_config_item_int ( ctx , " warn_pwd_expire " ,
2007-09-14 12:21:20 +04:00
WINBIND_WARN_PWD_EXPIRE ) ;
2007-07-04 18:03:10 +04:00
/* no or broken setting */
if ( ret < = 0 ) {
return DEFAULT_DAYS_TO_WARN_BEFORE_PWD_EXPIRES ;
}
return ret ;
}
2007-08-28 00:09:37 +04:00
/**
* Retrieve the winbind separator .
*
2008-08-19 18:19:54 +04:00
* @ param ctx PAM winbind context .
2007-08-28 00:09:37 +04:00
*
* @ return string separator character . NULL on failure .
*/
2008-04-03 17:41:26 +04:00
static char winbind_get_separator ( struct pwb_context * ctx )
2007-08-28 00:09:37 +04:00
{
2008-08-14 20:17:00 +04:00
wbcErr wbc_status ;
static struct wbcInterfaceDetails * details = NULL ;
2007-08-28 00:09:37 +04:00
2008-08-14 20:17:00 +04:00
wbc_status = wbcInterfaceDetails ( & details ) ;
if ( ! WBC_ERROR_IS_OK ( wbc_status ) ) {
_pam_log ( ctx , LOG_ERR ,
" Could not retrieve winbind interface details: %s " ,
wbcErrorString ( wbc_status ) ) ;
return ' \0 ' ;
}
2007-08-28 00:09:37 +04:00
2008-08-14 20:17:00 +04:00
if ( ! details ) {
2007-08-28 00:09:37 +04:00
return ' \0 ' ;
}
2008-08-14 20:17:00 +04:00
return details - > winbind_separator ;
2007-08-28 00:09:37 +04:00
}
2008-08-14 20:17:00 +04:00
2007-08-28 00:09:37 +04:00
/**
* Convert a upn to a name .
*
2008-08-19 18:19:54 +04:00
* @ param ctx PAM winbind context .
2007-08-28 00:09:37 +04:00
* @ param upn USer UPN to be trabslated .
*
* @ return converted name . NULL pointer on failure . Caller needs to free .
*/
2008-04-03 17:41:26 +04:00
static char * winbind_upn_to_username ( struct pwb_context * ctx ,
2007-09-14 12:21:20 +04:00
const char * upn )
2007-08-28 00:09:37 +04:00
{
2007-09-14 12:21:20 +04:00
char sep ;
2008-08-15 01:33:12 +04:00
wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE ;
struct wbcDomainSid sid ;
enum wbcSidType type ;
char * domain ;
char * name ;
2007-08-28 00:09:37 +04:00
/* This cannot work when the winbind separator = @ */
2008-04-03 17:41:26 +04:00
sep = winbind_get_separator ( ctx ) ;
2007-08-28 00:09:37 +04:00
if ( ! sep | | sep = = ' @ ' ) {
return NULL ;
}
2007-09-14 12:21:20 +04:00
2007-08-28 00:09:37 +04:00
/* Convert the UPN to a SID */
2008-08-15 01:33:12 +04:00
wbc_status = wbcLookupName ( " " , upn , & sid , & type ) ;
if ( ! WBC_ERROR_IS_OK ( wbc_status ) ) {
2007-08-28 00:09:37 +04:00
return NULL ;
}
2007-09-14 12:21:20 +04:00
2007-08-28 00:09:37 +04:00
/* Convert the the SID back to the sAMAccountName */
2007-09-14 12:21:20 +04:00
2008-08-15 01:33:12 +04:00
wbc_status = wbcLookupSid ( & sid , & domain , & name , & type ) ;
if ( ! WBC_ERROR_IS_OK ( wbc_status ) ) {
2007-08-28 00:09:37 +04:00
return NULL ;
}
2007-09-14 12:21:20 +04:00
2008-08-15 01:33:12 +04:00
return talloc_asprintf ( ctx , " %s \\ %s " , domain , name ) ;
2007-08-28 00:09:37 +04:00
}
2008-10-20 18:30:45 +04:00
static int _pam_delete_cred ( pam_handle_t * pamh , int flags ,
int argc , const char * * argv )
{
int retval = PAM_SUCCESS ;
struct pwb_context * ctx = NULL ;
struct wbcLogoffUserParams logoff ;
struct wbcAuthErrorInfo * error = NULL ;
const char * user ;
2008-11-23 21:37:36 +03:00
wbcErr wbc_status = WBC_ERR_SUCCESS ;
2008-10-20 18:30:45 +04:00
2009-04-03 11:57:53 +04:00
ZERO_STRUCT ( logoff ) ;
2008-10-20 18:30:45 +04:00
retval = _pam_winbind_init_context ( pamh , flags , argc , argv , & ctx ) ;
if ( retval ) {
goto out ;
}
_PAM_LOG_FUNCTION_ENTER ( " _pam_delete_cred " , ctx ) ;
if ( ctx - > ctrl & WINBIND_KRB5_AUTH ) {
/* destroy the ccache here */
uint32_t wbc_flags = 0 ;
const char * ccname = NULL ;
struct passwd * pwd = NULL ;
2008-11-13 16:44:14 +03:00
retval = pam_get_user ( pamh , & user , _ ( " Username: " ) ) ;
2008-10-20 18:30:45 +04:00
if ( retval ) {
_pam_log ( ctx , LOG_ERR ,
" could not identify user " ) ;
goto out ;
}
if ( user = = NULL ) {
_pam_log ( ctx , LOG_ERR ,
" username was NULL! " ) ;
retval = PAM_USER_UNKNOWN ;
goto out ;
}
_pam_log_debug ( ctx , LOG_DEBUG ,
" username [%s] obtained " , user ) ;
ccname = pam_getenv ( pamh , " KRB5CCNAME " ) ;
if ( ccname = = NULL ) {
_pam_log_debug ( ctx , LOG_DEBUG ,
" user has no KRB5CCNAME environment " ) ;
}
pwd = getpwnam ( user ) ;
if ( pwd = = NULL ) {
retval = PAM_USER_UNKNOWN ;
goto out ;
}
wbc_flags = WBFLAG_PAM_KRB5 |
WBFLAG_PAM_CONTACT_TRUSTDOM ;
logoff . username = user ;
2008-11-13 18:45:42 +03:00
if ( ccname ) {
wbc_status = wbcAddNamedBlob ( & logoff . num_blobs ,
& logoff . blobs ,
" ccfilename " ,
0 ,
( uint8_t * ) ccname ,
strlen ( ccname ) + 1 ) ;
if ( ! WBC_ERROR_IS_OK ( wbc_status ) ) {
goto out ;
}
2008-10-20 18:30:45 +04:00
}
wbc_status = wbcAddNamedBlob ( & logoff . num_blobs ,
& logoff . blobs ,
" flags " ,
0 ,
( uint8_t * ) & wbc_flags ,
sizeof ( wbc_flags ) ) ;
if ( ! WBC_ERROR_IS_OK ( wbc_status ) ) {
goto out ;
}
wbc_status = wbcAddNamedBlob ( & logoff . num_blobs ,
& logoff . blobs ,
" user_uid " ,
0 ,
( uint8_t * ) & pwd - > pw_uid ,
sizeof ( pwd - > pw_uid ) ) ;
if ( ! WBC_ERROR_IS_OK ( wbc_status ) ) {
goto out ;
}
wbc_status = wbcLogoffUserEx ( & logoff , & error ) ;
retval = wbc_auth_error_to_pam_error ( ctx , error , wbc_status ,
user , " wbcLogoffUser " ) ;
wbcFreeMemory ( error ) ;
wbcFreeMemory ( logoff . blobs ) ;
2009-04-03 14:50:50 +04:00
logoff . blobs = NULL ;
2008-10-20 18:30:45 +04:00
if ( ! WBC_ERROR_IS_OK ( wbc_status ) ) {
_pam_log ( ctx , LOG_INFO ,
" failed to logoff user %s: %s \n " ,
user , wbcErrorString ( wbc_status ) ) ;
}
}
out :
if ( logoff . blobs ) {
wbcFreeMemory ( logoff . blobs ) ;
}
if ( ! WBC_ERROR_IS_OK ( wbc_status ) ) {
retval = wbc_auth_error_to_pam_error ( ctx , error , wbc_status ,
user , " wbcLogoffUser " ) ;
}
/*
* Delete the krb5 ccname variable from the PAM environment
* if it was set by winbind .
*/
2009-01-19 18:26:07 +03:00
if ( ( ctx - > ctrl & WINBIND_KRB5_AUTH ) & & pam_getenv ( pamh , " KRB5CCNAME " ) ) {
2008-10-20 18:30:45 +04:00
pam_putenv ( pamh , " KRB5CCNAME " ) ;
}
_PAM_LOG_FUNCTION_LEAVE ( " _pam_delete_cred " , ctx , retval ) ;
TALLOC_FREE ( ctx ) ;
return retval ;
}
2000-05-09 15:43:00 +04:00
PAM_EXTERN
int pam_sm_authenticate ( pam_handle_t * pamh , int flags ,
int argc , const char * * argv )
{
2006-02-04 01:19:41 +03:00
const char * username ;
const char * password ;
const char * member = NULL ;
const char * cctype = NULL ;
2007-07-04 18:03:10 +04:00
int warn_pwd_expire ;
2006-02-04 01:19:41 +03:00
int retval = PAM_AUTH_ERR ;
2006-09-05 09:28:31 +04:00
char * username_ret = NULL ;
2007-01-25 04:18:31 +03:00
char * new_authtok_required = NULL ;
2007-04-20 14:54:55 +04:00
char * real_username = NULL ;
2008-04-03 17:41:26 +04:00
struct pwb_context * ctx = NULL ;
2006-02-04 01:19:41 +03:00
2008-04-03 17:41:26 +04:00
retval = _pam_winbind_init_context ( pamh , flags , argc , argv , & ctx ) ;
if ( retval ) {
2006-04-11 18:40:53 +04:00
goto out ;
2006-02-04 01:19:41 +03:00
}
2008-04-03 17:41:26 +04:00
_PAM_LOG_FUNCTION_ENTER ( " pam_sm_authenticate " , ctx ) ;
2006-02-04 01:19:41 +03:00
/* Get the username */
retval = pam_get_user ( pamh , & username , NULL ) ;
if ( ( retval ! = PAM_SUCCESS ) | | ( ! username ) ) {
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_DEBUG ,
2007-09-14 12:21:20 +04:00
" can not get the username " ) ;
2006-04-11 18:40:53 +04:00
retval = PAM_SERVICE_ERR ;
goto out ;
2006-02-04 01:19:41 +03:00
}
2007-08-28 00:09:37 +04:00
2007-03-01 06:10:29 +03:00
# if defined(AIX)
/* Decode the user name since AIX does not support logn user
names by default . The name is encoded as _ # uid . */
2007-09-14 12:21:20 +04:00
if ( username [ 0 ] = = ' _ ' ) {
uid_t id = atoi ( & username [ 1 ] ) ;
struct passwd * pw = NULL ;
2007-03-01 06:10:29 +03:00
2007-09-14 12:21:20 +04:00
if ( ( id ! = 0 ) & & ( ( pw = getpwuid ( id ) ) ! = NULL ) ) {
real_username = strdup ( pw - > pw_name ) ;
2007-03-01 06:10:29 +03:00
}
}
# endif
2007-09-14 12:21:20 +04:00
if ( ! real_username ) {
2007-03-01 06:10:29 +03:00
/* Just making a copy of the username we got from PAM */
2007-09-14 12:21:20 +04:00
if ( ( real_username = strdup ( username ) ) = = NULL ) {
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_DEBUG ,
2007-09-14 12:21:20 +04:00
" memory allocation failure when copying "
" username " ) ;
2007-03-01 06:10:29 +03:00
retval = PAM_SERVICE_ERR ;
goto out ;
}
2007-09-14 12:21:20 +04:00
}
2007-03-01 06:10:29 +03:00
2007-08-28 00:09:37 +04:00
/* Maybe this was a UPN */
if ( strchr ( real_username , ' @ ' ) ! = NULL ) {
char * samaccountname = NULL ;
2007-09-14 12:21:20 +04:00
2008-04-03 17:41:26 +04:00
samaccountname = winbind_upn_to_username ( ctx ,
2007-08-28 00:09:37 +04:00
real_username ) ;
if ( samaccountname ) {
free ( real_username ) ;
2008-08-14 18:53:51 +04:00
real_username = strdup ( samaccountname ) ;
2007-08-28 00:09:37 +04:00
}
}
2008-04-03 17:41:26 +04:00
retval = _winbind_read_password ( ctx , ctx - > ctrl , NULL ,
2008-10-30 12:53:52 +03:00
_ ( " Password: " ) , NULL ,
2006-02-04 01:19:41 +03:00
& password ) ;
if ( retval ! = PAM_SUCCESS ) {
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_ERR ,
2007-09-14 12:21:20 +04:00
" Could not retrieve user's password " ) ;
2006-04-11 18:40:53 +04:00
retval = PAM_AUTHTOK_ERR ;
goto out ;
2006-02-04 01:19:41 +03:00
}
/* Let's not give too much away in the log file */
2002-01-07 05:57:06 +03:00
# ifdef DEBUG_PASSWORD
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_INFO ,
2007-09-14 12:21:20 +04:00
" Verify user '%s' with password '%s' " ,
2007-03-01 06:10:29 +03:00
real_username , password ) ;
2002-01-07 05:57:06 +03:00
# else
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_INFO ,
2007-09-14 12:21:20 +04:00
" Verify user '%s' " , real_username ) ;
2002-01-07 05:57:06 +03:00
# endif
2008-04-03 17:41:26 +04:00
member = get_member_from_config ( ctx ) ;
cctype = get_krb5_cc_type_from_config ( ctx ) ;
warn_pwd_expire = get_warn_pwd_expire_from_config ( ctx ) ;
2007-07-04 18:03:10 +04:00
2006-02-04 01:19:41 +03:00
/* Now use the username to look up password */
2008-04-03 17:41:26 +04:00
retval = winbind_auth_request ( ctx , real_username , password ,
2008-08-19 13:07:59 +04:00
member , cctype , warn_pwd_expire ,
NULL , NULL , NULL ,
2007-09-14 12:21:20 +04:00
NULL , & username_ret ) ;
2004-08-18 20:25:41 +04:00
2006-02-04 01:19:41 +03:00
if ( retval = = PAM_NEW_AUTHTOK_REQD | |
retval = = PAM_AUTHTOK_EXPIRED ) {
2004-08-18 20:25:41 +04:00
2007-02-22 16:35:01 +03:00
char * new_authtok_required_during_auth = NULL ;
2008-08-14 18:53:51 +04:00
new_authtok_required = talloc_asprintf ( NULL , " %d " , retval ) ;
if ( ! new_authtok_required ) {
2006-04-11 18:40:53 +04:00
retval = PAM_BUF_ERR ;
goto out ;
2006-02-04 01:19:41 +03:00
}
2006-01-13 14:11:23 +03:00
2007-09-14 12:21:20 +04:00
pam_set_data ( pamh , PAM_WINBIND_NEW_AUTHTOK_REQD ,
new_authtok_required ,
_pam_winbind_cleanup_func ) ;
2006-01-13 14:11:23 +03:00
2006-04-11 18:40:53 +04:00
retval = PAM_SUCCESS ;
2007-02-22 16:35:01 +03:00
2008-08-14 18:53:51 +04:00
new_authtok_required_during_auth = talloc_asprintf ( NULL , " %d " , true ) ;
if ( ! new_authtok_required_during_auth ) {
2007-02-22 16:35:01 +03:00
retval = PAM_BUF_ERR ;
goto out ;
}
2007-09-14 12:21:20 +04:00
pam_set_data ( pamh , PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH ,
new_authtok_required_during_auth ,
_pam_winbind_cleanup_func ) ;
2007-02-22 16:35:01 +03:00
2006-04-11 18:40:53 +04:00
goto out ;
2006-02-04 01:19:41 +03:00
}
2006-04-11 18:40:53 +04:00
out :
2006-09-05 09:28:31 +04:00
if ( username_ret ) {
pam_set_item ( pamh , PAM_USER , username_ret ) ;
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_INFO ,
2007-09-14 12:21:20 +04:00
" Returned user was '%s' " , username_ret ) ;
2006-09-05 09:28:31 +04:00
free ( username_ret ) ;
}
2007-09-14 12:21:20 +04:00
if ( real_username ) {
free ( real_username ) ;
}
2007-01-25 04:56:34 +03:00
if ( ! new_authtok_required ) {
pam_set_data ( pamh , PAM_WINBIND_NEW_AUTHTOK_REQD , NULL , NULL ) ;
}
2007-02-05 20:12:13 +03:00
if ( retval ! = PAM_SUCCESS ) {
_pam_free_data_info3 ( pamh ) ;
}
2008-04-03 17:41:26 +04:00
_PAM_LOG_FUNCTION_LEAVE ( " pam_sm_authenticate " , ctx , retval ) ;
2008-08-14 18:53:51 +04:00
TALLOC_FREE ( ctx ) ;
2007-01-25 04:56:34 +03:00
2006-02-04 01:19:41 +03:00
return retval ;
2000-05-09 15:43:00 +04:00
}
PAM_EXTERN
int pam_sm_setcred ( pam_handle_t * pamh , int flags ,
int argc , const char * * argv )
{
2006-12-21 16:31:23 +03:00
int ret = PAM_SYSTEM_ERR ;
2008-04-03 17:41:26 +04:00
struct pwb_context * ctx = NULL ;
2006-12-18 18:29:05 +03:00
2008-04-03 17:41:26 +04:00
ret = _pam_winbind_init_context ( pamh , flags , argc , argv , & ctx ) ;
if ( ret ) {
2006-12-21 16:31:23 +03:00
goto out ;
2006-02-04 01:19:41 +03:00
}
2008-04-03 17:41:26 +04:00
_PAM_LOG_FUNCTION_ENTER ( " pam_sm_setcred " , ctx ) ;
2006-02-04 01:19:41 +03:00
2007-01-25 13:29:04 +03:00
switch ( flags & ~ PAM_SILENT ) {
2006-12-18 18:33:57 +03:00
case PAM_DELETE_CRED :
2008-10-20 18:30:45 +04:00
ret = _pam_delete_cred ( pamh , flags , argc , argv ) ;
2006-12-21 16:31:23 +03:00
break ;
2006-12-18 18:33:57 +03:00
case PAM_REFRESH_CRED :
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_WARNING ,
2007-09-14 12:21:20 +04:00
" PAM_REFRESH_CRED not implemented " ) ;
2006-12-21 16:31:23 +03:00
ret = PAM_SUCCESS ;
2006-12-18 18:33:57 +03:00
break ;
case PAM_REINITIALIZE_CRED :
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_WARNING ,
2007-09-14 12:21:20 +04:00
" PAM_REINITIALIZE_CRED not implemented " ) ;
2006-12-21 16:31:23 +03:00
ret = PAM_SUCCESS ;
2006-12-18 18:33:57 +03:00
break ;
case PAM_ESTABLISH_CRED :
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_WARNING ,
2007-09-14 12:21:20 +04:00
" PAM_ESTABLISH_CRED not implemented " ) ;
2006-12-21 16:31:23 +03:00
ret = PAM_SUCCESS ;
2006-12-18 18:33:57 +03:00
break ;
default :
2006-12-21 16:31:23 +03:00
ret = PAM_SYSTEM_ERR ;
2006-12-18 18:33:57 +03:00
break ;
2006-02-04 01:19:41 +03:00
}
2006-12-21 16:31:23 +03:00
out :
2008-04-03 17:41:26 +04:00
_PAM_LOG_FUNCTION_LEAVE ( " pam_sm_setcred " , ctx , ret ) ;
2008-08-14 18:53:51 +04:00
TALLOC_FREE ( ctx ) ;
2007-09-14 12:21:20 +04:00
2006-12-21 16:31:23 +03:00
return ret ;
2000-05-09 15:43:00 +04:00
}
/*
2007-09-14 12:21:20 +04:00
* Account management . We want to verify that the account exists
2000-05-09 15:43:00 +04:00
* before returning PAM_SUCCESS
*/
PAM_EXTERN
int pam_sm_acct_mgmt ( pam_handle_t * pamh , int flags ,
int argc , const char * * argv )
{
2006-02-04 01:19:41 +03:00
const char * username ;
2006-12-21 16:31:23 +03:00
int ret = PAM_USER_UNKNOWN ;
2006-02-04 01:19:41 +03:00
void * tmp = NULL ;
2008-04-03 17:41:26 +04:00
struct pwb_context * ctx = NULL ;
2006-02-04 01:19:41 +03:00
2008-04-03 17:41:26 +04:00
ret = _pam_winbind_init_context ( pamh , flags , argc , argv , & ctx ) ;
if ( ret ) {
goto out ;
2006-02-04 01:19:41 +03:00
}
2006-01-13 14:11:23 +03:00
2008-04-03 17:41:26 +04:00
_PAM_LOG_FUNCTION_ENTER ( " pam_sm_acct_mgmt " , ctx ) ;
2000-05-09 15:43:00 +04:00
2006-02-04 01:19:41 +03:00
/* Get the username */
2006-12-21 16:31:23 +03:00
ret = pam_get_user ( pamh , & username , NULL ) ;
if ( ( ret ! = PAM_SUCCESS ) | | ( ! username ) ) {
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_DEBUG ,
2007-09-14 12:21:20 +04:00
" can not get the username " ) ;
2006-12-21 16:31:23 +03:00
ret = PAM_SERVICE_ERR ;
goto out ;
2006-02-04 01:19:41 +03:00
}
2000-05-09 15:43:00 +04:00
2006-02-04 01:19:41 +03:00
/* Verify the username */
2008-04-03 17:41:26 +04:00
ret = valid_user ( ctx , username ) ;
2006-12-21 16:31:23 +03:00
switch ( ret ) {
2000-05-09 15:43:00 +04:00
case - 1 :
2006-02-04 01:19:41 +03:00
/* some sort of system error. The log was already printed */
2006-12-21 16:31:23 +03:00
ret = PAM_SERVICE_ERR ;
goto out ;
2000-05-09 15:43:00 +04:00
case 1 :
2006-02-04 01:19:41 +03:00
/* the user does not exist */
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_NOTICE , " user '%s' not found " ,
2007-09-14 12:21:20 +04:00
username ) ;
2008-04-03 17:41:26 +04:00
if ( ctx - > ctrl & WINBIND_UNKNOWN_OK_ARG ) {
2006-12-21 16:31:23 +03:00
ret = PAM_IGNORE ;
goto out ;
2006-02-04 01:19:41 +03:00
}
2006-12-21 16:31:23 +03:00
ret = PAM_USER_UNKNOWN ;
goto out ;
2000-05-09 15:43:00 +04:00
case 0 :
2007-09-14 12:21:20 +04:00
pam_get_data ( pamh , PAM_WINBIND_NEW_AUTHTOK_REQD ,
( const void * * ) & tmp ) ;
2006-02-04 01:19:41 +03:00
if ( tmp ! = NULL ) {
2006-12-21 16:31:23 +03:00
ret = atoi ( ( const char * ) tmp ) ;
switch ( ret ) {
2006-02-04 01:19:41 +03:00
case PAM_AUTHTOK_EXPIRED :
/* fall through, since new token is required in this case */
case PAM_NEW_AUTHTOK_REQD :
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_WARNING ,
2007-09-14 12:21:20 +04:00
" pam_sm_acct_mgmt success but %s is set " ,
2006-02-04 01:19:41 +03:00
PAM_WINBIND_NEW_AUTHTOK_REQD ) ;
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_NOTICE ,
2007-09-14 12:21:20 +04:00
" user '%s' needs new password " ,
username ) ;
2006-02-04 01:19:41 +03:00
/* PAM_AUTHTOKEN_REQD does not exist, but is documented in the manpage */
2006-12-21 16:31:23 +03:00
ret = PAM_NEW_AUTHTOK_REQD ;
goto out ;
2006-02-04 01:19:41 +03:00
default :
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_WARNING ,
2007-09-14 12:21:20 +04:00
" pam_sm_acct_mgmt success " ) ;
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_NOTICE ,
2007-09-14 12:21:20 +04:00
" user '%s' granted access " , username ) ;
2006-12-21 16:31:23 +03:00
ret = PAM_SUCCESS ;
goto out ;
2006-02-04 01:19:41 +03:00
}
}
/* Otherwise, the authentication looked good */
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_NOTICE ,
2007-09-14 12:21:20 +04:00
" user '%s' granted access " , username ) ;
2006-12-21 16:31:23 +03:00
ret = PAM_SUCCESS ;
goto out ;
2000-05-09 15:43:00 +04:00
default :
2006-02-04 01:19:41 +03:00
/* we don't know anything about this return value */
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_ERR ,
2007-09-14 12:21:20 +04:00
" internal module error (ret = %d, user = '%s') " ,
2006-12-21 16:31:23 +03:00
ret , username ) ;
ret = PAM_SERVICE_ERR ;
goto out ;
2006-02-04 01:19:41 +03:00
}
/* should not be reached */
2006-12-21 16:31:23 +03:00
ret = PAM_IGNORE ;
out :
2008-04-03 17:41:26 +04:00
_PAM_LOG_FUNCTION_LEAVE ( " pam_sm_acct_mgmt " , ctx , ret ) ;
2006-12-21 16:31:23 +03:00
2008-08-14 18:53:51 +04:00
TALLOC_FREE ( ctx ) ;
2007-09-14 12:21:20 +04:00
2006-12-21 16:31:23 +03:00
return ret ;
2000-05-09 15:43:00 +04:00
}
2006-02-04 01:19:41 +03:00
2002-04-04 01:39:01 +04:00
PAM_EXTERN
int pam_sm_open_session ( pam_handle_t * pamh , int flags ,
2006-02-04 01:19:41 +03:00
int argc , const char * * argv )
2002-04-04 01:39:01 +04:00
{
2008-08-14 16:39:52 +04:00
int ret = PAM_SUCCESS ;
2008-04-03 17:41:26 +04:00
struct pwb_context * ctx = NULL ;
2006-12-21 16:31:23 +03:00
2008-04-03 17:41:26 +04:00
ret = _pam_winbind_init_context ( pamh , flags , argc , argv , & ctx ) ;
if ( ret ) {
2006-12-21 16:31:23 +03:00
goto out ;
2006-02-04 01:19:41 +03:00
}
2008-04-03 17:41:26 +04:00
_PAM_LOG_FUNCTION_ENTER ( " pam_sm_open_session " , ctx ) ;
2006-02-04 01:19:41 +03:00
2008-08-14 16:39:52 +04:00
if ( ctx - > ctrl & WINBIND_MKHOMEDIR ) {
/* check and create homedir */
ret = _pam_mkhomedir ( ctx ) ;
}
2006-12-21 16:31:23 +03:00
out :
2008-04-03 17:41:26 +04:00
_PAM_LOG_FUNCTION_LEAVE ( " pam_sm_open_session " , ctx , ret ) ;
2006-12-21 16:31:23 +03:00
2008-08-14 18:53:51 +04:00
TALLOC_FREE ( ctx ) ;
2007-09-14 12:21:20 +04:00
2006-12-21 16:31:23 +03:00
return ret ;
2002-04-04 01:39:01 +04:00
}
2006-02-04 01:19:41 +03:00
2002-04-04 01:39:01 +04:00
PAM_EXTERN
int pam_sm_close_session ( pam_handle_t * pamh , int flags ,
2006-02-04 01:19:41 +03:00
int argc , const char * * argv )
2002-04-04 01:39:01 +04:00
{
2008-10-20 18:30:45 +04:00
int ret = PAM_SUCCESS ;
2008-04-03 17:41:26 +04:00
struct pwb_context * ctx = NULL ;
2006-04-11 18:40:53 +04:00
2008-10-20 18:30:45 +04:00
ret = _pam_winbind_init_context ( pamh , flags , argc , argv , & ctx ) ;
if ( ret ) {
2006-04-11 18:40:53 +04:00
goto out ;
2006-02-04 01:19:41 +03:00
}
2008-04-03 17:41:26 +04:00
_PAM_LOG_FUNCTION_ENTER ( " pam_sm_close_session " , ctx ) ;
2006-02-04 01:19:41 +03:00
2006-04-11 18:40:53 +04:00
out :
2008-10-20 18:30:45 +04:00
_PAM_LOG_FUNCTION_LEAVE ( " pam_sm_close_session " , ctx , ret ) ;
2008-04-03 17:41:26 +04:00
2008-08-14 18:53:51 +04:00
TALLOC_FREE ( ctx ) ;
2007-09-14 12:21:20 +04:00
2008-10-20 18:30:45 +04:00
return ret ;
2002-04-04 01:39:01 +04:00
}
2007-02-22 16:35:01 +03:00
/**
2007-09-14 12:21:20 +04:00
* evaluate whether we need to re - authenticate with kerberos after a
* password change
*
2008-08-19 18:19:54 +04:00
* @ param ctx PAM winbind context .
2007-02-22 16:35:01 +03:00
* @ param user The username
*
2007-09-13 18:14:02 +04:00
* @ return boolean Returns true if required , false if not .
2007-02-22 16:35:01 +03:00
*/
2008-04-03 17:41:26 +04:00
static bool _pam_require_krb5_auth_after_chauthtok ( struct pwb_context * ctx ,
2007-09-14 12:21:20 +04:00
const char * user )
2007-02-22 16:35:01 +03:00
{
2007-09-14 12:21:20 +04:00
/* Make sure that we only do this if a) the chauthtok got initiated
* during a logon attempt ( authenticate - > acct_mgmt - > chauthtok ) b ) any
* later password change via the " passwd " command if done by the user
2008-07-07 22:26:16 +04:00
* itself
* NB . If we login from gdm or xdm and the password expires ,
* we change the password , but there is no memory cache .
* Thus , even for passthrough login , we should do the
* authentication again to update memory cache .
* - - - BoYang
* */
2007-09-14 12:21:20 +04:00
2007-02-22 16:35:01 +03:00
char * new_authtok_reqd_during_auth = NULL ;
struct passwd * pwd = NULL ;
2008-04-03 17:41:26 +04:00
_pam_get_data ( ctx - > pamh , PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH ,
2007-09-14 12:21:20 +04:00
& new_authtok_reqd_during_auth ) ;
2008-04-03 17:41:26 +04:00
pam_set_data ( ctx - > pamh , PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH ,
2007-09-14 12:21:20 +04:00
NULL , NULL ) ;
2007-02-22 16:35:01 +03:00
if ( new_authtok_reqd_during_auth ) {
2007-09-13 18:14:02 +04:00
return true ;
2007-02-22 16:35:01 +03:00
}
pwd = getpwnam ( user ) ;
if ( ! pwd ) {
2007-09-13 18:14:02 +04:00
return false ;
2007-02-22 16:35:01 +03:00
}
if ( getuid ( ) = = pwd - > pw_uid ) {
2007-09-13 18:14:02 +04:00
return true ;
2007-02-22 16:35:01 +03:00
}
2007-09-13 18:14:02 +04:00
return false ;
2007-02-22 16:35:01 +03:00
}
2000-05-09 15:43:00 +04:00
2007-09-14 12:21:20 +04:00
PAM_EXTERN
2006-02-04 01:19:41 +03:00
int pam_sm_chauthtok ( pam_handle_t * pamh , int flags ,
int argc , const char * * argv )
2001-05-04 04:43:20 +04:00
{
2002-02-05 12:40:36 +03:00
unsigned int lctrl ;
2006-12-15 09:06:15 +03:00
int ret ;
2008-06-06 17:59:52 +04:00
bool cached_login = false ;
2001-05-04 04:43:20 +04:00
2002-02-05 12:40:36 +03:00
/* <DO NOT free() THESE> */
const char * user ;
char * pass_old , * pass_new ;
/* </DO NOT free() THESE> */
2001-05-04 04:43:20 +04:00
2006-04-11 18:40:53 +04:00
char * Announce ;
2007-09-14 12:21:20 +04:00
2002-02-05 12:40:36 +03:00
int retry = 0 ;
2007-02-05 20:35:25 +03:00
char * username_ret = NULL ;
2008-08-19 13:07:59 +04:00
struct wbcAuthErrorInfo * error = NULL ;
2008-04-03 17:41:26 +04:00
struct pwb_context * ctx = NULL ;
2007-02-05 20:35:25 +03:00
2008-04-03 17:41:26 +04:00
ret = _pam_winbind_init_context ( pamh , flags , argc , argv , & ctx ) ;
if ( ret ) {
2006-04-11 18:40:53 +04:00
goto out ;
2006-02-04 01:19:41 +03:00
}
2008-04-03 17:41:26 +04:00
_PAM_LOG_FUNCTION_ENTER ( " pam_sm_chauthtok " , ctx ) ;
2006-02-04 01:19:41 +03:00
2008-06-06 17:59:52 +04:00
cached_login = ( ctx - > ctrl & WINBIND_CACHED_LOGIN ) ;
/* clearing offline bit for auth */
2008-04-03 17:41:26 +04:00
ctx - > ctrl & = ~ WINBIND_CACHED_LOGIN ;
2006-05-03 19:19:31 +04:00
2002-02-05 12:40:36 +03:00
/*
* First get the name of a user
*/
2008-11-13 16:44:14 +03:00
ret = pam_get_user ( pamh , & user , _ ( " Username: " ) ) ;
2007-02-02 16:03:06 +03:00
if ( ret ) {
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_ERR ,
2006-02-04 01:19:41 +03:00
" password - could not identify user " ) ;
2006-04-11 18:40:53 +04:00
goto out ;
2002-02-05 12:40:36 +03:00
}
2001-05-04 04:43:20 +04:00
2007-02-02 16:03:06 +03:00
if ( user = = NULL ) {
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_ERR , " username was NULL! " ) ;
2007-02-02 16:03:06 +03:00
ret = PAM_USER_UNKNOWN ;
goto out ;
}
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_DEBUG , " username [%s] obtained " , user ) ;
2007-02-02 16:03:06 +03:00
2006-02-13 18:12:22 +03:00
/* check if this is really a user in winbindd, not only in NSS */
2008-04-03 17:41:26 +04:00
ret = valid_user ( ctx , user ) ;
2006-12-15 09:06:15 +03:00
switch ( ret ) {
2006-02-13 18:12:22 +03:00
case 1 :
2006-12-15 09:06:15 +03:00
ret = PAM_USER_UNKNOWN ;
2006-04-11 18:40:53 +04:00
goto out ;
2006-02-13 18:12:22 +03:00
case - 1 :
2006-12-15 09:06:15 +03:00
ret = PAM_SYSTEM_ERR ;
2006-04-11 18:40:53 +04:00
goto out ;
2006-02-13 18:12:22 +03:00
default :
break ;
}
2007-09-14 12:21:20 +04:00
2002-02-05 12:40:36 +03:00
/*
* obtain and verify the current password ( OLDAUTHTOK ) for
* the user .
*/
if ( flags & PAM_PRELIM_CHECK ) {
2006-05-02 23:22:39 +04:00
time_t pwdlastset_prelim = 0 ;
2007-09-14 12:21:20 +04:00
2002-02-05 12:40:36 +03:00
/* instruct user what is happening */
2008-08-14 18:53:51 +04:00
2008-10-30 12:53:52 +03:00
# define greeting _("Changing password for")
2008-08-14 18:53:51 +04:00
Announce = talloc_asprintf ( ctx , " %s %s " , greeting , user ) ;
if ( ! Announce ) {
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_CRIT ,
2007-09-14 12:21:20 +04:00
" password - out of memory " ) ;
2006-12-15 09:06:15 +03:00
ret = PAM_BUF_ERR ;
2006-04-11 18:40:53 +04:00
goto out ;
}
2002-02-05 12:40:36 +03:00
# undef greeting
2007-09-14 12:21:20 +04:00
2008-04-03 17:41:26 +04:00
lctrl = ctx - > ctrl | WINBIND__OLD_PASSWORD ;
ret = _winbind_read_password ( ctx , lctrl ,
2006-02-04 01:19:41 +03:00
Announce ,
2008-10-30 12:53:52 +03:00
_ ( " (current) NT password: " ) ,
2006-02-04 01:19:41 +03:00
NULL ,
( const char * * ) & pass_old ) ;
2008-08-14 18:53:51 +04:00
TALLOC_FREE ( Announce ) ;
2006-12-15 09:06:15 +03:00
if ( ret ! = PAM_SUCCESS ) {
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_NOTICE ,
2007-09-14 12:21:20 +04:00
" password - (old) token not obtained " ) ;
2006-04-11 18:40:53 +04:00
goto out ;
2002-02-05 12:40:36 +03:00
}
2006-12-15 09:06:15 +03:00
2002-02-05 12:40:36 +03:00
/* verify that this is the password for this user */
2007-09-14 12:21:20 +04:00
2008-04-03 17:41:26 +04:00
ret = winbind_auth_request ( ctx , user , pass_old ,
2008-08-19 13:07:59 +04:00
NULL , NULL , 0 ,
& error , NULL , NULL ,
2007-07-04 18:03:10 +04:00
& pwdlastset_prelim , NULL ) ;
2006-02-04 01:19:41 +03:00
2007-09-14 12:21:20 +04:00
if ( ret ! = PAM_ACCT_EXPIRED & &
2006-12-15 09:06:15 +03:00
ret ! = PAM_AUTHTOK_EXPIRED & &
ret ! = PAM_NEW_AUTHTOK_REQD & &
ret ! = PAM_SUCCESS ) {
2002-02-05 12:40:36 +03:00
pass_old = NULL ;
2007-02-05 20:35:25 +03:00
goto out ;
2002-02-05 12:40:36 +03:00
}
2006-05-02 23:22:39 +04:00
2007-09-14 12:21:20 +04:00
pam_set_data ( pamh , PAM_WINBIND_PWD_LAST_SET ,
( void * ) pwdlastset_prelim , NULL ) ;
ret = pam_set_item ( pamh , PAM_OLDAUTHTOK ,
( const void * ) pass_old ) ;
2002-02-05 12:40:36 +03:00
pass_old = NULL ;
2006-12-15 09:06:15 +03:00
if ( ret ! = PAM_SUCCESS ) {
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_CRIT ,
2007-09-14 12:21:20 +04:00
" failed to set PAM_OLDAUTHTOK " ) ;
2002-02-05 12:40:36 +03:00
}
} else if ( flags & PAM_UPDATE_AUTHTOK ) {
2007-09-14 12:21:20 +04:00
2006-05-02 23:22:39 +04:00
time_t pwdlastset_update = 0 ;
2007-09-14 12:21:20 +04:00
2002-02-05 12:40:36 +03:00
/*
* obtain the proposed password
*/
2007-09-14 12:21:20 +04:00
2002-02-05 12:40:36 +03:00
/*
2007-09-14 12:21:20 +04:00
* get the old token back .
2002-02-05 12:40:36 +03:00
*/
2007-09-14 12:21:20 +04:00
2006-12-15 09:06:15 +03:00
ret = _pam_get_item ( pamh , PAM_OLDAUTHTOK , & pass_old ) ;
2007-09-14 12:21:20 +04:00
2006-12-15 09:06:15 +03:00
if ( ret ! = PAM_SUCCESS ) {
2008-04-03 17:41:26 +04:00
_pam_log ( ctx , LOG_NOTICE ,
2007-09-14 12:21:20 +04:00
" user not authenticated " ) ;
2006-04-11 18:40:53 +04:00
goto out ;
2002-02-05 12:40:36 +03:00
}
2007-09-14 12:21:20 +04:00
2008-04-03 17:41:26 +04:00
lctrl = ctx - > ctrl & ~ WINBIND_TRY_FIRST_PASS_ARG ;
2007-09-14 12:21:20 +04:00
2002-02-05 12:40:36 +03:00
if ( on ( WINBIND_USE_AUTHTOK_ARG , lctrl ) ) {
2005-02-04 03:25:33 +03:00
lctrl | = WINBIND_USE_FIRST_PASS_ARG ;
2002-02-05 12:40:36 +03:00
}
retry = 0 ;
2006-12-15 09:06:15 +03:00
ret = PAM_AUTHTOK_ERR ;
while ( ( ret ! = PAM_SUCCESS ) & & ( retry + + < MAX_PASSWD_TRIES ) ) {
2002-02-05 12:40:36 +03:00
/*
* use_authtok is to force the use of a previously entered
* password - - needed for pluggable password strength checking
*/
2007-09-14 12:21:20 +04:00
2008-04-03 17:41:26 +04:00
ret = _winbind_read_password ( ctx , lctrl ,
2007-09-14 12:21:20 +04:00
NULL ,
2008-10-30 12:53:52 +03:00
_ ( " Enter new NT password: " ) ,
_ ( " Retype new NT password: " ) ,
2007-09-14 12:21:20 +04:00
( const char * * ) & pass_new ) ;
2006-12-15 09:06:15 +03:00
if ( ret ! = PAM_SUCCESS ) {
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_ALERT ,
2007-09-14 12:21:20 +04:00
" password - "
" new password not obtained " ) ;
2002-02-05 12:40:36 +03:00
pass_old = NULL ; /* tidy up */
2006-04-11 18:40:53 +04:00
goto out ;
2002-02-05 12:40:36 +03:00
}
2002-03-12 02:59:20 +03:00
2002-02-05 12:40:36 +03:00
/*
* At this point we know who the user is and what they
* propose as their new password . Verify that the new
* password is acceptable .
*/
2007-09-14 12:21:20 +04:00
2002-02-05 12:40:36 +03:00
if ( pass_new [ 0 ] = = ' \0 ' ) { /* "\0" password = NULL */
pass_new = NULL ;
}
}
2007-09-14 12:21:20 +04:00
2002-02-05 12:40:36 +03:00
/*
* By reaching here we have approved the passwords and must now
* rebuild the password database file .
*/
2007-09-14 12:21:20 +04:00
_pam_get_data ( pamh , PAM_WINBIND_PWD_LAST_SET ,
& pwdlastset_update ) ;
2002-02-05 12:40:36 +03:00
2008-06-06 17:59:52 +04:00
/*
* if cached creds were enabled , make sure to set the
* WINBIND_CACHED_LOGIN bit here in order to have winbindd
* update the cached creds storage - gd
*/
if ( cached_login ) {
ctx - > ctrl | = WINBIND_CACHED_LOGIN ;
}
2008-04-03 17:41:26 +04:00
ret = winbind_chauthtok_request ( ctx , user , pass_old ,
2007-09-14 12:21:20 +04:00
pass_new , pwdlastset_update ) ;
2006-12-15 09:06:15 +03:00
if ( ret ) {
2006-02-04 01:19:41 +03:00
_pam_overwrite ( pass_new ) ;
_pam_overwrite ( pass_old ) ;
pass_old = pass_new = NULL ;
2006-04-11 18:40:53 +04:00
goto out ;
2006-02-04 01:19:41 +03:00
}
2008-04-03 17:41:26 +04:00
if ( _pam_require_krb5_auth_after_chauthtok ( ctx , user ) ) {
2006-02-04 01:19:41 +03:00
2007-09-14 12:21:20 +04:00
const char * member = NULL ;
const char * cctype = NULL ;
int warn_pwd_expire ;
2008-08-19 13:07:59 +04:00
struct wbcLogonUserInfo * info = NULL ;
struct wbcUserPasswordPolicyInfo * policy = NULL ;
2007-09-14 12:21:20 +04:00
2008-04-03 17:41:26 +04:00
member = get_member_from_config ( ctx ) ;
cctype = get_krb5_cc_type_from_config ( ctx ) ;
warn_pwd_expire = get_warn_pwd_expire_from_config ( ctx ) ;
2007-09-14 12:21:20 +04:00
2008-07-07 22:26:16 +04:00
/* Keep WINBIND_CACHED_LOGIN bit for
* authentication after changing the password .
* This will update the cached credentials in case
* that winbindd_dual_pam_chauthtok ( ) fails
* to update them .
* - - - BoYang
* */
2008-06-06 17:59:52 +04:00
2008-04-03 17:41:26 +04:00
ret = winbind_auth_request ( ctx , user , pass_new ,
2008-08-19 13:07:59 +04:00
member , cctype , 0 ,
& error , & info , & policy ,
2007-07-04 18:03:10 +04:00
NULL , & username_ret ) ;
2006-02-04 01:19:41 +03:00
_pam_overwrite ( pass_new ) ;
_pam_overwrite ( pass_old ) ;
pass_old = pass_new = NULL ;
2007-02-05 20:35:25 +03:00
if ( ret = = PAM_SUCCESS ) {
2007-09-14 12:21:20 +04:00
2008-08-19 13:07:59 +04:00
struct wbcAuthUserInfo * user_info = NULL ;
if ( info & & info - > info ) {
user_info = info - > info ;
}
2007-09-14 12:21:20 +04:00
/* warn a user if the password is about to
* expire soon */
2008-08-19 13:07:59 +04:00
_pam_warn_password_expiry ( ctx , user_info , policy ,
2007-09-14 12:21:20 +04:00
warn_pwd_expire ,
NULL ) ;
2007-02-05 21:04:28 +03:00
2007-09-14 12:21:20 +04:00
/* set some info3 info for other modules in the
* stack */
2008-08-19 13:07:59 +04:00
_pam_set_data_info3 ( ctx , user_info ) ;
2007-02-05 20:35:25 +03:00
/* put krb5ccname into env */
2008-08-19 13:07:59 +04:00
_pam_setup_krb5_env ( ctx , info ) ;
2007-02-05 20:35:25 +03:00
if ( username_ret ) {
2007-09-14 12:21:20 +04:00
pam_set_item ( pamh , PAM_USER ,
username_ret ) ;
2008-04-03 17:41:26 +04:00
_pam_log_debug ( ctx , LOG_INFO ,
2007-09-14 12:21:20 +04:00
" Returned user was '%s' " ,
username_ret ) ;
2007-02-05 20:35:25 +03:00
free ( username_ret ) ;
}
2008-08-19 13:07:59 +04:00
wbcFreeMemory ( info ) ;
wbcFreeMemory ( policy ) ;
2006-12-15 09:06:15 +03:00
}
2007-02-05 20:35:25 +03:00
goto out ;
2006-02-04 01:19:41 +03:00
}
2002-02-05 12:40:36 +03:00
} else {
2006-12-15 09:06:15 +03:00
ret = PAM_SERVICE_ERR ;
2002-02-05 12:40:36 +03:00
}
2006-02-04 01:19:41 +03:00
2006-04-11 18:40:53 +04:00
out :
2008-08-19 13:07:59 +04:00
{
/* Deal with offline errors. */
int i ;
const char * codes [ ] = {
" NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND " ,
" NT_STATUS_NO_LOGON_SERVERS " ,
" NT_STATUS_ACCESS_DENIED "
} ;
for ( i = 0 ; i < ARRAY_SIZE ( codes ) ; i + + ) {
int _ret ;
if ( _pam_check_remark_auth_err ( ctx , error , codes [ i ] , & _ret ) ) {
break ;
}
}
}
2007-01-25 04:56:34 +03:00
2008-08-19 13:07:59 +04:00
wbcFreeMemory ( error ) ;
2007-02-05 20:35:25 +03:00
2008-04-03 17:41:26 +04:00
_PAM_LOG_FUNCTION_LEAVE ( " pam_sm_chauthtok " , ctx , ret ) ;
2008-08-14 18:53:51 +04:00
TALLOC_FREE ( ctx ) ;
2007-09-14 12:21:20 +04:00
2006-12-15 09:06:15 +03:00
return ret ;
2001-05-04 04:43:20 +04:00
}
2000-05-09 15:43:00 +04:00
# ifdef PAM_STATIC
/* static module data */
2001-05-04 04:43:20 +04:00
struct pam_module _pam_winbind_modstruct = {
2006-02-04 01:19:41 +03:00
MODULE_NAME ,
pam_sm_authenticate ,
pam_sm_setcred ,
pam_sm_acct_mgmt ,
pam_sm_open_session ,
pam_sm_close_session ,
pam_sm_chauthtok
2000-05-09 15:43:00 +04:00
} ;
# endif
/*
2002-02-05 12:40:36 +03:00
* Copyright ( c ) Andrew Tridgell < tridge @ samba . org > 2000
* Copyright ( c ) Tim Potter < tpot @ samba . org > 2000
* Copyright ( c ) Andrew Bartlettt < abartlet @ samba . org > 2002
2008-04-03 19:23:22 +04:00
* Copyright ( c ) Guenther Deschner < gd @ samba . org > 2005 - 2008
2006-08-23 02:53:08 +04:00
* Copyright ( c ) Jan Rêkorajski 1999.
2002-02-05 12:40:36 +03:00
* Copyright ( c ) Andrew G . Morgan 1996 - 8.
* Copyright ( c ) Alex O . Yuriev , 1996.
* Copyright ( c ) Cristian Gafton 1996.
2007-09-14 12:21:20 +04:00
* Copyright ( C ) Elliot Lee < sopwith @ redhat . com > 1996 , Red Hat Software .
2000-05-09 15:43:00 +04:00
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , and the entire permission notice in its entirety ,
* including the disclaimer of warranties .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission .
*
* ALTERNATIVELY , this product may be distributed under the terms of
* the GNU Public License , in which case the provisions of the GPL are
* required INSTEAD OF the above restrictions . ( This clause is
* necessary due to a potential bad interaction between the GPL and
* the restrictions contained in a BSD - style copyright . )
*
* THIS SOFTWARE IS PROVIDED ` AS IS ' ' AND ANY EXPRESS OR IMPLIED
* WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT ,
* INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES
* ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT ,
* STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE )
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE .
*/