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
2007-01-10 15:34:24 +03:00
Copyright Guenther Deschner < gd @ samba . org > 2005 - 2007
2000-05-09 15:43:00 +04:00
2005-02-04 03:25:33 +03:00
largely based on pam_userdb by Cristian Gafton < gafton @ redhat . com >
2002-02-05 12:40:36 +03:00
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
2007-01-25 04:56:34 +03:00
# define _PAM_LOG_FUNCTION_ENTER(function, pamh, ctrl, flags) \
do { \
_pam_log_debug ( pamh , ctrl , LOG_DEBUG , " [pamh: 0x%08x] ENTER: " function " (flags: 0x%04x) " , ( uint32 ) pamh , flags ) ; \
_pam_log_state ( pamh , ctrl ) ; \
} while ( 0 )
# define _PAM_LOG_FUNCTION_LEAVE(function, pamh, ctrl, retval) \
do { \
_pam_log_debug ( pamh , ctrl , LOG_DEBUG , " [pamh: 0x%08x] LEAVE: " function " returning %d " , ( uint32 ) pamh , retval ) ; \
_pam_log_state ( pamh , ctrl ) ; \
} while ( 0 )
2002-02-05 12:40:36 +03:00
/* data tokens */
# define MAX_PASSWD_TRIES 3
2006-09-13 20:39:52 +04:00
/*
* Work around the pam API that has functions with void * * as parameters .
* These lead to strict aliasing warnings with gcc .
*/
static int _pam_get_item ( const pam_handle_t * pamh , int item_type ,
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 ,
const char * module_data_name , const void * _data )
{
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
2006-09-13 20:39:52 +04:00
static void _pam_log_int ( const pam_handle_t * pamh , int err , const char * format , va_list args )
{
pam_vsyslog ( pamh , err , format , args ) ;
2006-12-18 18:35:52 +03:00
}
2006-09-13 20:39:52 +04:00
# else
2006-12-18 18:35:52 +03: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
char * format2 = NULL ;
const char * service ;
_pam_get_item ( pamh , PAM_SERVICE , & service ) ;
format2 = malloc ( strlen ( MODULE_NAME ) + strlen ( format ) + strlen ( service ) + 5 ) ;
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-01-25 18:05:23 +03: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
}
2007-02-13 13:56:04 +03:00
static void _pam_log ( const pam_handle_t * pamh , int ctrl , int err , const char * format , . . . ) PRINTF_ATTRIBUTE ( 4 , 5 ) ;
2006-09-13 20:39:52 +04:00
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-01-25 18:05:23 +03: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-01-25 18:05:23 +03: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-01-25 18:05:23 +03: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-01-25 18:05:23 +03:00
return False ;
2007-01-25 04:56:34 +03:00
}
2007-01-25 18:05:23 +03:00
return True ;
2007-01-25 04:56:34 +03:00
}
2007-01-25 18:05:23 +03: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-01-25 18:05:23 +03:00
return False ;
2007-01-25 04:56:34 +03:00
}
return _pam_log_is_debug_enabled ( ctrl ) ;
}
2007-02-13 13:56:04 +03:00
static void _pam_log_debug ( const pam_handle_t * pamh , int ctrl , int err , const char * format , . . . ) PRINTF_ATTRIBUTE ( 4 , 5 ) ;
2007-01-25 04:56:34 +03:00
static void _pam_log_debug ( const pam_handle_t * pamh , int ctrl , int err , const char * format , . . . )
{
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 ) ;
}
2007-01-25 04:56:34 +03:00
static void _pam_log_state_datum ( const pam_handle_t * pamh , int ctrl , int item_type , const char * key , int is_string )
{
const void * data = NULL ;
if ( item_type ! = 0 ) {
pam_get_item ( pamh , item_type , & data ) ;
} else {
pam_get_data ( pamh , key , & data ) ;
}
if ( data ! = NULL ) {
const char * type = ( item_type ! = 0 ) ? " ITEM " : " DATA " ;
if ( is_string ! = 0 ) {
_pam_log_debug ( pamh , ctrl , LOG_DEBUG , " [pamh: 0x%08x] STATE: %s(%s) = \" %s \" (0x%08x) " , ( uint32 ) pamh , type , key , ( const char * ) data , ( uint32 ) data ) ;
} else {
_pam_log_debug ( pamh , ctrl , LOG_DEBUG , " [pamh: 0x%08x] STATE: %s(%s) = 0x%08x " , ( uint32 ) pamh , type , key , ( uint32 ) data ) ;
}
}
}
# define _PAM_LOG_STATE_DATA_POINTER(pamh, ctrl, module_data_name) \
_pam_log_state_datum ( pamh , ctrl , 0 , module_data_name , 0 )
# define _PAM_LOG_STATE_DATA_STRING(pamh, ctrl, module_data_name) \
_pam_log_state_datum ( pamh , ctrl , 0 , module_data_name , 1 )
# define _PAM_LOG_STATE_ITEM_POINTER(pamh, ctrl, item_type) \
_pam_log_state_datum ( pamh , ctrl , item_type , # item_type , 0 )
# define _PAM_LOG_STATE_ITEM_STRING(pamh, ctrl, item_type) \
_pam_log_state_datum ( pamh , ctrl , item_type , # item_type , 1 )
# ifdef DEBUG_PASSWORD
# define _LOG_PASSWORD_AS_STRING 1
# else
# define _LOG_PASSWORD_AS_STRING 0
# endif
# define _PAM_LOG_STATE_ITEM_PASSWORD(pamh, ctrl, item_type) \
_pam_log_state_datum ( pamh , ctrl , item_type , # item_type , _LOG_PASSWORD_AS_STRING )
static void _pam_log_state ( const pam_handle_t * pamh , int ctrl )
{
if ( ! _pam_log_is_debug_state_enabled ( ctrl ) ) {
return ;
}
_PAM_LOG_STATE_ITEM_STRING ( pamh , ctrl , PAM_SERVICE ) ;
_PAM_LOG_STATE_ITEM_STRING ( pamh , ctrl , PAM_USER ) ;
_PAM_LOG_STATE_ITEM_STRING ( pamh , ctrl , PAM_TTY ) ;
_PAM_LOG_STATE_ITEM_STRING ( pamh , ctrl , PAM_RHOST ) ;
_PAM_LOG_STATE_ITEM_STRING ( pamh , ctrl , PAM_RUSER ) ;
_PAM_LOG_STATE_ITEM_PASSWORD ( pamh , ctrl , PAM_OLDAUTHTOK ) ;
_PAM_LOG_STATE_ITEM_PASSWORD ( pamh , ctrl , PAM_AUTHTOK ) ;
_PAM_LOG_STATE_ITEM_STRING ( pamh , ctrl , PAM_USER_PROMPT ) ;
_PAM_LOG_STATE_ITEM_POINTER ( pamh , ctrl , PAM_CONV ) ;
# ifdef PAM_FAIL_DELAY
_PAM_LOG_STATE_ITEM_POINTER ( pamh , ctrl , PAM_FAIL_DELAY ) ;
# endif
# ifdef PAM_REPOSITORY
_PAM_LOG_STATE_ITEM_POINTER ( pamh , ctrl , PAM_REPOSITORY ) ;
# endif
_PAM_LOG_STATE_DATA_STRING ( pamh , ctrl , PAM_WINBIND_HOMEDIR ) ;
_PAM_LOG_STATE_DATA_STRING ( pamh , ctrl , PAM_WINBIND_LOGONSCRIPT ) ;
2007-02-05 20:14:30 +03:00
_PAM_LOG_STATE_DATA_STRING ( pamh , ctrl , PAM_WINBIND_LOGONSERVER ) ;
2007-01-25 04:56:34 +03:00
_PAM_LOG_STATE_DATA_STRING ( pamh , ctrl , PAM_WINBIND_PROFILEPATH ) ;
_PAM_LOG_STATE_DATA_STRING ( pamh , ctrl , PAM_WINBIND_NEW_AUTHTOK_REQD ) ; /* Use atoi to get PAM result code */
2007-02-22 16:35:01 +03:00
_PAM_LOG_STATE_DATA_STRING ( pamh , ctrl , PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH ) ;
2007-01-25 04:56:34 +03:00
_PAM_LOG_STATE_DATA_POINTER ( pamh , ctrl , PAM_WINBIND_PWD_LAST_SET ) ;
}
2007-01-25 03:47:27 +03: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-01-25 03:47:27 +03:00
if ( iniparser_getboolean ( d , " global:debug " , False ) ) {
2006-04-11 18:40:53 +04:00
ctrl | = WINBIND_DEBUG_ARG ;
}
2007-01-25 04:56:34 +03:00
if ( iniparser_getboolean ( d , " global:debug_state " , False ) ) {
ctrl | = WINBIND_DEBUG_STATE ;
}
2007-01-25 03:47:27 +03: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-01-25 03:47:27 +03: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-01-25 03:47:27 +03: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-01-25 03:47:27 +03:00
if ( iniparser_getboolean ( d , " global:try_first_pass " , False ) ) {
ctrl | = WINBIND_TRY_FIRST_PASS_ARG ;
}
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 ;
2006-07-13 20:31:26 +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 ;
2006-07-13 20:31:26 +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 ;
2006-07-13 20:31:26 +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 ;
2002-02-05 12:40:36 +03:00
else {
2006-12-19 01:10:09 +03:00
_pam_log ( pamh , ctrl , LOG_ERR , " pam_parse: unknown option: %s " , * v ) ;
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
2006-01-13 14:11:23 +03:00
static void _pam_winbind_cleanup_func ( pam_handle_t * pamh , void * data , int error_status )
{
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 ) ) {
_pam_log_debug ( pamh , ctrl , LOG_DEBUG , " [pamh: 0x%08x] CLEAN: cleaning up PAM data 0x%08x (error_status = %d) " , ( uint32 ) pamh , ( uint32 ) data , error_status ) ;
}
2006-01-13 14:11:23 +03:00
SAFE_FREE ( data ) ;
}
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 [ ] = {
{ " NT_STATUS_OK " , " Success " } ,
{ " NT_STATUS_BACKUP_CONTROLLER " , " No primary Domain Controler available " } ,
2006-12-15 09:06:15 +03:00
{ " NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND " , " No domain controllers found " } ,
{ " NT_STATUS_NO_LOGON_SERVERS " , " No logon servers " } ,
2006-02-04 01:19:41 +03:00
{ " NT_STATUS_PWD_TOO_SHORT " , " Password too short " } ,
{ " NT_STATUS_PWD_TOO_RECENT " , " The password of this user is too recent to change " } ,
{ " NT_STATUS_PWD_HISTORY_CONFLICT " , " Password is already in password history " } ,
{ " NT_STATUS_PASSWORD_EXPIRED " , " Your password has expired " } ,
{ " NT_STATUS_PASSWORD_MUST_CHANGE " , " You need to change your password now " } ,
{ " NT_STATUS_INVALID_WORKSTATION " , " You are not allowed to logon from this workstation " } ,
{ " NT_STATUS_INVALID_LOGON_HOURS " , " You are not allowed to logon at this time " } ,
{ " NT_STATUS_ACCOUNT_EXPIRED " , " Your account has expired. Please contact your System administrator " } , /* SCNR */
{ " NT_STATUS_ACCOUNT_DISABLED " , " Your account is disabled. Please contact your System administrator " } , /* SCNR */
{ " NT_STATUS_ACCOUNT_LOCKED_OUT " , " Your account has been locked. Please contact your System administrator " } , /* SCNR */
{ " NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT " , " Invalid Trust Account " } ,
{ " NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT " , " Invalid Trust Account " } ,
{ " NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT " , " Invalid Trust Account " } ,
{ " NT_STATUS_ACCESS_DENIED " , " Access is denied " } ,
{ NULL , NULL }
} ;
const char * _get_ntstatus_error_string ( const char * nt_status_string )
{
int i ;
for ( i = 0 ; ntstatus_errors [ i ] . ntstatus_string ! = NULL ; i + + ) {
2006-04-11 18:40:53 +04:00
if ( ! strcasecmp ( ntstatus_errors [ i ] . ntstatus_string , nt_status_string ) ) {
2006-02-04 01:19:41 +03:00
return ntstatus_errors [ i ] . error_string ;
}
}
return NULL ;
}
2002-02-05 12:40:36 +03:00
/* --- authentication management functions --- */
/* Attempt a conversation */
2000-05-09 15:43:00 +04:00
2002-02-05 12:40:36 +03:00
static int converse ( pam_handle_t * pamh , int nargs ,
struct pam_message * * message ,
struct pam_response * * response )
{
2006-02-04 01:19:41 +03:00
int retval ;
struct pam_conv * conv ;
2006-07-11 22:01:26 +04:00
retval = _pam_get_item ( pamh , PAM_CONV , & conv ) ;
2006-02-04 01:19:41 +03:00
if ( retval = = PAM_SUCCESS ) {
retval = conv - > conv ( nargs , ( const struct pam_message * * ) message ,
response , conv - > appdata_ptr ) ;
}
2002-02-05 12:40:36 +03:00
2006-02-04 01:19:41 +03:00
return retval ; /* propagate error status */
2002-02-05 12:40:36 +03:00
}
2007-02-05 18:25:31 +03:00
static int _make_remark ( pam_handle_t * pamh , int flags , 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-02-05 18:25:31 +03:00
if ( flags & WINBIND_SILENT ) {
return PAM_SUCCESS ;
}
2002-02-05 12:40:36 +03:00
pmsg [ 0 ] = & msg [ 0 ] ;
2006-05-07 00:12:42 +04:00
msg [ 0 ] . msg = CONST_DISCARD ( char * , text ) ;
2002-02-05 12:40:36 +03:00
msg [ 0 ] . msg_style = type ;
resp = NULL ;
retval = converse ( pamh , 1 , pmsg , & resp ) ;
if ( resp ) {
_pam_drop_reply ( resp , 1 ) ;
}
return retval ;
2000-05-09 15:43:00 +04:00
}
2007-02-05 18:25:31 +03:00
static int _make_remark_v ( pam_handle_t * pamh , int flags , 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 ) {
_pam_log ( pamh , 0 , LOG_ERR , " memory allocation failure " ) ;
return ret ;
}
2006-02-04 01:19:41 +03:00
2007-02-05 18:25:31 +03:00
ret = _make_remark ( pamh , flags , type , var ) ;
2006-08-01 19:17:18 +04:00
SAFE_FREE ( var ) ;
return ret ;
2006-02-04 01:19:41 +03:00
}
2007-02-13 13:56:04 +03:00
static int _make_remark_format ( pam_handle_t * pamh , int flags , int type , const char * format , . . . ) PRINTF_ATTRIBUTE ( 4 , 5 ) ;
2007-02-05 18:25:31 +03:00
static int _make_remark_format ( pam_handle_t * pamh , int flags , int type , const char * format , . . . )
2007-01-25 04:56:34 +03:00
{
int ret ;
va_list args ;
va_start ( args , format ) ;
2007-02-05 18:25:31 +03:00
ret = _make_remark_v ( pamh , flags , type , format , args ) ;
2007-01-25 04:56:34 +03:00
va_end ( args ) ;
return ret ;
}
2006-02-04 01:19:41 +03:00
static int pam_winbind_request ( pam_handle_t * pamh , int ctrl ,
enum winbindd_cmd req_type ,
2002-09-25 19:19:00 +04:00
struct winbindd_request * request ,
struct winbindd_response * response )
2000-05-09 15:43:00 +04:00
{
/* Fill in request and send down pipe */
2001-05-04 04:43:20 +04:00
init_request ( request , req_type ) ;
2000-05-09 15:43:00 +04:00
2007-03-22 21:09:21 +03:00
if ( write_sock ( request , sizeof ( * request ) , 0 , 0 ) = = - 1 ) {
2006-09-13 20:39:52 +04:00
_pam_log ( pamh , ctrl , LOG_ERR , " pam_winbind_request: write to socket failed! " ) ;
2002-09-25 19:19:00 +04:00
close_sock ( ) ;
2002-02-05 12:40:36 +03:00
return PAM_SERVICE_ERR ;
2000-05-09 15:43:00 +04:00
}
/* Wait for reply */
2001-05-04 04:43:20 +04:00
if ( read_reply ( response ) = = - 1 ) {
2006-09-13 20:39:52 +04:00
_pam_log ( pamh , ctrl , LOG_ERR , " pam_winbind_request: read from socket failed! " ) ;
2002-09-25 19:19:00 +04:00
close_sock ( ) ;
2002-02-05 12:40:36 +03:00
return PAM_SERVICE_ERR ;
2000-05-09 15:43:00 +04:00
}
2002-09-25 19:19:00 +04:00
/* We are done with the socket - close it and avoid mischeif */
close_sock ( ) ;
2000-05-09 15:43:00 +04:00
/* Copy reply data from socket */
2007-02-05 17:34:12 +03:00
if ( response - > result = = WINBINDD_OK ) {
return PAM_SUCCESS ;
}
/* no need to check for pam_error codes for getpwnam() */
switch ( req_type ) {
case WINBINDD_GETPWNAM :
case WINBINDD_LOOKUPNAME :
2007-02-13 14:04:10 +03:00
if ( strlen ( response - > data . auth . nt_status_string ) > 0 ) {
_pam_log ( pamh , ctrl , LOG_ERR , " request failed, NT error was %s " ,
2007-02-05 17:34:12 +03:00
response - > data . auth . nt_status_string ) ;
2007-02-13 14:04:10 +03:00
} else {
_pam_log ( pamh , ctrl , LOG_ERR , " request failed " ) ;
}
2007-02-05 17:34:12 +03:00
return PAM_USER_UNKNOWN ;
default :
break ;
2000-05-09 15:43:00 +04:00
}
2006-02-04 01:19:41 +03:00
2007-02-05 17:34:12 +03:00
if ( response - > data . auth . pam_error ! = PAM_SUCCESS ) {
_pam_log ( pamh , ctrl , LOG_ERR , " request failed: %s, PAM error was %s (%d), NT error was %s " ,
response - > data . auth . error_string ,
pam_strerror ( pamh , response - > data . auth . pam_error ) ,
response - > data . auth . pam_error ,
response - > data . auth . nt_status_string ) ;
return response - > data . auth . pam_error ;
}
_pam_log ( pamh , ctrl , LOG_ERR , " request failed, but PAM error 0! " ) ;
return PAM_SERVICE_ERR ;
2000-05-09 15:43:00 +04:00
}
2006-09-13 20:39:52 +04:00
static int pam_winbind_request_log ( pam_handle_t * pamh ,
2002-10-26 06:20:59 +04:00
int ctrl ,
2006-02-04 01:19:41 +03:00
enum winbindd_cmd req_type ,
struct winbindd_request * request ,
struct winbindd_response * response ,
2002-10-26 06:20:59 +04:00
const char * user )
2001-05-04 04:43:20 +04:00
{
2002-02-05 12:40:36 +03:00
int retval ;
2001-05-04 04:43:20 +04:00
2006-02-04 01:19:41 +03:00
retval = pam_winbind_request ( pamh , ctrl , req_type , request , response ) ;
2002-02-05 12:40:36 +03:00
switch ( retval ) {
case PAM_AUTH_ERR :
/* incorrect password */
2006-09-13 20:39:52 +04:00
_pam_log ( pamh , ctrl , LOG_WARNING , " user '%s' denied access (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 */
2006-09-13 20:39:52 +04:00
_pam_log ( pamh , ctrl , LOG_WARNING , " user '%s' account expired " , user ) ;
2002-07-15 14:35:28 +04:00
return retval ;
case PAM_AUTHTOK_EXPIRED :
/* password expired */
2006-09-13 20:39:52 +04:00
_pam_log ( pamh , ctrl , LOG_WARNING , " user '%s' password expired " , 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 */
2006-09-13 20:39:52 +04:00
_pam_log ( pamh , ctrl , LOG_WARNING , " user '%s' new password 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 */
2006-09-13 20:39:52 +04:00
_pam_log_debug ( pamh , ctrl , LOG_NOTICE , " user '%s' not found " , user ) ;
2002-02-05 12:40:36 +03:00
if ( ctrl & WINBIND_UNKNOWN_OK_ARG ) {
return PAM_IGNORE ;
}
return retval ;
case PAM_SUCCESS :
2007-02-13 14:04:10 +03:00
/* Otherwise, the authentication looked good */
switch ( req_type ) {
case WINBINDD_INFO :
break ;
case WINBINDD_PAM_AUTH :
_pam_log ( pamh , ctrl , LOG_NOTICE , " user '%s' granted access " , user ) ;
break ;
case WINBINDD_PAM_CHAUTHTOK :
_pam_log ( pamh , ctrl , LOG_NOTICE , " user '%s' password changed " , user ) ;
break ;
default :
_pam_log ( pamh , ctrl , LOG_NOTICE , " user '%s' OK " , user ) ;
break ;
2002-10-26 06:20:59 +04:00
}
2006-02-04 01:19:41 +03:00
2002-02-05 12:40:36 +03:00
return retval ;
default :
/* we don't know anything about this return value */
2006-09-13 20:39:52 +04:00
_pam_log ( pamh , ctrl , LOG_ERR , " internal module error (retval = %d, user = '%s') " ,
2002-02-05 12:40:36 +03:00
retval , user ) ;
return retval ;
}
2002-10-26 06:20:59 +04:00
}
2007-02-05 21:04:28 +03:00
/**
* send a password expiry message if required
*
* @ param pamh PAM handle
* @ param ctrl PAM winbind options .
* @ param next_change expected ( calculated ) next expiry date .
* @ param already_expired pointer to a boolean to indicate if the password is
* already expired .
*
* @ return boolean Returns True if message has been sent , False if not .
*/
static BOOL _pam_send_password_expiry_message ( pam_handle_t * pamh , int ctrl , time_t next_change , time_t now , 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 ) {
* already_expired = False ;
}
if ( next_change < = now ) {
PAM_WB_REMARK_DIRECT ( pamh , ctrl , " NT_STATUS_PASSWORD_EXPIRED " ) ;
if ( already_expired ) {
* already_expired = True ;
}
return True ;
}
2007-01-10 15:34:24 +03:00
if ( ( next_change < 0 ) | |
( next_change > now + DAYS_TO_WARN_BEFORE_PWD_EXPIRES * SECONDS_PER_DAY ) ) {
return False ;
}
if ( ( localtime_r ( & now , & tm_now ) = = NULL ) | |
( localtime_r ( & next_change , & tm_next_change ) = = NULL ) ) {
return False ;
}
days = ( tm_next_change . tm_yday + tm_next_change . tm_year * 365 ) - ( tm_now . tm_yday + tm_now . tm_year * 365 ) ;
if ( days = = 0 ) {
2007-02-05 18:25:31 +03:00
_make_remark ( pamh , ctrl , PAM_TEXT_INFO , " Your password expires today " ) ;
2007-01-10 15:34:24 +03:00
return True ;
}
if ( days > 0 & & days < DAYS_TO_WARN_BEFORE_PWD_EXPIRES ) {
2007-02-05 18:25:31 +03:00
_make_remark_format ( pamh , ctrl , PAM_TEXT_INFO , " Your password will expire in %d %s " ,
2007-01-10 15:34:24 +03:00
days , ( days > 1 ) ? " days " : " day " ) ;
return True ;
}
return False ;
}
2007-02-05 21:04:28 +03:00
/**
* Send a warning if the password expires in the near future
*
* @ param pamh PAM handle
* @ param ctrl PAM winbind options .
* @ param response The full authentication response structure .
* @ param already_expired boolean , is the pwd already expired ?
*
* @ return void .
*/
static void _pam_warn_password_expiry ( pam_handle_t * pamh ,
int flags ,
const struct winbindd_response * response ,
BOOL * already_expired )
2007-01-10 15:34:24 +03:00
{
time_t now = time ( NULL ) ;
time_t next_change = 0 ;
2007-02-05 21:04:28 +03:00
if ( already_expired ) {
* already_expired = False ;
}
2007-01-10 15:34:24 +03:00
/* accounts with ACB_PWNOEXP set never receive a warning */
if ( response - > data . auth . info3 . acct_flags & ACB_PWNOEXP ) {
return ;
}
2007-01-11 18:41:02 +03:00
/* no point in sending a warning if this is a grace logon */
if ( PAM_WB_GRACE_LOGON ( response - > data . auth . info3 . user_flgs ) ) {
return ;
}
2007-01-10 15:34:24 +03:00
/* check if the info3 must change timestamp has been set */
next_change = response - > data . auth . info3 . pass_must_change_time ;
2007-02-05 21:04:28 +03:00
if ( _pam_send_password_expiry_message ( pamh , flags , next_change , now ,
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 */
2007-01-10 15:34:24 +03:00
if ( response - > data . auth . policy . expire < = 0 ) {
return ;
}
next_change = response - > data . auth . info3 . pass_last_set_time +
response - > data . auth . policy . expire ;
2007-02-05 21:04:28 +03:00
if ( _pam_send_password_expiry_message ( pamh , flags , next_change , now ,
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-02-05 17:46:36 +03:00
static BOOL safe_append_string ( char * dest ,
2007-01-25 03:47:27 +03:00
const char * src ,
int dest_buffer_size )
/**
* Append a string , making sure not to overflow and to always return a NULL - terminated
* string .
*
* @ 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-02-05 17:46:36 +03:00
* @ return False if dest buffer is not big enough ( no bytes copied ) , True on success .
2007-01-25 03:47:27 +03:00
*/
{
int dest_length = strlen ( dest ) ;
int src_length = strlen ( src ) ;
if ( dest_length + src_length + 1 > dest_buffer_size ) {
2007-02-05 17:46:36 +03:00
return False ;
2007-01-25 03:47:27 +03:00
}
memcpy ( dest + dest_length , src , src_length + 1 ) ;
2007-02-05 17:46:36 +03:00
return True ;
2007-01-25 03:47:27 +03:00
}
2007-02-05 17:46:36 +03:00
static BOOL winbind_name_to_sid_string ( pam_handle_t * pamh ,
2007-01-25 03:47:27 +03:00
int ctrl ,
const char * user ,
const char * name ,
char * sid_list_buffer ,
int sid_list_buffer_size )
/**
* Convert a names into a SID string , appending it to a buffer .
*
* @ param pamh PAM handle
* @ param ctrl PAM winbind options .
* @ 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-02-05 17:46:36 +03:00
* @ return False on failure , True on success .
2007-01-25 03:47:27 +03:00
*/
{
const char * sid_string ;
struct winbindd_response sid_response ;
/* lookup name? */
if ( IS_SID_STRING ( name ) ) {
sid_string = name ;
} else {
struct winbindd_request sid_request ;
ZERO_STRUCT ( sid_request ) ;
ZERO_STRUCT ( sid_response ) ;
_pam_log_debug ( pamh , ctrl , LOG_DEBUG , " no sid given, looking up: %s \n " , name ) ;
/* fortunatly winbindd can handle non-separated names */
strncpy ( sid_request . data . name . name , name ,
sizeof ( sid_request . data . name . name ) - 1 ) ;
if ( pam_winbind_request_log ( pamh , ctrl , WINBINDD_LOOKUPNAME , & sid_request , & sid_response , user ) ) {
_pam_log ( pamh , ctrl , LOG_INFO , " could not lookup name: %s \n " , name ) ;
2007-02-05 17:46:36 +03:00
return False ;
2007-01-25 03:47:27 +03:00
}
sid_string = sid_response . data . sid . sid ;
}
if ( ! safe_append_string ( sid_list_buffer , sid_string , sid_list_buffer_size ) ) {
2007-02-05 17:46:36 +03:00
return False ;
2007-01-25 03:47:27 +03:00
}
2007-02-05 17:46:36 +03:00
return True ;
2007-01-25 03:47:27 +03:00
}
2007-02-05 17:46:36 +03:00
static BOOL winbind_name_list_to_sid_string_list ( pam_handle_t * pamh ,
2007-01-25 03:47:27 +03:00
int ctrl ,
const char * user ,
const char * name_list ,
char * sid_list_buffer ,
int sid_list_buffer_size )
/**
* Convert a list of names into a list of sids .
*
* @ param pamh PAM handle
* @ param ctrl PAM winbind options .
* @ 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-02-05 17:46:36 +03:00
* @ return False on failure , True on success .
2007-01-25 03:47:27 +03:00
*/
{
2007-02-05 17:46:36 +03:00
BOOL result = False ;
2007-01-25 03:47:27 +03:00
char * current_name = NULL ;
const char * search_location ;
const char * comma ;
if ( sid_list_buffer_size > 0 ) {
sid_list_buffer [ 0 ] = 0 ;
}
search_location = name_list ;
while ( ( comma = strstr ( search_location , " , " ) ) ! = NULL ) {
current_name = strndup ( search_location , comma - search_location ) ;
if ( NULL = = current_name ) {
goto out ;
}
if ( ! winbind_name_to_sid_string ( pamh , ctrl , user , current_name , sid_list_buffer , sid_list_buffer_size ) ) {
goto out ;
}
2007-01-25 18:05:23 +03:00
SAFE_FREE ( current_name ) ;
2007-01-25 03:47:27 +03:00
if ( ! safe_append_string ( sid_list_buffer , " , " , sid_list_buffer_size ) ) {
goto out ;
}
search_location = comma + 1 ;
}
if ( ! winbind_name_to_sid_string ( pamh , ctrl , user , search_location , sid_list_buffer , sid_list_buffer_size ) ) {
goto out ;
}
2007-02-05 17:46:36 +03: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
*
* @ param pamh PAM handle
* @ param ctrl PAM winbind options .
* @ param krb5ccname env variable retrieved from winbindd .
*
* @ return void .
*/
static void _pam_setup_krb5_env ( pam_handle_t * pamh , int ctrl , const char * krb5ccname )
{
char var [ PATH_MAX ] ;
int ret ;
if ( off ( ctrl , WINBIND_KRB5_AUTH ) ) {
return ;
}
if ( ! krb5ccname | | ( strlen ( krb5ccname ) = = 0 ) ) {
return ;
}
_pam_log_debug ( pamh , ctrl , LOG_DEBUG , " request returned KRB5CCNAME: %s " , krb5ccname ) ;
if ( snprintf ( var , sizeof ( var ) , " KRB5CCNAME=%s " , krb5ccname ) = = - 1 ) {
return ;
}
ret = pam_putenv ( pamh , var ) ;
if ( ret ) {
_pam_log ( pamh , ctrl , LOG_ERR , " failed to set KRB5CCNAME to %s: %s " ,
var , pam_strerror ( pamh , ret ) ) ;
}
}
2007-02-05 20:12:13 +03:00
/**
* Set string into the PAM stack .
*
* @ param pamh PAM handle
* @ param ctrl PAM winbind options .
* @ param data_name Key name for pam_set_data .
* @ param value String value .
*
* @ return void .
*/
static void _pam_set_data_string ( pam_handle_t * pamh , int ctrl , const char * data_name , const char * value )
{
int ret ;
if ( ! data_name | | ! value | | ( strlen ( data_name ) = = 0 ) | | ( strlen ( value ) = = 0 ) ) {
return ;
}
ret = pam_set_data ( pamh , data_name , ( void * ) strdup ( value ) , _pam_winbind_cleanup_func ) ;
if ( ret ) {
_pam_log_debug ( pamh , ctrl , LOG_DEBUG , " Could not set data %s: %s \n " ,
data_name , pam_strerror ( pamh , ret ) ) ;
}
}
/**
* Set info3 strings into the PAM stack .
*
* @ param pamh PAM handle
* @ param ctrl PAM winbind options .
* @ param data_name Key name for pam_set_data .
* @ param value String value .
*
* @ return void .
*/
static void _pam_set_data_info3 ( pam_handle_t * pamh , int ctrl , struct winbindd_response * response )
{
_pam_set_data_string ( pamh , ctrl , PAM_WINBIND_HOMEDIR , response - > data . auth . info3 . home_dir ) ;
_pam_set_data_string ( pamh , ctrl , PAM_WINBIND_LOGONSCRIPT , response - > data . auth . info3 . logon_script ) ;
_pam_set_data_string ( pamh , ctrl , PAM_WINBIND_LOGONSERVER , response - > data . auth . info3 . logon_srv ) ;
_pam_set_data_string ( pamh , ctrl , PAM_WINBIND_PROFILEPATH , response - > data . auth . info3 . profile_path ) ;
}
/**
* 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 .
*
* @ param pamh PAM handle
* @ param ctrl PAM winbind options .
* @ param username User in PAM request .
* @ param info3_user_flgs Info3 flags containing logon type bits .
*
* @ return void .
*/
static void _pam_warn_logon_type ( pam_handle_t * pamh , int ctrl , const char * username , uint32 info3_user_flgs )
{
/* inform about logon type */
if ( PAM_WB_GRACE_LOGON ( info3_user_flgs ) ) {
_make_remark ( pamh , ctrl , PAM_ERROR_MSG ,
" Grace login. Please change your password as soon you're online again " ) ;
_pam_log_debug ( pamh , ctrl , LOG_DEBUG ,
" User %s logged on using grace logon \n " , username ) ;
} else if ( PAM_WB_CACHED_LOGON ( info3_user_flgs ) ) {
_make_remark ( pamh , ctrl , PAM_ERROR_MSG ,
2007-04-20 00:00:40 +04:00
" Domain Controller unreachable, using cached credentials instead. Network resources may be unavailable " ) ;
2007-02-05 20:28:55 +03:00
_pam_log_debug ( pamh , ctrl , LOG_DEBUG ,
2007-04-20 03:25:37 +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 .
*
* @ param pamh PAM handle
* @ param ctrl PAM winbind options .
* @ param username User in PAM request .
* @ param info3_user_flgs Info3 flags containing logon type bits .
*
* @ return void .
*/
static void _pam_warn_krb5_failure ( pam_handle_t * pamh , int ctrl , const char * username , uint32 info3_user_flgs )
{
if ( PAM_WB_KRB5_CLOCK_SKEW ( info3_user_flgs ) ) {
_make_remark ( pamh , ctrl , PAM_ERROR_MSG ,
" Failed to establish your Kerberos Ticket cache "
" due time differences \n "
" with the domain controller. "
" Please verify the system time. \n " ) ;
_pam_log_debug ( pamh , ctrl , LOG_DEBUG ,
" User %s: Clock skew when getting Krb5 TGT \n " , username ) ;
}
}
2007-02-05 17:43:06 +03:00
/**
* Compose Password Restriction String for a PAM_ERROR_MSG conversation .
*
* @ param response The struct winbindd_response .
*
* @ return string ( caller needs to free ) .
*/
static char * _pam_compose_pwd_restriction_string ( struct winbindd_response * response )
{
char * str = NULL ;
size_t offset = 0 , ret = 0 , str_size = 1024 ;
str = ( char * ) malloc ( str_size ) ;
if ( ! str ) {
return NULL ;
}
memset ( str , ' \0 ' , str_size ) ;
offset = snprintf ( str , str_size , " Your password " ) ;
if ( offset = = - 1 ) {
goto failed ;
}
if ( response - > data . auth . policy . min_length_password > 0 ) {
ret = snprintf ( str + offset , str_size - offset ,
" must be at least %d characters; " ,
response - > data . auth . policy . min_length_password ) ;
if ( ret = = - 1 ) {
goto failed ;
}
offset + = ret ;
}
if ( response - > data . auth . policy . password_history > 0 ) {
ret = snprintf ( str + offset , str_size - offset ,
" cannot repeat any of your previous %d passwords; " ,
response - > data . auth . policy . password_history ) ;
if ( ret = = - 1 ) {
goto failed ;
}
offset + = ret ;
}
if ( response - > data . auth . policy . password_properties & DOMAIN_PASSWORD_COMPLEX ) {
ret = snprintf ( str + offset , str_size - offset ,
" must contain capitals, numerals or punctuation; "
" and cannot contain your account or full name; " ) ;
if ( ret = = - 1 ) {
goto failed ;
}
offset + = ret ;
}
ret = snprintf ( str + offset , str_size - offset ,
" Please type a different password. "
" Type a password which meets these requirements in both text boxes. " ) ;
if ( ret = = - 1 ) {
goto failed ;
}
return str ;
failed :
SAFE_FREE ( str ) ;
return NULL ;
}
2002-10-26 06:20:59 +04:00
/* talk to winbindd */
2006-09-13 20:39:52 +04:00
static int winbind_auth_request ( pam_handle_t * pamh ,
2006-02-04 01:19:41 +03:00
int ctrl ,
const char * user ,
const char * pass ,
const char * member ,
const char * cctype ,
2006-12-15 09:06:15 +03:00
struct winbindd_response * p_response ,
2006-09-05 09:28:31 +04:00
time_t * pwd_last_set ,
char * * user_ret )
2002-10-26 06:20:59 +04:00
{
struct winbindd_request request ;
struct winbindd_response response ;
2006-02-04 01:19:41 +03:00
int ret ;
2007-02-05 21:04:28 +03:00
BOOL already_expired = False ;
2002-10-26 06:20:59 +04:00
ZERO_STRUCT ( request ) ;
2006-02-04 01:19:41 +03:00
ZERO_STRUCT ( response ) ;
2002-10-26 06:20:59 +04:00
2006-05-02 23:22:39 +04:00
if ( pwd_last_set ) {
* pwd_last_set = 0 ;
}
2002-10-26 06:20:59 +04:00
strncpy ( request . data . auth . user , user ,
2006-02-04 01:19:41 +03:00
sizeof ( request . data . auth . user ) - 1 ) ;
2002-10-26 06:20:59 +04:00
strncpy ( request . data . auth . pass , pass ,
2006-02-04 01:19:41 +03:00
sizeof ( request . data . auth . pass ) - 1 ) ;
request . data . auth . krb5_cc_type [ 0 ] = ' \0 ' ;
request . data . auth . uid = - 1 ;
2006-08-23 02:53:08 +04:00
request . flags = WBFLAG_PAM_INFO3_TEXT | WBFLAG_PAM_CONTACT_TRUSTDOM ;
2006-02-04 01:19:41 +03:00
2007-02-13 18:56:09 +03:00
if ( 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 ;
}
request . data . auth . uid = pwd - > pw_uid ;
}
2004-08-18 20:25:41 +04:00
2007-02-13 18:56:09 +03:00
if ( ctrl & WINBIND_KRB5_AUTH ) {
_pam_log_debug ( pamh , ctrl , LOG_DEBUG , " enabling krb5 login flag \n " ) ;
request . flags | = WBFLAG_PAM_KRB5 | WBFLAG_PAM_FALLBACK_AFTER_KRB5 ;
}
2006-02-04 01:19:41 +03:00
if ( ctrl & WINBIND_CACHED_LOGIN ) {
2006-09-13 20:39:52 +04:00
_pam_log_debug ( pamh , ctrl , LOG_DEBUG , " enabling cached login flag \n " ) ;
2006-02-04 01:19:41 +03:00
request . flags | = WBFLAG_PAM_CACHED_LOGIN ;
}
2006-09-05 09:28:31 +04:00
if ( user_ret ) {
* user_ret = NULL ;
request . flags | = WBFLAG_PAM_UNIX_NAME ;
}
2006-02-04 01:19:41 +03:00
if ( cctype ! = NULL ) {
strncpy ( request . data . auth . krb5_cc_type , cctype ,
sizeof ( request . data . auth . krb5_cc_type ) - 1 ) ;
2006-09-13 20:39:52 +04:00
_pam_log_debug ( pamh , ctrl , LOG_DEBUG , " enabling request for a %s krb5 ccache \n " , cctype ) ;
2006-02-04 01:19:41 +03:00
}
request . data . auth . require_membership_of_sid [ 0 ] = ' \0 ' ;
if ( member ! = NULL ) {
2004-08-18 20:25:41 +04:00
2007-01-25 03:47:27 +03:00
if ( ! winbind_name_list_to_sid_string_list ( pamh , ctrl , user , member ,
request . data . auth . require_membership_of_sid ,
sizeof ( request . data . auth . require_membership_of_sid ) ) ) {
2004-08-18 20:25:41 +04:00
2007-01-25 03:47:27 +03:00
_pam_log_debug ( pamh , ctrl , LOG_ERR , " 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
2006-02-04 01:19:41 +03:00
ret = pam_winbind_request_log ( pamh , ctrl , WINBINDD_PAM_AUTH , & request , & response , user ) ;
2004-08-18 20:25:41 +04:00
2006-05-02 23:22:39 +04:00
if ( pwd_last_set ) {
* pwd_last_set = response . data . auth . info3 . pass_last_set_time ;
}
2006-12-15 09:06:15 +03:00
if ( p_response ) {
/* We want to process the response in the caller. */
* p_response = response ;
2006-02-04 01:19:41 +03:00
return ret ;
}
if ( ret ) {
2007-02-05 18:25:31 +03:00
PAM_WB_REMARK_CHECK_RESPONSE_RET ( pamh , ctrl , response , " NT_STATUS_PASSWORD_EXPIRED " ) ;
PAM_WB_REMARK_CHECK_RESPONSE_RET ( pamh , ctrl , response , " NT_STATUS_PASSWORD_MUST_CHANGE " ) ;
PAM_WB_REMARK_CHECK_RESPONSE_RET ( pamh , ctrl , response , " NT_STATUS_INVALID_WORKSTATION " ) ;
PAM_WB_REMARK_CHECK_RESPONSE_RET ( pamh , ctrl , response , " NT_STATUS_INVALID_LOGON_HOURS " ) ;
PAM_WB_REMARK_CHECK_RESPONSE_RET ( pamh , ctrl , response , " NT_STATUS_ACCOUNT_EXPIRED " ) ;
PAM_WB_REMARK_CHECK_RESPONSE_RET ( pamh , ctrl , response , " NT_STATUS_ACCOUNT_DISABLED " ) ;
PAM_WB_REMARK_CHECK_RESPONSE_RET ( pamh , ctrl , response , " NT_STATUS_ACCOUNT_LOCKED_OUT " ) ;
PAM_WB_REMARK_CHECK_RESPONSE_RET ( pamh , ctrl , response , " NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT " ) ;
PAM_WB_REMARK_CHECK_RESPONSE_RET ( pamh , ctrl , response , " NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT " ) ;
PAM_WB_REMARK_CHECK_RESPONSE_RET ( pamh , ctrl , response , " NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT " ) ;
PAM_WB_REMARK_CHECK_RESPONSE_RET ( pamh , ctrl , response , " NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND " ) ;
PAM_WB_REMARK_CHECK_RESPONSE_RET ( pamh , ctrl , response , " NT_STATUS_NO_LOGON_SERVERS " ) ;
2007-02-05 21:04:28 +03:00
PAM_WB_REMARK_CHECK_RESPONSE_RET ( pamh , ctrl , response , " NT_STATUS_WRONG_PASSWORD " ) ;
PAM_WB_REMARK_CHECK_RESPONSE_RET ( pamh , ctrl , response , " NT_STATUS_ACCESS_DENIED " ) ;
2006-02-04 01:19:41 +03:00
}
2007-02-05 21:11:41 +03:00
if ( ret = = PAM_SUCCESS ) {
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 */
_pam_warn_password_expiry ( pamh , ctrl , & response , & already_expired ) ;
2006-02-04 01:19:41 +03:00
2007-02-05 21:11:41 +03:00
if ( already_expired = = True ) {
_pam_log_debug ( pamh , ctrl , LOG_DEBUG , " Password has expired "
2007-02-13 14:04:10 +03:00
" (Password was last set: %lld, the policy says "
" it should expire here %lld (now it's: %lu)) \n " ,
2007-02-05 21:11:41 +03:00
response . data . auth . info3 . pass_last_set_time ,
response . data . auth . info3 . pass_last_set_time +
response . data . auth . policy . expire ,
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 */
_pam_warn_logon_type ( pamh , ctrl , user , response . data . auth . info3 . user_flgs ) ;
2007-05-07 00:33:33 +04:00
/* inform about krb5 failures */
_pam_warn_krb5_failure ( pamh , ctrl , user , response . data . auth . info3 . user_flgs ) ;
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 */
_pam_set_data_info3 ( pamh , ctrl , & response ) ;
2006-10-17 03:13:56 +04:00
2007-02-05 21:04:28 +03:00
/* put krb5ccname into env */
_pam_setup_krb5_env ( pamh , ctrl , response . data . auth . krb5ccname ) ;
2007-02-05 20:28:55 +03:00
2007-02-05 21:04:28 +03:00
/* If winbindd returned a username, return the pointer to it here. */
if ( user_ret & & response . extra_data . data ) {
/* We have to trust it's a null terminated string. */
* user_ret = ( char * ) response . extra_data . data ;
}
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 */
2006-02-04 01:19:41 +03:00
static int winbind_chauthtok_request ( pam_handle_t * pamh ,
int ctrl ,
const char * user ,
const char * oldpass ,
2006-05-02 23:22:39 +04:00
const char * newpass ,
time_t pwd_last_set )
2001-05-04 04:43:20 +04:00
{
struct winbindd_request request ;
struct winbindd_response response ;
2006-02-04 01:19:41 +03:00
int ret ;
2001-05-04 04:43:20 +04:00
ZERO_STRUCT ( request ) ;
2006-02-04 01:19:41 +03:00
ZERO_STRUCT ( response ) ;
2001-05-04 04:43:20 +04:00
2006-02-04 01:19:41 +03:00
if ( request . data . chauthtok . user = = NULL ) return - 2 ;
2001-05-04 04:43:20 +04:00
strncpy ( request . data . chauthtok . user , user ,
2006-02-04 01:19:41 +03:00
sizeof ( request . data . chauthtok . user ) - 1 ) ;
if ( oldpass ! = NULL ) {
strncpy ( request . data . chauthtok . oldpass , oldpass ,
sizeof ( request . data . chauthtok . oldpass ) - 1 ) ;
} else {
request . data . chauthtok . oldpass [ 0 ] = ' \0 ' ;
}
2001-05-04 04:43:20 +04:00
2006-02-04 01:19:41 +03:00
if ( newpass ! = NULL ) {
strncpy ( request . data . chauthtok . newpass , newpass ,
sizeof ( request . data . chauthtok . newpass ) - 1 ) ;
} else {
request . data . chauthtok . newpass [ 0 ] = ' \0 ' ;
}
if ( ctrl & WINBIND_KRB5_AUTH ) {
2006-08-23 02:53:08 +04:00
request . flags = WBFLAG_PAM_KRB5 | WBFLAG_PAM_CONTACT_TRUSTDOM ;
2006-02-04 01:19:41 +03:00
}
ret = pam_winbind_request_log ( pamh , ctrl , WINBINDD_PAM_CHAUTHTOK , & request , & response , user ) ;
if ( ret = = PAM_SUCCESS ) {
return ret ;
}
2007-02-05 18:25:31 +03:00
PAM_WB_REMARK_CHECK_RESPONSE_RET ( pamh , ctrl , response , " NT_STATUS_BACKUP_CONTROLLER " ) ;
PAM_WB_REMARK_CHECK_RESPONSE_RET ( pamh , ctrl , response , " NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND " ) ;
PAM_WB_REMARK_CHECK_RESPONSE_RET ( pamh , ctrl , response , " NT_STATUS_NO_LOGON_SERVERS " ) ;
PAM_WB_REMARK_CHECK_RESPONSE_RET ( pamh , ctrl , response , " NT_STATUS_ACCESS_DENIED " ) ;
2006-02-04 01:19:41 +03:00
/* TODO: tell the min pwd length ? */
2007-02-05 18:25:31 +03:00
PAM_WB_REMARK_CHECK_RESPONSE_RET ( pamh , ctrl , response , " NT_STATUS_PWD_TOO_SHORT " ) ;
2006-02-04 01:19:41 +03:00
/* TODO: tell the minage ? */
2007-02-05 18:25:31 +03:00
PAM_WB_REMARK_CHECK_RESPONSE_RET ( pamh , ctrl , response , " NT_STATUS_PWD_TOO_RECENT " ) ;
2006-02-04 01:19:41 +03:00
/* TODO: tell the history length ? */
2007-02-05 18:25:31 +03:00
PAM_WB_REMARK_CHECK_RESPONSE_RET ( pamh , ctrl , response , " NT_STATUS_PWD_HISTORY_CONFLICT " ) ;
2006-02-04 01:19:41 +03:00
2006-04-11 18:40:53 +04:00
if ( ! strcasecmp ( response . data . auth . nt_status_string , " 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 ;
2006-02-04 01:19:41 +03:00
/* FIXME: avoid to send multiple PAM messages after another */
switch ( response . data . auth . reject_reason ) {
2006-05-02 23:22:39 +04:00
case - 1 :
break ;
case REJECT_REASON_OTHER :
2006-05-03 00:03:30 +04:00
if ( ( response . data . auth . policy . min_passwordage > 0 ) & &
( pwd_last_set + response . data . auth . policy . min_passwordage > time ( NULL ) ) ) {
2007-02-05 18:25:31 +03:00
PAM_WB_REMARK_DIRECT ( pamh , ctrl , " NT_STATUS_PWD_TOO_RECENT " ) ;
2006-05-02 23:22:39 +04:00
}
2006-02-04 01:19:41 +03:00
break ;
case REJECT_REASON_TOO_SHORT :
2007-02-05 18:25:31 +03:00
PAM_WB_REMARK_DIRECT ( pamh , ctrl , " NT_STATUS_PWD_TOO_SHORT " ) ;
2006-02-04 01:19:41 +03:00
break ;
case REJECT_REASON_IN_HISTORY :
2007-02-05 18:25:31 +03:00
PAM_WB_REMARK_DIRECT ( pamh , ctrl , " NT_STATUS_PWD_HISTORY_CONFLICT " ) ;
2006-02-04 01:19:41 +03:00
break ;
case REJECT_REASON_NOT_COMPLEX :
2007-02-05 18:25:31 +03:00
_make_remark ( pamh , ctrl , PAM_ERROR_MSG , " Password does not meet complexity requirements " ) ;
2006-02-04 01:19:41 +03:00
break ;
default :
2006-09-13 20:39:52 +04:00
_pam_log_debug ( pamh , ctrl , LOG_DEBUG ,
2006-02-04 01:19:41 +03:00
" unknown password change reject reason: %d " ,
response . data . auth . reject_reason ) ;
break ;
}
2007-02-05 17:43:06 +03:00
pwd_restriction_string = _pam_compose_pwd_restriction_string ( & response ) ;
if ( pwd_restriction_string ) {
2007-02-05 18:25:31 +03:00
_make_remark ( pamh , ctrl , PAM_ERROR_MSG , pwd_restriction_string ) ;
2007-02-05 17:43:06 +03:00
SAFE_FREE ( pwd_restriction_string ) ;
}
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
*/
2006-09-13 20:39:52 +04:00
static int valid_user ( pam_handle_t * pamh , int ctrl , 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 . */
struct passwd * pwd = NULL ;
struct winbindd_request request ;
struct winbindd_response response ;
int ret ;
ZERO_STRUCT ( request ) ;
ZERO_STRUCT ( response ) ;
pwd = getpwnam ( user ) ;
if ( pwd = = NULL ) {
return 1 ;
}
2006-04-11 18:40:53 +04:00
strncpy ( request . data . username , user ,
sizeof ( request . data . username ) - 1 ) ;
2006-02-13 18:12:22 +03:00
ret = pam_winbind_request_log ( pamh , ctrl , WINBINDD_GETPWNAM , & request , & response , user ) ;
switch ( ret ) {
case PAM_USER_UNKNOWN :
return 1 ;
case PAM_SUCCESS :
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
2006-02-04 01:19:41 +03:00
static int _winbind_read_password ( pam_handle_t * pamh ,
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 ;
2007-01-25 04:56:34 +03:00
_pam_log ( pamh , ctrl , LOG_DEBUG , " getting password (0x%08x) " , ctrl ) ;
2002-02-05 12:40:36 +03:00
/*
* make sure nothing inappropriate gets returned
*/
* pass = token = NULL ;
/*
* which authentication token are we getting ?
*/
authtok_flag = on ( WINBIND__OLD_PASSWORD , ctrl ) ? PAM_OLDAUTHTOK : PAM_AUTHTOK ;
/*
* should we obtain the password from a PAM item ?
*/
if ( on ( WINBIND_TRY_FIRST_PASS_ARG , ctrl ) | | on ( WINBIND_USE_FIRST_PASS_ARG , ctrl ) ) {
2006-07-11 22:01:26 +04:00
retval = _pam_get_item ( pamh , authtok_flag , & item ) ;
2002-02-05 12:40:36 +03:00
if ( retval ! = PAM_SUCCESS ) {
/* very strange. */
2006-09-13 20:39:52 +04:00
_pam_log ( pamh , ctrl , LOG_ALERT ,
2002-02-05 12:40:36 +03:00
" pam_get_item returned error to unix-read-password "
) ;
return retval ;
} else if ( item ! = NULL ) { /* we have a password! */
* pass = item ;
item = NULL ;
2007-01-25 04:56:34 +03:00
_pam_log ( pamh , ctrl , LOG_DEBUG ,
" 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 ) ) {
return PAM_AUTHTOK_RECOVER_ERR ; /* didn't work */
} 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 ;
2006-05-07 00:12:42 +04:00
msg [ 0 ] . msg = CONST_DISCARD ( 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 ;
2006-05-07 00:12:42 +04:00
msg [ i + + ] . msg = CONST_DISCARD ( 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 ;
2006-05-07 00:12:42 +04:00
msg [ i + + ] . msg = CONST_DISCARD ( char * , prompt2 ) ;
2002-02-05 12:40:36 +03:00
+ + replies ;
}
/* so call the conversation expecting i responses */
resp = NULL ;
retval = converse ( pamh , i , pmsg , & resp ) ;
if ( resp ! = NULL ) {
/* interpret the response */
if ( retval = = PAM_SUCCESS ) { /* a good conversation */
2006-04-11 18:40:53 +04:00
token = x_strdup ( resp [ i - replies ] . resp ) ;
2002-02-05 12:40:36 +03:00
if ( token ! = NULL ) {
if ( replies = = 2 ) {
/* verify that password entered correctly */
if ( ! resp [ i - 1 ] . resp
2006-04-11 18:40:53 +04:00
| | strcmp ( token , resp [ i - 1 ] . resp ) ) {
2002-02-05 12:40:36 +03:00
_pam_delete ( token ) ; /* mistyped */
retval = PAM_AUTHTOK_RECOVER_ERR ;
2007-02-05 18:25:31 +03:00
_make_remark ( pamh , ctrl , PAM_ERROR_MSG , MISTYPED_PASS ) ;
2002-02-05 12:40:36 +03:00
}
}
} else {
2006-09-13 20:39:52 +04:00
_pam_log ( pamh , ctrl , LOG_NOTICE , " could not recover authentication token " ) ;
2006-07-11 14:39:32 +04:00
retval = PAM_AUTHTOK_RECOVER_ERR ;
2002-02-05 12:40:36 +03:00
}
}
/*
* tidy up the conversation ( resp_retcode ) is ignored
* - - what is it for anyway ? AGM
*/
_pam_drop_reply ( resp , i ) ;
} else {
retval = ( retval = = PAM_SUCCESS )
? PAM_AUTHTOK_RECOVER_ERR : retval ;
}
2000-05-09 15:43:00 +04:00
}
2002-02-05 12:40:36 +03:00
if ( retval ! = PAM_SUCCESS ) {
2006-09-13 20:39:52 +04:00
_pam_log_debug ( pamh , ctrl , LOG_DEBUG ,
2002-02-05 12:40:36 +03:00
" unable to obtain a password " ) ;
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 */
2000-05-09 15:43:00 +04:00
2002-02-05 12:40:36 +03:00
retval = pam_set_item ( pamh , authtok_flag , token ) ;
_pam_delete ( token ) ; /* clean it up */
2006-02-04 01:19:41 +03:00
if ( retval ! = PAM_SUCCESS | |
2006-07-11 22:01:26 +04:00
( retval = _pam_get_item ( pamh , authtok_flag , & item ) ) ! = PAM_SUCCESS ) {
2002-02-05 12:40:36 +03:00
2006-09-13 20:39:52 +04:00
_pam_log ( pamh , ctrl , LOG_CRIT , " error manipulating 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
* pass = item ;
item = NULL ; /* break link to password */
return PAM_SUCCESS ;
2000-05-09 15:43:00 +04:00
}
2006-09-13 20:39:52 +04:00
const char * get_conf_item_string ( const pam_handle_t * pamh ,
int argc ,
2006-02-04 01:19:41 +03:00
const char * * argv ,
2006-04-11 18:40:53 +04:00
int ctrl ,
dictionary * d ,
2006-02-04 01:19:41 +03:00
const char * item ,
2006-09-13 20:39:52 +04:00
int config_flag )
2006-02-04 01:19:41 +03:00
{
int i = 0 ;
const char * parm_opt = NULL ;
2006-04-11 18:40:53 +04:00
char * key = NULL ;
2006-02-04 01:19:41 +03:00
2006-09-13 20:39:52 +04:00
if ( ! ( 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 */
2006-04-11 18:40:53 +04:00
if ( d ! = NULL ) {
2006-04-11 19:18:46 +04:00
if ( ! asprintf ( & key , " global:%s " , item ) ) {
2006-04-11 18:40:53 +04:00
goto out ;
}
parm_opt = iniparser_getstr ( d , key ) ;
SAFE_FREE ( key ) ;
}
2006-02-04 01:19:41 +03:00
for ( i = 0 ; i < argc ; i + + ) {
if ( ( strncmp ( argv [ i ] , item , strlen ( item ) ) = = 0 ) ) {
char * p ;
2006-11-15 05:06:58 +03:00
if ( ( p = strchr ( argv [ i ] , ' = ' ) ) = = NULL ) {
2006-09-13 20:39:52 +04:00
_pam_log ( pamh , ctrl , LOG_INFO , " no \" = \" delimiter for \" %s \" found \n " , item ) ;
2006-02-04 01:19:41 +03:00
goto out ;
}
2006-09-13 20:39:52 +04:00
_pam_log_debug ( pamh , ctrl , LOG_INFO , " PAM config: %s '%s' \n " , item , p + 1 ) ;
2006-02-04 01:19:41 +03:00
return p + 1 ;
}
}
2006-05-11 01:12:10 +04:00
if ( d ! = NULL ) {
2006-09-13 20:39:52 +04:00
_pam_log_debug ( pamh , ctrl , LOG_INFO , " CONFIG file: %s '%s' \n " , item , parm_opt ) ;
2006-05-11 01:12:10 +04:00
}
2006-02-04 01:19:41 +03:00
out :
return parm_opt ;
}
2006-09-13 20:39:52 +04:00
const char * get_krb5_cc_type_from_config ( const pam_handle_t * pamh , int argc , const char * * argv , int ctrl , dictionary * d )
2006-02-04 01:19:41 +03:00
{
2006-09-13 20:39:52 +04:00
return get_conf_item_string ( pamh , argc , argv , ctrl , d , " krb5_ccache_type " , WINBIND_KRB5_CCACHE_TYPE ) ;
2006-02-04 01:19:41 +03:00
}
2006-09-13 20:39:52 +04:00
const char * get_member_from_config ( const pam_handle_t * pamh , int argc , const char * * argv , int ctrl , dictionary * d )
2006-02-04 01:19:41 +03:00
{
const char * ret = NULL ;
2006-09-13 20:39:52 +04:00
ret = get_conf_item_string ( pamh , argc , argv , ctrl , d , " require_membership_of " , WINBIND_REQUIRED_MEMBERSHIP ) ;
2006-02-04 01:19:41 +03:00
if ( ret ) {
return ret ;
}
2006-09-13 20:39:52 +04:00
return get_conf_item_string ( pamh , argc , argv , ctrl , d , " require-membership-of " , WINBIND_REQUIRED_MEMBERSHIP ) ;
2006-02-04 01:19:41 +03:00
}
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 ;
int retval = PAM_AUTH_ERR ;
2006-10-17 02:41:24 +04:00
dictionary * d = NULL ;
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 ;
2006-02-04 01:19:41 +03:00
/* parse arguments */
2006-09-13 20:39:52 +04:00
int ctrl = _pam_parse ( pamh , flags , argc , argv , & d ) ;
2006-02-04 01:19:41 +03:00
if ( ctrl = = - 1 ) {
2006-04-11 18:40:53 +04:00
retval = PAM_SYSTEM_ERR ;
goto out ;
2006-02-04 01:19:41 +03:00
}
2007-01-25 04:56:34 +03:00
_PAM_LOG_FUNCTION_ENTER ( " pam_sm_authenticate " , pamh , ctrl , flags ) ;
2006-02-04 01:19:41 +03:00
/* Get the username */
retval = pam_get_user ( pamh , & username , NULL ) ;
if ( ( retval ! = PAM_SUCCESS ) | | ( ! username ) ) {
2006-09-13 20:39:52 +04:00
_pam_log_debug ( pamh , ctrl , LOG_DEBUG , " 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-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 . */
if ( username [ 0 ] = = ' _ ' ) {
uid_t id = atoi ( & username [ 1 ] ) ;
struct passwd * pw = NULL ;
if ( ( id ! = 0 ) & & ( ( pw = getpwuid ( id ) ) ! = NULL ) ) {
real_username = strdup ( pw - > pw_name ) ;
}
}
# endif
if ( ! real_username ) {
/* Just making a copy of the username we got from PAM */
if ( ( real_username = strdup ( username ) ) = = NULL ) {
_pam_log_debug ( pamh , ctrl , LOG_DEBUG ,
" memory allocation failure when copying username " ) ;
retval = PAM_SERVICE_ERR ;
goto out ;
}
}
2006-02-04 01:19:41 +03:00
retval = _winbind_read_password ( pamh , ctrl , NULL ,
" Password: " , NULL ,
& password ) ;
if ( retval ! = PAM_SUCCESS ) {
2006-09-13 20:39:52 +04:00
_pam_log ( pamh , ctrl , LOG_ERR , " 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
2006-09-13 20:39:52 +04:00
_pam_log_debug ( pamh , ctrl , LOG_INFO , " 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
2007-03-01 06:10:29 +03:00
_pam_log_debug ( pamh , ctrl , LOG_INFO , " Verify user '%s' " , real_username ) ;
2002-01-07 05:57:06 +03:00
# endif
2006-09-13 20:39:52 +04:00
member = get_member_from_config ( pamh , argc , argv , ctrl , d ) ;
2004-08-18 20:25:41 +04:00
2006-09-13 20:39:52 +04:00
cctype = get_krb5_cc_type_from_config ( pamh , argc , argv , ctrl , d ) ;
2004-08-18 20:25:41 +04:00
2006-02-04 01:19:41 +03:00
/* Now use the username to look up password */
2006-09-05 09:28:31 +04:00
retval = winbind_auth_request ( pamh , ctrl , username , password , member ,
2006-12-15 09:06:15 +03:00
cctype , NULL , 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 ;
2007-01-25 04:18:31 +03:00
if ( ! asprintf ( & new_authtok_required , " %d " , retval ) ) {
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-01-25 04:18:31 +03: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
if ( ! asprintf ( & new_authtok_required_during_auth , " %d " , True ) ) {
retval = PAM_BUF_ERR ;
goto out ;
}
pam_set_data ( pamh , PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH ,
new_authtok_required_during_auth , _pam_winbind_cleanup_func ) ;
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 ) ;
2006-09-14 13:27:10 +04:00
_pam_log_debug ( pamh , ctrl , LOG_INFO , " Returned user was '%s' " , username_ret ) ;
2006-09-05 09:28:31 +04:00
free ( username_ret ) ;
}
2007-03-01 06:10:29 +03:00
if ( real_username ) {
free ( real_username ) ;
}
2006-04-11 18:40:53 +04:00
if ( d ) {
iniparser_freedict ( d ) ;
}
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 ) ;
}
2007-01-25 04:56:34 +03:00
_PAM_LOG_FUNCTION_LEAVE ( " pam_sm_authenticate " , pamh , ctrl , retval ) ;
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 ;
2006-12-18 18:29:05 +03:00
dictionary * d = NULL ;
2006-02-04 01:19:41 +03:00
/* parse arguments */
2006-12-18 18:29:05 +03:00
int ctrl = _pam_parse ( pamh , flags , argc , argv , & d ) ;
2006-02-04 01:19:41 +03:00
if ( ctrl = = - 1 ) {
2006-12-21 16:31:23 +03:00
ret = PAM_SYSTEM_ERR ;
goto out ;
2006-02-04 01:19:41 +03:00
}
2007-01-25 04:56:34 +03:00
_PAM_LOG_FUNCTION_ENTER ( " pam_sm_setcred " , pamh , ctrl , flags ) ;
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 :
2006-12-21 16:31:23 +03:00
ret = pam_sm_close_session ( pamh , flags , argc , argv ) ;
break ;
2006-12-18 18:33:57 +03:00
case PAM_REFRESH_CRED :
_pam_log_debug ( pamh , ctrl , LOG_WARNING , " 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 :
_pam_log_debug ( pamh , ctrl , LOG_WARNING , " 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 :
_pam_log_debug ( pamh , ctrl , LOG_WARNING , " 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 :
if ( d ) {
iniparser_freedict ( d ) ;
}
2007-01-25 04:56:34 +03:00
_PAM_LOG_FUNCTION_LEAVE ( " pam_sm_setcred " , pamh , ctrl , ret ) ;
2006-12-21 16:31:23 +03:00
return ret ;
2000-05-09 15:43:00 +04:00
}
/*
* Account management . We want to verify that the account exists
* 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 ;
2006-12-21 16:31:23 +03:00
dictionary * d = NULL ;
2006-02-04 01:19:41 +03:00
/* parse arguments */
2006-12-21 16:31:23 +03:00
int ctrl = _pam_parse ( pamh , flags , argc , argv , & d ) ;
2006-02-04 01:19:41 +03:00
if ( ctrl = = - 1 ) {
return PAM_SYSTEM_ERR ;
}
2006-01-13 14:11:23 +03:00
2007-01-25 04:56:34 +03:00
_PAM_LOG_FUNCTION_ENTER ( " pam_sm_acct_mgmt " , pamh , ctrl , flags ) ;
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 ) ) {
2006-09-13 20:39:52 +04:00
_pam_log_debug ( pamh , ctrl , LOG_DEBUG , " 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 */
2006-12-21 16:31:23 +03:00
ret = valid_user ( pamh , ctrl , username ) ;
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 */
2006-09-13 20:39:52 +04:00
_pam_log_debug ( pamh , ctrl , LOG_NOTICE , " user '%s' not found " , username ) ;
2006-02-04 01:19:41 +03:00
if ( 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 :
2006-02-04 01:19:41 +03:00
pam_get_data ( pamh , PAM_WINBIND_NEW_AUTHTOK_REQD , ( const void * * ) & tmp ) ;
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 :
2006-09-13 20:39:52 +04:00
_pam_log ( pamh , ctrl , LOG_WARNING , " pam_sm_acct_mgmt success but %s is set " ,
2006-02-04 01:19:41 +03:00
PAM_WINBIND_NEW_AUTHTOK_REQD ) ;
2006-09-13 20:39:52 +04:00
_pam_log ( pamh , ctrl , LOG_NOTICE , " 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 :
2006-09-13 20:39:52 +04:00
_pam_log ( pamh , ctrl , LOG_WARNING , " pam_sm_acct_mgmt success " ) ;
_pam_log ( pamh , ctrl , LOG_NOTICE , " 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 */
2006-09-13 20:39:52 +04:00
_pam_log ( pamh , ctrl , LOG_NOTICE , " 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 */
2006-12-21 16:31:23 +03:00
_pam_log ( pamh , ctrl , LOG_ERR , " internal module error (ret = %d, user = '%s') " ,
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 :
if ( d ) {
iniparser_freedict ( d ) ;
}
2007-01-25 04:56:34 +03:00
_PAM_LOG_FUNCTION_LEAVE ( " pam_sm_acct_mgmt " , pamh , ctrl , ret ) ;
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
{
2006-12-21 16:31:23 +03:00
int ret = PAM_SYSTEM_ERR ;
dictionary * d = NULL ;
2006-02-04 01:19:41 +03:00
/* parse arguments */
2006-12-21 16:31:23 +03:00
int ctrl = _pam_parse ( pamh , flags , argc , argv , & d ) ;
2006-02-04 01:19:41 +03:00
if ( ctrl = = - 1 ) {
2006-12-21 16:31:23 +03:00
ret = PAM_SYSTEM_ERR ;
goto out ;
2006-02-04 01:19:41 +03:00
}
2007-01-25 04:56:34 +03:00
_PAM_LOG_FUNCTION_ENTER ( " pam_sm_open_session " , pamh , ctrl , flags ) ;
2006-02-04 01:19:41 +03:00
2006-12-21 16:31:23 +03:00
ret = PAM_SUCCESS ;
out :
if ( d ) {
iniparser_freedict ( d ) ;
}
2007-01-25 04:56:34 +03:00
_PAM_LOG_FUNCTION_LEAVE ( " pam_sm_open_session " , pamh , ctrl , ret ) ;
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
{
2006-10-17 02:41:24 +04:00
dictionary * d = NULL ;
2006-04-11 19:11:27 +04:00
int retval = PAM_SUCCESS ;
2006-04-11 18:40:53 +04:00
2006-02-04 01:19:41 +03:00
/* parse arguments */
2006-09-13 20:39:52 +04:00
int ctrl = _pam_parse ( pamh , flags , argc , argv , & d ) ;
2006-02-04 01:19:41 +03:00
if ( ctrl = = - 1 ) {
2006-04-11 18:40:53 +04:00
retval = PAM_SYSTEM_ERR ;
goto out ;
2006-02-04 01:19:41 +03:00
}
2007-01-25 04:56:34 +03:00
_PAM_LOG_FUNCTION_ENTER ( " pam_sm_close_session " , pamh , ctrl , flags ) ;
2006-02-04 01:19:41 +03:00
if ( ! ( flags & PAM_DELETE_CRED ) ) {
2006-04-11 18:40:53 +04:00
retval = PAM_SUCCESS ;
goto out ;
2006-02-04 01:19:41 +03:00
}
if ( ctrl & WINBIND_KRB5_AUTH ) {
/* destroy the ccache here */
struct winbindd_request request ;
struct winbindd_response response ;
const char * user ;
const char * ccname = NULL ;
struct passwd * pwd = NULL ;
ZERO_STRUCT ( request ) ;
ZERO_STRUCT ( response ) ;
retval = pam_get_user ( pamh , & user , " Username: " ) ;
2007-02-02 16:03:06 +03:00
if ( retval ) {
_pam_log ( pamh , ctrl , LOG_ERR , " could not identify user " ) ;
2006-04-11 18:40:53 +04:00
goto out ;
2006-02-04 01:19:41 +03:00
}
2007-02-02 16:03:06 +03:00
if ( user = = NULL ) {
_pam_log ( pamh , ctrl , LOG_ERR , " username was NULL! " ) ;
retval = PAM_USER_UNKNOWN ;
goto out ;
}
_pam_log_debug ( pamh , ctrl , LOG_DEBUG , " username [%s] obtained " , user ) ;
2006-02-04 01:19:41 +03:00
ccname = pam_getenv ( pamh , " KRB5CCNAME " ) ;
if ( ccname = = NULL ) {
2006-09-13 20:39:52 +04:00
_pam_log_debug ( pamh , ctrl , LOG_DEBUG , " user has no KRB5CCNAME environment " ) ;
2006-02-04 01:19:41 +03:00
}
2006-04-11 18:40:53 +04:00
strncpy ( request . data . logoff . user , user ,
sizeof ( request . data . logoff . user ) - 1 ) ;
2006-09-06 14:59:39 +04:00
if ( ccname ) {
strncpy ( request . data . logoff . krb5ccname , ccname ,
sizeof ( request . data . logoff . krb5ccname ) - 1 ) ;
}
2006-02-04 01:19:41 +03:00
pwd = getpwnam ( user ) ;
if ( pwd = = NULL ) {
2006-04-11 18:40:53 +04:00
retval = PAM_USER_UNKNOWN ;
goto out ;
2006-02-04 01:19:41 +03:00
}
request . data . logoff . uid = pwd - > pw_uid ;
2006-08-23 02:53:08 +04:00
request . flags = WBFLAG_PAM_KRB5 | WBFLAG_PAM_CONTACT_TRUSTDOM ;
2006-02-04 01:19:41 +03:00
2006-04-11 18:40:53 +04:00
retval = pam_winbind_request_log ( pamh , ctrl , WINBINDD_PAM_LOGOFF , & request , & response , user ) ;
2006-02-04 01:19:41 +03:00
}
2006-04-11 18:40:53 +04:00
out :
if ( d ) {
iniparser_freedict ( d ) ;
}
2007-01-25 04:56:34 +03:00
_PAM_LOG_FUNCTION_LEAVE ( " pam_sm_close_session " , pamh , ctrl , retval ) ;
2006-04-11 18:40:53 +04:00
return retval ;
2002-04-04 01:39:01 +04:00
}
2007-02-22 16:35:01 +03:00
/**
* evaluate whether we need to re - authenticate with kerberos after a password change
*
* @ param pamh PAM handle
* @ param ctrl PAM winbind options .
* @ param user The username
*
* @ return boolean Returns True if required , False if not .
*/
static BOOL _pam_require_krb5_auth_after_chauthtok ( pam_handle_t * pamh , int ctrl , const char * user )
{
/* 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 itself
*/
char * new_authtok_reqd_during_auth = NULL ;
struct passwd * pwd = NULL ;
if ( ! ( ctrl & WINBIND_KRB5_AUTH ) ) {
return False ;
}
_pam_get_data ( pamh , PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH , & new_authtok_reqd_during_auth ) ;
pam_set_data ( pamh , PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH , NULL , NULL ) ;
if ( new_authtok_reqd_during_auth ) {
return True ;
}
pwd = getpwnam ( user ) ;
if ( ! pwd ) {
return False ;
}
if ( getuid ( ) = = pwd - > pw_uid ) {
return True ;
}
return False ;
}
2000-05-09 15:43:00 +04:00
2006-02-04 01:19:41 +03:00
PAM_EXTERN
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 ;
2006-02-04 01:19:41 +03:00
unsigned int ctrl ;
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 ;
2002-02-05 12:40:36 +03:00
int retry = 0 ;
2006-10-17 02:41:24 +04:00
dictionary * d = NULL ;
2007-02-05 20:35:25 +03:00
char * username_ret = NULL ;
struct winbindd_response response ;
ZERO_STRUCT ( response ) ;
2002-02-05 12:40:36 +03:00
2006-09-13 20:39:52 +04:00
ctrl = _pam_parse ( pamh , flags , argc , argv , & d ) ;
2006-02-04 01:19:41 +03:00
if ( ctrl = = - 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-04 01:19:41 +03:00
}
2007-01-25 04:56:34 +03:00
_PAM_LOG_FUNCTION_ENTER ( " pam_sm_chauthtok " , pamh , ctrl , flags ) ;
2006-02-04 01:19:41 +03:00
2006-05-03 19:19:31 +04:00
/* clearing offline bit for the auth in the password change */
ctrl & = ~ WINBIND_CACHED_LOGIN ;
2002-02-05 12:40:36 +03:00
/*
* First get the name of a user
*/
2006-12-15 09:06:15 +03:00
ret = pam_get_user ( pamh , & user , " Username: " ) ;
2007-02-02 16:03:06 +03:00
if ( ret ) {
_pam_log ( pamh , ctrl , 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 ) {
_pam_log ( pamh , ctrl , LOG_ERR , " username was NULL! " ) ;
ret = PAM_USER_UNKNOWN ;
goto out ;
}
_pam_log_debug ( pamh , ctrl , LOG_DEBUG , " username [%s] obtained " , user ) ;
2006-02-13 18:12:22 +03:00
/* check if this is really a user in winbindd, not only in NSS */
2006-12-15 09:06:15 +03:00
ret = valid_user ( pamh , ctrl , user ) ;
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 ;
}
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 ;
2002-02-05 12:40:36 +03:00
/* instruct user what is happening */
# define greeting "Changing password for "
2006-04-11 18:40:53 +04:00
Announce = ( char * ) malloc ( sizeof ( greeting ) + strlen ( user ) ) ;
if ( Announce = = NULL ) {
2006-09-13 20:39:52 +04:00
_pam_log ( pamh , ctrl , LOG_CRIT , " 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 ;
}
( void ) strcpy ( Announce , greeting ) ;
( void ) strcpy ( Announce + sizeof ( greeting ) - 1 , user ) ;
2002-02-05 12:40:36 +03:00
# undef greeting
lctrl = ctrl | WINBIND__OLD_PASSWORD ;
2006-12-15 09:06:15 +03:00
ret = _winbind_read_password ( pamh , lctrl ,
2006-02-04 01:19:41 +03:00
Announce ,
" (current) NT password: " ,
NULL ,
( const char * * ) & pass_old ) ;
2006-12-15 09:06:15 +03:00
if ( ret ! = PAM_SUCCESS ) {
2006-09-13 20:39:52 +04:00
_pam_log ( pamh , ctrl , LOG_NOTICE , " 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 */
2006-12-15 09:06:15 +03:00
ret = winbind_auth_request ( pamh , ctrl , user , pass_old ,
NULL , NULL , & response , & pwdlastset_prelim , NULL ) ;
2006-02-04 01:19:41 +03:00
2006-12-15 09:06:15 +03:00
if ( ret ! = PAM_ACCT_EXPIRED & &
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-10-17 03:06:48 +04:00
pam_set_data ( pamh , PAM_WINBIND_PWD_LAST_SET , ( void * ) pwdlastset_prelim , NULL ) ;
2006-05-02 23:22:39 +04:00
2006-12-15 09:06:15 +03:00
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 ) {
2006-09-13 20:39:52 +04:00
_pam_log ( pamh , ctrl , LOG_CRIT , " failed to set PAM_OLDAUTHTOK " ) ;
2002-02-05 12:40:36 +03:00
}
} else if ( flags & PAM_UPDATE_AUTHTOK ) {
2006-05-02 23:22:39 +04:00
time_t pwdlastset_update = 0 ;
2002-02-05 12:40:36 +03:00
/*
* obtain the proposed password
*/
/*
* get the old token back .
*/
2006-12-15 09:06:15 +03:00
ret = _pam_get_item ( pamh , PAM_OLDAUTHTOK , & pass_old ) ;
2002-02-05 12:40:36 +03:00
2006-12-15 09:06:15 +03:00
if ( ret ! = PAM_SUCCESS ) {
2006-09-13 20:39:52 +04:00
_pam_log ( pamh , ctrl , LOG_NOTICE , " user not authenticated " ) ;
2006-04-11 18:40:53 +04:00
goto out ;
2002-02-05 12:40:36 +03:00
}
2007-01-25 05:24:56 +03:00
lctrl = ctrl & ~ WINBIND_TRY_FIRST_PASS_ARG ;
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
*/
2006-12-15 09:06:15 +03:00
ret = _winbind_read_password ( pamh , lctrl ,
2006-02-04 01:19:41 +03:00
NULL ,
" Enter new NT password: " ,
" Retype new NT password: " ,
( const char * * ) & pass_new ) ;
2002-02-05 12:40:36 +03:00
2006-12-15 09:06:15 +03:00
if ( ret ! = PAM_SUCCESS ) {
2006-09-13 20:39:52 +04:00
_pam_log_debug ( pamh , ctrl , LOG_ALERT
2006-02-04 01:19:41 +03: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 .
*/
if ( pass_new [ 0 ] = = ' \0 ' ) { /* "\0" password = NULL */
pass_new = NULL ;
}
}
/*
* By reaching here we have approved the passwords and must now
* rebuild the password database file .
*/
2006-07-11 22:01:26 +04:00
_pam_get_data ( pamh , PAM_WINBIND_PWD_LAST_SET ,
& pwdlastset_update ) ;
2002-02-05 12:40:36 +03:00
2006-12-15 09:06:15 +03:00
ret = winbind_chauthtok_request ( pamh , ctrl , user , pass_old , pass_new , pwdlastset_update ) ;
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
}
2007-02-22 16:35:01 +03:00
if ( _pam_require_krb5_auth_after_chauthtok ( pamh , ctrl , user ) ) {
2006-02-04 01:19:41 +03:00
2006-09-13 20:39:52 +04:00
const char * member = get_member_from_config ( pamh , argc , argv , ctrl , d ) ;
const char * cctype = get_krb5_cc_type_from_config ( pamh , argc , argv , ctrl , d ) ;
2006-02-04 01:19:41 +03:00
2006-12-15 09:06:15 +03:00
ret = winbind_auth_request ( pamh , ctrl , user , pass_new ,
2007-02-05 20:35:25 +03:00
member , cctype , & response , 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-02-05 21:04:28 +03:00
/* warn a user if the password is about to expire soon */
_pam_warn_password_expiry ( pamh , ctrl , & response , NULL ) ;
2007-02-05 20:35:25 +03:00
/* set some info3 info for other modules in the stack */
_pam_set_data_info3 ( pamh , ctrl , & response ) ;
/* put krb5ccname into env */
_pam_setup_krb5_env ( pamh , ctrl , response . data . auth . krb5ccname ) ;
if ( username_ret ) {
pam_set_item ( pamh , PAM_USER , username_ret ) ;
_pam_log_debug ( pamh , ctrl , LOG_INFO , " Returned user was '%s' " , username_ret ) ;
free ( username_ret ) ;
}
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 :
if ( d ) {
iniparser_freedict ( d ) ;
}
2007-01-25 04:56:34 +03:00
2007-02-05 20:35:25 +03:00
/* Deal with offline errors. */
PAM_WB_REMARK_CHECK_RESPONSE ( pamh , ctrl , response , " NT_STATUS_NO_LOGON_SERVERS " ) ;
PAM_WB_REMARK_CHECK_RESPONSE ( pamh , ctrl , response , " NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND " ) ;
PAM_WB_REMARK_CHECK_RESPONSE ( pamh , ctrl , response , " NT_STATUS_ACCESS_DENIED " ) ;
2007-01-25 04:56:34 +03:00
_PAM_LOG_FUNCTION_LEAVE ( " pam_sm_chauthtok " , pamh , ctrl , ret ) ;
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
2007-01-10 15:34:24 +03:00
* Copyright ( c ) Guenther Deschner < gd @ samba . org > 2005 - 2007
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.
* 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 .
*/