1997-07-08 20:54:44 +04:00
/*
Unix SMB / Netbios implementation .
Version 1.9 .
Samba utility functions
1998-01-22 16:27:43 +03:00
Copyright ( C ) Andrew Tridgell 1992 - 1998
1997-07-08 20:54:44 +04:00
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
the Free Software Foundation ; either version 2 of the License , or
( 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
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
1996-05-04 11:50:46 +04:00
/* fork a child process to exec passwd and write to its
2001-05-03 03:32:09 +04:00
* tty to change a users password . This is running as the
* user who is attempting to change the password .
*/
1996-05-04 11:50:46 +04:00
/*
* This code was copied / borrowed and stolen from various sources .
* The primary source was the poppasswd . c from the authors of POPMail . This software
* was included as a client to change passwords using the ' passwd ' program
* on the remote machine .
*
* This routine is called by set_user_password ( ) in password . c only if ALLOW_PASSWORD_CHANGE
* is defined in the compiler directives located in the Makefile .
*
* This code has been hacked by Bob Nance ( nance @ niehs . nih . gov ) and Evan Patterson
* ( patters2 @ niehs . nih . gov ) at the National Institute of Environmental Health Sciences
* and rights to modify , distribute or incorporate this change to the CAP suite or
* using it for any other reason are granted , so long as this disclaimer is left intact .
*/
/*
This code was hacked considerably for inclusion in Samba , primarily
by Andrew . Tridgell @ anu . edu . au . The biggest change was the addition
of the " password chat " option , which allows the easy runtime
specification of the expected sequence of events to change a
password .
*/
# include "includes.h"
2000-11-14 02:03:34 +03:00
extern struct passdb_ops pdb_ops ;
1996-05-04 11:50:46 +04:00
2001-09-10 15:23:41 +04:00
static BOOL check_oem_password ( char * user ,
uchar * lmdata , uchar * lmhash ,
uchar * ntdata , uchar * nthash ,
SAM_ACCOUNT * * hnd , char * new_passwd ,
int new_passwd_size ) ;
1998-07-29 07:08:05 +04:00
# if ALLOW_CHANGE_PASSWORD
1996-05-04 11:50:46 +04:00
static int findpty ( char * * slave )
{
2000-03-22 00:08:07 +03:00
int master ;
static fstring line ;
2000-04-18 06:09:50 +04:00
DIR * dirp ;
2000-03-22 00:08:07 +03:00
char * dpname ;
1998-07-29 07:08:05 +04:00
# if defined(HAVE_GRANTPT)
2000-03-22 00:08:07 +03:00
/* Try to open /dev/ptmx. If that fails, fall through to old method. */
if ( ( master = sys_open ( " /dev/ptmx " , O_RDWR , 0 ) ) > = 0 )
{
grantpt ( master ) ;
unlockpt ( master ) ;
* slave = ( char * ) ptsname ( master ) ;
if ( * slave = = NULL )
{
DEBUG ( 0 ,
( " findpty: Unable to create master/slave pty pair. \n " ) ) ;
/* Stop fd leak on error. */
close ( master ) ;
return - 1 ;
}
else
{
DEBUG ( 10 ,
( " findpty: Allocated slave pty %s \n " , * slave ) ) ;
return ( master ) ;
}
}
1999-12-13 16:27:58 +03:00
# endif /* HAVE_GRANTPT */
2000-03-22 00:08:07 +03:00
fstrcpy ( line , " /dev/ptyXX " ) ;
2000-04-18 06:09:50 +04:00
dirp = opendir ( " /dev " ) ;
2000-03-22 00:08:07 +03:00
if ( ! dirp )
return ( - 1 ) ;
2000-04-18 06:09:50 +04:00
while ( ( dpname = readdirname ( dirp ) ) ! = NULL )
2000-03-22 00:08:07 +03:00
{
if ( strncmp ( dpname , " pty " , 3 ) = = 0 & & strlen ( dpname ) = = 5 )
{
DEBUG ( 3 ,
( " pty: try to open %s, line was %s \n " , dpname ,
line ) ) ;
line [ 8 ] = dpname [ 3 ] ;
line [ 9 ] = dpname [ 4 ] ;
if ( ( master = sys_open ( line , O_RDWR , 0 ) ) > = 0 )
{
DEBUG ( 3 , ( " pty: opened %s \n " , line ) ) ;
line [ 5 ] = ' t ' ;
* slave = line ;
2000-04-18 06:09:50 +04:00
closedir ( dirp ) ;
2000-03-22 00:08:07 +03:00
return ( master ) ;
}
}
}
2000-04-18 06:09:50 +04:00
closedir ( dirp ) ;
2000-03-22 00:08:07 +03:00
return ( - 1 ) ;
1996-05-04 11:50:46 +04:00
}
2000-03-22 00:08:07 +03:00
static int dochild ( int master , char * slavedev , char * name ,
char * passwordprogram , BOOL as_root )
1996-05-04 11:50:46 +04:00
{
2000-03-22 00:08:07 +03:00
int slave ;
struct termios stermios ;
struct passwd * pass = Get_Pwnam ( name , True ) ;
gid_t gid ;
uid_t uid ;
if ( pass = = NULL )
{
DEBUG ( 0 ,
( " dochild: user name %s doesn't exist in the UNIX password database. \n " ,
name ) ) ;
return False ;
}
gid = pass - > pw_gid ;
uid = pass - > pw_uid ;
gain_root_privilege ( ) ;
/* Start new session - gets rid of controlling terminal. */
if ( setsid ( ) < 0 )
{
DEBUG ( 3 ,
( " Weirdness, couldn't let go of controlling terminal \n " ) ) ;
return ( False ) ;
}
/* Open slave pty and acquire as new controlling terminal. */
if ( ( slave = sys_open ( slavedev , O_RDWR , 0 ) ) < 0 )
{
DEBUG ( 3 , ( " More weirdness, could not open %s \n " , slavedev ) ) ;
return ( False ) ;
}
1998-07-29 07:08:05 +04:00
# ifdef I_PUSH
2000-03-22 00:08:07 +03:00
ioctl ( slave , I_PUSH , " ptem " ) ;
ioctl ( slave , I_PUSH , " ldterm " ) ;
1998-07-29 07:08:05 +04:00
# elif defined(TIOCSCTTY)
2000-03-22 00:08:07 +03:00
if ( ioctl ( slave , TIOCSCTTY , 0 ) < 0 )
{
DEBUG ( 3 , ( " Error in ioctl call for slave pty \n " ) ) ;
/* return(False); */
}
# endif
/* Close master. */
close ( master ) ;
/* Make slave stdin/out/err of child. */
if ( dup2 ( slave , STDIN_FILENO ) ! = STDIN_FILENO )
{
DEBUG ( 3 , ( " Could not re-direct stdin \n " ) ) ;
return ( False ) ;
}
if ( dup2 ( slave , STDOUT_FILENO ) ! = STDOUT_FILENO )
{
DEBUG ( 3 , ( " Could not re-direct stdout \n " ) ) ;
return ( False ) ;
}
if ( dup2 ( slave , STDERR_FILENO ) ! = STDERR_FILENO )
{
DEBUG ( 3 , ( " Could not re-direct stderr \n " ) ) ;
return ( False ) ;
}
if ( slave > 2 )
close ( slave ) ;
/* Set proper terminal attributes - no echo, canonical input processing,
no map NL to CR / NL on output . */
if ( tcgetattr ( 0 , & stermios ) < 0 )
{
DEBUG ( 3 ,
( " could not read default terminal attributes on pty \n " ) ) ;
return ( False ) ;
}
stermios . c_lflag & = ~ ( ECHO | ECHOE | ECHOK | ECHONL ) ;
stermios . c_lflag | = ICANON ;
2001-10-03 01:58:09 +04:00
stermios . c_oflag & = ~ ( ONLCR ) ;
2000-03-22 00:08:07 +03:00
if ( tcsetattr ( 0 , TCSANOW , & stermios ) < 0 )
{
DEBUG ( 3 , ( " could not set attributes of pty \n " ) ) ;
return ( False ) ;
}
/* make us completely into the right uid */
if ( ! as_root )
{
become_user_permanently ( uid , gid ) ;
}
DEBUG ( 10 ,
( " Invoking '%s' as password change program. \n " ,
passwordprogram ) ) ;
/* execl() password-change application */
if ( execl ( " /bin/sh " , " sh " , " -c " , passwordprogram , NULL ) < 0 )
{
DEBUG ( 3 , ( " Bad status returned from %s \n " , passwordprogram ) ) ;
return ( False ) ;
}
return ( True ) ;
1996-05-04 11:50:46 +04:00
}
1999-12-13 16:27:58 +03:00
static int expect ( int master , char * issue , char * expected )
1996-05-04 11:50:46 +04:00
{
1999-12-13 16:27:58 +03:00
pstring buffer ;
int attempts , timeout , nread , len ;
BOOL match = False ;
1996-05-04 11:50:46 +04:00
2001-10-03 01:58:09 +04:00
for ( attempts = 0 ; attempts < 2 ; attempts + + ) {
if ( ! strequal ( issue , " . " ) ) {
1999-12-13 16:27:58 +03:00
if ( lp_passwd_chat_debug ( ) )
DEBUG ( 100 , ( " expect: sending [%s] \n " , issue ) ) ;
1996-05-04 11:50:46 +04:00
2001-10-03 01:58:09 +04:00
if ( ( len = write ( master , issue , strlen ( issue ) ) ) ! = strlen ( issue ) ) {
DEBUG ( 2 , ( " expect: (short) write returned %d \n " , len ) ) ;
return False ;
}
1999-12-13 16:27:58 +03:00
}
1996-05-04 11:50:46 +04:00
1999-12-13 16:27:58 +03:00
if ( strequal ( expected , " . " ) )
return True ;
timeout = 2000 ;
nread = 0 ;
buffer [ nread ] = 0 ;
while ( ( len = read_with_timeout ( master , buffer + nread , 1 ,
2000-03-22 00:08:07 +03:00
sizeof ( buffer ) - nread - 1 ,
2001-10-03 01:58:09 +04:00
timeout ) ) > 0 ) {
1999-12-13 16:27:58 +03:00
nread + = len ;
buffer [ nread ] = 0 ;
2001-10-03 01:58:09 +04:00
{
/* Eat leading/trailing whitespace before match. */
pstring str ;
pstrcpy ( str , buffer ) ;
trim_string ( str , " " , " " ) ;
if ( ( match = ( unix_wild_match ( expected , str ) = = 0 ) ) )
timeout = 200 ;
}
1999-12-13 16:27:58 +03:00
}
if ( lp_passwd_chat_debug ( ) )
2001-10-03 01:58:09 +04:00
DEBUG ( 100 , ( " expect: expected [%s] received [%s] match %s \n " ,
expected , buffer , match ? " yes " : " no " ) ) ;
1999-12-13 16:27:58 +03:00
if ( match )
break ;
2001-10-03 01:58:09 +04:00
if ( len < 0 ) {
1999-12-13 16:27:58 +03:00
DEBUG ( 2 , ( " expect: %s \n " , strerror ( errno ) ) ) ;
return False ;
}
}
2001-10-03 01:58:09 +04:00
DEBUG ( 10 , ( " expect: returning %s \n " , match ? " True " : " False " ) ) ;
1999-12-13 16:27:58 +03:00
return match ;
1996-05-04 11:50:46 +04:00
}
static void pwd_sub ( char * buf )
{
2000-03-22 00:08:07 +03:00
all_string_sub ( buf , " \\ n " , " \n " , 0 ) ;
all_string_sub ( buf , " \\ r " , " \r " , 0 ) ;
all_string_sub ( buf , " \\ s " , " " , 0 ) ;
all_string_sub ( buf , " \\ t " , " \t " , 0 ) ;
1996-05-04 11:50:46 +04:00
}
1999-12-13 16:27:58 +03:00
static int talktochild ( int master , char * seq )
1996-05-04 11:50:46 +04:00
{
1999-12-13 16:27:58 +03:00
int count = 0 ;
fstring issue , expected ;
1996-05-04 11:50:46 +04:00
1999-12-13 16:27:58 +03:00
fstrcpy ( issue , " . " ) ;
1996-05-04 11:50:46 +04:00
1999-12-13 16:27:58 +03:00
while ( next_token ( & seq , expected , NULL , sizeof ( expected ) ) )
{
pwd_sub ( expected ) ;
count + + ;
1996-05-04 11:50:46 +04:00
1999-12-13 16:27:58 +03:00
if ( ! expect ( master , issue , expected ) )
{
2000-03-22 00:08:07 +03:00
DEBUG ( 3 , ( " Response %d incorrect \n " , count ) ) ;
1999-12-13 16:27:58 +03:00
return False ;
}
1996-05-04 11:50:46 +04:00
1999-12-13 16:27:58 +03:00
if ( ! next_token ( & seq , issue , NULL , sizeof ( issue ) ) )
fstrcpy ( issue , " . " ) ;
1996-05-04 11:50:46 +04:00
1999-12-13 16:27:58 +03:00
pwd_sub ( issue ) ;
}
1996-05-04 11:50:46 +04:00
1999-12-13 16:27:58 +03:00
return ( count > 0 ) ;
1996-05-04 11:50:46 +04:00
}
2000-03-22 00:08:07 +03:00
static BOOL chat_with_program ( char * passwordprogram , char * name ,
char * chatsequence , BOOL as_root )
1996-05-04 11:50:46 +04:00
{
2000-03-22 00:08:07 +03:00
char * slavedev ;
int master ;
pid_t pid , wpid ;
int wstat ;
BOOL chstat = False ;
/* allocate a pseudo-terminal device */
if ( ( master = findpty ( & slavedev ) ) < 0 )
{
DEBUG ( 3 ,
( " Cannot Allocate pty for password change: %s \n " ,
name ) ) ;
return ( False ) ;
}
1998-03-27 22:59:14 +03:00
1999-12-13 16:27:58 +03:00
/*
2000-03-22 00:08:07 +03:00
* We need to temporarily stop CatchChild from eating
* SIGCLD signals as it also eats the exit status code . JRA .
1999-12-13 16:27:58 +03:00
*/
2000-03-22 00:08:07 +03:00
CatchChildLeaveStatus ( ) ;
2000-05-02 06:23:41 +04:00
if ( ( pid = sys_fork ( ) ) < 0 )
2000-03-22 00:08:07 +03:00
{
DEBUG ( 3 ,
( " Cannot fork() child for password change: %s \n " ,
name ) ) ;
close ( master ) ;
CatchChild ( ) ;
return ( False ) ;
}
/* we now have a pty */
if ( pid > 0 )
{ /* This is the parent process */
if ( ( chstat = talktochild ( master , chatsequence ) ) = = False )
{
DEBUG ( 3 ,
( " Child failed to change password: %s \n " ,
name ) ) ;
kill ( pid , SIGKILL ) ; /* be sure to end this process */
}
while ( ( wpid = sys_waitpid ( pid , & wstat , 0 ) ) < 0 )
{
if ( errno = = EINTR )
{
errno = 0 ;
continue ;
}
break ;
}
if ( wpid < 0 )
{
DEBUG ( 3 , ( " The process is no longer waiting! \n \n " ) ) ;
close ( master ) ;
CatchChild ( ) ;
return ( False ) ;
}
/*
* Go back to ignoring children .
*/
CatchChild ( ) ;
close ( master ) ;
if ( pid ! = wpid )
{
DEBUG ( 3 ,
( " We were waiting for the wrong process ID \n " ) ) ;
return ( False ) ;
}
if ( WIFEXITED ( wstat ) = = 0 )
{
DEBUG ( 3 ,
( " The process exited while we were waiting \n " ) ) ;
return ( False ) ;
}
if ( WEXITSTATUS ( wstat ) ! = 0 )
{
DEBUG ( 3 ,
( " The status of the process exiting was %d \n " ,
wstat ) ) ;
return ( False ) ;
}
}
else
{
/* CHILD */
1998-07-27 22:50:45 +04:00
2000-03-22 00:08:07 +03:00
/*
* Lose any oplock capabilities .
*/
2000-06-09 10:58:06 +04:00
oplock_set_capability ( False , False ) ;
2000-03-22 00:08:07 +03:00
/* make sure it doesn't freeze */
alarm ( 20 ) ;
if ( as_root )
2000-06-23 09:57:48 +04:00
become_root ( ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 3 ,
( " Dochild for user %s (uid=%d,gid=%d) \n " , name ,
( int ) getuid ( ) , ( int ) getgid ( ) ) ) ;
chstat =
dochild ( master , slavedev , name , passwordprogram ,
as_root ) ;
2000-06-23 09:57:48 +04:00
if ( as_root )
unbecome_root ( ) ;
2000-03-22 00:08:07 +03:00
/*
* The child should never return from dochild ( ) . . . .
*/
DEBUG ( 0 ,
( " chat_with_program: Error: dochild() returned %d \n " ,
chstat ) ) ;
exit ( 1 ) ;
}
if ( chstat )
DEBUG ( 3 ,
( " Password change %ssuccessful for user %s \n " ,
( chstat ? " " : " un " ) , name ) ) ;
return ( chstat ) ;
1996-05-04 11:50:46 +04:00
}
2000-03-22 00:08:07 +03:00
BOOL chgpasswd ( char * name , char * oldpass , char * newpass , BOOL as_root )
1996-05-04 11:50:46 +04:00
{
2000-03-22 00:08:07 +03:00
pstring passwordprogram ;
pstring chatsequence ;
size_t i ;
size_t len ;
1996-05-04 11:50:46 +04:00
2000-03-22 00:08:07 +03:00
strlower ( name ) ;
DEBUG ( 3 , ( " Password change for user: %s \n " , name ) ) ;
1996-05-04 11:50:46 +04:00
# if DEBUG_PASSWORD
2000-03-22 00:08:07 +03:00
DEBUG ( 100 , ( " Passwords: old=%s new=%s \n " , oldpass , newpass ) ) ;
1996-05-04 11:50:46 +04:00
# endif
2000-03-22 00:08:07 +03:00
/* Take the passed information and test it for minimum criteria */
/* Minimum password length */
2001-05-03 03:32:09 +04:00
if ( strlen ( newpass ) < lp_min_passwd_length ( ) ) {
/* too short, must be at least MINPASSWDLENGTH */
DEBUG ( 0 , ( " Password Change: user %s, New password is shorter than minimum password length = %d \n " ,
2000-03-22 00:08:07 +03:00
name , lp_min_passwd_length ( ) ) ) ;
return ( False ) ; /* inform the user */
}
1998-03-27 22:59:14 +03:00
2000-03-22 00:08:07 +03:00
/* Password is same as old password */
2001-05-03 03:32:09 +04:00
if ( strcmp ( oldpass , newpass ) = = 0 ) {
/* don't allow same password */
DEBUG ( 2 , ( " Password Change: %s, New password is same as old \n " , name ) ) ; /* log the attempt */
2000-03-22 00:08:07 +03:00
return ( False ) ; /* inform the user */
}
/*
* Check the old and new passwords don ' t contain any control
* characters .
*/
len = strlen ( oldpass ) ;
2001-05-03 03:32:09 +04:00
for ( i = 0 ; i < len ; i + + ) {
if ( iscntrl ( ( int ) oldpass [ i ] ) ) {
2000-03-22 00:08:07 +03:00
DEBUG ( 0 ,
( " chat_with_program: oldpass contains control characters (disallowed). \n " ) ) ;
return False ;
}
}
len = strlen ( newpass ) ;
2001-05-03 03:32:09 +04:00
for ( i = 0 ; i < len ; i + + ) {
if ( iscntrl ( ( int ) newpass [ i ] ) ) {
2000-03-22 00:08:07 +03:00
DEBUG ( 0 ,
( " chat_with_program: newpass contains control characters (disallowed). \n " ) ) ;
return False ;
}
}
2001-05-03 03:32:09 +04:00
# ifdef WITH_PAM
if ( lp_pam_password_change ( ) ) {
BOOL ret ;
if ( as_root )
become_root ( ) ;
ret = smb_pam_passchange ( name , oldpass , newpass ) ;
if ( as_root )
unbecome_root ( ) ;
return ret ;
}
# endif
pstrcpy ( passwordprogram , lp_passwd_program ( ) ) ;
pstrcpy ( chatsequence , lp_passwd_chat ( ) ) ;
if ( ! * chatsequence ) {
2001-10-03 01:58:09 +04:00
DEBUG ( 2 , ( " chgpasswd: Null chat sequence - no password changing \n " ) ) ;
2001-05-03 03:32:09 +04:00
return ( False ) ;
}
if ( ! * passwordprogram ) {
2001-10-03 01:58:09 +04:00
DEBUG ( 2 , ( " chgpasswd: Null password program - no password changing \n " ) ) ;
2001-05-03 03:32:09 +04:00
return ( False ) ;
}
2001-10-03 01:58:09 +04:00
if ( as_root ) {
/* The password program *must* contain the user name to work. Fail if not. */
if ( strstr ( passwordprogram , " %u " ) = = NULL ) {
DEBUG ( 0 , ( " chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \
the string % % u , and the given string % s does not . \ n " , passwordprogram ));
return False ;
}
}
2000-03-22 00:08:07 +03:00
pstring_sub ( passwordprogram , " %u " , name ) ;
/* note that we do NOT substitute the %o and %n in the password program
as this would open up a security hole where the user could use
a new password containing shell escape characters */
pstring_sub ( chatsequence , " %u " , name ) ;
all_string_sub ( chatsequence , " %o " , oldpass , sizeof ( pstring ) ) ;
all_string_sub ( chatsequence , " %n " , newpass , sizeof ( pstring ) ) ;
return ( chat_with_program
( passwordprogram , name , chatsequence , as_root ) ) ;
1996-05-04 11:50:46 +04:00
}
1998-05-14 05:30:40 +04:00
# else /* ALLOW_CHANGE_PASSWORD */
2001-05-01 01:05:58 +04:00
2000-03-22 00:08:07 +03:00
BOOL chgpasswd ( char * name , char * oldpass , char * newpass , BOOL as_root )
1996-05-04 11:50:46 +04:00
{
2000-03-22 00:08:07 +03:00
DEBUG ( 0 , ( " Password changing not compiled in (user=%s) \n " , name ) ) ;
return ( False ) ;
1996-05-04 11:50:46 +04:00
}
1998-05-14 05:30:40 +04:00
# endif /* ALLOW_CHANGE_PASSWORD */
1998-01-17 10:08:21 +03:00
/***********************************************************
Code to check the lanman hashed password .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-03-22 00:08:07 +03:00
BOOL check_lanman_password ( char * user , uchar * pass1 ,
2000-11-14 02:03:34 +03:00
uchar * pass2 , SAM_ACCOUNT * * hnd )
1998-01-17 10:08:21 +03:00
{
2000-03-22 00:08:07 +03:00
uchar unenc_new_pw [ 16 ] ;
uchar unenc_old_pw [ 16 ] ;
2000-11-14 02:03:34 +03:00
SAM_ACCOUNT * sampass = NULL ;
uint16 acct_ctrl ;
2001-03-11 03:51:54 +03:00
uint8 * lanman_pw ;
2001-05-04 19:44:27 +04:00
BOOL ret ;
2000-06-23 09:57:48 +04:00
become_root ( ) ;
2001-05-04 19:44:27 +04:00
ret = pdb_getsampwnam ( sampass , user ) ;
2000-06-23 09:57:48 +04:00
unbecome_root ( ) ;
2000-03-22 00:08:07 +03:00
2001-05-04 19:44:27 +04:00
if ( ret = = False ) {
2000-11-14 02:03:34 +03:00
DEBUG ( 0 , ( " check_lanman_password: getsampwnam returned NULL \n " ) ) ;
2001-09-29 17:08:26 +04:00
pdb_free_sam ( & sampass ) ;
2000-03-22 00:08:07 +03:00
return False ;
}
2000-11-14 02:03:34 +03:00
acct_ctrl = pdb_get_acct_ctrl ( sampass ) ;
lanman_pw = pdb_get_lanman_passwd ( sampass ) ;
2000-03-22 00:08:07 +03:00
2001-05-04 19:44:27 +04:00
if ( acct_ctrl & ACB_DISABLED ) {
DEBUG ( 0 , ( " check_lanman_password: account %s disabled. \n " , user ) ) ;
2001-09-29 17:08:26 +04:00
pdb_free_sam ( & sampass ) ;
2000-03-22 00:08:07 +03:00
return False ;
}
2001-09-29 17:08:26 +04:00
if ( lanman_pw = = NULL ) {
if ( acct_ctrl & ACB_PWNOTREQ ) {
/* this saves the pointer for the caller */
* hnd = sampass ;
return True ;
} else {
DEBUG ( 0 , ( " check_lanman_password: no lanman password ! \n " ) ) ;
pdb_free_sam ( & sampass ) ;
return False ;
}
2000-03-22 00:08:07 +03:00
}
/* Get the new lanman hash. */
2000-11-14 02:03:34 +03:00
D_P16 ( lanman_pw , pass2 , unenc_new_pw ) ;
2000-03-22 00:08:07 +03:00
/* Use this to get the old lanman hash. */
D_P16 ( unenc_new_pw , pass1 , unenc_old_pw ) ;
/* Check that the two old passwords match. */
2001-05-04 19:44:27 +04:00
if ( memcmp ( lanman_pw , unenc_old_pw , 16 ) ) {
2000-11-14 02:03:34 +03:00
DEBUG ( 0 , ( " check_lanman_password: old password doesn't match. \n " ) ) ;
2001-09-29 17:08:26 +04:00
pdb_free_sam ( & sampass ) ;
2000-03-22 00:08:07 +03:00
return False ;
}
2000-11-14 02:03:34 +03:00
/* this saves the pointer for the caller */
* hnd = sampass ;
2000-03-22 00:08:07 +03:00
return True ;
1998-01-17 10:08:21 +03:00
}
/***********************************************************
Code to change the lanman hashed password .
It nulls out the NT hashed password as it will
no longer be valid .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-11-14 02:03:34 +03:00
BOOL change_lanman_password ( SAM_ACCOUNT * sampass , uchar * pass1 ,
2000-03-22 00:08:07 +03:00
uchar * pass2 )
1998-01-17 10:08:21 +03:00
{
2000-03-22 00:08:07 +03:00
static uchar null_pw [ 16 ] ;
uchar unenc_new_pw [ 16 ] ;
BOOL ret ;
2000-11-14 02:03:34 +03:00
uint16 acct_ctrl ;
2001-03-11 03:51:54 +03:00
uint8 * pwd ;
2000-03-22 00:08:07 +03:00
2001-05-04 19:44:27 +04:00
if ( sampass = = NULL ) {
2000-11-14 02:03:34 +03:00
DEBUG ( 0 , ( " change_lanman_password: no smb password entry. \n " ) ) ;
2000-03-22 00:08:07 +03:00
return False ;
}
2001-05-04 19:44:27 +04:00
2000-11-14 02:03:34 +03:00
acct_ctrl = pdb_get_acct_ctrl ( sampass ) ;
pwd = pdb_get_lanman_passwd ( sampass ) ;
2000-03-22 00:08:07 +03:00
2001-05-04 19:44:27 +04:00
if ( acct_ctrl & ACB_DISABLED ) {
2000-11-14 02:03:34 +03:00
DEBUG ( 0 , ( " change_lanman_password: account %s disabled. \n " ,
pdb_get_username ( sampass ) ) ) ;
2000-03-22 00:08:07 +03:00
return False ;
}
2001-09-29 17:08:26 +04:00
if ( pwd = = NULL ) {
if ( acct_ctrl & ACB_PWNOTREQ ) {
uchar no_pw [ 14 ] ;
memset ( no_pw , ' \0 ' , 14 ) ;
E_P16 ( no_pw , null_pw ) ;
/* Get the new lanman hash. */
D_P16 ( null_pw , pass2 , unenc_new_pw ) ;
} else {
DEBUG ( 0 , ( " change_lanman_password: no lanman password ! \n " ) ) ;
return False ;
}
} else {
/* Get the new lanman hash. */
D_P16 ( pwd , pass2 , unenc_new_pw ) ;
2000-03-22 00:08:07 +03:00
}
2001-09-29 17:08:26 +04:00
if ( ! pdb_set_lanman_passwd ( sampass , unenc_new_pw ) ) {
2000-03-22 00:08:07 +03:00
return False ;
}
2001-09-29 17:08:26 +04:00
if ( ! pdb_set_nt_passwd ( sampass , NULL ) ) {
return False ; /* We lose the NT hash. Sorry. */
}
2000-03-22 00:08:07 +03:00
2000-11-14 02:03:34 +03:00
/* Now flush the sam_passwd struct to persistent storage */
2000-06-23 09:57:48 +04:00
become_root ( ) ;
2000-11-14 02:03:34 +03:00
ret = pdb_update_sam_account ( sampass , False ) ;
2000-06-23 09:57:48 +04:00
unbecome_root ( ) ;
2000-03-22 00:08:07 +03:00
return ret ;
1998-01-17 10:08:21 +03:00
}
1998-03-18 22:07:53 +03:00
/***********************************************************
1998-10-19 21:32:10 +04:00
Code to check and change the OEM hashed password .
1998-03-18 22:07:53 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-10-19 21:32:10 +04:00
BOOL pass_oem_change ( char * user ,
2000-03-22 00:08:07 +03:00
uchar * lmdata , uchar * lmhash ,
uchar * ntdata , uchar * nthash )
1998-03-18 22:07:53 +03:00
{
1998-10-19 21:32:10 +04:00
fstring new_passwd ;
2000-11-14 02:03:34 +03:00
SAM_ACCOUNT * sampass = NULL ;
2000-03-22 00:08:07 +03:00
BOOL ret = check_oem_password ( user , lmdata , lmhash , ntdata , nthash ,
2000-11-14 02:03:34 +03:00
& sampass , new_passwd , sizeof ( new_passwd ) ) ;
1998-10-19 21:32:10 +04:00
/*
* At this point we have the new case - sensitive plaintext
* password in the fstring new_passwd . If we wanted to synchronise
* with UNIX passwords we would call a UNIX password changing
* function here . However it would have to be done as root
* as the plaintext of the old users password is not
* available . JRA .
*/
2001-09-29 17:08:26 +04:00
if ( ( ret ) & & lp_unix_password_sync ( ) )
2000-03-22 00:08:07 +03:00
ret = chgpasswd ( user , " " , new_passwd , True ) ;
1998-10-19 21:32:10 +04:00
if ( ret )
2001-09-29 17:08:26 +04:00
ret = change_oem_password ( sampass , new_passwd ) ;
1998-10-19 21:32:10 +04:00
memset ( new_passwd , 0 , sizeof ( new_passwd ) ) ;
2001-09-29 17:08:26 +04:00
pdb_free_sam ( & sampass ) ;
2001-05-04 19:44:27 +04:00
1998-10-19 21:32:10 +04:00
return ret ;
}
1998-03-18 22:07:53 +03:00
1998-10-19 21:32:10 +04:00
/***********************************************************
Code to check the OEM hashed password .
1998-03-18 22:07:53 +03:00
1998-10-19 21:32:10 +04:00
this function ignores the 516 byte nt OEM hashed password
but does use the lm OEM password to check the nt hashed - hash .
1998-03-18 22:07:53 +03:00
1998-10-19 21:32:10 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-09-10 15:23:41 +04:00
static BOOL check_oem_password ( char * user ,
uchar * lmdata , uchar * lmhash ,
uchar * ntdata , uchar * nthash ,
SAM_ACCOUNT * * hnd , char * new_passwd ,
int new_passwd_size )
1998-10-19 21:32:10 +04:00
{
1998-10-21 20:58:34 +04:00
static uchar null_pw [ 16 ] ;
static uchar null_ntpw [ 16 ] ;
2000-11-14 02:03:34 +03:00
SAM_ACCOUNT * sampass = NULL ;
2001-03-11 03:51:54 +03:00
uint8 * lanman_pw , * nt_pw ;
2000-11-14 02:03:34 +03:00
uint16 acct_ctrl ;
1999-12-13 16:27:58 +03:00
int new_pw_len ;
1998-10-19 21:32:10 +04:00
uchar new_ntp16 [ 16 ] ;
uchar unenc_old_ntpw [ 16 ] ;
uchar new_p16 [ 16 ] ;
uchar unenc_old_pw [ 16 ] ;
1998-10-21 20:28:44 +04:00
char no_pw [ 2 ] ;
2001-05-04 19:44:27 +04:00
BOOL ret ;
1998-10-21 20:58:34 +04:00
1998-10-19 21:32:10 +04:00
BOOL nt_pass_set = ( ntdata ! = NULL & & nthash ! = NULL ) ;
2001-05-04 19:44:27 +04:00
pdb_init_sam ( & sampass ) ;
2000-06-23 09:57:48 +04:00
become_root ( ) ;
2001-05-04 19:44:27 +04:00
ret = pdb_getsampwnam ( sampass , user ) ;
2000-06-23 09:57:48 +04:00
unbecome_root ( ) ;
1998-10-19 21:32:10 +04:00
2001-05-04 19:44:27 +04:00
if ( ret = = False ) {
2000-03-22 00:08:07 +03:00
DEBUG ( 0 , ( " check_oem_password: getsmbpwnam returned NULL \n " ) ) ;
1998-10-19 21:32:10 +04:00
return False ;
}
2001-05-04 19:44:27 +04:00
* hnd = sampass ;
2000-11-14 02:03:34 +03:00
acct_ctrl = pdb_get_acct_ctrl ( sampass ) ;
2001-05-04 19:44:27 +04:00
if ( acct_ctrl & ACB_DISABLED ) {
2000-11-14 02:03:34 +03:00
DEBUG ( 0 , ( " check_lanman_password: account %s disabled. \n " , user ) ) ;
1998-10-19 21:32:10 +04:00
return False ;
}
/* construct a null password (in case one is needed */
no_pw [ 0 ] = 0 ;
no_pw [ 1 ] = 0 ;
nt_lm_owf_gen ( no_pw , null_ntpw , null_pw ) ;
2000-11-14 02:03:34 +03:00
/* save pointers to passwords so we don't have to keep looking them up */
lanman_pw = pdb_get_lanman_passwd ( sampass ) ;
nt_pw = pdb_get_nt_passwd ( sampass ) ;
1998-10-19 21:32:10 +04:00
/* check for null passwords */
2001-05-04 19:44:27 +04:00
if ( lanman_pw = = NULL ) {
2001-09-29 17:08:26 +04:00
if ( ! ( acct_ctrl & ACB_PWNOTREQ ) ) {
2000-11-14 02:03:34 +03:00
DEBUG ( 0 , ( " check_oem_password: no lanman password ! \n " ) ) ;
1998-10-19 21:32:10 +04:00
return False ;
}
}
2001-09-29 17:08:26 +04:00
2001-05-04 19:44:27 +04:00
if ( pdb_get_nt_passwd ( sampass ) = = NULL & & nt_pass_set ) {
2001-09-29 17:08:26 +04:00
if ( ! ( acct_ctrl & ACB_PWNOTREQ ) ) {
2000-11-14 02:03:34 +03:00
DEBUG ( 0 , ( " check_oem_password: no ntlm password ! \n " ) ) ;
1998-10-19 21:32:10 +04:00
return False ;
}
}
2001-09-29 17:08:26 +04:00
1998-10-19 21:32:10 +04:00
/*
* Call the hash function to get the new password .
*/
2001-06-20 23:55:59 +04:00
SamOEMhash ( ( uchar * ) lmdata , ( uchar * ) lanman_pw , 516 ) ;
1998-10-19 21:32:10 +04:00
1999-12-13 16:27:58 +03:00
/*
* The length of the new password is in the last 4 bytes of
* the data buffer .
*/
new_pw_len = IVAL ( lmdata , 512 ) ;
2001-05-04 19:44:27 +04:00
if ( new_pw_len < 0 | | new_pw_len > new_passwd_size - 1 ) {
DEBUG ( 0 , ( " check_oem_password: incorrect password length (%d). \n " , new_pw_len ) ) ;
1998-10-19 21:32:10 +04:00
return False ;
}
2001-05-04 19:44:27 +04:00
if ( nt_pass_set ) {
1999-12-13 16:27:58 +03:00
/*
* nt passwords are in unicode
*/
2001-07-04 11:15:53 +04:00
pull_ucs2 ( NULL , new_passwd ,
( const smb_ucs2_t * ) & lmdata [ 512 - new_pw_len ] ,
new_passwd_size , new_pw_len , 0 ) ;
2001-05-04 19:44:27 +04:00
} else {
2000-03-22 00:08:07 +03:00
memcpy ( new_passwd , & lmdata [ 512 - new_pw_len ] , new_pw_len ) ;
2001-07-04 11:15:53 +04:00
new_passwd [ new_pw_len ] = 0 ;
1999-12-13 16:27:58 +03:00
}
1998-10-19 21:32:10 +04:00
/*
* To ensure we got the correct new password , hash it and
* use it as a key to test the passed old password .
*/
nt_lm_owf_gen ( new_passwd , new_ntp16 , new_p16 ) ;
if ( ! nt_pass_set )
{
/*
* Now use new_p16 as the key to see if the old
* password matches .
*/
2000-03-22 00:08:07 +03:00
D_P16 ( new_p16 , lmhash , unenc_old_pw ) ;
1998-10-19 21:32:10 +04:00
2000-11-14 02:03:34 +03:00
if ( memcmp ( lanman_pw , unenc_old_pw , 16 ) )
1998-10-19 21:32:10 +04:00
{
2000-11-14 02:03:34 +03:00
DEBUG ( 0 , ( " check_oem_password: old lm password doesn't match. \n " ) ) ;
1998-10-19 21:32:10 +04:00
return False ;
}
# ifdef DEBUG_PASSWORD
2000-03-22 00:08:07 +03:00
DEBUG ( 100 ,
( " check_oem_password: password %s ok \n " , new_passwd ) ) ;
1998-10-19 21:32:10 +04:00
# endif
return True ;
}
/*
* Now use new_p16 as the key to see if the old
* password matches .
*/
D_P16 ( new_ntp16 , lmhash , unenc_old_pw ) ;
D_P16 ( new_ntp16 , nthash , unenc_old_ntpw ) ;
2000-11-14 02:03:34 +03:00
if ( memcmp ( lanman_pw , unenc_old_pw , 16 ) )
1998-10-19 21:32:10 +04:00
{
2000-11-14 02:03:34 +03:00
DEBUG ( 0 , ( " check_oem_password: old lm password doesn't match. \n " ) ) ;
1998-10-19 21:32:10 +04:00
return False ;
}
2000-11-14 02:03:34 +03:00
if ( memcmp ( nt_pw , unenc_old_ntpw , 16 ) )
1998-10-19 21:32:10 +04:00
{
2000-11-14 02:03:34 +03:00
DEBUG ( 0 , ( " check_oem_password: old nt password doesn't match. \n " ) ) ;
1998-10-19 21:32:10 +04:00
return False ;
}
# ifdef DEBUG_PASSWORD
2000-03-22 00:08:07 +03:00
DEBUG ( 100 , ( " check_oem_password: password %s ok \n " , new_passwd ) ) ;
1998-10-19 21:32:10 +04:00
# endif
return True ;
1998-03-18 22:07:53 +03:00
}
/***********************************************************
Code to change the oem password . Changes both the lanman
and NT hashes .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-09-29 17:08:26 +04:00
BOOL change_oem_password ( SAM_ACCOUNT * hnd , char * new_passwd )
1998-03-18 22:07:53 +03:00
{
2001-09-29 17:08:26 +04:00
BOOL ret ;
1998-03-18 22:07:53 +03:00
2001-09-29 17:08:26 +04:00
if ( ! pdb_set_plaintext_passwd ( hnd , new_passwd ) ) {
return False ;
}
1998-03-18 22:07:53 +03:00
2000-03-22 00:08:07 +03:00
/* Now write it into the file. */
2000-06-23 09:57:48 +04:00
become_root ( ) ;
2001-09-29 17:08:26 +04:00
ret = pdb_update_sam_account ( hnd , False ) ;
2000-06-23 09:57:48 +04:00
unbecome_root ( ) ;
1998-03-18 22:07:53 +03:00
2000-03-22 00:08:07 +03:00
return ret ;
1998-03-18 22:07:53 +03:00
}
2000-01-06 02:46:47 +03:00
/***********************************************************
Code to check a plaintext password against smbpasswd entries .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-03-22 00:08:07 +03:00
BOOL check_plaintext_password ( char * user , char * old_passwd ,
2000-11-14 02:03:34 +03:00
int old_passwd_size , SAM_ACCOUNT * * hnd )
2000-01-06 02:46:47 +03:00
{
2000-11-14 02:03:34 +03:00
SAM_ACCOUNT * sampass = NULL ;
2000-03-22 00:08:07 +03:00
uchar old_pw [ 16 ] , old_ntpw [ 16 ] ;
2001-05-04 19:44:27 +04:00
BOOL ret ;
pdb_init_sam ( & sampass ) ;
2000-01-06 02:46:47 +03:00
2000-06-23 09:57:48 +04:00
become_root ( ) ;
2001-05-04 19:44:27 +04:00
ret = pdb_getsampwnam ( sampass , user ) ;
2000-06-23 09:57:48 +04:00
unbecome_root ( ) ;
2000-01-06 02:46:47 +03:00
2001-05-04 19:44:27 +04:00
* hnd = sampass ;
if ( ret = = False )
2000-03-22 00:08:07 +03:00
{
2000-11-14 02:03:34 +03:00
DEBUG ( 0 , ( " check_plaintext_password: getsmbpwnam returned NULL \n " ) ) ;
2000-03-22 00:08:07 +03:00
return False ;
}
2000-01-06 02:46:47 +03:00
2000-11-14 02:03:34 +03:00
if ( pdb_get_acct_ctrl ( sampass ) & ACB_DISABLED )
2000-03-22 00:08:07 +03:00
{
2000-11-14 02:03:34 +03:00
DEBUG ( 0 , ( " check_plaintext_password: account %s disabled. \n " , user ) ) ;
2000-03-22 00:08:07 +03:00
return ( False ) ;
}
2000-01-06 02:46:47 +03:00
2000-03-22 00:08:07 +03:00
nt_lm_owf_gen ( old_passwd , old_ntpw , old_pw ) ;
2000-01-06 02:46:47 +03:00
# ifdef DEBUG_PASSWORD
2000-11-14 02:03:34 +03:00
DEBUG ( 100 , ( " check_plaintext_password: nt_passwd \n " ) ) ;
dump_data ( 100 , pdb_get_nt_passwd ( sampass ) , 16 ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 100 , ( " check_plaintext_password: old_ntpw \n " ) ) ;
dump_data ( 100 , old_ntpw , 16 ) ;
2000-11-14 02:03:34 +03:00
DEBUG ( 100 , ( " check_plaintext_password: lanman_passwd \n " ) ) ;
2001-07-07 10:44:50 +04:00
dump_data ( 100 , pdb_get_lanman_passwd ( sampass ) , 16 ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 100 , ( " check_plaintext_password: old_pw \n " ) ) ;
dump_data ( 100 , old_pw , 16 ) ;
2000-01-06 02:46:47 +03:00
# endif
2000-11-14 02:03:34 +03:00
if ( memcmp ( pdb_get_nt_passwd ( sampass ) , old_ntpw , 16 )
& & memcmp ( pdb_get_lanman_passwd ( sampass ) , old_pw , 16 ) )
2000-03-22 00:08:07 +03:00
return ( False ) ;
else
return ( True ) ;
2000-01-06 02:46:47 +03:00
}