2007-04-23 04:43:47 +04:00
/*
Unix SMB / CIFS mplementation .
DSDB replication service helper function for outgoing traffic
Copyright ( C ) Stefan Metzmacher 2007
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-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2007-04-23 04:43:47 +04:00
( 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
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2007-04-23 04:43:47 +04:00
*/
# include "includes.h"
# include "dsdb/samdb/samdb.h"
# include "auth/auth.h"
# include "smbd/service.h"
# include "lib/events/events.h"
# include "lib/messaging/irpc.h"
# include "dsdb/repl/drepl_service.h"
# include "lib/ldb/include/ldb_errors.h"
# include "lib/util/dlinklist.h"
# include "librpc/gen_ndr/ndr_misc.h"
# include "librpc/gen_ndr/ndr_drsuapi.h"
# include "librpc/gen_ndr/ndr_drsblobs.h"
# include "libcli/composite/composite.h"
# include "auth/gensec/gensec.h"
struct dreplsrv_out_drsuapi_state {
struct composite_context * creq ;
struct dreplsrv_out_connection * conn ;
struct dreplsrv_drsuapi_connection * drsuapi ;
struct drsuapi_DsBindInfoCtr bind_info_ctr ;
struct drsuapi_DsBind bind_r ;
} ;
static void dreplsrv_out_drsuapi_connect_recv ( struct composite_context * creq ) ;
static struct composite_context * dreplsrv_out_drsuapi_send ( struct dreplsrv_out_connection * conn )
{
struct composite_context * c ;
struct composite_context * creq ;
struct dreplsrv_out_drsuapi_state * st ;
c = composite_create ( conn , conn - > service - > task - > event_ctx ) ;
if ( c = = NULL ) return NULL ;
st = talloc_zero ( c , struct dreplsrv_out_drsuapi_state ) ;
if ( composite_nomem ( st , c ) ) return c ;
c - > private_data = st ;
st - > creq = c ;
st - > conn = conn ;
st - > drsuapi = conn - > drsuapi ;
if ( st - > drsuapi & & ! st - > drsuapi - > pipe - > conn - > dead ) {
composite_done ( c ) ;
return c ;
} else if ( st - > drsuapi & & st - > drsuapi - > pipe - > conn - > dead ) {
talloc_free ( st - > drsuapi ) ;
conn - > drsuapi = NULL ;
}
st - > drsuapi = talloc_zero ( st , struct dreplsrv_drsuapi_connection ) ;
if ( composite_nomem ( st - > drsuapi , c ) ) return c ;
2007-08-20 01:23:03 +04:00
creq = dcerpc_pipe_connect_b_send ( st , conn - > binding , & ndr_table_drsuapi ,
2007-04-23 04:43:47 +04:00
conn - > service - > system_session_info - > credentials ,
2007-12-07 04:37:04 +03:00
c - > event_ctx , conn - > service - > task - > lp_ctx ) ;
2007-04-23 04:43:47 +04:00
composite_continue ( c , creq , dreplsrv_out_drsuapi_connect_recv , st ) ;
return c ;
}
static void dreplsrv_out_drsuapi_bind_send ( struct dreplsrv_out_drsuapi_state * st ) ;
static void dreplsrv_out_drsuapi_connect_recv ( struct composite_context * creq )
{
struct dreplsrv_out_drsuapi_state * st = talloc_get_type ( creq - > async . private_data ,
struct dreplsrv_out_drsuapi_state ) ;
struct composite_context * c = st - > creq ;
c - > status = dcerpc_pipe_connect_b_recv ( creq , st - > drsuapi , & st - > drsuapi - > pipe ) ;
if ( ! composite_is_ok ( c ) ) return ;
c - > status = gensec_session_key ( st - > drsuapi - > pipe - > conn - > security_state . generic_state ,
& st - > drsuapi - > gensec_skey ) ;
if ( ! composite_is_ok ( c ) ) return ;
dreplsrv_out_drsuapi_bind_send ( st ) ;
}
static void dreplsrv_out_drsuapi_bind_recv ( struct rpc_request * req ) ;
static void dreplsrv_out_drsuapi_bind_send ( struct dreplsrv_out_drsuapi_state * st )
{
struct composite_context * c = st - > creq ;
struct rpc_request * req ;
st - > bind_info_ctr . length = 28 ;
st - > bind_info_ctr . info . info28 = st - > conn - > service - > bind_info28 ;
st - > bind_r . in . bind_guid = & st - > conn - > service - > ntds_guid ;
st - > bind_r . in . bind_info = & st - > bind_info_ctr ;
st - > bind_r . out . bind_handle = & st - > drsuapi - > bind_handle ;
req = dcerpc_drsuapi_DsBind_send ( st - > drsuapi - > pipe , st , & st - > bind_r ) ;
composite_continue_rpc ( c , req , dreplsrv_out_drsuapi_bind_recv , st ) ;
}
static void dreplsrv_out_drsuapi_bind_recv ( struct rpc_request * req )
{
2007-05-16 18:52:54 +04:00
struct dreplsrv_out_drsuapi_state * st = talloc_get_type ( req - > async . private_data ,
2007-04-23 04:43:47 +04:00
struct dreplsrv_out_drsuapi_state ) ;
struct composite_context * c = st - > creq ;
c - > status = dcerpc_ndr_request_recv ( req ) ;
if ( ! composite_is_ok ( c ) ) return ;
if ( ! W_ERROR_IS_OK ( st - > bind_r . out . result ) ) {
composite_error ( c , werror_to_ntstatus ( st - > bind_r . out . result ) ) ;
return ;
}
ZERO_STRUCT ( st - > drsuapi - > remote_info28 ) ;
if ( st - > bind_r . out . bind_info ) {
switch ( st - > bind_r . out . bind_info - > length ) {
case 24 : {
struct drsuapi_DsBindInfo24 * info24 ;
info24 = & st - > bind_r . out . bind_info - > info . info24 ;
st - > drsuapi - > remote_info28 . supported_extensions = info24 - > supported_extensions ;
st - > drsuapi - > remote_info28 . site_guid = info24 - > site_guid ;
st - > drsuapi - > remote_info28 . u1 = info24 - > u1 ;
st - > drsuapi - > remote_info28 . repl_epoch = 0 ;
break ;
}
case 28 :
st - > drsuapi - > remote_info28 = st - > bind_r . out . bind_info - > info . info28 ;
break ;
}
}
composite_done ( c ) ;
}
static NTSTATUS dreplsrv_out_drsuapi_recv ( struct composite_context * c )
{
NTSTATUS status ;
struct dreplsrv_out_drsuapi_state * st = talloc_get_type ( c - > private_data ,
struct dreplsrv_out_drsuapi_state ) ;
status = composite_wait ( c ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
st - > conn - > drsuapi = talloc_steal ( st - > conn , st - > drsuapi ) ;
}
talloc_free ( c ) ;
return status ;
}
struct dreplsrv_op_pull_source_state {
struct composite_context * creq ;
struct dreplsrv_out_operation * op ;
struct dreplsrv_drsuapi_connection * drsuapi ;
bool have_all ;
uint32_t ctr_level ;
struct drsuapi_DsGetNCChangesCtr1 * ctr1 ;
struct drsuapi_DsGetNCChangesCtr6 * ctr6 ;
} ;
static void dreplsrv_op_pull_source_connect_recv ( struct composite_context * creq ) ;
struct composite_context * dreplsrv_op_pull_source_send ( struct dreplsrv_out_operation * op )
{
struct composite_context * c ;
struct composite_context * creq ;
struct dreplsrv_op_pull_source_state * st ;
c = composite_create ( op , op - > service - > task - > event_ctx ) ;
if ( c = = NULL ) return NULL ;
st = talloc_zero ( c , struct dreplsrv_op_pull_source_state ) ;
if ( composite_nomem ( st , c ) ) return c ;
st - > creq = c ;
st - > op = op ;
creq = dreplsrv_out_drsuapi_send ( op - > source_dsa - > conn ) ;
composite_continue ( c , creq , dreplsrv_op_pull_source_connect_recv , st ) ;
return c ;
}
static void dreplsrv_op_pull_source_get_changes_send ( struct dreplsrv_op_pull_source_state * st ) ;
static void dreplsrv_op_pull_source_connect_recv ( struct composite_context * creq )
{
struct dreplsrv_op_pull_source_state * st = talloc_get_type ( creq - > async . private_data ,
struct dreplsrv_op_pull_source_state ) ;
struct composite_context * c = st - > creq ;
c - > status = dreplsrv_out_drsuapi_recv ( creq ) ;
if ( ! composite_is_ok ( c ) ) return ;
dreplsrv_op_pull_source_get_changes_send ( st ) ;
}
static void dreplsrv_op_pull_source_get_changes_recv ( struct rpc_request * req ) ;
static void dreplsrv_op_pull_source_get_changes_send ( struct dreplsrv_op_pull_source_state * st )
{
struct composite_context * c = st - > creq ;
struct repsFromTo1 * rf1 = st - > op - > source_dsa - > repsFrom1 ;
struct dreplsrv_service * service = st - > op - > service ;
struct dreplsrv_partition * partition = st - > op - > source_dsa - > partition ;
struct dreplsrv_drsuapi_connection * drsuapi = st - > op - > source_dsa - > conn - > drsuapi ;
struct rpc_request * req ;
struct drsuapi_DsGetNCChanges * r ;
r = talloc ( st , struct drsuapi_DsGetNCChanges ) ;
if ( composite_nomem ( r , c ) ) return ;
r - > in . level = talloc ( r , int32_t ) ;
if ( composite_nomem ( r - > in . level , c ) ) return ;
r - > out . level = talloc ( r , int32_t ) ;
if ( composite_nomem ( r - > out . level , c ) ) return ;
r - > in . bind_handle = & drsuapi - > bind_handle ;
if ( drsuapi - > remote_info28 . supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8 ) {
* r - > in . level = 8 ;
r - > in . req . req8 . destination_dsa_guid = service - > ntds_guid ;
r - > in . req . req8 . source_dsa_invocation_id = rf1 - > source_dsa_invocation_id ;
r - > in . req . req8 . naming_context = & partition - > nc ;
r - > in . req . req8 . highwatermark = rf1 - > highwatermark ;
r - > in . req . req8 . uptodateness_vector = NULL ; /*&partition->uptodatevector_ex;*/
r - > in . req . req8 . replica_flags = rf1 - > replica_flags ;
r - > in . req . req8 . max_object_count = 133 ;
r - > in . req . req8 . max_ndr_size = 1336811 ;
r - > in . req . req8 . unknown4 = 0 ;
r - > in . req . req8 . h1 = 0 ;
r - > in . req . req8 . unique_ptr1 = 0 ;
r - > in . req . req8 . unique_ptr2 = 0 ;
r - > in . req . req8 . mapping_ctr . num_mappings = 0 ;
r - > in . req . req8 . mapping_ctr . mappings = NULL ;
} else {
* r - > in . level = 5 ;
r - > in . req . req5 . destination_dsa_guid = service - > ntds_guid ;
r - > in . req . req5 . source_dsa_invocation_id = rf1 - > source_dsa_invocation_id ;
r - > in . req . req5 . naming_context = & partition - > nc ;
r - > in . req . req5 . highwatermark = rf1 - > highwatermark ;
r - > in . req . req5 . uptodateness_vector = NULL ; /*&partition->uptodatevector_ex;*/
r - > in . req . req5 . replica_flags = rf1 - > replica_flags ;
r - > in . req . req5 . max_object_count = 133 ;
r - > in . req . req5 . max_ndr_size = 1336770 ;
r - > in . req . req5 . unknown4 = 0 ;
r - > in . req . req5 . h1 = 0 ;
}
req = dcerpc_drsuapi_DsGetNCChanges_send ( drsuapi - > pipe , r , r ) ;
composite_continue_rpc ( c , req , dreplsrv_op_pull_source_get_changes_recv , st ) ;
}
static void dreplsrv_op_pull_source_apply_changes_send ( struct dreplsrv_op_pull_source_state * st ,
struct drsuapi_DsGetNCChanges * r ,
uint32_t ctr_level ,
struct drsuapi_DsGetNCChangesCtr1 * ctr1 ,
struct drsuapi_DsGetNCChangesCtr6 * ctr6 ) ;
static void dreplsrv_op_pull_source_get_changes_recv ( struct rpc_request * req )
{
2007-05-16 18:52:54 +04:00
struct dreplsrv_op_pull_source_state * st = talloc_get_type ( req - > async . private_data ,
2007-04-23 04:43:47 +04:00
struct dreplsrv_op_pull_source_state ) ;
struct composite_context * c = st - > creq ;
struct drsuapi_DsGetNCChanges * r = talloc_get_type ( req - > ndr . struct_ptr ,
struct drsuapi_DsGetNCChanges ) ;
uint32_t ctr_level = 0 ;
struct drsuapi_DsGetNCChangesCtr1 * ctr1 = NULL ;
struct drsuapi_DsGetNCChangesCtr6 * ctr6 = NULL ;
c - > status = dcerpc_ndr_request_recv ( req ) ;
if ( ! composite_is_ok ( c ) ) return ;
if ( ! W_ERROR_IS_OK ( r - > out . result ) ) {
composite_error ( c , werror_to_ntstatus ( r - > out . result ) ) ;
return ;
}
if ( * r - > out . level = = 1 ) {
ctr_level = 1 ;
ctr1 = & r - > out . ctr . ctr1 ;
} else if ( * r - > out . level = = 2 ) {
ctr_level = 1 ;
ctr1 = r - > out . ctr . ctr2 . ctr . mszip1 . ctr1 ;
} else if ( * r - > out . level = = 6 ) {
ctr_level = 6 ;
ctr6 = & r - > out . ctr . ctr6 ;
} else if ( * r - > out . level = = 7 & &
r - > out . ctr . ctr7 . level = = 6 & &
r - > out . ctr . ctr7 . type = = DRSUAPI_COMPRESSION_TYPE_MSZIP ) {
ctr_level = 6 ;
ctr6 = r - > out . ctr . ctr7 . ctr . mszip6 . ctr6 ;
} else {
composite_error ( c , werror_to_ntstatus ( WERR_BAD_NET_RESP ) ) ;
return ;
}
dreplsrv_op_pull_source_apply_changes_send ( st , r , ctr_level , ctr1 , ctr6 ) ;
}
static void dreplsrv_op_pull_source_apply_changes_send ( struct dreplsrv_op_pull_source_state * st ,
struct drsuapi_DsGetNCChanges * r ,
uint32_t ctr_level ,
struct drsuapi_DsGetNCChangesCtr1 * ctr1 ,
struct drsuapi_DsGetNCChangesCtr6 * ctr6 )
{
struct composite_context * c = st - > creq ;
struct repsFromTo1 rf1 = * st - > op - > source_dsa - > repsFrom1 ;
struct dreplsrv_service * service = st - > op - > service ;
struct dreplsrv_partition * partition = st - > op - > source_dsa - > partition ;
struct dreplsrv_drsuapi_connection * drsuapi = st - > op - > source_dsa - > conn - > drsuapi ;
const struct drsuapi_DsReplicaOIDMapping_Ctr * mapping_ctr ;
uint32_t object_count ;
struct drsuapi_DsReplicaObjectListItemEx * first_object ;
uint32_t linked_attributes_count ;
struct drsuapi_DsReplicaLinkedAttribute * linked_attributes ;
const struct drsuapi_DsReplicaCursor2CtrEx * uptodateness_vector ;
bool more_data = false ;
WERROR status ;
switch ( ctr_level ) {
case 1 :
mapping_ctr = & ctr1 - > mapping_ctr ;
object_count = ctr1 - > object_count ;
first_object = ctr1 - > first_object ;
linked_attributes_count = 0 ;
linked_attributes = NULL ;
rf1 . highwatermark = ctr1 - > new_highwatermark ;
uptodateness_vector = NULL ; /* TODO: map it */
break ;
case 6 :
mapping_ctr = & ctr6 - > mapping_ctr ;
object_count = ctr6 - > object_count ;
first_object = ctr6 - > first_object ;
linked_attributes_count = ctr6 - > linked_attributes_count ;
linked_attributes = ctr6 - > linked_attributes ;
rf1 . highwatermark = ctr6 - > new_highwatermark ;
uptodateness_vector = ctr6 - > uptodateness_vector ;
break ;
default :
composite_error ( c , werror_to_ntstatus ( WERR_BAD_NET_RESP ) ) ;
return ;
}
status = dsdb_extended_replicated_objects_commit ( service - > samdb ,
partition - > nc . dn ,
mapping_ctr ,
object_count ,
first_object ,
linked_attributes_count ,
linked_attributes ,
& rf1 ,
uptodateness_vector ,
& drsuapi - > gensec_skey ,
st , NULL ) ;
if ( ! W_ERROR_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Failed to commit objects: %s \n " , win_errstr ( status ) ) ) ;
composite_error ( c , werror_to_ntstatus ( status ) ) ;
return ;
}
/* if it applied fine, we need to update the highwatermark */
* st - > op - > source_dsa - > repsFrom1 = rf1 ;
/*
* TODO : update our uptodatevector !
*/
/*
* if the tmp_highest_usn is higher than highest_usn
* there ' s more to pull from this source_dsa
*/
if ( rf1 . highwatermark . tmp_highest_usn > rf1 . highwatermark . highest_usn ) {
more_data = true ;
}
if ( more_data ) {
dreplsrv_op_pull_source_get_changes_send ( st ) ;
return ;
}
composite_done ( c ) ;
}
WERROR dreplsrv_op_pull_source_recv ( struct composite_context * c )
{
NTSTATUS status ;
status = composite_wait ( c ) ;
talloc_free ( c ) ;
return ntstatus_to_werror ( status ) ;
}