1998-11-12 10:06:48 +03:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1998-11-12 10:06:48 +03:00
SMB client password change routine
Copyright ( C ) Andrew Tridgell 1994 - 1998
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 .
*/
# include "includes.h"
/*************************************************************
2005-09-30 21:13:37 +04:00
Change a password on a remote machine using IPC calls .
1998-11-12 10:06:48 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-09-30 21:13:37 +04:00
2006-02-04 01:19:41 +03:00
NTSTATUS remote_password_change ( const char * remote_machine , const char * user_name ,
1998-11-13 02:49:32 +03:00
const char * old_passwd , const char * new_passwd ,
char * err_str , size_t err_str_len )
1998-11-12 10:06:48 +03:00
{
struct nmb_name calling , called ;
2006-07-11 22:01:26 +04:00
struct cli_state * cli ;
2005-09-30 21:13:37 +04:00
struct rpc_pipe_client * pipe_hnd ;
1998-11-12 10:06:48 +03:00
struct in_addr ip ;
2004-01-26 11:45:02 +03:00
NTSTATUS result ;
2006-01-29 01:49:25 +03:00
BOOL pass_must_change = False ;
1998-11-12 10:06:48 +03:00
1999-12-13 16:27:58 +03:00
* err_str = ' \0 ' ;
1998-11-12 10:06:48 +03:00
if ( ! resolve_name ( remote_machine , & ip , 0x20 ) ) {
1998-11-13 02:49:32 +03:00
slprintf ( err_str , err_str_len - 1 , " unable to find an IP address for machine %s. \n " ,
1998-11-12 10:06:48 +03:00
remote_machine ) ;
2006-02-04 01:19:41 +03:00
return NT_STATUS_UNSUCCESSFUL ;
1998-11-12 10:06:48 +03:00
}
2006-07-11 22:01:26 +04:00
cli = cli_initialise ( ) ;
if ( ! cli ) {
return NT_STATUS_NO_MEMORY ;
}
if ( ! cli_connect ( cli , remote_machine , & ip ) ) {
1998-11-13 02:49:32 +03:00
slprintf ( err_str , err_str_len - 1 , " unable to connect to SMB server on machine %s. Error was : %s. \n " ,
2006-07-11 22:01:26 +04:00
remote_machine , cli_errstr ( cli ) ) ;
result = cli_nt_error ( cli ) ;
cli_shutdown ( cli ) ;
return result ;
1998-11-12 10:06:48 +03:00
}
2002-11-13 02:20:50 +03:00
make_nmb_name ( & calling , global_myname ( ) , 0x0 ) ;
2000-01-07 09:55:36 +03:00
make_nmb_name ( & called , remote_machine , 0x20 ) ;
1998-11-12 10:06:48 +03:00
2006-07-11 22:01:26 +04:00
if ( ! cli_session_request ( cli , & calling , & called ) ) {
1998-11-13 02:49:32 +03:00
slprintf ( err_str , err_str_len - 1 , " machine %s rejected the session setup. Error was : %s. \n " ,
2006-07-11 22:01:26 +04:00
remote_machine , cli_errstr ( cli ) ) ;
result = cli_nt_error ( cli ) ;
cli_shutdown ( cli ) ;
return result ;
1998-11-12 10:06:48 +03:00
}
2006-07-11 22:01:26 +04:00
cli - > protocol = PROTOCOL_NT1 ;
1998-11-12 10:06:48 +03:00
2006-07-11 22:01:26 +04:00
if ( ! cli_negprot ( cli ) ) {
1998-11-13 02:49:32 +03:00
slprintf ( err_str , err_str_len - 1 , " machine %s rejected the negotiate protocol. Error was : %s. \n " ,
2006-07-11 22:01:26 +04:00
remote_machine , cli_errstr ( cli ) ) ;
result = cli_nt_error ( cli ) ;
cli_shutdown ( cli ) ;
2006-02-04 01:19:41 +03:00
return result ;
1998-11-12 10:06:48 +03:00
}
2004-01-26 11:45:02 +03:00
/* Given things like SMB signing, restrict anonymous and the like,
try an authenticated connection first */
2006-08-16 21:14:16 +04:00
result = cli_session_setup ( cli , user_name ,
old_passwd , strlen ( old_passwd ) + 1 ,
old_passwd , strlen ( old_passwd ) + 1 , " " ) ;
2006-01-29 01:49:25 +03:00
2006-08-16 21:14:16 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2006-01-29 01:49:25 +03:00
2006-11-06 22:21:44 +03:00
/* Password must change or Password expired are the only valid
* error conditions here from where we can proceed , the rest like
* account locked out or logon failure will lead to errors later
* anyway */
2006-01-29 01:49:25 +03:00
2006-11-06 22:21:44 +03:00
if ( ! NT_STATUS_EQUAL ( result , NT_STATUS_PASSWORD_MUST_CHANGE ) & &
! NT_STATUS_EQUAL ( result , NT_STATUS_PASSWORD_EXPIRED ) ) {
2006-08-16 21:14:16 +04:00
slprintf ( err_str , err_str_len - 1 , " Could not "
" connect to machine %s: %s \n " ,
remote_machine , cli_errstr ( cli ) ) ;
cli_shutdown ( cli ) ;
return result ;
2006-01-29 01:49:25 +03:00
}
2006-08-16 21:14:16 +04:00
pass_must_change = True ;
2004-01-26 11:45:02 +03:00
/*
* We should connect as the anonymous user here , in case
* the server has " must change password " checked . . .
* Thanks to < Nicholas . S . Jenkins @ cdc . com > for this fix .
*/
1998-11-12 10:06:48 +03:00
2006-08-16 21:14:16 +04:00
result = cli_session_setup ( cli , " " , " " , 0 , " " , 0 , " " ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
2004-01-26 11:45:02 +03:00
slprintf ( err_str , err_str_len - 1 , " machine %s rejected the session setup. Error was : %s. \n " ,
2006-07-11 22:01:26 +04:00
remote_machine , cli_errstr ( cli ) ) ;
cli_shutdown ( cli ) ;
2006-02-04 01:19:41 +03:00
return result ;
2004-01-26 11:45:02 +03:00
}
2006-07-11 22:01:26 +04:00
cli_init_creds ( cli , " " , " " , NULL ) ;
2004-01-26 11:45:02 +03:00
} else {
2006-07-11 22:01:26 +04:00
cli_init_creds ( cli , user_name , " " , old_passwd ) ;
2004-01-26 11:45:02 +03:00
}
1998-11-12 10:06:48 +03:00
2006-07-11 22:01:26 +04:00
if ( ! cli_send_tconX ( cli , " IPC$ " , " IPC " , " " , 1 ) ) {
1998-11-13 02:49:32 +03:00
slprintf ( err_str , err_str_len - 1 , " machine %s rejected the tconX on the IPC$ share. Error was : %s. \n " ,
2006-07-11 22:01:26 +04:00
remote_machine , cli_errstr ( cli ) ) ;
result = cli_nt_error ( cli ) ;
cli_shutdown ( cli ) ;
2006-02-04 01:19:41 +03:00
return result ;
1998-11-12 10:06:48 +03:00
}
2005-09-30 21:13:37 +04:00
/* Try not to give the password away too easily */
2004-01-26 11:45:02 +03:00
2006-01-29 01:49:25 +03:00
if ( ! pass_must_change ) {
2006-07-11 22:01:26 +04:00
pipe_hnd = cli_rpc_pipe_open_ntlmssp ( cli ,
2005-09-30 21:13:37 +04:00
PI_SAMR ,
PIPE_AUTH_LEVEL_PRIVACY ,
" " , /* what domain... ? */
user_name ,
old_passwd ,
& result ) ;
2006-01-29 01:49:25 +03:00
} else {
/*
* If the user password must be changed the ntlmssp bind will
* fail the same way as the session setup above did . The
* difference ist that with a pipe bind we don ' t get a good
* error message , the result will be that the rpc call below
* will just fail . So we do it anonymously , there ' s no other
* way .
*/
2006-07-11 22:01:26 +04:00
pipe_hnd = cli_rpc_pipe_open_noauth ( cli , PI_SAMR , & result ) ;
2006-01-29 01:49:25 +03:00
}
2005-09-30 21:13:37 +04:00
if ( ! pipe_hnd ) {
2004-01-26 11:45:02 +03:00
if ( lp_client_lanman_auth ( ) ) {
2005-09-30 21:13:37 +04:00
/* Use the old RAP method. */
2006-07-11 22:01:26 +04:00
if ( ! cli_oem_change_password ( cli , user_name , new_passwd , old_passwd ) ) {
2004-01-26 11:45:02 +03:00
slprintf ( err_str , err_str_len - 1 , " machine %s rejected the password change: Error was : %s. \n " ,
2006-07-11 22:01:26 +04:00
remote_machine , cli_errstr ( cli ) ) ;
result = cli_nt_error ( cli ) ;
cli_shutdown ( cli ) ;
2006-02-04 01:19:41 +03:00
return result ;
2004-01-26 11:45:02 +03:00
}
} else {
2005-09-30 21:13:37 +04:00
slprintf ( err_str , err_str_len - 1 ,
" SAMR connection to machine %s failed. Error was %s, "
" but LANMAN password changed are disabled \n " ,
nt_errstr ( result ) , remote_machine ) ;
2006-07-11 22:01:26 +04:00
result = cli_nt_error ( cli ) ;
cli_shutdown ( cli ) ;
2006-02-04 01:19:41 +03:00
return result ;
2004-01-26 11:45:02 +03:00
}
}
2006-07-11 22:01:26 +04:00
if ( NT_STATUS_IS_OK ( result = rpccli_samr_chgpasswd_user ( pipe_hnd , cli - > mem_ctx , user_name ,
2004-04-12 15:18:32 +04:00
new_passwd , old_passwd ) ) ) {
/* Great - it all worked! */
2006-07-11 22:01:26 +04:00
cli_shutdown ( cli ) ;
2006-02-04 01:19:41 +03:00
return NT_STATUS_OK ;
2004-04-12 15:18:32 +04:00
} else if ( ! ( NT_STATUS_EQUAL ( result , NT_STATUS_ACCESS_DENIED )
| | NT_STATUS_EQUAL ( result , NT_STATUS_UNSUCCESSFUL ) ) ) {
/* it failed, but for reasons such as wrong password, too short etc ... */
slprintf ( err_str , err_str_len - 1 , " machine %s rejected the password change: Error was : %s. \n " ,
remote_machine , get_friendly_nt_error_msg ( result ) ) ;
2006-07-11 22:01:26 +04:00
cli_shutdown ( cli ) ;
2006-02-04 01:19:41 +03:00
return result ;
2004-04-12 15:18:32 +04:00
}
/* OK, that failed, so try again... */
2005-09-30 21:13:37 +04:00
cli_rpc_pipe_close ( pipe_hnd ) ;
2004-04-12 15:18:32 +04:00
/* Try anonymous NTLMSSP... */
2006-07-11 22:01:26 +04:00
cli_init_creds ( cli , " " , " " , NULL ) ;
2004-04-12 15:18:32 +04:00
result = NT_STATUS_UNSUCCESSFUL ;
2005-09-30 21:13:37 +04:00
/* OK, this is ugly, but... try an anonymous pipe. */
2006-07-11 22:01:26 +04:00
pipe_hnd = cli_rpc_pipe_open_noauth ( cli , PI_SAMR , & result ) ;
2005-09-30 21:13:37 +04:00
if ( pipe_hnd & &
( NT_STATUS_IS_OK ( result = rpccli_samr_chgpasswd_user ( pipe_hnd ,
2006-07-11 22:01:26 +04:00
cli - > mem_ctx ,
2005-09-30 21:13:37 +04:00
user_name ,
new_passwd ,
old_passwd ) ) ) ) {
2004-04-12 15:18:32 +04:00
/* Great - it all worked! */
2006-07-11 22:01:26 +04:00
cli_shutdown ( cli ) ;
2006-02-04 01:19:41 +03:00
return NT_STATUS_OK ;
2004-04-12 15:18:32 +04:00
} else {
if ( ! ( NT_STATUS_EQUAL ( result , NT_STATUS_ACCESS_DENIED )
| | NT_STATUS_EQUAL ( result , NT_STATUS_UNSUCCESSFUL ) ) ) {
/* it failed, but again it was due to things like new password too short */
slprintf ( err_str , err_str_len - 1 ,
" machine %s rejected the (anonymous) password change: Error was : %s. \n " ,
remote_machine , get_friendly_nt_error_msg ( result ) ) ;
2006-07-11 22:01:26 +04:00
cli_shutdown ( cli ) ;
2006-02-04 01:19:41 +03:00
return result ;
2004-04-12 15:18:32 +04:00
}
/* We have failed to change the user's password, and we think the server
just might not support SAMR password changes , so fall back */
if ( lp_client_lanman_auth ( ) ) {
2005-09-30 21:13:37 +04:00
/* Use the old RAP method. */
2006-07-11 22:01:26 +04:00
if ( cli_oem_change_password ( cli , user_name , new_passwd , old_passwd ) ) {
2004-04-12 15:18:32 +04:00
/* SAMR failed, but the old LanMan protocol worked! */
2006-07-11 22:01:26 +04:00
cli_shutdown ( cli ) ;
2006-02-04 01:19:41 +03:00
return NT_STATUS_OK ;
2004-01-26 11:45:02 +03:00
}
2004-04-12 15:18:32 +04:00
slprintf ( err_str , err_str_len - 1 ,
" machine %s rejected the password change: Error was : %s. \n " ,
2006-07-11 22:01:26 +04:00
remote_machine , cli_errstr ( cli ) ) ;
result = cli_nt_error ( cli ) ;
cli_shutdown ( cli ) ;
2006-02-04 01:19:41 +03:00
return result ;
2004-01-26 11:45:02 +03:00
} else {
2005-09-30 21:13:37 +04:00
slprintf ( err_str , err_str_len - 1 ,
" SAMR connection to machine %s failed. Error was %s, "
" but LANMAN password changed are disabled \n " ,
nt_errstr ( result ) , remote_machine ) ;
2006-07-11 22:01:26 +04:00
cli_shutdown ( cli ) ;
2006-02-04 01:19:41 +03:00
return NT_STATUS_UNSUCCESSFUL ;
2004-01-26 11:45:02 +03:00
}
}
1998-11-12 10:06:48 +03:00
}