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
2000-05-09 15:43:00 +04:00
largely based on pam_userdb by Christian 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
2002-02-05 12:40:36 +03:00
/* data tokens */
# define MAX_PASSWD_TRIES 3
2000-05-09 15:43:00 +04:00
/* some syslogging */
static void _pam_log ( int err , const char * format , . . . )
{
va_list args ;
va_start ( args , format ) ;
openlog ( MODULE_NAME , LOG_CONS | LOG_PID , LOG_AUTH ) ;
vsyslog ( err , format , args ) ;
va_end ( args ) ;
closelog ( ) ;
}
static int _pam_parse ( int argc , const char * * argv )
{
2002-02-05 12:40:36 +03:00
int ctrl ;
/* step through arguments */
for ( ctrl = 0 ; argc - - > 0 ; + + argv ) {
/* generic options */
if ( ! strcmp ( * argv , " debug " ) )
ctrl | = WINBIND_DEBUG_ARG ;
else if ( ! strcasecmp ( * argv , " use_authtok " ) )
ctrl | = WINBIND_USE_AUTHTOK_ARG ;
else if ( ! strcasecmp ( * argv , " use_first_pass " ) )
ctrl | = WINBIND_USE_FIRST_PASS_ARG ;
2002-03-23 11:28:19 +03:00
else if ( ! strcasecmp ( * argv , " try_first_pass " ) )
ctrl | = WINBIND_TRY_FIRST_PASS_ARG ;
2002-02-05 12:40:36 +03:00
else if ( ! strcasecmp ( * argv , " unknown_ok " ) )
ctrl | = WINBIND_UNKNOWN_OK_ARG ;
else {
_pam_log ( LOG_ERR , " pam_parse: unknown option; %s " , * argv ) ;
}
}
return ctrl ;
}
/* --- 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 )
{
int retval ;
struct pam_conv * conv ;
retval = pam_get_item ( pamh , PAM_CONV , ( const void * * ) & conv ) ;
if ( retval = = PAM_SUCCESS ) {
retval = conv - > conv ( nargs , ( const struct pam_message * * ) message ,
response , conv - > appdata_ptr ) ;
}
return retval ; /* propagate error status */
}
2002-08-17 21:00:51 +04:00
static int _make_remark ( pam_handle_t * pamh , 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 ;
pmsg [ 0 ] = & msg [ 0 ] ;
msg [ 0 ] . msg = text ;
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
}
2002-09-25 19:19:00 +04:00
static int pam_winbind_request ( enum winbindd_cmd req_type ,
struct winbindd_request * request ,
struct winbindd_response * response )
2000-05-09 15:43:00 +04:00
{
2002-09-25 19:19:00 +04:00
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
2001-05-04 04:43:20 +04:00
if ( write_sock ( request , sizeof ( * request ) ) = = - 1 ) {
2002-02-05 12:40:36 +03:00
_pam_log ( LOG_ERR , " 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 ) {
2002-02-05 12:40:36 +03:00
_pam_log ( LOG_ERR , " 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 */
2001-05-04 04:43:20 +04:00
if ( response - > result ! = WINBINDD_OK ) {
2002-02-05 12:40:36 +03:00
if ( response - > data . auth . pam_error ! = PAM_SUCCESS ) {
2003-01-15 21:57:41 +03:00
_pam_log ( LOG_ERR , " request failed: %s, PAM error was %d, NT error was %s " ,
response - > data . auth . error_string ,
2002-02-05 12:40:36 +03:00
response - > data . auth . pam_error ,
response - > data . auth . nt_status_string ) ;
return response - > data . auth . pam_error ;
} else {
_pam_log ( LOG_ERR , " request failed, but PAM error 0! " ) ;
return PAM_SERVICE_ERR ;
}
2000-05-09 15:43:00 +04:00
}
2002-02-05 12:40:36 +03:00
return PAM_SUCCESS ;
2000-05-09 15:43:00 +04:00
}
2002-10-26 06:20:59 +04:00
static int pam_winbind_request_log ( enum winbindd_cmd req_type ,
struct winbindd_request * request ,
struct winbindd_response * response ,
int ctrl ,
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
2002-10-26 06:20:59 +04:00
retval = pam_winbind_request ( req_type , request , response ) ;
2002-02-05 12:40:36 +03:00
switch ( retval ) {
case PAM_AUTH_ERR :
/* incorrect password */
_pam_log ( LOG_WARNING , " user `%s' denied access (incorrect password) " , user ) ;
return retval ;
2002-07-15 14:35:28 +04:00
case PAM_ACCT_EXPIRED :
/* account expired */
_pam_log ( LOG_WARNING , " user `%s' account expired " , user ) ;
return retval ;
case PAM_AUTHTOK_EXPIRED :
/* password expired */
_pam_log ( LOG_WARNING , " user `%s' password expired " , user ) ;
return retval ;
2002-08-17 21:00:51 +04:00
case PAM_NEW_AUTHTOK_REQD :
/* password expired */
_pam_log ( LOG_WARNING , " user `%s' new password required " , user ) ;
return retval ;
2002-02-05 12:40:36 +03:00
case PAM_USER_UNKNOWN :
/* the user does not exist */
if ( ctrl & WINBIND_DEBUG_ARG )
_pam_log ( LOG_NOTICE , " user `%s' not found " ,
user ) ;
if ( ctrl & WINBIND_UNKNOWN_OK_ARG ) {
return PAM_IGNORE ;
}
return retval ;
case PAM_SUCCESS :
2002-10-26 06:20:59 +04:00
if ( req_type = = WINBINDD_PAM_AUTH ) {
/* Otherwise, the authentication looked good */
_pam_log ( LOG_NOTICE , " user '%s' granted acces " , user ) ;
} else if ( req_type = = WINBINDD_PAM_CHAUTHTOK ) {
/* Otherwise, the authentication looked good */
_pam_log ( LOG_NOTICE , " user '%s' password changed " , user ) ;
} else {
/* Otherwise, the authentication looked good */
_pam_log ( LOG_NOTICE , " user '%s' OK " , user ) ;
}
2002-02-05 12:40:36 +03:00
return retval ;
default :
/* we don't know anything about this return value */
_pam_log ( LOG_ERR , " internal module error (retval = %d, user = `%s' " ,
retval , user ) ;
return retval ;
}
2002-10-26 06:20:59 +04:00
}
/* talk to winbindd */
static int winbind_auth_request ( const char * user , const char * pass , int ctrl )
{
struct winbindd_request request ;
struct winbindd_response response ;
ZERO_STRUCT ( request ) ;
strncpy ( request . data . auth . user , user ,
sizeof ( request . data . auth . user ) - 1 ) ;
strncpy ( request . data . auth . pass , pass ,
sizeof ( request . data . auth . pass ) - 1 ) ;
return pam_winbind_request_log ( WINBINDD_PAM_AUTH , & request , & response , ctrl , user ) ;
2001-05-04 04:43:20 +04:00
}
/* talk to winbindd */
static int winbind_chauthtok_request ( const char * user , const char * oldpass ,
2002-10-26 06:20:59 +04:00
const char * newpass , int ctrl )
2001-05-04 04:43:20 +04:00
{
struct winbindd_request request ;
struct winbindd_response response ;
ZERO_STRUCT ( request ) ;
if ( request . data . chauthtok . user = = NULL ) return - 2 ;
strncpy ( request . data . chauthtok . user , user ,
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 ' ;
}
if ( newpass ! = NULL ) {
strncpy ( request . data . chauthtok . newpass , newpass ,
sizeof ( request . data . chauthtok . newpass ) - 1 ) ;
} else {
request . data . chauthtok . newpass [ 0 ] = ' \0 ' ;
}
2002-10-26 06:20:59 +04:00
return pam_winbind_request_log ( WINBINDD_PAM_CHAUTHTOK , & request , & response , ctrl , user ) ;
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
*/
static int valid_user ( const char * user )
{
if ( getpwnam ( user ) ) return 0 ;
return 1 ;
}
static char * _pam_delete ( register char * xx )
{
_pam_overwrite ( xx ) ;
_pam_drop ( xx ) ;
return NULL ;
}
/*
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
2002-08-17 21:00:51 +04: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 ;
/*
* 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 ) ) {
retval = pam_get_item ( pamh , authtok_flag , ( const void * * ) & item ) ;
if ( retval ! = PAM_SUCCESS ) {
/* very strange. */
_pam_log ( LOG_ALERT ,
" pam_get_item returned error to unix-read-password "
) ;
return retval ;
} else if ( item ! = NULL ) { /* we have a password! */
* pass = item ;
item = NULL ;
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 */
if ( comment ! = NULL ) {
pmsg [ 0 ] = & msg [ 0 ] ;
msg [ 0 ] . msg_style = PAM_TEXT_INFO ;
msg [ 0 ] . msg = comment ;
i = 1 ;
} else {
i = 0 ;
}
pmsg [ i ] = & msg [ i ] ;
msg [ i ] . msg_style = PAM_PROMPT_ECHO_OFF ;
msg [ i + + ] . msg = prompt1 ;
replies = 1 ;
if ( prompt2 ! = NULL ) {
pmsg [ i ] = & msg [ i ] ;
msg [ i ] . msg_style = PAM_PROMPT_ECHO_OFF ;
msg [ i + + ] . msg = prompt2 ;
+ + 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 */
token = x_strdup ( resp [ i - replies ] . resp ) ;
if ( token ! = NULL ) {
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 ;
_make_remark ( pamh , PAM_ERROR_MSG , MISTYPED_PASS ) ;
}
}
} else {
_pam_log ( LOG_NOTICE
, " could not recover authentication token " ) ;
}
}
/*
* 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 ) {
if ( on ( WINBIND_DEBUG_ARG , ctrl ) )
_pam_log ( LOG_DEBUG ,
" 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 */
if ( retval ! = PAM_SUCCESS
| | ( retval = pam_get_item ( pamh , authtok_flag
, ( const void * * ) & item ) )
! = PAM_SUCCESS ) {
_pam_log ( LOG_CRIT , " error manipulating password " ) ;
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
}
PAM_EXTERN
int pam_sm_authenticate ( pam_handle_t * pamh , int flags ,
int argc , const char * * argv )
{
const char * username ;
const char * password ;
int retval = PAM_AUTH_ERR ;
/* parse arguments */
2002-02-05 12:40:36 +03:00
int ctrl = _pam_parse ( argc , argv ) ;
2000-05-09 15:43:00 +04:00
/* Get the username */
retval = pam_get_user ( pamh , & username , NULL ) ;
if ( ( retval ! = PAM_SUCCESS ) | | ( ! username ) ) {
2002-02-05 12:40:36 +03:00
if ( ctrl & WINBIND_DEBUG_ARG )
2000-05-09 15:43:00 +04:00
_pam_log ( LOG_DEBUG , " can not get the username " ) ;
return PAM_SERVICE_ERR ;
}
2002-02-05 12:40:36 +03:00
retval = _winbind_read_password ( pamh , ctrl , NULL ,
" Password: " , NULL ,
& password ) ;
2000-05-09 15:43:00 +04:00
if ( retval ! = PAM_SUCCESS ) {
2002-03-23 11:28:19 +03:00
_pam_log ( LOG_ERR , " Could not retrieve user's password " ) ;
2000-05-09 15:43:00 +04:00
return PAM_AUTHTOK_ERR ;
}
2002-02-05 12:40:36 +03:00
if ( ctrl & WINBIND_DEBUG_ARG ) {
2002-01-07 05:57:06 +03:00
/* Let's not give too much away in the log file */
# ifdef DEBUG_PASSWORD
2000-05-09 15:43:00 +04:00
_pam_log ( LOG_INFO , " Verify user `%s' with password `%s' " ,
username , password ) ;
2002-01-07 05:57:06 +03:00
# else
_pam_log ( LOG_INFO , " Verify user `%s' " , username ) ;
# endif
}
2000-05-09 15:43:00 +04:00
/* Now use the username to look up password */
2002-02-05 12:40:36 +03:00
return winbind_auth_request ( username , password , ctrl ) ;
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 )
{
return PAM_SUCCESS ;
}
/*
* 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 )
{
const char * username ;
int retval = PAM_USER_UNKNOWN ;
/* parse arguments */
2002-02-05 12:40:36 +03:00
int ctrl = _pam_parse ( argc , argv ) ;
2000-05-09 15:43:00 +04:00
/* Get the username */
retval = pam_get_user ( pamh , & username , NULL ) ;
if ( ( retval ! = PAM_SUCCESS ) | | ( ! username ) ) {
2002-02-05 12:40:36 +03:00
if ( ctrl & WINBIND_DEBUG_ARG )
2000-05-09 15:43:00 +04:00
_pam_log ( LOG_DEBUG , " can not get the username " ) ;
return PAM_SERVICE_ERR ;
}
/* Verify the username */
retval = valid_user ( username ) ;
switch ( retval ) {
case - 1 :
/* some sort of system error. The log was already printed */
return PAM_SERVICE_ERR ;
case 1 :
/* the user does not exist */
2002-02-05 12:40:36 +03:00
if ( ctrl & WINBIND_DEBUG_ARG )
2000-05-09 15:43:00 +04:00
_pam_log ( LOG_NOTICE , " user `%s' not found " ,
username ) ;
2002-02-05 12:40:36 +03:00
if ( ctrl & WINBIND_UNKNOWN_OK_ARG )
2000-05-09 15:43:00 +04:00
return PAM_IGNORE ;
return PAM_USER_UNKNOWN ;
case 0 :
/* Otherwise, the authentication looked good */
_pam_log ( LOG_NOTICE , " user '%s' granted acces " , username ) ;
return PAM_SUCCESS ;
default :
/* we don't know anything about this return value */
_pam_log ( LOG_ERR , " internal module error (retval = %d, user = `%s' " ,
retval , username ) ;
return PAM_SERVICE_ERR ;
}
/* should not be reached */
return PAM_IGNORE ;
}
2002-04-04 01:39:01 +04:00
PAM_EXTERN
int pam_sm_open_session ( pam_handle_t * pamh , int flags ,
int argc , const char * * argv )
{
/* parse arguments */
int ctrl = _pam_parse ( argc , argv ) ;
if ( ctrl & WINBIND_DEBUG_ARG )
_pam_log ( LOG_DEBUG , " libpam_winbind:pam_sm_open_session handler " ) ;
return PAM_SUCCESS ;
}
PAM_EXTERN
int pam_sm_close_session ( pam_handle_t * pamh , int flags ,
int argc , const char * * argv )
{
/* parse arguments */
int ctrl = _pam_parse ( argc , argv ) ;
if ( ctrl & WINBIND_DEBUG_ARG )
_pam_log ( LOG_DEBUG , " libpam_winbind:pam_sm_close_session handler " ) ;
return PAM_SUCCESS ;
}
2000-05-09 15:43:00 +04:00
2002-02-05 12:40:36 +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 ;
int retval ;
unsigned int ctrl = _pam_parse ( argc , argv ) ;
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
2002-02-05 12:40:36 +03:00
char * Announce ;
int retry = 0 ;
/*
* First get the name of a user
*/
retval = pam_get_user ( pamh , & user , " Username: " ) ;
if ( retval = = PAM_SUCCESS ) {
if ( user = = NULL ) {
_pam_log ( LOG_ERR , " username was NULL! " ) ;
return PAM_USER_UNKNOWN ;
}
if ( retval = = PAM_SUCCESS & & on ( WINBIND_DEBUG_ARG , ctrl ) )
_pam_log ( LOG_DEBUG , " username [%s] obtained " ,
user ) ;
} else {
if ( on ( WINBIND_DEBUG_ARG , ctrl ) )
_pam_log ( LOG_DEBUG ,
" password - could not identify user " ) ;
return retval ;
}
2001-05-04 04:43: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 ) {
/* instruct user what is happening */
# define greeting "Changing password for "
Announce = ( char * ) malloc ( sizeof ( greeting ) + strlen ( user ) ) ;
if ( Announce = = NULL ) {
_pam_log ( LOG_CRIT ,
" password - out of memory " ) ;
return PAM_BUF_ERR ;
}
( void ) strcpy ( Announce , greeting ) ;
( void ) strcpy ( Announce + sizeof ( greeting ) - 1 , user ) ;
# undef greeting
lctrl = ctrl | WINBIND__OLD_PASSWORD ;
retval = _winbind_read_password ( pamh , lctrl
, Announce
, " (current) NT password: "
, NULL
, ( const char * * ) & pass_old ) ;
free ( Announce ) ;
if ( retval ! = PAM_SUCCESS ) {
_pam_log ( LOG_NOTICE
, " password - (old) token not obtained " ) ;
return retval ;
}
/* verify that this is the password for this user */
retval = winbind_auth_request ( user , pass_old , ctrl ) ;
if ( retval ! = PAM_ACCT_EXPIRED
2002-07-15 14:35:28 +04:00
& & retval ! = PAM_AUTHTOK_EXPIRED
2002-02-05 12:40:36 +03:00
& & retval ! = PAM_NEW_AUTHTOK_REQD
& & retval ! = PAM_SUCCESS ) {
pass_old = NULL ;
return retval ;
}
retval = pam_set_item ( pamh , PAM_OLDAUTHTOK , ( const void * ) pass_old ) ;
pass_old = NULL ;
if ( retval ! = PAM_SUCCESS ) {
_pam_log ( LOG_CRIT ,
" failed to set PAM_OLDAUTHTOK " ) ;
}
} else if ( flags & PAM_UPDATE_AUTHTOK ) {
/*
* obtain the proposed password
*/
/*
* get the old token back .
*/
retval = pam_get_item ( pamh , PAM_OLDAUTHTOK
, ( const void * * ) & pass_old ) ;
if ( retval ! = PAM_SUCCESS ) {
_pam_log ( LOG_NOTICE , " user not authenticated " ) ;
return retval ;
}
lctrl = ctrl ;
if ( on ( WINBIND_USE_AUTHTOK_ARG , lctrl ) ) {
ctrl = WINBIND_USE_FIRST_PASS_ARG | lctrl ;
}
retry = 0 ;
retval = PAM_AUTHTOK_ERR ;
while ( ( retval ! = PAM_SUCCESS ) & & ( retry + + < MAX_PASSWD_TRIES ) ) {
/*
* use_authtok is to force the use of a previously entered
* password - - needed for pluggable password strength checking
*/
retval = _winbind_read_password ( pamh , lctrl
, NULL
, " Enter new NT password: "
, " Retype new NT password: "
, ( const char * * ) & pass_new ) ;
if ( retval ! = PAM_SUCCESS ) {
if ( on ( WINBIND_DEBUG_ARG , ctrl ) ) {
_pam_log ( LOG_ALERT
, " password - new password not obtained " ) ;
}
pass_old = NULL ; /* tidy up */
return retval ;
}
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 .
*/
2002-10-26 06:20:59 +04:00
retval = winbind_chauthtok_request ( user , pass_old , pass_new , ctrl ) ;
2002-02-05 12:40:36 +03:00
_pam_overwrite ( pass_new ) ;
_pam_overwrite ( pass_old ) ;
pass_old = pass_new = NULL ;
} else {
retval = PAM_SERVICE_ERR ;
}
return retval ;
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 = {
2000-05-09 15:43:00 +04:00
MODULE_NAME ,
pam_sm_authenticate ,
pam_sm_setcred ,
pam_sm_acct_mgmt ,
2002-04-04 01:39:01 +04:00
pam_sm_open_session ,
pam_sm_close_session ,
2001-05-04 04:43:20 +04:00
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
* Copyright ( c ) Jan R <EFBFBD> korajski 1999.
* 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 .
*/