2004-11-12 02:25:33 +03:00
/*
Unix SMB / CIFS implementation .
test suite for netlogon rpc operations
Copyright ( C ) Andrew Tridgell 2003
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2003 - 2004
Copyright ( C ) Tim Potter 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
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"
# include "librpc/gen_ndr/ndr_netlogon.h"
# include "auth/auth.h"
2004-11-13 06:57:54 +03:00
# include "dlinklist.h"
# include "lib/crypto/crypto.h"
2004-11-12 02:25:33 +03:00
# define TEST_MACHINE_NAME "samsynctest"
/*
try a netlogon SamLogon
*/
static NTSTATUS test_SamLogon ( struct dcerpc_pipe * p , TALLOC_CTX * mem_ctx ,
struct creds_CredentialState * creds ,
const char * domain , const char * username ,
struct samr_Password * lm_hash ,
struct samr_Password * nt_hash ,
struct netr_SamInfo3 * * info3 )
{
NTSTATUS status ;
struct netr_LogonSamLogon r ;
struct netr_Authenticator auth , auth2 ;
struct netr_NetworkInfo ninfo ;
ninfo . identity_info . domain_name . string = domain ;
ninfo . identity_info . parameter_control = 0 ;
ninfo . identity_info . logon_id_low = 0 ;
ninfo . identity_info . logon_id_high = 0 ;
ninfo . identity_info . account_name . string = username ;
ninfo . identity_info . workstation . string = TEST_MACHINE_NAME ;
generate_random_buffer ( ninfo . challenge ,
sizeof ( ninfo . challenge ) ) ;
if ( nt_hash ) {
ninfo . nt . length = 24 ;
ninfo . nt . data = talloc ( mem_ctx , 24 ) ;
SMBOWFencrypt ( nt_hash - > hash , ninfo . challenge , ninfo . nt . data ) ;
2004-11-13 06:57:54 +03:00
} else {
ninfo . nt . length = 0 ;
ninfo . nt . data = NULL ;
2004-11-12 02:25:33 +03:00
}
if ( lm_hash ) {
ninfo . lm . length = 24 ;
ninfo . lm . data = talloc ( mem_ctx , 24 ) ;
SMBOWFencrypt ( lm_hash - > hash , ninfo . challenge , ninfo . lm . data ) ;
2004-11-13 06:57:54 +03:00
} else {
ninfo . lm . length = 0 ;
ninfo . lm . data = NULL ;
2004-11-12 02:25:33 +03:00
}
r . in . server_name = talloc_asprintf ( mem_ctx , " \\ \\ %s " , dcerpc_server_name ( p ) ) ;
r . in . workstation = TEST_MACHINE_NAME ;
r . in . credential = & auth ;
r . in . return_authenticator = & auth2 ;
r . in . logon_level = 2 ;
r . in . logon . network = & ninfo ;
ZERO_STRUCT ( auth2 ) ;
creds_client_authenticator ( creds , & auth ) ;
r . in . validation_level = 3 ;
status = dcerpc_netr_LogonSamLogon ( p , mem_ctx , & r ) ;
if ( ! creds_client_check ( creds , & r . out . return_authenticator - > cred ) ) {
printf ( " Credential chaining failed \n " ) ;
}
2004-11-13 06:57:54 +03:00
if ( info3 ) {
* info3 = r . out . validation . sam3 ;
}
2004-11-12 02:25:33 +03:00
return status ;
}
struct samsync_state {
2004-11-13 16:48:59 +03:00
/* we remember the sequence numbers so we can easily do a DatabaseDelta */
uint64_t seq_num [ 3 ] ;
char * domain_name [ 2 ] ;
2004-11-13 06:57:54 +03:00
struct samsync_secret * secrets ;
struct samsync_trusted_domain * trusted_domains ;
2004-11-13 16:48:59 +03:00
struct creds_CredentialState * creds ;
struct policy_handle * connect_handle ;
struct policy_handle * domain_handle [ 2 ] ;
struct dom_sid * sid [ 2 ] ;
struct dcerpc_pipe * p ;
struct dcerpc_pipe * p_samr ;
2004-11-13 06:57:54 +03:00
} ;
struct samsync_secret {
struct samsync_secret * prev , * next ;
DATA_BLOB secret ;
char * name ;
} ;
struct samsync_trusted_domain {
struct samsync_trusted_domain * prev , * next ;
struct dom_sid * sid ;
char * name ;
2004-11-12 02:25:33 +03:00
} ;
2004-11-13 16:48:59 +03:00
static struct policy_handle * samsync_open_domain ( TALLOC_CTX * mem_ctx ,
struct samsync_state * samsync_state ,
const char * domain ,
struct dom_sid * * sid )
{
struct samr_String name ;
struct samr_OpenDomain o ;
struct samr_LookupDomain l ;
struct policy_handle * domain_handle = talloc_p ( mem_ctx , struct policy_handle ) ;
NTSTATUS nt_status ;
name . string = domain ;
l . in . connect_handle = samsync_state - > connect_handle ;
l . in . domain = & name ;
nt_status = dcerpc_samr_LookupDomain ( samsync_state - > p_samr , mem_ctx , & l ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
printf ( " LookupDomain failed - %s \n " , nt_errstr ( nt_status ) ) ;
return NULL ;
}
2004-11-12 02:25:33 +03:00
2004-11-13 16:48:59 +03:00
o . in . connect_handle = samsync_state - > connect_handle ;
o . in . access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED ;
o . in . sid = l . out . sid ;
o . out . domain_handle = domain_handle ;
if ( sid ) {
* sid = l . out . sid ;
}
nt_status = dcerpc_samr_OpenDomain ( samsync_state - > p_samr , mem_ctx , & o ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
printf ( " OpenDomain failed - %s \n " , nt_errstr ( nt_status ) ) ;
return NULL ;
}
return domain_handle ;
}
static BOOL samsync_handle_domain ( TALLOC_CTX * mem_ctx , struct samsync_state * samsync_state ,
2004-11-12 02:25:33 +03:00
int database_id , struct netr_DELTA_ENUM * delta )
{
struct netr_DELTA_DOMAIN * domain = delta - > delta_union . domain ;
2004-11-13 16:48:59 +03:00
struct dom_sid * dom_sid ;
samsync_state - > seq_num [ database_id ] =
2004-11-12 02:25:33 +03:00
domain - > sequence_num ;
2004-11-13 16:48:59 +03:00
switch ( database_id ) {
case SAM_DATABASE_DOMAIN :
break ;
case SAM_DATABASE_BUILTIN :
if ( StrCaseCmp ( " BUILTIN " , domain - > domain_name . string ) ! = 0 ) {
printf ( " BUILTIN domain has different name: %s \n " , domain - > domain_name . string ) ;
}
break ;
case SAM_DATABASE_PRIVS :
printf ( " DOMAIN entry on privs DB! \n " ) ;
return False ;
break ;
}
if ( ! samsync_state - > domain_name [ database_id ] ) {
samsync_state - > domain_name [ database_id ] =
talloc_reference ( samsync_state , domain - > domain_name . string ) ;
} else {
if ( StrCaseCmp ( samsync_state - > domain_name [ database_id ] , domain - > domain_name . string ) ! = 0 ) {
printf ( " Domain has name varies!: %s != %s \n " , samsync_state - > domain_name [ database_id ] ,
domain - > domain_name . string ) ;
return False ;
}
}
2004-11-12 02:25:33 +03:00
2004-11-13 16:48:59 +03:00
if ( ! samsync_state - > domain_handle [ database_id ] ) {
samsync_state - > domain_handle [ database_id ]
= samsync_open_domain ( mem_ctx , samsync_state , samsync_state - > domain_name [ database_id ] ,
& dom_sid ) ;
}
if ( samsync_state - > domain_handle [ database_id ] ) {
samsync_state - > sid [ database_id ] = talloc_reference ( samsync_state , dom_sid ) ;
}
2004-11-12 02:25:33 +03:00
printf ( " \t sequence_nums[%d/%s]=%llu \n " ,
2004-11-13 16:48:59 +03:00
database_id , domain - > domain_name . string ,
samsync_state - > seq_num [ database_id ] ) ;
2004-11-12 02:25:33 +03:00
return True ;
}
2004-11-13 16:48:59 +03:00
static BOOL samsync_handle_policy ( TALLOC_CTX * mem_ctx , struct samsync_state * samsync_state ,
int database_id , struct netr_DELTA_ENUM * delta )
{
struct netr_DELTA_POLICY * policy = delta - > delta_union . policy ;
samsync_state - > seq_num [ database_id ] =
policy - > sequence_num ;
if ( ! samsync_state - > domain_name [ SAM_DATABASE_DOMAIN ] ) {
samsync_state - > domain_name [ SAM_DATABASE_DOMAIN ] =
talloc_reference ( samsync_state , policy - > primary_domain_name . string ) ;
} else {
if ( StrCaseCmp ( samsync_state - > domain_name [ SAM_DATABASE_DOMAIN ] , policy - > primary_domain_name . string ) ! = 0 ) {
printf ( " PRIMARY domain has name varies between DOMAIN and POLICY!: %s != %s \n " , samsync_state - > domain_name [ SAM_DATABASE_DOMAIN ] ,
policy - > primary_domain_name . string ) ;
return False ;
}
}
if ( ! sid_equal ( samsync_state - > sid [ SAM_DATABASE_DOMAIN ] , policy - > sid ) ) {
printf ( " Domain SID from POLICY (%s) does not match domain sid from SAMR (%s) \n " ,
dom_sid_string ( mem_ctx , policy - > sid ) , dom_sid_string ( mem_ctx , samsync_state - > sid [ SAM_DATABASE_DOMAIN ] ) ) ;
return False ;
}
printf ( " \t sequence_nums[%d/PRIVS]=%llu \n " ,
database_id ,
samsync_state - > seq_num [ database_id ] ) ;
return True ;
}
# define TEST_INT_EQUAL(i1, i2) do {\
if ( i1 ! = i2 ) { \
printf ( " integer mismatch: " # i1 " :%d != " # i2 " : %d \n " , \
i1 , i2 ) ; \
ret = False ; \
} \
} while ( 0 )
# define TEST_TIME_EQUAL(t1, t2) do {\
if ( t1 ! = t2 ) { \
printf ( " NTTIME mismatch: " # t1 " :%s != " # t2 " : %s \n " , \
nt_time_string ( mem_ctx , t1 ) , nt_time_string ( mem_ctx , t2 ) ) ; \
ret = False ; \
} \
} while ( 0 )
# define TEST_STRING_EQUAL(s1, s2) do {\
if ( ! ( ( ! s1 . string | | s1 . string [ 0 ] = = ' \0 ' ) & & ( ! s2 . string | | s2 . string [ 0 ] = = ' \0 ' ) ) \
& & strcmp_safe ( s1 . string , s2 . string ) ! = 0 ) { \
printf ( " string mismatch: " # s1 " :%s != " # s2 " : %s \n " , \
s1 . string , s2 . string ) ; \
ret = False ; \
} \
} while ( 0 )
static BOOL samsync_handle_user ( TALLOC_CTX * mem_ctx , struct samsync_state * samsync_state ,
int database_id , struct netr_DELTA_ENUM * delta )
2004-11-12 02:25:33 +03:00
{
uint32 rid = delta - > delta_id_union . rid ;
struct netr_DELTA_USER * user = delta - > delta_union . user ;
struct netr_SamInfo3 * info3 ;
struct samr_Password lm_hash ;
struct samr_Password nt_hash ;
2004-11-13 06:57:54 +03:00
struct samr_Password * lm_hash_p = NULL ;
struct samr_Password * nt_hash_p = NULL ;
2004-11-13 16:48:59 +03:00
const char * domain = samsync_state - > domain_name [ database_id ] ;
2004-11-12 02:25:33 +03:00
const char * username = user - > account_name . string ;
2004-11-13 16:48:59 +03:00
NTSTATUS nt_status ;
BOOL ret = True ;
2004-11-12 02:25:33 +03:00
2004-11-13 16:48:59 +03:00
struct samr_OpenUser r ;
struct samr_QueryUserInfo q ;
struct policy_handle user_handle ;
2004-11-12 02:25:33 +03:00
2004-11-13 16:48:59 +03:00
if ( ! samsync_state - > domain_name | | ! samsync_state - > domain_handle [ database_id ] ) {
printf ( " SamSync needs domain information before the users \n " ) ;
return False ;
}
r . in . domain_handle = samsync_state - > domain_handle [ database_id ] ;
r . in . access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED ;
r . in . rid = rid ;
r . out . user_handle = & user_handle ;
nt_status = dcerpc_samr_OpenUser ( samsync_state - > p_samr , mem_ctx , & r ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
printf ( " OpenUser(%u) failed - %s \n " , rid , nt_errstr ( nt_status ) ) ;
return False ;
}
q . in . user_handle = & user_handle ;
q . in . level = 21 ;
2004-11-12 02:25:33 +03:00
2004-11-13 16:48:59 +03:00
nt_status = dcerpc_samr_QueryUserInfo ( samsync_state - > p_samr , mem_ctx , & q ) ;
if ( ! test_samr_handle_Close ( samsync_state - > p_samr , mem_ctx , & user_handle ) ) {
return False ;
}
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
printf ( " QueryUserInfo level %u failed - %s \n " ,
q . in . level , nt_errstr ( nt_status ) ) ;
return False ;
}
TEST_STRING_EQUAL ( q . out . info - > info21 . account_name , user - > account_name ) ;
TEST_STRING_EQUAL ( q . out . info - > info21 . full_name , user - > full_name ) ;
TEST_INT_EQUAL ( q . out . info - > info21 . rid , user - > rid ) ;
TEST_INT_EQUAL ( q . out . info - > info21 . primary_gid , user - > primary_gid ) ;
TEST_STRING_EQUAL ( q . out . info - > info21 . home_directory , user - > home_directory ) ;
TEST_STRING_EQUAL ( q . out . info - > info21 . home_drive , user - > home_drive ) ;
TEST_STRING_EQUAL ( q . out . info - > info21 . logon_script , user - > logon_script ) ;
TEST_STRING_EQUAL ( q . out . info - > info21 . description , user - > description ) ;
TEST_STRING_EQUAL ( q . out . info - > info21 . workstations , user - > workstations ) ;
TEST_TIME_EQUAL ( q . out . info - > info21 . last_logon , user - > last_logon ) ;
TEST_TIME_EQUAL ( q . out . info - > info21 . last_logoff , user - > last_logoff ) ;
TEST_INT_EQUAL ( q . out . info - > info21 . logon_hours . units_per_week ,
user - > logon_hours . units_per_week ) ;
if ( ret ) {
if ( memcmp ( q . out . info - > info21 . logon_hours . bitmap , user - > logon_hours . bitmap ,
q . out . info - > info21 . logon_hours . units_per_week / 8 ) ! = 0 ) {
printf ( " Logon hours mismatch \n " ) ;
ret = False ;
}
}
TEST_INT_EQUAL ( q . out . info - > info21 . bad_password_count ,
user - > bad_password_count ) ;
TEST_INT_EQUAL ( q . out . info - > info21 . logon_count ,
user - > logon_count ) ;
TEST_TIME_EQUAL ( q . out . info - > info21 . last_password_change ,
user - > last_password_change ) ;
TEST_TIME_EQUAL ( q . out . info - > info21 . acct_expiry ,
user - > acct_expiry ) ;
TEST_INT_EQUAL ( q . out . info - > info21 . logon_hours . units_per_week ,
user - > logon_hours . units_per_week ) ;
TEST_INT_EQUAL ( q . out . info - > info21 . acct_flags , user - > acct_flags ) ;
TEST_INT_EQUAL ( q . out . info - > info21 . nt_password_set , user - > nt_password_present ) ;
TEST_INT_EQUAL ( q . out . info - > info21 . lm_password_set , user - > lm_password_present ) ;
TEST_INT_EQUAL ( q . out . info - > info21 . password_expired , user - > password_expired ) ;
TEST_STRING_EQUAL ( q . out . info - > info21 . comment , user - > comment ) ;
TEST_STRING_EQUAL ( q . out . info - > info21 . parameters , user - > parameters ) ;
TEST_INT_EQUAL ( q . out . info - > info21 . country_code , user - > country_code ) ;
TEST_INT_EQUAL ( q . out . info - > info21 . code_page , user - > code_page ) ;
TEST_STRING_EQUAL ( q . out . info - > info21 . profile_path , user - > profile_path ) ;
if ( user - > lm_password_present ) {
2004-11-12 02:25:33 +03:00
sam_rid_crypt ( rid , user - > lmpassword . hash , lm_hash . hash , 0 ) ;
2004-11-13 06:57:54 +03:00
lm_hash_p = & lm_hash ;
2004-11-12 02:25:33 +03:00
}
2004-11-13 16:48:59 +03:00
if ( user - > nt_password_present ) {
2004-11-12 02:25:33 +03:00
sam_rid_crypt ( rid , user - > ntpassword . hash , nt_hash . hash , 0 ) ;
2004-11-13 06:57:54 +03:00
nt_hash_p = & nt_hash ;
2004-11-12 02:25:33 +03:00
}
2004-11-13 06:57:54 +03:00
if ( user - > user_private_info . SensitiveData ) {
DATA_BLOB data ;
struct netr_USER_KEYS keys ;
data . data = user - > user_private_info . SensitiveData ;
data . length = user - > user_private_info . DataLength ;
2004-11-13 16:48:59 +03:00
creds_arcfour_crypt ( samsync_state - > creds , data . data , data . length ) ;
2004-11-13 06:57:54 +03:00
#if 0
printf ( " Sensitive Data for %s: \n " , username ) ;
dump_data ( 0 , data . data , data . length ) ;
# endif
nt_status = ndr_pull_struct_blob ( & data , mem_ctx , & keys , ( ndr_pull_flags_fn_t ) ndr_pull_netr_USER_KEYS ) ;
2004-11-13 16:48:59 +03:00
if ( NT_STATUS_IS_OK ( nt_status ) ) {
if ( keys . keys . keys2 . lmpassword . length = = 16 ) {
sam_rid_crypt ( rid , keys . keys . keys2 . lmpassword . pwd . hash , lm_hash . hash , 0 ) ;
lm_hash_p = & lm_hash ;
}
if ( keys . keys . keys2 . ntpassword . length = = 16 ) {
sam_rid_crypt ( rid , keys . keys . keys2 . ntpassword . pwd . hash , nt_hash . hash , 0 ) ;
nt_hash_p = & nt_hash ;
}
2004-11-13 06:57:54 +03:00
}
}
2004-11-13 16:48:59 +03:00
2004-11-13 06:57:54 +03:00
if ( ! lm_hash_p & & ! nt_hash_p ) {
2004-11-12 02:25:33 +03:00
printf ( " NO password set for %s \n " ,
user - > account_name . string ) ;
return True ;
}
2004-11-13 06:57:54 +03:00
2004-11-13 16:48:59 +03:00
nt_status = test_SamLogon ( samsync_state - > p , mem_ctx , samsync_state - > creds ,
2004-11-12 02:25:33 +03:00
domain ,
username ,
2004-11-13 06:57:54 +03:00
lm_hash_p ,
nt_hash_p ,
2004-11-12 02:25:33 +03:00
& info3 ) ;
if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_ACCOUNT_DISABLED ) ) {
if ( user - > acct_flags & ACB_DISABLED ) {
return True ;
}
} else if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT ) ) {
if ( user - > acct_flags & ACB_WSTRUST ) {
return True ;
}
} else if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT ) ) {
if ( user - > acct_flags & ACB_SVRTRUST ) {
return True ;
}
} else if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT ) ) {
if ( user - > acct_flags & ACB_DOMTRUST ) {
return True ;
}
} else if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT ) ) {
if ( user - > acct_flags & ACB_DOMTRUST ) {
return True ;
}
} else if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_ACCOUNT_LOCKED_OUT ) ) {
if ( user - > acct_flags & ACB_AUTOLOCK ) {
return True ;
}
2004-11-13 16:48:59 +03:00
} else if ( NT_STATUS_IS_OK ( nt_status ) ) {
TEST_INT_EQUAL ( user - > rid , info3 - > base . rid ) ;
TEST_INT_EQUAL ( user - > primary_gid , info3 - > base . primary_gid ) ;
TEST_INT_EQUAL ( user - > acct_flags , info3 - > base . acct_flags ) ;
TEST_STRING_EQUAL ( user - > account_name , info3 - > base . account_name ) ;
TEST_STRING_EQUAL ( user - > full_name , info3 - > base . full_name ) ;
TEST_STRING_EQUAL ( user - > logon_script , info3 - > base . logon_script ) ;
TEST_STRING_EQUAL ( user - > profile_path , info3 - > base . profile_path ) ;
TEST_STRING_EQUAL ( user - > home_directory , info3 - > base . home_directory ) ;
TEST_STRING_EQUAL ( user - > home_drive , info3 - > base . home_drive ) ;
TEST_STRING_EQUAL ( user - > logon_script , info3 - > base . logon_script ) ;
TEST_TIME_EQUAL ( user - > last_logon , info3 - > base . last_logon ) ;
TEST_TIME_EQUAL ( user - > acct_expiry , info3 - > base . acct_expiry ) ;
TEST_TIME_EQUAL ( user - > last_password_change , info3 - > base . last_password_change ) ;
/* Does the concept of a logoff time ever really
* exist ? ( not in any sensible way , according to the
* doco I read - - abartlet ) */
/* This copes with the two different versions of 0 I see */
if ( ! ( ( user - > last_logoff = = 0 )
& & ( info3 - > base . last_logoff = = 0x7fffffffffffffffLL ) ) ) {
TEST_TIME_EQUAL ( user - > last_logoff , info3 - > base . last_logoff ) ;
2004-11-12 02:25:33 +03:00
}
2004-11-13 16:48:59 +03:00
return ret ;
2004-11-12 02:25:33 +03:00
} else {
printf ( " Could not validate password for user %s \\ %s: %s \n " ,
domain , username , nt_errstr ( nt_status ) ) ;
return False ;
}
return False ;
}
2004-11-13 16:48:59 +03:00
static BOOL samsync_handle_secret ( TALLOC_CTX * mem_ctx , struct samsync_state * samsync_state ,
2004-11-13 06:57:54 +03:00
int database_id , struct netr_DELTA_ENUM * delta )
{
struct netr_DELTA_SECRET * secret = delta - > delta_union . secret ;
const char * name = delta - > delta_id_union . name ;
struct samsync_secret * new = talloc_p ( samsync_state , struct samsync_secret ) ;
2004-11-13 16:48:59 +03:00
creds_arcfour_crypt ( samsync_state - > creds , secret - > current_cipher . cipher_data ,
2004-11-13 06:57:54 +03:00
secret - > current_cipher . maxlen ) ;
2004-11-13 16:48:59 +03:00
creds_arcfour_crypt ( samsync_state - > creds , secret - > old_cipher . cipher_data ,
2004-11-13 06:57:54 +03:00
secret - > old_cipher . maxlen ) ;
new - > name = talloc_reference ( new , name ) ;
new - > secret = data_blob_talloc ( new , secret - > current_cipher . cipher_data , secret - > current_cipher . maxlen ) ;
2004-11-13 16:48:59 +03:00
DLIST_ADD ( samsync_state - > secrets , new ) ;
2004-11-13 06:57:54 +03:00
return True ;
}
2004-11-13 16:48:59 +03:00
static BOOL samsync_handle_trusted_domain ( TALLOC_CTX * mem_ctx , struct samsync_state * samsync_state ,
2004-11-13 06:57:54 +03:00
int database_id , struct netr_DELTA_ENUM * delta )
{
struct netr_DELTA_TRUSTED_DOMAIN * trusted_domain = delta - > delta_union . trusted_domain ;
struct dom_sid * dom_sid = delta - > delta_id_union . sid ;
struct samsync_trusted_domain * new = talloc_p ( samsync_state , struct samsync_trusted_domain ) ;
new - > name = talloc_reference ( new , trusted_domain - > domain_name . string ) ;
new - > sid = talloc_reference ( new , dom_sid ) ;
2004-11-13 16:48:59 +03:00
DLIST_ADD ( samsync_state - > trusted_domains , new ) ;
2004-11-13 06:57:54 +03:00
return True ;
}
2004-11-12 02:25:33 +03:00
/*
try a netlogon DatabaseSync
*/
2004-11-13 16:48:59 +03:00
static BOOL test_DatabaseSync ( struct samsync_state * samsync_state ,
TALLOC_CTX * mem_ctx )
2004-11-12 02:25:33 +03:00
{
NTSTATUS status ;
struct netr_DatabaseSync r ;
const uint32_t database_ids [ ] = { SAM_DATABASE_DOMAIN , SAM_DATABASE_BUILTIN , SAM_DATABASE_PRIVS } ;
int i , d ;
BOOL ret = True ;
2004-11-13 06:57:54 +03:00
struct samsync_trusted_domain * t ;
struct samsync_secret * s ;
2004-11-12 02:25:33 +03:00
2004-11-13 16:48:59 +03:00
const char * domain , * username ;
2004-11-12 02:25:33 +03:00
2004-11-13 16:48:59 +03:00
r . in . logon_server = talloc_asprintf ( mem_ctx , " \\ \\ %s " , dcerpc_server_name ( samsync_state - > p ) ) ;
2004-11-12 02:25:33 +03:00
r . in . computername = TEST_MACHINE_NAME ;
r . in . preferredmaximumlength = ( uint32_t ) - 1 ;
ZERO_STRUCT ( r . in . return_authenticator ) ;
for ( i = 0 ; i < ARRAY_SIZE ( database_ids ) ; i + + ) {
r . in . sync_context = 0 ;
r . in . database_id = database_ids [ i ] ;
printf ( " Testing DatabaseSync of id %d \n " , r . in . database_id ) ;
do {
2004-11-13 16:48:59 +03:00
creds_client_authenticator ( samsync_state - > creds , & r . in . credential ) ;
2004-11-12 02:25:33 +03:00
2004-11-13 16:48:59 +03:00
status = dcerpc_netr_DatabaseSync ( samsync_state - > p , mem_ctx , & r ) ;
2004-11-12 02:25:33 +03:00
if ( ! NT_STATUS_IS_OK ( status ) & &
! NT_STATUS_EQUAL ( status , STATUS_MORE_ENTRIES ) ) {
printf ( " DatabaseSync - %s \n " , nt_errstr ( status ) ) ;
ret = False ;
break ;
}
2004-11-13 16:48:59 +03:00
if ( ! creds_client_check ( samsync_state - > creds , & r . out . return_authenticator . cred ) ) {
2004-11-12 02:25:33 +03:00
printf ( " Credential chaining failed \n " ) ;
}
r . in . sync_context = r . out . sync_context ;
for ( d = 0 ; d < r . out . delta_enum_array - > num_deltas ; d + + ) {
switch ( r . out . delta_enum_array - > delta_enum [ d ] . delta_type ) {
case NETR_DELTA_DOMAIN :
2004-11-13 16:48:59 +03:00
ret & = samsync_handle_domain ( mem_ctx , samsync_state ,
2004-11-12 02:25:33 +03:00
r . in . database_id , & r . out . delta_enum_array - > delta_enum [ d ] ) ;
break ;
case NETR_DELTA_USER :
2004-11-13 16:48:59 +03:00
ret & = samsync_handle_user ( mem_ctx , samsync_state ,
2004-11-12 02:25:33 +03:00
r . in . database_id , & r . out . delta_enum_array - > delta_enum [ d ] ) ;
break ;
2004-11-13 06:57:54 +03:00
case NETR_DELTA_TRUSTED_DOMAIN :
2004-11-13 16:48:59 +03:00
ret & = samsync_handle_trusted_domain ( mem_ctx , samsync_state ,
2004-11-13 06:57:54 +03:00
r . in . database_id , & r . out . delta_enum_array - > delta_enum [ d ] ) ;
break ;
case NETR_DELTA_SECRET :
2004-11-13 16:48:59 +03:00
ret & = samsync_handle_secret ( mem_ctx , samsync_state ,
r . in . database_id , & r . out . delta_enum_array - > delta_enum [ d ] ) ;
break ;
case NETR_DELTA_POLICY :
ret & = samsync_handle_policy ( mem_ctx , samsync_state ,
2004-11-13 06:57:54 +03:00
r . in . database_id , & r . out . delta_enum_array - > delta_enum [ d ] ) ;
break ;
2004-11-12 02:25:33 +03:00
}
}
} while ( NT_STATUS_EQUAL ( status , STATUS_MORE_ENTRIES ) ) ;
2004-11-13 16:48:59 +03:00
}
2004-11-13 06:57:54 +03:00
2004-11-13 16:48:59 +03:00
domain = samsync_state - > domain_name [ SAM_DATABASE_DOMAIN ] ;
if ( ! domain ) {
printf ( " Never got a DOMAIN object in samsync! \n " ) ;
return False ;
}
username = talloc_asprintf ( mem_ctx , " %s$ " , domain ) ;
for ( t = samsync_state - > trusted_domains ; t ; t = t - > next ) {
char * secret_name = talloc_asprintf ( mem_ctx , " G$$%s " , t - > name ) ;
for ( s = samsync_state - > secrets ; s ; s = s - > next ) {
printf ( " Checking secret %s against %s \n " ,
s - > name , secret_name ) ;
if ( StrCaseCmp ( s - > name , secret_name ) = = 0 ) {
NTSTATUS nt_status ;
struct samr_Password nt_hash ;
mdfour ( nt_hash . hash , s - > secret . data , s - > secret . length ) ;
2004-11-13 06:57:54 +03:00
printf ( " Checking password for %s \\ %s \n " , t - > name , username ) ;
2004-11-13 16:48:59 +03:00
nt_status = test_SamLogon ( samsync_state - > p , mem_ctx , samsync_state - > creds ,
t - > name ,
username ,
NULL ,
& nt_hash ,
NULL ) ;
if ( ! NT_STATUS_EQUAL ( nt_status , NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT ) ) {
printf ( " Could not verify trust password to %s: %s \n " ,
t - > name , nt_errstr ( nt_status ) ) ;
ret = False ;
}
/* break it */
nt_hash . hash [ 0 ] + + ;
nt_status = test_SamLogon ( samsync_state - > p , mem_ctx , samsync_state - > creds ,
t - > name ,
username ,
NULL ,
& nt_hash ,
NULL ) ;
if ( ! NT_STATUS_EQUAL ( nt_status , NT_STATUS_WRONG_PASSWORD ) ) {
printf ( " Verifiction of trust password to %s: should have failed (wrong password), instead: %s \n " ,
t - > name , nt_errstr ( nt_status ) ) ;
ret = False ;
ret = False ;
2004-11-13 06:57:54 +03:00
}
2004-11-13 16:48:59 +03:00
break ;
2004-11-13 06:57:54 +03:00
}
}
2004-11-12 02:25:33 +03:00
}
return ret ;
}
/*
try a netlogon DatabaseDeltas
*/
2004-11-13 16:48:59 +03:00
static BOOL test_DatabaseDeltas ( struct samsync_state * samsync_state , TALLOC_CTX * mem_ctx )
2004-11-12 02:25:33 +03:00
{
NTSTATUS status ;
struct netr_DatabaseDeltas r ;
const uint32_t database_ids [ ] = { 0 , 1 , 2 } ;
int i ;
BOOL ret = True ;
2004-11-13 16:48:59 +03:00
r . in . logon_server = talloc_asprintf ( mem_ctx , " \\ \\ %s " , dcerpc_server_name ( samsync_state - > p ) ) ;
2004-11-12 02:25:33 +03:00
r . in . computername = TEST_MACHINE_NAME ;
r . in . preferredmaximumlength = ( uint32_t ) - 1 ;
ZERO_STRUCT ( r . in . return_authenticator ) ;
for ( i = 0 ; i < ARRAY_SIZE ( database_ids ) ; i + + ) {
r . in . database_id = database_ids [ i ] ;
2004-11-13 16:48:59 +03:00
r . in . sequence_num = samsync_state - > seq_num [ i ] ;
2004-11-12 02:25:33 +03:00
if ( r . in . sequence_num = = 0 ) continue ;
r . in . sequence_num - = 1 ;
printf ( " Testing DatabaseDeltas of id %d at %llu \n " ,
r . in . database_id , r . in . sequence_num ) ;
do {
2004-11-13 16:48:59 +03:00
creds_client_authenticator ( samsync_state - > creds , & r . in . credential ) ;
2004-11-12 02:25:33 +03:00
2004-11-13 16:48:59 +03:00
status = dcerpc_netr_DatabaseDeltas ( samsync_state - > p , mem_ctx , & r ) ;
2004-11-12 02:25:33 +03:00
if ( ! NT_STATUS_IS_OK ( status ) & &
! NT_STATUS_EQUAL ( status , STATUS_MORE_ENTRIES ) ) {
printf ( " DatabaseDeltas - %s \n " , nt_errstr ( status ) ) ;
ret = False ;
break ;
}
2004-11-13 16:48:59 +03:00
if ( ! creds_client_check ( samsync_state - > creds , & r . out . return_authenticator . cred ) ) {
2004-11-12 02:25:33 +03:00
printf ( " Credential chaining failed \n " ) ;
}
r . in . sequence_num + + ;
} while ( NT_STATUS_EQUAL ( status , STATUS_MORE_ENTRIES ) ) ;
}
return ret ;
}
/*
try a netlogon DatabaseSync2
*/
static BOOL test_DatabaseSync2 ( struct dcerpc_pipe * p , TALLOC_CTX * mem_ctx ,
struct creds_CredentialState * creds )
{
NTSTATUS status ;
struct netr_DatabaseSync2 r ;
const uint32_t database_ids [ ] = { 0 , 1 , 2 } ;
int i ;
BOOL ret = True ;
r . in . logon_server = talloc_asprintf ( mem_ctx , " \\ \\ %s " , dcerpc_server_name ( p ) ) ;
r . in . computername = TEST_MACHINE_NAME ;
r . in . preferredmaximumlength = ( uint32_t ) - 1 ;
ZERO_STRUCT ( r . in . return_authenticator ) ;
for ( i = 0 ; i < ARRAY_SIZE ( database_ids ) ; i + + ) {
r . in . sync_context = 0 ;
r . in . database_id = database_ids [ i ] ;
r . in . restart_state = 0 ;
printf ( " Testing DatabaseSync2 of id %d \n " , r . in . database_id ) ;
do {
creds_client_authenticator ( creds , & r . in . credential ) ;
status = dcerpc_netr_DatabaseSync2 ( p , mem_ctx , & r ) ;
if ( ! NT_STATUS_IS_OK ( status ) & &
! NT_STATUS_EQUAL ( status , STATUS_MORE_ENTRIES ) ) {
printf ( " DatabaseSync2 - %s \n " , nt_errstr ( status ) ) ;
ret = False ;
break ;
}
if ( ! creds_client_check ( creds , & r . out . return_authenticator . cred ) ) {
printf ( " Credential chaining failed \n " ) ;
}
r . in . sync_context = r . out . sync_context ;
} while ( NT_STATUS_EQUAL ( status , STATUS_MORE_ENTRIES ) ) ;
}
return ret ;
}
BOOL torture_rpc_samsync ( void )
{
NTSTATUS status ;
TALLOC_CTX * mem_ctx ;
BOOL ret = True ;
struct test_join * join_ctx ;
const char * machine_password ;
const char * binding = lp_parm_string ( - 1 , " torture " , " binding " ) ;
struct dcerpc_binding b ;
2004-11-13 16:48:59 +03:00
struct samr_Connect c ;
struct samsync_state * samsync_state ;
2004-11-12 02:25:33 +03:00
mem_ctx = talloc_init ( " torture_rpc_netlogon " ) ;
join_ctx = torture_join_domain ( TEST_MACHINE_NAME , lp_workgroup ( ) , ACB_SVRTRUST ,
& machine_password ) ;
if ( ! join_ctx ) {
printf ( " Failed to join as BDC \n " ) ;
return False ;
}
2004-11-13 16:48:59 +03:00
samsync_state = talloc_zero_p ( mem_ctx , struct samsync_state ) ;
samsync_state - > p_samr = torture_join_samr_pipe ( join_ctx ) ;
samsync_state - > connect_handle = talloc_zero_p ( samsync_state , struct policy_handle ) ;
c . in . system_name = NULL ;
c . in . access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED ;
c . out . connect_handle = samsync_state - > connect_handle ;
status = dcerpc_samr_Connect ( samsync_state - > p_samr , mem_ctx , & c ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " samr_Connect failed \n " ) ;
ret = False ;
goto failed ;
}
2004-11-12 02:25:33 +03:00
status = dcerpc_parse_binding ( mem_ctx , binding , & b ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " Bad binding string %s \n " , binding ) ;
return False ;
2004-11-13 16:48:59 +03:00
goto failed ;
2004-11-12 02:25:33 +03:00
}
b . flags & = ~ DCERPC_AUTH_OPTIONS ;
2004-11-13 16:48:59 +03:00
b . flags | = DCERPC_SCHANNEL_BDC | DCERPC_SIGN | DCERPC_SCHANNEL_128 ;
2004-11-12 02:25:33 +03:00
2004-11-13 16:48:59 +03:00
status = dcerpc_pipe_connect_b ( & samsync_state - > p , & b ,
2004-11-12 02:25:33 +03:00
DCERPC_NETLOGON_UUID ,
DCERPC_NETLOGON_VERSION ,
lp_workgroup ( ) ,
TEST_MACHINE_NAME ,
machine_password ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2004-11-13 16:48:59 +03:00
ret = False ;
goto failed ;
2004-11-12 02:25:33 +03:00
}
2004-11-13 16:48:59 +03:00
status = dcerpc_schannel_creds ( samsync_state - > p - > security_state . generic_state , mem_ctx , & samsync_state - > creds ) ;
2004-11-12 02:25:33 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2004-11-13 16:48:59 +03:00
ret = False ;
2004-11-12 02:25:33 +03:00
}
2004-11-13 16:48:59 +03:00
if ( ! test_DatabaseSync ( samsync_state , mem_ctx ) ) {
2004-11-12 02:25:33 +03:00
ret = False ;
}
2004-11-13 16:48:59 +03:00
if ( ! test_DatabaseDeltas ( samsync_state , mem_ctx ) ) {
2004-11-12 02:25:33 +03:00
ret = False ;
}
2004-11-13 16:48:59 +03:00
if ( ! test_DatabaseSync2 ( samsync_state - > p , mem_ctx , samsync_state - > creds ) ) {
2004-11-12 02:25:33 +03:00
ret = False ;
}
2004-11-13 16:48:59 +03:00
failed :
torture_rpc_close ( samsync_state - > p ) ;
2004-11-12 02:25:33 +03:00
torture_leave_domain ( join_ctx ) ;
2004-11-13 16:48:59 +03:00
talloc_destroy ( mem_ctx ) ;
2004-11-12 02:25:33 +03:00
return ret ;
}