2004-08-14 07:32:42 +04:00
/*
Unix SMB / CIFS implementation .
Copyright ( C ) Stefan Metzmacher 2004
2005-01-13 10:50:09 +03:00
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2005
2004-08-14 07:32:42 +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 .
*/
2004-08-16 20:52:57 +04:00
# include "includes.h"
2004-11-02 14:42:35 +03:00
# include "libnet/libnet.h"
2004-11-01 13:30:34 +03:00
# include "librpc/gen_ndr/ndr_samr.h"
2004-11-02 09:14:15 +03:00
# include "lib/crypto/crypto.h"
2004-08-16 20:52:57 +04:00
2004-08-14 07:32:42 +04:00
/*
2004-08-16 20:52:57 +04:00
* do a password change using DCERPC / SAMR calls
* 1. connect to the SAMR pipe of users domain PDC ( maybe a standalone server or workstation )
2004-08-20 14:22:22 +04:00
* 2. try samr_ChangePasswordUser3
* 3. try samr_ChangePasswordUser2
* 4. try samr_OemChangePasswordUser2
* ( not yet : 5. try samr_ChangePasswordUser )
2004-08-14 07:32:42 +04:00
*/
2004-08-20 14:22:22 +04:00
static NTSTATUS libnet_ChangePassword_samr ( struct libnet_context * ctx , TALLOC_CTX * mem_ctx , union libnet_ChangePassword * r )
2004-08-14 07:32:42 +04:00
{
NTSTATUS status ;
2004-08-16 20:52:57 +04:00
union libnet_rpc_connect c ;
2004-08-19 19:06:06 +04:00
#if 0
struct policy_handle user_handle ;
struct samr_Password hash1 , hash2 , hash3 , hash4 , hash5 , hash6 ;
struct samr_ChangePasswordUser pw ;
# endif
struct samr_OemChangePasswordUser2 oe2 ;
struct samr_ChangePasswordUser2 pw2 ;
2004-08-14 07:32:42 +04:00
struct samr_ChangePasswordUser3 pw3 ;
2004-11-13 16:45:41 +03:00
struct samr_String server , account ;
2004-08-19 19:06:06 +04:00
struct samr_AsciiName a_server , a_account ;
2004-08-14 07:32:42 +04:00
struct samr_CryptPassword nt_pass , lm_pass ;
struct samr_Password nt_verifier , lm_verifier ;
uint8_t old_nt_hash [ 16 ] , new_nt_hash [ 16 ] ;
uint8_t old_lm_hash [ 16 ] , new_lm_hash [ 16 ] ;
2004-08-20 14:22:22 +04:00
/* prepare connect to the SAMR pipe of the users domain PDC */
2004-08-16 20:52:57 +04:00
c . pdc . level = LIBNET_RPC_CONNECT_PDC ;
2004-08-20 14:22:22 +04:00
c . pdc . in . domain_name = r - > samr . in . domain_name ;
2004-08-16 20:52:57 +04:00
c . pdc . in . dcerpc_iface_name = DCERPC_SAMR_NAME ;
c . pdc . in . dcerpc_iface_uuid = DCERPC_SAMR_UUID ;
c . pdc . in . dcerpc_iface_version = DCERPC_SAMR_VERSION ;
2004-08-20 14:22:22 +04:00
/* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
2004-08-16 20:52:57 +04:00
status = libnet_rpc_connect ( ctx , mem_ctx , & c ) ;
2004-08-14 07:32:42 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2004-08-20 14:22:22 +04:00
r - > samr . out . error_string = talloc_asprintf ( mem_ctx ,
2004-08-19 19:06:06 +04:00
" Connection to SAMR pipe of PDC of domain '%s' failed: %s \n " ,
2004-08-20 14:22:22 +04:00
r - > samr . in . domain_name , nt_errstr ( status ) ) ;
2004-08-14 07:32:42 +04:00
return status ;
}
2004-08-16 20:52:57 +04:00
/* prepare password change for account */
2004-11-13 16:45:41 +03:00
server . string = talloc_asprintf ( mem_ctx , " \\ \\ %s " , dcerpc_server_name ( c . pdc . out . dcerpc_pipe ) ) ;
account . string = r - > samr . in . account_name ;
2004-08-14 07:32:42 +04:00
2004-08-20 14:22:22 +04:00
E_md4hash ( r - > samr . in . oldpassword , old_nt_hash ) ;
E_md4hash ( r - > samr . in . newpassword , new_nt_hash ) ;
2004-08-14 07:32:42 +04:00
2004-08-20 14:22:22 +04:00
E_deshash ( r - > samr . in . oldpassword , old_lm_hash ) ;
E_deshash ( r - > samr . in . newpassword , new_lm_hash ) ;
2004-08-14 07:32:42 +04:00
2004-08-20 14:22:22 +04:00
/* prepare samr_ChangePasswordUser3 */
encode_pw_buffer ( lm_pass . data , r - > samr . in . newpassword , STR_UNICODE ) ;
2004-08-14 07:32:42 +04:00
arcfour_crypt ( lm_pass . data , old_nt_hash , 516 ) ;
E_old_pw_hash ( new_lm_hash , old_lm_hash , lm_verifier . hash ) ;
2004-08-20 14:22:22 +04:00
encode_pw_buffer ( nt_pass . data , r - > samr . in . newpassword , STR_UNICODE ) ;
2004-08-14 07:32:42 +04:00
arcfour_crypt ( nt_pass . data , old_nt_hash , 516 ) ;
E_old_pw_hash ( new_nt_hash , old_nt_hash , nt_verifier . hash ) ;
pw3 . in . server = & server ;
pw3 . in . account = & account ;
pw3 . in . nt_password = & nt_pass ;
pw3 . in . nt_verifier = & nt_verifier ;
pw3 . in . lm_change = 1 ;
pw3 . in . lm_password = & lm_pass ;
pw3 . in . lm_verifier = & lm_verifier ;
pw3 . in . password3 = NULL ;
2004-08-20 14:22:22 +04:00
/* 2. try samr_ChangePasswordUser3 */
2004-08-16 20:52:57 +04:00
status = dcerpc_samr_ChangePasswordUser3 ( c . pdc . out . dcerpc_pipe , mem_ctx , & pw3 ) ;
2004-08-14 07:32:42 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2004-08-20 14:22:22 +04:00
r - > samr . out . error_string = talloc_asprintf ( mem_ctx ,
2004-08-20 13:12:53 +04:00
" samr_ChangePasswordUser3 failed: %s \n " ,
nt_errstr ( status ) ) ;
2004-08-19 19:06:06 +04:00
goto ChangePasswordUser2 ;
2004-08-14 07:32:42 +04:00
}
2004-08-20 14:22:22 +04:00
/* check result of samr_ChangePasswordUser3 */
2004-08-16 20:52:57 +04:00
if ( ! NT_STATUS_IS_OK ( pw3 . out . result ) ) {
2004-08-20 14:22:22 +04:00
r - > samr . out . error_string = talloc_asprintf ( mem_ctx ,
2004-08-20 13:12:53 +04:00
" samr_ChangePasswordUser3 for '%s \\ %s' failed: %s \n " ,
2004-08-20 14:22:22 +04:00
r - > samr . in . domain_name , r - > samr . in . account_name ,
2004-08-20 13:12:53 +04:00
nt_errstr ( pw3 . out . result ) ) ;
2004-08-14 07:32:42 +04:00
/* TODO: give the reason of the reject */
2004-08-25 15:04:47 +04:00
if ( NT_STATUS_EQUAL ( pw3 . out . result , NT_STATUS_PASSWORD_RESTRICTION ) ) {
status = pw3 . out . result ;
2004-08-19 19:27:07 +04:00
goto disconnect ;
}
2004-08-19 19:06:06 +04:00
goto ChangePasswordUser2 ;
}
goto disconnect ;
ChangePasswordUser2 :
2004-08-20 14:22:22 +04:00
/* prepare samr_ChangePasswordUser2 */
encode_pw_buffer ( lm_pass . data , r - > samr . in . newpassword , STR_ASCII | STR_TERMINATE ) ;
2004-08-19 19:06:06 +04:00
arcfour_crypt ( lm_pass . data , old_lm_hash , 516 ) ;
E_old_pw_hash ( new_lm_hash , old_lm_hash , lm_verifier . hash ) ;
2004-08-20 14:22:22 +04:00
encode_pw_buffer ( nt_pass . data , r - > samr . in . newpassword , STR_UNICODE ) ;
2004-08-19 19:06:06 +04:00
arcfour_crypt ( nt_pass . data , old_nt_hash , 516 ) ;
E_old_pw_hash ( new_nt_hash , old_nt_hash , nt_verifier . hash ) ;
pw2 . in . server = & server ;
pw2 . in . account = & account ;
pw2 . in . nt_password = & nt_pass ;
pw2 . in . nt_verifier = & nt_verifier ;
pw2 . in . lm_change = 1 ;
pw2 . in . lm_password = & lm_pass ;
pw2 . in . lm_verifier = & lm_verifier ;
2004-08-20 14:22:22 +04:00
/* 3. try samr_ChangePasswordUser2 */
2004-08-19 19:06:06 +04:00
status = dcerpc_samr_ChangePasswordUser2 ( c . pdc . out . dcerpc_pipe , mem_ctx , & pw2 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2004-08-20 14:22:22 +04:00
r - > samr . out . error_string = talloc_asprintf ( mem_ctx ,
2004-08-20 13:12:53 +04:00
" samr_ChangePasswordUser2 failed: %s \n " ,
nt_errstr ( status ) ) ;
2004-08-19 19:06:06 +04:00
goto OemChangePasswordUser2 ;
}
2004-08-20 14:22:22 +04:00
/* check result of samr_ChangePasswordUser2 */
2004-08-19 19:06:06 +04:00
if ( ! NT_STATUS_IS_OK ( pw2 . out . result ) ) {
2004-08-20 14:22:22 +04:00
r - > samr . out . error_string = talloc_asprintf ( mem_ctx ,
2004-08-20 13:12:53 +04:00
" samr_ChangePasswordUser2 for '%s \\ %s' failed: %s \n " ,
2004-08-20 14:22:22 +04:00
r - > samr . in . domain_name , r - > samr . in . account_name ,
2004-08-20 13:12:53 +04:00
nt_errstr ( pw2 . out . result ) ) ;
2004-08-25 15:04:47 +04:00
if ( NT_STATUS_EQUAL ( pw2 . out . result , NT_STATUS_PASSWORD_RESTRICTION ) ) {
status = pw2 . out . result ;
goto disconnect ;
}
2004-08-19 19:06:06 +04:00
goto OemChangePasswordUser2 ;
}
goto disconnect ;
OemChangePasswordUser2 :
2004-08-20 14:22:22 +04:00
/* prepare samr_OemChangePasswordUser2 */
2004-11-13 16:45:41 +03:00
a_server . string = talloc_asprintf ( mem_ctx , " \\ \\ %s " , dcerpc_server_name ( c . pdc . out . dcerpc_pipe ) ) ;
a_account . string = r - > samr . in . account_name ;
2004-08-19 19:06:06 +04:00
2004-08-20 14:22:22 +04:00
encode_pw_buffer ( lm_pass . data , r - > samr . in . newpassword , STR_ASCII ) ;
2004-08-19 19:06:06 +04:00
arcfour_crypt ( lm_pass . data , old_lm_hash , 516 ) ;
E_old_pw_hash ( new_lm_hash , old_lm_hash , lm_verifier . hash ) ;
oe2 . in . server = & a_server ;
oe2 . in . account = & a_account ;
oe2 . in . password = & lm_pass ;
oe2 . in . hash = & lm_verifier ;
2004-08-20 14:22:22 +04:00
/* 4. try samr_OemChangePasswordUser2 */
2004-08-19 19:06:06 +04:00
status = dcerpc_samr_OemChangePasswordUser2 ( c . pdc . out . dcerpc_pipe , mem_ctx , & oe2 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2004-08-20 14:22:22 +04:00
r - > samr . out . error_string = talloc_asprintf ( mem_ctx ,
2004-08-20 13:12:53 +04:00
" samr_OemChangePasswordUser2 failed: %s \n " ,
nt_errstr ( status ) ) ;
2004-08-19 19:06:06 +04:00
goto ChangePasswordUser ;
}
2004-08-20 14:22:22 +04:00
/* check result of samr_OemChangePasswordUser2 */
2004-08-20 13:12:53 +04:00
if ( ! NT_STATUS_IS_OK ( oe2 . out . result ) ) {
2004-08-20 14:22:22 +04:00
r - > samr . out . error_string = talloc_asprintf ( mem_ctx ,
2004-08-20 13:12:53 +04:00
" samr_OemChangePasswordUser2 for '%s \\ %s' failed: %s \n " ,
2004-08-20 14:22:22 +04:00
r - > samr . in . domain_name , r - > samr . in . account_name ,
2004-08-20 13:12:53 +04:00
nt_errstr ( oe2 . out . result ) ) ;
2004-08-25 15:04:47 +04:00
if ( NT_STATUS_EQUAL ( oe2 . out . result , NT_STATUS_PASSWORD_RESTRICTION ) ) {
status = oe2 . out . result ;
goto disconnect ;
}
2004-08-19 19:06:06 +04:00
goto ChangePasswordUser ;
}
goto disconnect ;
ChangePasswordUser :
#if 0
2004-08-20 14:22:22 +04:00
/* prepare samr_ChangePasswordUser */
2004-08-19 19:06:06 +04:00
E_old_pw_hash ( new_lm_hash , old_lm_hash , hash1 . hash ) ;
E_old_pw_hash ( old_lm_hash , new_lm_hash , hash2 . hash ) ;
E_old_pw_hash ( new_nt_hash , old_nt_hash , hash3 . hash ) ;
E_old_pw_hash ( old_nt_hash , new_nt_hash , hash4 . hash ) ;
E_old_pw_hash ( old_lm_hash , new_nt_hash , hash5 . hash ) ;
E_old_pw_hash ( old_nt_hash , new_lm_hash , hash6 . hash ) ;
/* TODO: ask for a user_handle */
pw . in . handle = & user_handle ;
pw . in . lm_present = 1 ;
pw . in . old_lm_crypted = & hash1 ;
pw . in . new_lm_crypted = & hash2 ;
pw . in . nt_present = 1 ;
pw . in . old_nt_crypted = & hash3 ;
pw . in . new_nt_crypted = & hash4 ;
pw . in . cross1_present = 1 ;
pw . in . nt_cross = & hash5 ;
pw . in . cross2_present = 1 ;
pw . in . lm_cross = & hash6 ;
2004-08-20 14:22:22 +04:00
/* 5. try samr_ChangePasswordUser */
2004-08-19 19:06:06 +04:00
status = dcerpc_samr_ChangePasswordUser ( c . pdc . out . dcerpc_pipe , mem_ctx , & pw ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2004-08-20 14:22:22 +04:00
r - > samr . out . error_string = talloc_asprintf ( mem_ctx ,
2004-08-20 13:12:53 +04:00
" samr_ChangePasswordUser failed: %s \n " ,
nt_errstr ( status ) ) ;
2004-08-16 20:52:57 +04:00
goto disconnect ;
2004-08-14 07:32:42 +04:00
}
2004-08-20 14:22:22 +04:00
/* check result of samr_ChangePasswordUser */
2004-08-20 13:12:53 +04:00
if ( ! NT_STATUS_IS_OK ( pw . out . result ) ) {
2004-08-20 14:22:22 +04:00
r - > samr . out . error_string = talloc_asprintf ( mem_ctx ,
2004-08-20 13:12:53 +04:00
" samr_ChangePasswordUser for '%s \\ %s' failed: %s \n " ,
2004-08-20 14:22:22 +04:00
r - > samr . in . domain_name , r - > samr . in . account_name ,
2004-08-20 13:12:53 +04:00
nt_errstr ( pw . out . result ) ) ;
2004-08-25 15:04:47 +04:00
if ( NT_STATUS_EQUAL ( pw . out . result , NT_STATUS_PASSWORD_RESTRICTION ) ) {
status = pw . out . result ;
goto disconnect ;
}
2004-08-19 19:06:06 +04:00
goto disconnect ;
}
# endif
2004-08-16 20:52:57 +04:00
disconnect :
/* close connection */
dcerpc_pipe_close ( c . pdc . out . dcerpc_pipe ) ;
2004-08-14 07:32:42 +04:00
2004-08-16 20:52:57 +04:00
return status ;
2004-08-14 07:32:42 +04:00
}
2004-08-16 20:52:57 +04:00
static NTSTATUS libnet_ChangePassword_generic ( struct libnet_context * ctx , TALLOC_CTX * mem_ctx , union libnet_ChangePassword * r )
2004-08-14 07:32:42 +04:00
{
2004-08-18 15:01:06 +04:00
NTSTATUS status ;
union libnet_ChangePassword r2 ;
2004-08-20 14:22:22 +04:00
r2 . samr . level = LIBNET_CHANGE_PASSWORD_SAMR ;
r2 . samr . in . account_name = r - > generic . in . account_name ;
r2 . samr . in . domain_name = r - > generic . in . domain_name ;
r2 . samr . in . oldpassword = r - > generic . in . oldpassword ;
r2 . samr . in . newpassword = r - > generic . in . newpassword ;
2004-08-18 15:01:06 +04:00
status = libnet_ChangePassword ( ctx , mem_ctx , & r2 ) ;
2004-08-20 14:22:22 +04:00
r - > generic . out . error_string = r2 . samr . out . error_string ;
2004-08-18 15:01:06 +04:00
return status ;
2004-08-14 07:32:42 +04:00
}
2004-08-16 20:52:57 +04:00
NTSTATUS libnet_ChangePassword ( struct libnet_context * ctx , TALLOC_CTX * mem_ctx , union libnet_ChangePassword * r )
2004-08-14 07:32:42 +04:00
{
switch ( r - > generic . level ) {
case LIBNET_CHANGE_PASSWORD_GENERIC :
return libnet_ChangePassword_generic ( ctx , mem_ctx , r ) ;
2004-08-20 14:22:22 +04:00
case LIBNET_CHANGE_PASSWORD_SAMR :
return libnet_ChangePassword_samr ( ctx , mem_ctx , r ) ;
2004-08-16 20:52:57 +04:00
case LIBNET_CHANGE_PASSWORD_KRB5 :
return NT_STATUS_NOT_IMPLEMENTED ;
case LIBNET_CHANGE_PASSWORD_LDAP :
return NT_STATUS_NOT_IMPLEMENTED ;
2004-08-14 07:32:42 +04:00
case LIBNET_CHANGE_PASSWORD_RAP :
2004-08-16 20:52:57 +04:00
return NT_STATUS_NOT_IMPLEMENTED ;
}
return NT_STATUS_INVALID_LEVEL ;
}
2005-01-13 07:46:53 +03:00
static NTSTATUS libnet_SetPassword_samr_handle_26 ( struct libnet_context * ctx , TALLOC_CTX * mem_ctx , union libnet_SetPassword * r )
{
NTSTATUS status ;
struct samr_SetUserInfo sui ;
union samr_UserInfo u_info ;
DATA_BLOB session_key ;
DATA_BLOB confounded_session_key = data_blob_talloc ( mem_ctx , NULL , 16 ) ;
uint8_t confounder [ 16 ] ;
struct MD5Context md5 ;
/* prepare samr_SetUserInfo level 26 */
ZERO_STRUCT ( u_info ) ;
encode_pw_buffer ( u_info . info26 . password . data , r - > samr_handle . in . newpassword , STR_UNICODE ) ;
u_info . info26 . pw_len = strlen ( r - > samr_handle . in . newpassword ) ;
status = dcerpc_fetch_session_key ( r - > samr_handle . in . dcerpc_pipe , & session_key ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
r - > samr_handle . out . error_string = talloc_asprintf ( mem_ctx ,
" dcerpc_fetch_session_key failed: %s \n " ,
nt_errstr ( status ) ) ;
return status ;
}
generate_random_buffer ( ( uint8_t * ) confounder , 16 ) ;
MD5Init ( & md5 ) ;
MD5Update ( & md5 , confounder , 16 ) ;
MD5Update ( & md5 , session_key . data , session_key . length ) ;
MD5Final ( confounded_session_key . data , & md5 ) ;
arcfour_crypt_blob ( u_info . info26 . password . data , 516 , & confounded_session_key ) ;
memcpy ( & u_info . info26 . password . data [ 516 ] , confounder , 16 ) ;
sui . in . user_handle = r - > samr_handle . in . user_handle ;
sui . in . info = & u_info ;
sui . in . level = 26 ;
/* 7. try samr_SetUserInfo level 26 to set the password */
status = dcerpc_samr_SetUserInfo ( r - > samr_handle . in . dcerpc_pipe , mem_ctx , & sui ) ;
/* check result of samr_SetUserInfo level 26 */
if ( ! NT_STATUS_IS_OK ( status ) ) {
r - > samr_handle . out . error_string
= talloc_asprintf ( mem_ctx ,
" SetUserInfo level 26 for [%s] failed: %s \n " ,
r - > samr_handle . in . account_name , nt_errstr ( status ) ) ;
}
return status ;
}
static NTSTATUS libnet_SetPassword_samr_handle_25 ( struct libnet_context * ctx , TALLOC_CTX * mem_ctx , union libnet_SetPassword * r )
{
NTSTATUS status ;
struct samr_SetUserInfo sui ;
union samr_UserInfo u_info ;
DATA_BLOB session_key ;
DATA_BLOB confounded_session_key = data_blob_talloc ( mem_ctx , NULL , 16 ) ;
uint8_t confounder [ 16 ] ;
struct MD5Context md5 ;
/* prepare samr_SetUserInfo level 25 */
ZERO_STRUCT ( u_info ) ;
u_info . info25 . info . fields_present = SAMR_FIELD_PASSWORD ;
encode_pw_buffer ( u_info . info25 . password . data , r - > samr_handle . in . newpassword , STR_UNICODE ) ;
status = dcerpc_fetch_session_key ( r - > samr_handle . in . dcerpc_pipe , & session_key ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
r - > samr_handle . out . error_string = talloc_asprintf ( mem_ctx ,
" dcerpc_fetch_session_key failed: %s \n " ,
nt_errstr ( status ) ) ;
return status ;
}
generate_random_buffer ( ( uint8_t * ) confounder , 16 ) ;
MD5Init ( & md5 ) ;
MD5Update ( & md5 , confounder , 16 ) ;
MD5Update ( & md5 , session_key . data , session_key . length ) ;
MD5Final ( confounded_session_key . data , & md5 ) ;
arcfour_crypt_blob ( u_info . info25 . password . data , 516 , & confounded_session_key ) ;
memcpy ( & u_info . info25 . password . data [ 516 ] , confounder , 16 ) ;
sui . in . user_handle = r - > samr_handle . in . user_handle ;
sui . in . info = & u_info ;
sui . in . level = 25 ;
/* 8. try samr_SetUserInfo level 25 to set the password */
status = dcerpc_samr_SetUserInfo ( r - > samr_handle . in . dcerpc_pipe , mem_ctx , & sui ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
r - > samr_handle . out . error_string
= talloc_asprintf ( mem_ctx ,
" SetUserInfo level 25 for [%s] failed: %s \n " ,
r - > samr_handle . in . account_name , nt_errstr ( status ) ) ;
}
return status ;
}
static NTSTATUS libnet_SetPassword_samr_handle_24 ( struct libnet_context * ctx , TALLOC_CTX * mem_ctx , union libnet_SetPassword * r )
{
NTSTATUS status ;
struct samr_SetUserInfo sui ;
union samr_UserInfo u_info ;
DATA_BLOB session_key ;
/* prepare samr_SetUserInfo level 24 */
ZERO_STRUCT ( u_info ) ;
encode_pw_buffer ( u_info . info24 . password . data , r - > samr_handle . in . newpassword , STR_UNICODE ) ;
/* w2k3 ignores this length */
u_info . info24 . pw_len = strlen_m ( r - > samr_handle . in . newpassword ) * 2 ;
status = dcerpc_fetch_session_key ( r - > samr_handle . in . dcerpc_pipe , & session_key ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
r - > samr_handle . out . error_string = talloc_asprintf ( mem_ctx ,
" dcerpc_fetch_session_key failed: %s \n " ,
nt_errstr ( status ) ) ;
return status ;
}
arcfour_crypt_blob ( u_info . info24 . password . data , 516 , & session_key ) ;
sui . in . user_handle = r - > samr_handle . in . user_handle ;
sui . in . info = & u_info ;
sui . in . level = 24 ;
/* 9. try samr_SetUserInfo level 24 to set the password */
status = dcerpc_samr_SetUserInfo ( r - > samr_handle . in . dcerpc_pipe , mem_ctx , & sui ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
r - > samr_handle . out . error_string
= talloc_asprintf ( mem_ctx ,
" SetUserInfo level 24 for [%s] failed: %s \n " ,
r - > samr_handle . in . account_name , nt_errstr ( status ) ) ;
}
return status ;
}
static NTSTATUS libnet_SetPassword_samr_handle_23 ( struct libnet_context * ctx , TALLOC_CTX * mem_ctx , union libnet_SetPassword * r )
{
NTSTATUS status ;
struct samr_SetUserInfo sui ;
union samr_UserInfo u_info ;
DATA_BLOB session_key ;
/* prepare samr_SetUserInfo level 23 */
ZERO_STRUCT ( u_info ) ;
u_info . info23 . info . fields_present = SAMR_FIELD_PASSWORD ;
encode_pw_buffer ( u_info . info23 . password . data , r - > samr_handle . in . newpassword , STR_UNICODE ) ;
status = dcerpc_fetch_session_key ( r - > samr_handle . in . dcerpc_pipe , & session_key ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
r - > samr_handle . out . error_string
= talloc_asprintf ( mem_ctx ,
" dcerpc_fetch_session_key failed: %s \n " ,
nt_errstr ( status ) ) ;
return status ;
}
arcfour_crypt_blob ( u_info . info23 . password . data , 516 , & session_key ) ;
sui . in . user_handle = r - > samr_handle . in . user_handle ;
sui . in . info = & u_info ;
sui . in . level = 23 ;
/* 10. try samr_SetUserInfo level 23 to set the password */
status = dcerpc_samr_SetUserInfo ( r - > samr_handle . in . dcerpc_pipe , mem_ctx , & sui ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
r - > samr_handle . out . error_string
= talloc_asprintf ( mem_ctx ,
" SetUserInfo level 23 for [%s] failed: %s \n " ,
r - > samr_handle . in . account_name , nt_errstr ( status ) ) ;
}
return status ;
}
/*
* 1. try samr_SetUserInfo level 26 to set the password
* 2. try samr_SetUserInfo level 25 to set the password
* 3. try samr_SetUserInfo level 24 to set the password
* 4. try samr_SetUserInfo level 23 to set the password
*/
static NTSTATUS libnet_SetPassword_samr_handle ( struct libnet_context * ctx , TALLOC_CTX * mem_ctx , union libnet_SetPassword * r )
{
NTSTATUS status ;
enum libnet_SetPassword_level levels [ ] = {
LIBNET_SET_PASSWORD_SAMR_HANDLE_26 ,
LIBNET_SET_PASSWORD_SAMR_HANDLE_25 ,
LIBNET_SET_PASSWORD_SAMR_HANDLE_24 ,
LIBNET_SET_PASSWORD_SAMR_HANDLE_23 ,
} ;
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( levels ) ; i + + ) {
r - > generic . level = levels [ i ] ;
status = libnet_SetPassword ( ctx , mem_ctx , r ) ;
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_INVALID_INFO_CLASS ) ) {
break ;
}
}
return status ;
}
2004-08-16 20:52:57 +04:00
/*
* set a password with DCERPC / SAMR calls
2004-08-20 14:22:22 +04:00
* 1. connect to the SAMR pipe of users domain PDC ( maybe a standalone server or workstation )
* is it correct to contact the the pdc of the domain of the user who ' s password should be set ?
* 2. do a samr_Connect to get a policy handle
* 3. do a samr_LookupDomain to get the domain sid
* 4. do a samr_OpenDomain to get a domain handle
* 5. do a samr_LookupNames to get the users rid
* 6. do a samr_OpenUser to get a user handle
2005-01-13 07:46:53 +03:00
* 7 call libnet_SetPassword_samr_handle to set the password
2004-08-16 20:52:57 +04:00
*/
2004-08-20 14:22:22 +04:00
static NTSTATUS libnet_SetPassword_samr ( struct libnet_context * ctx , TALLOC_CTX * mem_ctx , union libnet_SetPassword * r )
2004-08-16 20:52:57 +04:00
{
2004-08-20 13:52:37 +04:00
NTSTATUS status ;
union libnet_rpc_connect c ;
struct samr_Connect sc ;
struct policy_handle p_handle ;
struct samr_LookupDomain ld ;
2004-11-13 16:45:41 +03:00
struct samr_String d_name ;
2004-08-20 13:52:37 +04:00
struct samr_OpenDomain od ;
struct policy_handle d_handle ;
struct samr_LookupNames ln ;
struct samr_OpenUser ou ;
struct policy_handle u_handle ;
2005-01-13 07:46:53 +03:00
union libnet_SetPassword r2 ;
2004-08-20 13:52:37 +04:00
2004-08-20 14:22:22 +04:00
/* prepare connect to the SAMR pipe of users domain PDC */
2004-08-20 13:52:37 +04:00
c . pdc . level = LIBNET_RPC_CONNECT_PDC ;
2004-08-20 14:22:22 +04:00
c . pdc . in . domain_name = r - > samr . in . domain_name ;
2004-08-20 13:52:37 +04:00
c . pdc . in . dcerpc_iface_name = DCERPC_SAMR_NAME ;
c . pdc . in . dcerpc_iface_uuid = DCERPC_SAMR_UUID ;
c . pdc . in . dcerpc_iface_version = DCERPC_SAMR_VERSION ;
2004-08-20 14:22:22 +04:00
/* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
2004-08-20 13:52:37 +04:00
status = libnet_rpc_connect ( ctx , mem_ctx , & c ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2004-08-20 14:22:22 +04:00
r - > samr . out . error_string = talloc_asprintf ( mem_ctx ,
2005-01-13 07:46:53 +03:00
" Connection to SAMR pipe of PDC of domain '%s' failed: %s \n " ,
r - > samr . in . domain_name , nt_errstr ( status ) ) ;
2004-08-20 13:52:37 +04:00
return status ;
}
2004-08-20 14:22:22 +04:00
/* prepare samr_Connect */
2004-08-20 13:52:37 +04:00
ZERO_STRUCT ( p_handle ) ;
2004-09-15 17:02:16 +04:00
sc . in . system_name = NULL ;
2004-12-02 07:37:36 +03:00
sc . in . access_mask = SEC_FLAG_MAXIMUM_ALLOWED ;
2004-09-21 07:51:38 +04:00
sc . out . connect_handle = & p_handle ;
2004-08-20 13:52:37 +04:00
2004-08-20 14:22:22 +04:00
/* 2. do a samr_Connect to get a policy handle */
2004-08-20 13:52:37 +04:00
status = dcerpc_samr_Connect ( c . pdc . out . dcerpc_pipe , mem_ctx , & sc ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2004-08-20 14:22:22 +04:00
r - > samr . out . error_string = talloc_asprintf ( mem_ctx ,
2004-08-20 13:52:37 +04:00
" samr_Connect failed: %s \n " ,
nt_errstr ( status ) ) ;
goto disconnect ;
}
2004-08-20 14:22:22 +04:00
/* prepare samr_LookupDomain */
2004-11-13 16:45:41 +03:00
d_name . string = r - > samr . in . domain_name ;
2004-09-21 07:51:38 +04:00
ld . in . connect_handle = & p_handle ;
2004-08-20 13:52:37 +04:00
ld . in . domain = & d_name ;
2004-08-20 14:22:22 +04:00
/* 3. do a samr_LookupDomain to get the domain sid */
2004-08-20 13:52:37 +04:00
status = dcerpc_samr_LookupDomain ( c . pdc . out . dcerpc_pipe , mem_ctx , & ld ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2004-08-20 14:22:22 +04:00
r - > samr . out . error_string = talloc_asprintf ( mem_ctx ,
2004-08-20 13:52:37 +04:00
" samr_LookupDomain for [%s] failed: %s \n " ,
2004-08-20 14:22:22 +04:00
r - > samr . in . domain_name , nt_errstr ( status ) ) ;
2004-08-20 13:52:37 +04:00
goto disconnect ;
}
2004-08-20 14:22:22 +04:00
/* prepare samr_OpenDomain */
2004-08-20 13:52:37 +04:00
ZERO_STRUCT ( d_handle ) ;
2004-09-21 07:51:38 +04:00
od . in . connect_handle = & p_handle ;
2004-12-02 07:37:36 +03:00
od . in . access_mask = SEC_FLAG_MAXIMUM_ALLOWED ;
2004-08-20 13:52:37 +04:00
od . in . sid = ld . out . sid ;
od . out . domain_handle = & d_handle ;
2004-08-20 14:22:22 +04:00
/* 4. do a samr_OpenDomain to get a domain handle */
2004-08-20 13:52:37 +04:00
status = dcerpc_samr_OpenDomain ( c . pdc . out . dcerpc_pipe , mem_ctx , & od ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2004-08-20 14:22:22 +04:00
r - > samr . out . error_string = talloc_asprintf ( mem_ctx ,
2004-08-20 13:52:37 +04:00
" samr_OpenDomain for [%s] failed: %s \n " ,
2004-08-20 14:22:22 +04:00
r - > samr . in . domain_name , nt_errstr ( status ) ) ;
2004-08-20 13:52:37 +04:00
goto disconnect ;
}
2004-08-20 14:22:22 +04:00
/* prepare samr_LookupNames */
2004-09-21 07:51:38 +04:00
ln . in . domain_handle = & d_handle ;
2004-08-20 13:52:37 +04:00
ln . in . num_names = 1 ;
2005-01-27 10:08:20 +03:00
ln . in . names = talloc_array ( mem_ctx , struct samr_String , 1 ) ;
2004-08-20 13:52:37 +04:00
if ( ! ln . in . names ) {
2004-08-20 14:22:22 +04:00
r - > samr . out . error_string = " Out of Memory " ;
2004-08-20 13:52:37 +04:00
return NT_STATUS_NO_MEMORY ;
}
2004-11-13 16:45:41 +03:00
ln . in . names [ 0 ] . string = r - > samr . in . account_name ;
2004-08-20 13:52:37 +04:00
2004-08-20 14:22:22 +04:00
/* 5. do a samr_LookupNames to get the users rid */
2004-08-20 13:52:37 +04:00
status = dcerpc_samr_LookupNames ( c . pdc . out . dcerpc_pipe , mem_ctx , & ln ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2004-08-20 14:22:22 +04:00
r - > samr . out . error_string = talloc_asprintf ( mem_ctx ,
2004-08-20 13:52:37 +04:00
" samr_LookupNames for [%s] failed: %s \n " ,
2004-08-20 14:22:22 +04:00
r - > samr . in . account_name , nt_errstr ( status ) ) ;
2004-08-20 13:52:37 +04:00
goto disconnect ;
}
/* check if we got one RID for the user */
if ( ln . out . rids . count ! = 1 ) {
2004-08-20 14:22:22 +04:00
r - > samr . out . error_string = talloc_asprintf ( mem_ctx ,
2004-08-20 13:52:37 +04:00
" samr_LookupNames for [%s] returns %d RIDs \n " ,
2004-08-20 14:22:22 +04:00
r - > samr . in . account_name , ln . out . rids . count ) ;
2004-08-25 15:04:47 +04:00
status = NT_STATUS_INVALID_PARAMETER ;
2004-08-20 13:52:37 +04:00
goto disconnect ;
}
2004-08-20 14:22:22 +04:00
/* prepare samr_OpenUser */
2004-08-20 13:52:37 +04:00
ZERO_STRUCT ( u_handle ) ;
2004-09-21 07:51:38 +04:00
ou . in . domain_handle = & d_handle ;
2004-12-02 07:37:36 +03:00
ou . in . access_mask = SEC_FLAG_MAXIMUM_ALLOWED ;
2004-08-20 13:52:37 +04:00
ou . in . rid = ln . out . rids . ids [ 0 ] ;
2004-09-21 07:51:38 +04:00
ou . out . user_handle = & u_handle ;
2004-08-20 13:52:37 +04:00
2004-08-20 14:22:22 +04:00
/* 6. do a samr_OpenUser to get a user handle */
2004-08-20 13:52:37 +04:00
status = dcerpc_samr_OpenUser ( c . pdc . out . dcerpc_pipe , mem_ctx , & ou ) ;
2004-08-20 14:22:22 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
r - > samr . out . error_string = talloc_asprintf ( mem_ctx ,
" samr_OpenUser for [%s] failed: %s \n " ,
r - > samr . in . account_name , nt_errstr ( status ) ) ;
goto disconnect ;
}
2005-01-13 07:46:53 +03:00
r2 . samr_handle . level = LIBNET_SET_PASSWORD_SAMR_HANDLE ;
r2 . samr_handle . in . account_name = r - > samr . in . account_name ;
r2 . samr_handle . in . newpassword = r - > samr . in . newpassword ;
r2 . samr_handle . in . user_handle = & u_handle ;
r2 . samr_handle . in . dcerpc_pipe = c . pdc . out . dcerpc_pipe ;
2004-08-24 20:28:08 +04:00
2005-01-13 07:46:53 +03:00
status = libnet_SetPassword ( ctx , mem_ctx , & r2 ) ;
2004-08-24 20:28:08 +04:00
2005-01-13 07:46:53 +03:00
r - > generic . out . error_string = r2 . samr_handle . out . error_string ;
2004-08-20 13:52:37 +04:00
disconnect :
/* close connection */
dcerpc_pipe_close ( c . pdc . out . dcerpc_pipe ) ;
return status ;
2004-08-16 20:52:57 +04:00
}
static NTSTATUS libnet_SetPassword_generic ( struct libnet_context * ctx , TALLOC_CTX * mem_ctx , union libnet_SetPassword * r )
{
2004-08-20 13:52:37 +04:00
NTSTATUS status ;
union libnet_SetPassword r2 ;
2004-08-20 14:22:22 +04:00
r2 . samr . level = LIBNET_SET_PASSWORD_SAMR ;
r2 . samr . in . account_name = r - > generic . in . account_name ;
r2 . samr . in . domain_name = r - > generic . in . domain_name ;
r2 . samr . in . newpassword = r - > generic . in . newpassword ;
2004-08-20 13:52:37 +04:00
2005-01-13 07:46:53 +03:00
r - > generic . out . error_string = " Unknown Error " ;
2004-08-20 13:52:37 +04:00
status = libnet_SetPassword ( ctx , mem_ctx , & r2 ) ;
2004-08-20 14:22:22 +04:00
r - > generic . out . error_string = r2 . samr . out . error_string ;
2004-08-20 13:52:37 +04:00
return status ;
2004-08-16 20:52:57 +04:00
}
NTSTATUS libnet_SetPassword ( struct libnet_context * ctx , TALLOC_CTX * mem_ctx , union libnet_SetPassword * r )
{
switch ( r - > generic . level ) {
case LIBNET_SET_PASSWORD_GENERIC :
return libnet_SetPassword_generic ( ctx , mem_ctx , r ) ;
2004-08-20 14:22:22 +04:00
case LIBNET_SET_PASSWORD_SAMR :
return libnet_SetPassword_samr ( ctx , mem_ctx , r ) ;
2005-01-13 07:46:53 +03:00
case LIBNET_SET_PASSWORD_SAMR_HANDLE :
return libnet_SetPassword_samr_handle ( ctx , mem_ctx , r ) ;
case LIBNET_SET_PASSWORD_SAMR_HANDLE_26 :
return libnet_SetPassword_samr_handle_26 ( ctx , mem_ctx , r ) ;
case LIBNET_SET_PASSWORD_SAMR_HANDLE_25 :
return libnet_SetPassword_samr_handle_25 ( ctx , mem_ctx , r ) ;
case LIBNET_SET_PASSWORD_SAMR_HANDLE_24 :
return libnet_SetPassword_samr_handle_24 ( ctx , mem_ctx , r ) ;
case LIBNET_SET_PASSWORD_SAMR_HANDLE_23 :
return libnet_SetPassword_samr_handle_23 ( ctx , mem_ctx , r ) ;
2004-08-16 20:52:57 +04:00
case LIBNET_SET_PASSWORD_KRB5 :
return NT_STATUS_NOT_IMPLEMENTED ;
case LIBNET_SET_PASSWORD_LDAP :
return NT_STATUS_NOT_IMPLEMENTED ;
case LIBNET_SET_PASSWORD_RAP :
return NT_STATUS_NOT_IMPLEMENTED ;
2004-08-14 07:32:42 +04:00
}
return NT_STATUS_INVALID_LEVEL ;
}