2021-11-24 15:21:28 +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
2011-05-28 22:24:01 +04:00
1998-11-12 10:06:48 +03: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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
1998-11-12 10:06:48 +03:00
( at your option ) any later version .
2011-05-28 22:24:01 +04:00
1998-11-12 10:06:48 +03:00
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 .
2011-05-28 22:24:01 +04:00
1998-11-12 10:06:48 +03:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
1998-11-12 10:06:48 +03:00
*/
# include "includes.h"
2010-05-28 04:18:21 +04:00
# include "../librpc/gen_ndr/ndr_samr.h"
2011-02-28 12:19:44 +03:00
# include "rpc_client/cli_pipe.h"
2010-08-03 00:52:00 +04:00
# include "rpc_client/cli_samr.h"
2011-05-06 13:47:43 +04:00
# include "libsmb/libsmb.h"
2011-02-24 12:46:55 +03:00
# include "libsmb/clirap.h"
2011-03-23 16:18:59 +03:00
# include "libsmb/nmblib.h"
2012-05-20 19:54:29 +04:00
# include "../libcli/smb/smbXcli_base.h"
1998-11-12 10:06:48 +03:00
/*************************************************************
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
2017-08-18 17:08:46 +03:00
NTSTATUS remote_password_change ( const char * remote_machine ,
const char * domain , const char * user_name ,
2007-11-23 14:04:35 +03:00
const char * old_passwd , const char * new_passwd ,
char * * err_str )
1998-11-12 10:06:48 +03:00
{
2009-11-13 00:56:33 +03:00
struct cli_state * cli = NULL ;
2016-10-28 14:48:23 +03:00
struct cli_credentials * creds = NULL ;
2009-11-13 00:56:33 +03:00
struct rpc_pipe_client * pipe_hnd = NULL ;
2022-07-26 17:27:32 +03:00
NTSTATUS status ;
2004-01-26 11:45:02 +03:00
NTSTATUS result ;
2007-10-19 04:40:25 +04:00
bool pass_must_change = False ;
1998-11-12 10:06:48 +03:00
2007-11-23 14:04:35 +03:00
* err_str = NULL ;
1999-12-13 16:27:58 +03:00
2011-05-28 22:45:11 +04:00
result = cli_connect_nb ( remote_machine , NULL , 0 , 0x20 , NULL ,
2015-12-16 12:04:35 +03:00
SMB_SIGNING_IPC_DEFAULT , 0 , & cli ) ;
2007-06-20 21:38:42 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2018-12-17 22:57:59 +03:00
if ( NT_STATUS_EQUAL ( result , NT_STATUS_NOT_SUPPORTED ) ) {
if ( asprintf ( err_str , " Unable to connect to SMB server on "
" machine %s. NetBIOS support disabled \n " ,
remote_machine ) = = - 1 ) {
* err_str = NULL ;
}
} else {
if ( asprintf ( err_str , " Unable to connect to SMB server on "
" machine %s. Error was : %s. \n " ,
remote_machine , nt_errstr ( result ) ) = = - 1 ) {
* err_str = NULL ;
}
2009-01-01 03:30:11 +03:00
}
2006-07-11 22:01:26 +04:00
return result ;
1998-11-12 10:06:48 +03:00
}
2008-09-01 23:28:57 +04:00
2016-10-28 14:48:23 +03:00
creds = cli_session_creds_init ( cli ,
user_name ,
2017-08-18 17:08:46 +03:00
domain ,
2016-10-28 14:48:23 +03:00
NULL , /* realm */
old_passwd ,
2016-10-30 18:10:03 +03:00
false , /* use_kerberos */
false , /* fallback_after_kerberos */
false , /* use_ccache */
false ) ; /* password_is_nt_hash */
2016-10-28 14:48:23 +03:00
SMB_ASSERT ( creds ! = NULL ) ;
2015-12-16 12:04:35 +03:00
result = smbXcli_negprot ( cli - > conn , cli - > timeout ,
lp_client_ipc_min_protocol ( ) ,
lp_client_ipc_max_protocol ( ) ) ;
2008-09-11 20:57:49 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2009-01-01 03:30:11 +03:00
if ( asprintf ( err_str , " machine %s rejected the negotiate "
2021-11-24 15:21:28 +03:00
" protocol. Error was : %s. \n " ,
2009-01-01 03:30:11 +03:00
remote_machine , nt_errstr ( result ) ) = = - 1 ) {
* err_str = NULL ;
}
2006-07-11 22:01:26 +04:00
cli_shutdown ( cli ) ;
2006-02-04 01:19:41 +03:00
return result ;
1998-11-12 10:06:48 +03:00
}
2008-09-01 23:28:57 +04:00
2021-11-24 15:21:28 +03:00
/* Given things like SMB signing, restrict anonymous and the like,
2004-01-26 11:45:02 +03:00
try an authenticated connection first */
2016-10-28 14:48:23 +03:00
result = cli_session_setup_creds ( cli , creds ) ;
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 ) ) {
2009-01-01 03:30:11 +03:00
if ( asprintf ( err_str , " Could not connect to machine %s: "
2011-02-04 16:25:52 +03:00
" %s \n " , remote_machine , nt_errstr ( result ) ) = = - 1 ) {
2009-01-01 03:30:11 +03:00
* err_str = NULL ;
}
2006-08-16 21:14:16 +04:00
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
2016-10-28 13:15:20 +03:00
result = cli_session_setup_anon ( cli ) ;
2006-08-16 21:14:16 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2009-01-01 03:30:11 +03:00
if ( asprintf ( err_str , " machine %s rejected the session "
2021-11-24 15:21:28 +03:00
" setup. Error was : %s. \n " ,
2011-02-04 16:25:52 +03:00
remote_machine , nt_errstr ( result ) ) = = - 1 ) {
2009-01-01 03:30:11 +03:00
* err_str = NULL ;
}
2006-07-11 22:01:26 +04:00
cli_shutdown ( cli ) ;
2006-02-04 01:19:41 +03:00
return result ;
2004-01-26 11:45:02 +03:00
}
}
1998-11-12 10:06:48 +03:00
2016-12-08 09:13:57 +03:00
result = cli_tree_connect ( cli , " IPC$ " , " IPC " , NULL ) ;
2009-01-26 10:37:13 +03:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
if ( asprintf ( err_str , " machine %s rejected the tconX on the "
" IPC$ share. Error was : %s. \n " ,
remote_machine , nt_errstr ( result ) ) ) {
2009-01-01 03:30:11 +03:00
* err_str = NULL ;
}
2006-07-11 22:01:26 +04:00
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 ) {
2021-11-18 13:43:08 +03:00
const struct sockaddr_storage * remote_sockaddr =
smbXcli_conn_remote_sockaddr ( cli - > conn ) ;
2016-10-28 14:48:23 +03:00
result = cli_rpc_pipe_open_with_creds ( cli ,
& ndr_table_samr ,
NCACN_NP ,
DCERPC_AUTH_TYPE_NTLMSSP ,
DCERPC_AUTH_LEVEL_PRIVACY ,
remote_machine ,
2021-11-18 13:43:08 +03:00
remote_sockaddr ,
2016-10-28 14:48:23 +03:00
creds ,
& pipe_hnd ) ;
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
2023-07-05 12:26:30 +03:00
* difference is that with a pipe bind we don ' t get a good
2006-01-29 01:49:25 +03:00
* error message , the result will be that the rpc call below
* will just fail . So we do it anonymously , there ' s no other
* way .
*/
2008-07-20 13:04:31 +04:00
result = cli_rpc_pipe_open_noauth (
2013-05-24 15:29:28 +04:00
cli , & ndr_table_samr , & pipe_hnd ) ;
2006-01-29 01:49:25 +03:00
}
2005-09-30 21:13:37 +04:00
2008-07-20 13:04:31 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
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 ) ) {
2011-02-04 16:25:52 +03:00
result = cli_nt_error ( cli ) ;
2009-01-01 03:30:11 +03:00
if ( asprintf ( err_str , " machine %s rejected the "
2007-11-23 14:04:35 +03:00
" password change: Error was : %s. \n " ,
2011-02-04 16:25:52 +03:00
remote_machine , nt_errstr ( result ) ) = = - 1 ) {
2009-01-01 03:30:11 +03:00
* err_str = NULL ;
}
2006-07-11 22:01:26 +04:00
cli_shutdown ( cli ) ;
2006-02-04 01:19:41 +03:00
return result ;
2004-01-26 11:45:02 +03:00
}
} else {
2009-01-01 03:30:11 +03:00
if ( asprintf ( err_str , " SAMR connection to machine %s "
2007-11-23 14:04:35 +03:00
" failed. Error was %s, but LANMAN password "
2009-06-17 12:23:21 +04:00
" changes are disabled \n " ,
2009-06-15 10:33:22 +04:00
remote_machine , nt_errstr ( result ) ) = = - 1 ) {
2009-01-01 03:30:11 +03:00
* err_str = NULL ;
}
2006-07-11 22:01:26 +04:00
cli_shutdown ( cli ) ;
2006-02-04 01:19:41 +03:00
return result ;
2004-01-26 11:45:02 +03:00
}
}
2022-07-26 17:27:32 +03:00
status = dcerpc_samr_chgpasswd_user4 ( pipe_hnd - > binding_handle ,
talloc_tos ( ) ,
pipe_hnd - > srv_name_slash ,
user_name ,
old_passwd ,
new_passwd ,
& result ) ;
if ( NT_STATUS_IS_OK ( status ) & & NT_STATUS_IS_OK ( result ) ) {
/* All good, password successfully changed. */
cli_shutdown ( cli ) ;
return NT_STATUS_OK ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
if ( NT_STATUS_EQUAL ( status ,
NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE ) | |
NT_STATUS_EQUAL ( status , NT_STATUS_NOT_SUPPORTED ) | |
NT_STATUS_EQUAL ( status , NT_STATUS_NOT_IMPLEMENTED ) ) {
/* DO NOT FALLBACK TO RC4 */
if ( lp_weak_crypto ( ) = = SAMBA_WEAK_CRYPTO_DISALLOWED ) {
cli_shutdown ( cli ) ;
return NT_STATUS_STRONG_CRYPTO_NOT_SUPPORTED ;
}
}
} else {
if ( ! NT_STATUS_IS_OK ( result ) ) {
int rc = asprintf (
err_str ,
" machine %s rejected to change the password "
" with error: %s " ,
remote_machine ,
get_friendly_nt_error_msg ( result ) ) ;
if ( rc < = 0 ) {
* err_str = NULL ;
}
cli_shutdown ( cli ) ;
return result ;
}
}
2008-06-25 12:35:59 +04:00
result = rpccli_samr_chgpasswd_user2 ( pipe_hnd , talloc_tos ( ) ,
user_name , new_passwd , old_passwd ) ;
2008-04-19 20:17:13 +04:00
if ( NT_STATUS_IS_OK ( result ) ) {
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
2021-11-24 15:21:28 +03:00
} else if ( ! ( NT_STATUS_EQUAL ( result , NT_STATUS_ACCESS_DENIED )
2004-04-12 15:18:32 +04:00
| | NT_STATUS_EQUAL ( result , NT_STATUS_UNSUCCESSFUL ) ) ) {
/* it failed, but for reasons such as wrong password, too short etc ... */
2008-09-01 23:28:57 +04:00
2009-01-01 03:30:11 +03:00
if ( asprintf ( err_str , " machine %s rejected the password change: "
2007-11-23 14:04:35 +03:00
" Error was : %s. \n " ,
2009-01-01 03:30:11 +03:00
remote_machine , get_friendly_nt_error_msg ( result ) ) = = - 1 ) {
* err_str = NULL ;
}
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... */
2008-04-20 15:51:46 +04:00
TALLOC_FREE ( pipe_hnd ) ;
2008-09-01 23:28:57 +04:00
2004-04-12 15:18:32 +04:00
/* Try anonymous NTLMSSP... */
result = NT_STATUS_UNSUCCESSFUL ;
2008-09-01 23:28:57 +04:00
2005-09-30 21:13:37 +04:00
/* OK, this is ugly, but... try an anonymous pipe. */
2013-05-24 15:29:28 +04:00
result = cli_rpc_pipe_open_noauth ( cli , & ndr_table_samr ,
2008-07-20 13:04:31 +04:00
& pipe_hnd ) ;
2005-09-30 21:13:37 +04:00
2008-07-20 13:04:31 +04:00
if ( NT_STATUS_IS_OK ( result ) & &
2008-06-25 12:35:59 +04:00
( NT_STATUS_IS_OK ( result = rpccli_samr_chgpasswd_user2 (
2008-04-19 20:17:13 +04:00
pipe_hnd , talloc_tos ( ) , 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 {
2021-11-24 15:21:28 +03:00
if ( ! ( NT_STATUS_EQUAL ( result , NT_STATUS_ACCESS_DENIED )
2004-04-12 15:18:32 +04:00
| | NT_STATUS_EQUAL ( result , NT_STATUS_UNSUCCESSFUL ) ) ) {
/* it failed, but again it was due to things like new password too short */
2009-01-01 03:30:11 +03:00
if ( asprintf ( err_str , " machine %s rejected the "
2007-11-23 14:04:35 +03:00
" (anonymous) password change: Error was : "
" %s. \n " , remote_machine ,
2009-01-01 03:30:11 +03:00
get_friendly_nt_error_msg ( result ) ) = = - 1 ) {
* err_str = NULL ;
}
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
}
2008-09-01 23:28:57 +04:00
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 */
2008-09-01 23:28:57 +04:00
2004-04-12 15:18:32 +04: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-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
}
2011-02-04 16:25:52 +03:00
result = cli_nt_error ( cli ) ;
2009-01-01 03:30:11 +03:00
if ( asprintf ( err_str , " machine %s rejected the password "
2007-11-23 14:04:35 +03:00
" change: Error was : %s. \n " ,
2011-02-04 16:25:52 +03:00
remote_machine , nt_errstr ( result ) ) = = - 1 ) {
2009-01-01 03:30:11 +03:00
* err_str = NULL ;
}
2006-07-11 22:01:26 +04:00
cli_shutdown ( cli ) ;
2006-02-04 01:19:41 +03:00
return result ;
2004-01-26 11:45:02 +03:00
} else {
2009-01-01 03:30:11 +03:00
if ( asprintf ( err_str , " SAMR connection to machine %s "
2007-11-23 14:04:35 +03:00
" failed. Error was %s, but LANMAN password "
2010-05-12 23:41:52 +04:00
" changes are disabled \n " ,
2015-04-14 17:59:13 +03:00
remote_machine , nt_errstr ( result ) ) = = - 1 ) {
2009-01-01 03:30:11 +03:00
* err_str = NULL ;
}
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
}