2003-04-08 04:42:44 +00:00
/*
Unix SMB / CIFS implementation .
Use PAM to update user passwords in the local SAM
Copyright ( C ) Steve Langasek 1998 - 2003
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-07-09 19:25:36 +00:00
the Free Software Foundation ; either version 3 of the License , or
2003-04-08 04:42:44 +00:00
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
2007-07-10 00:52:41 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2003-04-08 04:42:44 +00:00
2001-04-24 20:00:12 +00:00
*/
/* indicate the following groups are defined */
# define PAM_SM_PASSWORD
# include "includes.h"
2003-04-08 04:42:44 +00:00
/* This is only used in the Sun implementation. FIXME: we really
want a define here that distinguishes between the Solaris PAM
and others ( including FreeBSD ) . */
2001-04-24 20:00:12 +00:00
2003-04-08 04:42:44 +00:00
# ifndef LINUX
2007-05-23 20:31:28 +00:00
# if defined(HAVE_SECURITY_PAM_APPL_H)
2001-04-24 20:00:12 +00:00
# include <security/pam_appl.h>
2007-05-23 20:31:28 +00:00
# elif defined(HAVE_PAM_PAM_APPL_H)
# include <pam/pam_appl.h>
# endif
2003-04-08 04:42:44 +00:00
# endif
2001-04-24 20:00:12 +00:00
2007-05-23 20:31:28 +00:00
# if defined(HAVE_SECURITY_PAM_MODULES_H)
2001-04-24 20:00:12 +00:00
# include <security/pam_modules.h>
2007-05-23 20:31:28 +00:00
# elif defined(HAVE_PAM_PAM_MODULES_H)
# include <pam/pam_modules.h>
# endif
2001-04-24 20:00:12 +00:00
# include "general.h"
# include "support.h"
2002-01-12 23:12:13 +00:00
int smb_update_db ( pam_handle_t * pamh , int ctrl , const char * user , const char * pass_new )
2001-04-24 20:00:12 +00:00
{
2003-04-08 04:42:44 +00:00
int retval ;
2007-11-21 17:42:52 -08:00
char * err_str = NULL ;
char * msg_str = NULL ;
2003-04-08 04:42:44 +00:00
2007-11-21 17:42:52 -08:00
retval = NT_STATUS_IS_OK ( local_password_change ( user , LOCAL_SET_PASSWORD , pass_new ,
& err_str ,
& msg_str ) ) ;
2003-04-08 04:42:44 +00:00
if ( ! retval ) {
2007-11-21 17:42:52 -08:00
if ( err_str ) {
make_remark ( pamh , ctrl , PAM_ERROR_MSG , err_str ) ;
2003-04-08 04:42:44 +00:00
}
/* FIXME: what value is appropriate here? */
retval = PAM_AUTHTOK_ERR ;
} else {
2007-11-21 17:42:52 -08:00
if ( msg_str ) {
make_remark ( pamh , ctrl , PAM_TEXT_INFO , msg_str ) ;
2003-04-08 04:42:44 +00:00
}
retval = PAM_SUCCESS ;
}
2001-04-24 20:00:12 +00:00
2007-11-21 17:42:52 -08:00
SAFE_FREE ( err_str ) ;
SAFE_FREE ( msg_str ) ;
2003-04-08 04:42:44 +00:00
return retval ;
2001-04-24 20:00:12 +00:00
}
/* data tokens */
# define _SMB_OLD_AUTHTOK "-SMB-OLD-PASS"
# define _SMB_NEW_AUTHTOK "-SMB-NEW-PASS"
/*
* FUNCTION : pam_sm_chauthtok ( )
*
* This function is called twice by the PAM library , once with
* PAM_PRELIM_CHECK set , and then again with PAM_UPDATE_AUTHTOK set . With
* Linux - PAM , these two passes generally involve first checking the old
* token and then changing the token . This is what we do here .
*
* Having obtained a new password . The function updates the
* SMB_PASSWD_FILE file ( normally , $ ( LIBDIR ) / smbpasswd ) .
*/
int pam_sm_chauthtok ( pam_handle_t * pamh , int flags ,
int argc , const char * * argv )
{
unsigned int ctrl ;
int retval ;
2006-02-20 20:09:36 +00:00
struct samu * sampass = NULL ;
2003-04-08 04:42:44 +00:00
void ( * oldsig_handler ) ( int ) ;
2001-04-24 20:00:12 +00:00
const char * user ;
2002-07-15 10:35:28 +00:00
char * pass_old ;
char * pass_new ;
2001-04-24 20:00:12 +00:00
/* Samba initialization. */
2006-03-20 10:18:23 +00:00
load_case_tables ( ) ;
2008-03-06 10:41:42 -05:00
lp_set_in_client ( True ) ;
2001-04-24 20:00:12 +00:00
2009-05-26 15:40:21 +02:00
ctrl = set_ctrl ( pamh , flags , argc , argv ) ;
2001-04-24 20:00:12 +00:00
/*
* First get the name of a user . No need to do anything if we can ' t
* determine this .
*/
retval = pam_get_user ( pamh , & user , " Username: " ) ;
if ( retval ! = PAM_SUCCESS ) {
if ( on ( SMB_DEBUG , ctrl ) ) {
2009-05-26 15:40:21 +02:00
_log_err ( pamh , LOG_DEBUG , " password: could not identify user " ) ;
2001-04-24 20:00:12 +00:00
}
return retval ;
}
if ( on ( SMB_DEBUG , ctrl ) ) {
2009-05-26 15:40:21 +02:00
_log_err ( pamh , LOG_DEBUG , " username [%s] obtained " , user ) ;
2001-04-24 20:00:12 +00:00
}
2007-12-12 17:26:49 -08:00
if ( geteuid ( ) ! = 0 ) {
2009-05-26 15:40:21 +02:00
_log_err ( pamh , LOG_DEBUG , " Cannot access samba password database, not running as root. " ) ;
2007-12-12 17:26:49 -08:00
return PAM_AUTHINFO_UNAVAIL ;
}
2003-04-08 04:42:44 +00:00
/* Getting into places that might use LDAP -- protect the app
from a SIGPIPE it ' s not expecting */
oldsig_handler = CatchSignal ( SIGPIPE , SIGNAL_CAST SIG_IGN ) ;
2007-05-24 20:26:07 +00:00
if ( ! initialize_password_db ( False , NULL ) ) {
2009-05-26 15:40:21 +02:00
_log_err ( pamh , LOG_ALERT , " Cannot access samba password database " ) ;
2003-04-08 04:42:44 +00:00
CatchSignal ( SIGPIPE , SIGNAL_CAST oldsig_handler ) ;
2001-04-24 20:00:12 +00:00
return PAM_AUTHINFO_UNAVAIL ;
}
/* obtain user record */
2006-02-21 14:34:11 +00:00
if ( ! ( sampass = samu_new ( NULL ) ) ) {
2003-04-08 04:42:44 +00:00
CatchSignal ( SIGPIPE , SIGNAL_CAST oldsig_handler ) ;
2006-02-21 14:34:11 +00:00
return nt_status_to_pam ( NT_STATUS_NO_MEMORY ) ;
2002-09-25 15:19:00 +00:00
}
2001-04-24 20:00:12 +00:00
2002-09-25 15:19:00 +00:00
if ( ! pdb_getsampwnam ( sampass , user ) ) {
2009-05-26 15:40:21 +02:00
_log_err ( pamh , LOG_ALERT , " Failed to find entry for user %s. " , user ) ;
2003-04-08 04:42:44 +00:00
CatchSignal ( SIGPIPE , SIGNAL_CAST oldsig_handler ) ;
2001-04-24 20:00:12 +00:00
return PAM_USER_UNKNOWN ;
}
2006-03-20 10:18:23 +00:00
if ( on ( SMB_DEBUG , ctrl ) ) {
2009-05-26 15:40:21 +02:00
_log_err ( pamh , LOG_DEBUG , " Located account for %s " , user ) ;
2006-03-20 10:18:23 +00:00
}
2001-04-24 20:00:12 +00:00
if ( flags & PAM_PRELIM_CHECK ) {
/*
* obtain and verify the current password ( OLDAUTHTOK ) for
* the user .
*/
char * Announce ;
2002-01-12 23:12:13 +00:00
if ( _smb_blankpasswd ( ctrl , sampass ) ) {
2001-04-24 20:00:12 +00:00
2006-02-20 20:09:36 +00:00
TALLOC_FREE ( sampass ) ;
2003-04-08 04:42:44 +00:00
CatchSignal ( SIGPIPE , SIGNAL_CAST oldsig_handler ) ;
2001-04-24 20:00:12 +00:00
return PAM_SUCCESS ;
}
/* Password change by root, or for an expired token, doesn't
require authentication . Is this a good choice ? */
if ( getuid ( ) ! = 0 & & ! ( flags & PAM_CHANGE_EXPIRED_AUTHTOK ) ) {
/* tell user what is happening */
# define greeting "Changing password for "
2005-05-31 01:44:44 +00:00
Announce = SMB_MALLOC_ARRAY ( char , sizeof ( greeting ) + strlen ( user ) ) ;
2001-04-24 20:00:12 +00:00
if ( Announce = = NULL ) {
2009-05-26 15:40:21 +02:00
_log_err ( pamh , LOG_CRIT , " password: out of memory " ) ;
2006-02-20 20:09:36 +00:00
TALLOC_FREE ( sampass ) ;
2003-04-08 04:42:44 +00:00
CatchSignal ( SIGPIPE , SIGNAL_CAST oldsig_handler ) ;
2001-04-24 20:00:12 +00:00
return PAM_BUF_ERR ;
}
strncpy ( Announce , greeting , sizeof ( greeting ) ) ;
strncpy ( Announce + sizeof ( greeting ) - 1 , user , strlen ( user ) + 1 ) ;
# undef greeting
set ( SMB__OLD_PASSWD , ctrl ) ;
2002-01-12 23:12:13 +00:00
retval = _smb_read_password ( pamh , ctrl , Announce , " Current SMB password: " ,
NULL , _SMB_OLD_AUTHTOK , & pass_old ) ;
SAFE_FREE ( Announce ) ;
2001-04-24 20:00:12 +00:00
if ( retval ! = PAM_SUCCESS ) {
2009-05-26 15:40:21 +02:00
_log_err ( pamh , LOG_NOTICE ,
" password - (old) token not obtained " ) ;
2006-02-20 20:09:36 +00:00
TALLOC_FREE ( sampass ) ;
2003-04-08 04:42:44 +00:00
CatchSignal ( SIGPIPE , SIGNAL_CAST oldsig_handler ) ;
2001-04-24 20:00:12 +00:00
return retval ;
}
/* verify that this is the password for this user */
2002-01-12 23:12:13 +00:00
retval = _smb_verify_password ( pamh , sampass , pass_old , ctrl ) ;
2001-04-24 20:00:12 +00:00
} else {
pass_old = NULL ;
retval = PAM_SUCCESS ; /* root doesn't have to */
}
pass_old = NULL ;
2006-02-20 20:09:36 +00:00
TALLOC_FREE ( sampass ) ;
2003-04-08 04:42:44 +00:00
CatchSignal ( SIGPIPE , SIGNAL_CAST oldsig_handler ) ;
2001-04-24 20:00:12 +00:00
return retval ;
} else if ( flags & PAM_UPDATE_AUTHTOK ) {
/*
* obtain the proposed password
*/
/*
* get the old token back . NULL was ok only if root [ at this
* point we assume that this has already been enforced on a
* previous call to this function ] .
*/
if ( off ( SMB_NOT_SET_PASS , ctrl ) ) {
2009-05-22 17:56:37 +02:00
retval = _pam_get_item ( pamh , PAM_OLDAUTHTOK ,
& pass_old ) ;
2001-04-24 20:00:12 +00:00
} else {
2009-05-22 17:56:37 +02:00
retval = _pam_get_data ( pamh , _SMB_OLD_AUTHTOK ,
& pass_old ) ;
2001-04-24 20:00:12 +00:00
if ( retval = = PAM_NO_MODULE_DATA ) {
pass_old = NULL ;
retval = PAM_SUCCESS ;
}
}
if ( retval ! = PAM_SUCCESS ) {
2009-05-26 15:40:21 +02:00
_log_err ( pamh , LOG_NOTICE , " password: user not authenticated " ) ;
2006-02-20 20:09:36 +00:00
TALLOC_FREE ( sampass ) ;
2003-04-08 04:42:44 +00:00
CatchSignal ( SIGPIPE , SIGNAL_CAST oldsig_handler ) ;
2001-04-24 20:00:12 +00:00
return retval ;
}
/*
* use_authtok is to force the use of a previously entered
* password - - needed for pluggable password strength checking
* or other module stacking
*/
if ( on ( SMB_USE_AUTHTOK , ctrl ) ) {
set ( SMB_USE_FIRST_PASS , ctrl ) ;
}
retval = _smb_read_password ( pamh , ctrl
, NULL
, " Enter new SMB password: "
, " Retype new SMB password: "
, _SMB_NEW_AUTHTOK
, & pass_new ) ;
if ( retval ! = PAM_SUCCESS ) {
if ( on ( SMB_DEBUG , ctrl ) ) {
2009-05-26 15:40:21 +02:00
_log_err ( pamh , LOG_ALERT ,
" password: new password not obtained " ) ;
2001-04-24 20:00:12 +00:00
}
pass_old = NULL ; /* tidy up */
2006-02-20 20:09:36 +00:00
TALLOC_FREE ( sampass ) ;
2003-04-08 04:42:44 +00:00
CatchSignal ( SIGPIPE , SIGNAL_CAST oldsig_handler ) ;
2001-04-24 20:00:12 +00:00
return retval ;
}
/*
* 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 ;
}
retval = _pam_smb_approve_pass ( pamh , ctrl , pass_old , pass_new ) ;
if ( retval ! = PAM_SUCCESS ) {
2009-05-26 15:40:21 +02:00
_log_err ( pamh , LOG_NOTICE , " new password not acceptable " ) ;
2001-04-24 20:00:12 +00:00
pass_new = pass_old = NULL ; /* tidy up */
2006-02-20 20:09:36 +00:00
TALLOC_FREE ( sampass ) ;
2003-04-08 04:42:44 +00:00
CatchSignal ( SIGPIPE , SIGNAL_CAST oldsig_handler ) ;
2001-04-24 20:00:12 +00:00
return retval ;
}
/*
* By reaching here we have approved the passwords and must now
* rebuild the smb password file .
*/
/* update the password database */
retval = smb_update_db ( pamh , ctrl , user , pass_new ) ;
if ( retval = = PAM_SUCCESS ) {
2003-05-12 18:12:31 +00:00
uid_t uid ;
2001-04-24 20:00:12 +00:00
/* password updated */
2006-02-03 22:19:41 +00:00
if ( ! sid_to_uid ( pdb_get_user_sid ( sampass ) , & uid ) ) {
2009-05-26 15:40:21 +02:00
_log_err ( pamh , LOG_NOTICE ,
" Unable to get uid for user %s " ,
2003-05-12 18:12:31 +00:00
pdb_get_username ( sampass ) ) ;
2009-05-26 15:40:21 +02:00
_log_err ( pamh , LOG_NOTICE , " password for (%s) changed by (%s/%d) " ,
2003-05-12 18:12:31 +00:00
user , uidtoname ( getuid ( ) ) , getuid ( ) ) ;
} else {
2009-05-26 15:40:21 +02:00
_log_err ( pamh , LOG_NOTICE , " password for (%s/%d) changed by (%s/%d) " ,
2003-05-12 18:12:31 +00:00
user , uid , uidtoname ( getuid ( ) ) , getuid ( ) ) ;
}
} else {
2009-05-26 15:40:21 +02:00
_log_err ( pamh , LOG_ERR , " password change failed for user %s " , user ) ;
2003-05-12 18:12:31 +00:00
}
2001-04-24 20:00:12 +00:00
pass_old = pass_new = NULL ;
2002-01-12 23:12:13 +00:00
if ( sampass ) {
2006-02-20 20:09:36 +00:00
TALLOC_FREE ( sampass ) ;
2002-01-12 23:12:13 +00:00
sampass = NULL ;
}
2001-04-24 20:00:12 +00:00
} else { /* something has broken with the library */
2009-05-26 15:40:21 +02:00
_log_err ( pamh , LOG_ALERT , " password received unknown request " ) ;
2001-04-24 20:00:12 +00:00
retval = PAM_ABORT ;
}
2002-01-12 23:12:13 +00:00
if ( sampass ) {
2006-02-20 20:09:36 +00:00
TALLOC_FREE ( sampass ) ;
2002-01-12 23:12:13 +00:00
sampass = NULL ;
}
2001-04-24 20:00:12 +00:00
2006-02-20 20:09:36 +00:00
TALLOC_FREE ( sampass ) ;
2003-04-08 04:42:44 +00:00
CatchSignal ( SIGPIPE , SIGNAL_CAST oldsig_handler ) ;
2001-04-24 20:00:12 +00:00
return retval ;
}
/* static module data */
# ifdef PAM_STATIC
struct pam_module _pam_smbpass_passwd_modstruct = {
" pam_smbpass " ,
NULL ,
NULL ,
NULL ,
NULL ,
NULL ,
pam_sm_chauthtok
} ;
# endif