2008-06-13 13:57:09 +04:00
/*
Unix SMB / CIFS implementation .
Extract the user / system database from a remote SamSync server
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2004 - 2005
Copyright ( C ) Guenther Deschner < gd @ samba . org > 2008
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 3 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 , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
2008-07-30 19:47:40 +04:00
# include "libnet/libnet.h"
2009-03-16 13:27:58 +03:00
# include "../lib/crypto/crypto.h"
2009-03-27 04:16:17 +03:00
# include "../libcli/samsync/samsync.h"
2009-03-17 12:06:46 +03:00
# include "../libcli/auth/libcli_auth.h"
2009-11-26 20:21:28 +03:00
# include "../librpc/gen_ndr/cli_netlogon.h"
2008-06-13 13:57:09 +04:00
/**
* Fix up the delta , dealing with encryption issues so that the final
* callback need only do the printing or application logic
*/
2008-06-23 19:03:53 +04:00
static NTSTATUS samsync_fix_delta_array ( TALLOC_CTX * mem_ctx ,
2009-04-06 16:56:13 +04:00
struct netlogon_creds_CredentialState * creds ,
2008-06-23 19:03:53 +04:00
enum netr_SamDatabaseID database_id ,
struct netr_DELTA_ENUM_ARRAY * r )
2008-06-13 13:57:09 +04:00
{
NTSTATUS status ;
int i ;
for ( i = 0 ; i < r - > num_deltas ; i + + ) {
status = samsync_fix_delta ( mem_ctx ,
2009-03-27 04:16:17 +03:00
creds ,
2008-06-13 13:57:09 +04:00
database_id ,
& r - > delta_enum [ i ] ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
}
return NT_STATUS_OK ;
}
2008-06-16 14:09:08 +04:00
/**
2008-06-23 19:03:53 +04:00
* libnet_samsync_init_context
2008-06-16 14:09:08 +04:00
*/
2008-06-23 19:03:53 +04:00
NTSTATUS libnet_samsync_init_context ( TALLOC_CTX * mem_ctx ,
const struct dom_sid * domain_sid ,
struct samsync_context * * ctx_p )
2008-06-16 14:09:08 +04:00
{
struct samsync_context * ctx ;
* ctx_p = NULL ;
ctx = TALLOC_ZERO_P ( mem_ctx , struct samsync_context ) ;
NT_STATUS_HAVE_NO_MEMORY ( ctx ) ;
if ( domain_sid ) {
ctx - > domain_sid = sid_dup_talloc ( mem_ctx , domain_sid ) ;
NT_STATUS_HAVE_NO_MEMORY ( ctx - > domain_sid ) ;
ctx - > domain_sid_str = sid_string_talloc ( mem_ctx , ctx - > domain_sid ) ;
NT_STATUS_HAVE_NO_MEMORY ( ctx - > domain_sid_str ) ;
}
* ctx_p = ctx ;
return NT_STATUS_OK ;
}
2008-06-17 21:49:58 +04:00
/**
* samsync_database_str
*/
static const char * samsync_database_str ( enum netr_SamDatabaseID database_id )
{
switch ( database_id ) {
case SAM_DATABASE_DOMAIN :
return " DOMAIN " ;
case SAM_DATABASE_BUILTIN :
return " BUILTIN " ;
case SAM_DATABASE_PRIVS :
return " PRIVS " ;
default :
return " unknown " ;
}
}
2008-06-16 14:09:08 +04:00
/**
* samsync_debug_str
*/
static const char * samsync_debug_str ( TALLOC_CTX * mem_ctx ,
enum net_samsync_mode mode ,
enum netr_SamDatabaseID database_id )
{
const char * action = NULL ;
switch ( mode ) {
case NET_SAMSYNC_MODE_DUMP :
action = " Dumping (to stdout) " ;
break ;
case NET_SAMSYNC_MODE_FETCH_PASSDB :
action = " Fetching (to passdb) " ;
break ;
case NET_SAMSYNC_MODE_FETCH_LDIF :
action = " Fetching (to ldif) " ;
break ;
2008-06-18 14:52:00 +04:00
case NET_SAMSYNC_MODE_FETCH_KEYTAB :
action = " Fetching (to keytab) " ;
break ;
2008-06-16 14:09:08 +04:00
default :
action = " Unknown " ;
break ;
}
2008-06-17 21:49:58 +04:00
return talloc_asprintf ( mem_ctx , " %s %s database " ,
action , samsync_database_str ( database_id ) ) ;
2008-06-16 14:09:08 +04:00
}
/**
2008-06-23 19:03:53 +04:00
* libnet_samsync
2008-06-16 14:09:08 +04:00
*/
2008-12-09 16:48:10 +03:00
static void libnet_init_netr_ChangeLogEntry ( struct samsync_object * o ,
struct netr_ChangeLogEntry * e )
2008-11-04 17:49:27 +03:00
{
ZERO_STRUCTP ( e ) ;
e - > db_index = o - > database_id ;
e - > delta_type = o - > object_type ;
switch ( e - > delta_type ) {
case NETR_DELTA_DOMAIN :
case NETR_DELTA_DELETE_GROUP :
case NETR_DELTA_RENAME_GROUP :
case NETR_DELTA_DELETE_USER :
case NETR_DELTA_RENAME_USER :
case NETR_DELTA_DELETE_ALIAS :
case NETR_DELTA_RENAME_ALIAS :
case NETR_DELTA_DELETE_TRUST :
case NETR_DELTA_DELETE_ACCOUNT :
case NETR_DELTA_DELETE_SECRET :
case NETR_DELTA_DELETE_GROUP2 :
case NETR_DELTA_DELETE_USER2 :
case NETR_DELTA_MODIFY_COUNT :
break ;
case NETR_DELTA_USER :
case NETR_DELTA_GROUP :
case NETR_DELTA_GROUP_MEMBER :
case NETR_DELTA_ALIAS :
case NETR_DELTA_ALIAS_MEMBER :
e - > object_rid = o - > object_identifier . rid ;
break ;
case NETR_DELTA_SECRET :
e - > object . object_name = o - > object_identifier . name ;
e - > flags = NETR_CHANGELOG_NAME_INCLUDED ;
break ;
case NETR_DELTA_TRUSTED_DOMAIN :
case NETR_DELTA_ACCOUNT :
case NETR_DELTA_POLICY :
e - > object . object_sid = o - > object_identifier . sid ;
e - > flags = NETR_CHANGELOG_SID_INCLUDED ;
break ;
default :
break ;
}
}
/**
* libnet_samsync_delta
*/
2008-11-18 11:49:37 +03:00
static NTSTATUS libnet_samsync_delta ( TALLOC_CTX * mem_ctx ,
enum netr_SamDatabaseID database_id ,
uint64_t * sequence_num ,
2008-11-04 17:49:27 +03:00
struct samsync_context * ctx ,
struct netr_ChangeLogEntry * e )
2008-06-16 14:09:08 +04:00
{
NTSTATUS result ;
2008-11-17 19:14:19 +03:00
NTSTATUS callback_status ;
2008-06-23 19:29:01 +04:00
const char * logon_server = ctx - > cli - > desthost ;
2008-06-16 14:09:08 +04:00
const char * computername = global_myname ( ) ;
struct netr_Authenticator credential ;
struct netr_Authenticator return_authenticator ;
uint16_t restart_state = 0 ;
uint32_t sync_context = 0 ;
ZERO_STRUCT ( return_authenticator ) ;
do {
struct netr_DELTA_ENUM_ARRAY * delta_enum_array = NULL ;
2009-04-06 16:56:13 +04:00
netlogon_creds_client_authenticator ( ctx - > cli - > dc , & credential ) ;
2008-06-16 14:09:08 +04:00
2008-11-18 05:45:38 +03:00
if ( ctx - > single_object_replication & &
! ctx - > force_full_replication ) {
2008-11-04 17:49:27 +03:00
result = rpccli_netr_DatabaseRedo ( ctx - > cli , mem_ctx ,
logon_server ,
computername ,
& credential ,
& return_authenticator ,
* e ,
0 ,
& delta_enum_array ) ;
2008-11-18 11:49:37 +03:00
} else if ( ! ctx - > force_full_replication & &
sequence_num & & ( * sequence_num > 0 ) ) {
2008-11-18 05:45:38 +03:00
result = rpccli_netr_DatabaseDeltas ( ctx - > cli , mem_ctx ,
logon_server ,
computername ,
& credential ,
& return_authenticator ,
database_id ,
2008-11-18 11:49:37 +03:00
sequence_num ,
2008-11-18 05:45:38 +03:00
& delta_enum_array ,
0xffff ) ;
2008-11-04 17:49:27 +03:00
} else {
result = rpccli_netr_DatabaseSync2 ( ctx - > cli , mem_ctx ,
logon_server ,
computername ,
& credential ,
& return_authenticator ,
database_id ,
restart_state ,
& sync_context ,
& delta_enum_array ,
0xffff ) ;
}
2008-06-16 14:09:08 +04:00
if ( NT_STATUS_EQUAL ( result , NT_STATUS_NOT_SUPPORTED ) ) {
return result ;
}
/* Check returned credentials. */
2009-04-06 16:56:13 +04:00
if ( ! netlogon_creds_client_check ( ctx - > cli - > dc ,
& return_authenticator . cred ) ) {
2008-06-16 14:09:08 +04:00
DEBUG ( 0 , ( " credentials chain check failed \n " ) ) ;
return NT_STATUS_ACCESS_DENIED ;
}
if ( NT_STATUS_IS_ERR ( result ) ) {
break ;
}
samsync_fix_delta_array ( mem_ctx ,
2009-03-27 04:16:17 +03:00
ctx - > cli - > dc ,
2008-06-16 14:09:08 +04:00
database_id ,
delta_enum_array ) ;
/* Process results */
2008-11-17 18:31:59 +03:00
callback_status = ctx - > ops - > process_objects ( mem_ctx , database_id ,
delta_enum_array ,
2008-11-18 11:49:37 +03:00
sequence_num ,
2008-11-17 18:31:59 +03:00
ctx ) ;
2008-06-17 21:49:58 +04:00
if ( ! NT_STATUS_IS_OK ( callback_status ) ) {
result = callback_status ;
goto out ;
}
2008-06-16 14:09:08 +04:00
TALLOC_FREE ( delta_enum_array ) ;
} while ( NT_STATUS_EQUAL ( result , STATUS_MORE_ENTRIES ) ) ;
2008-06-17 21:49:58 +04:00
out :
2008-11-17 19:14:19 +03:00
2008-06-16 14:09:08 +04:00
return result ;
}
2008-06-17 23:22:06 +04:00
2008-11-04 17:49:27 +03:00
/**
* libnet_samsync
*/
NTSTATUS libnet_samsync ( enum netr_SamDatabaseID database_id ,
struct samsync_context * ctx )
{
NTSTATUS status = NT_STATUS_OK ;
2008-11-18 11:49:37 +03:00
NTSTATUS callback_status ;
TALLOC_CTX * mem_ctx ;
const char * debug_str ;
uint64_t sequence_num = 0 ;
2008-11-04 17:49:27 +03:00
int i = 0 ;
2008-11-18 11:49:37 +03:00
if ( ! ( mem_ctx = talloc_new ( ctx ) ) ) {
return NT_STATUS_NO_MEMORY ;
}
if ( ! ctx - > ops ) {
return NT_STATUS_INVALID_PARAMETER ;
}
if ( ctx - > ops - > startup ) {
status = ctx - > ops - > startup ( mem_ctx , ctx ,
database_id , & sequence_num ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto done ;
}
}
debug_str = samsync_debug_str ( mem_ctx , ctx - > mode , database_id ) ;
if ( debug_str ) {
d_fprintf ( stderr , " %s \n " , debug_str ) ;
}
2008-11-04 17:49:27 +03:00
if ( ! ctx - > single_object_replication ) {
2008-11-18 11:49:37 +03:00
status = libnet_samsync_delta ( mem_ctx , database_id ,
& sequence_num , ctx , NULL ) ;
goto done ;
2008-11-04 17:49:27 +03:00
}
for ( i = 0 ; i < ctx - > num_objects ; i + + ) {
struct netr_ChangeLogEntry e ;
if ( ctx - > objects [ i ] . database_id ! = database_id ) {
continue ;
}
libnet_init_netr_ChangeLogEntry ( & ctx - > objects [ i ] , & e ) ;
2008-11-18 11:49:37 +03:00
status = libnet_samsync_delta ( mem_ctx , database_id ,
& sequence_num , ctx , & e ) ;
2008-11-04 17:49:27 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-11-18 11:49:37 +03:00
goto done ;
2008-11-04 17:49:27 +03:00
}
}
2008-11-18 11:49:37 +03:00
done :
if ( NT_STATUS_IS_OK ( status ) & & ctx - > ops - > finish ) {
callback_status = ctx - > ops - > finish ( mem_ctx , ctx ,
database_id , sequence_num ) ;
if ( ! NT_STATUS_IS_OK ( callback_status ) ) {
status = callback_status ;
}
}
if ( NT_STATUS_IS_ERR ( status ) & & ! ctx - > error_message ) {
ctx - > error_message = talloc_asprintf ( ctx ,
" Failed to fetch %s database: %s " ,
samsync_database_str ( database_id ) ,
nt_errstr ( status ) ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_SUPPORTED ) ) {
ctx - > error_message =
talloc_asprintf_append ( ctx - > error_message ,
" \n Perhaps %s is a Windows native mode domain? " ,
ctx - > domain_name ) ;
}
}
talloc_destroy ( mem_ctx ) ;
2008-11-04 17:49:27 +03:00
return status ;
}
2008-06-17 23:22:06 +04:00
/**
* pull_netr_AcctLockStr
*/
NTSTATUS pull_netr_AcctLockStr ( TALLOC_CTX * mem_ctx ,
struct lsa_BinaryString * r ,
struct netr_AcctLockStr * * str_p )
{
struct netr_AcctLockStr * str ;
enum ndr_err_code ndr_err ;
DATA_BLOB blob ;
if ( ! mem_ctx | | ! r | | ! str_p ) {
return NT_STATUS_INVALID_PARAMETER ;
}
* str_p = NULL ;
str = TALLOC_ZERO_P ( mem_ctx , struct netr_AcctLockStr ) ;
if ( ! str ) {
return NT_STATUS_NO_MEMORY ;
}
blob = data_blob_const ( r - > array , r - > length ) ;
2008-09-23 11:49:56 +04:00
ndr_err = ndr_pull_struct_blob ( & blob , mem_ctx , NULL , str ,
2008-06-17 23:22:06 +04:00
( ndr_pull_flags_fn_t ) ndr_pull_netr_AcctLockStr ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return ndr_map_error2ntstatus ( ndr_err ) ;
}
* str_p = str ;
return NT_STATUS_OK ;
}