2007-04-23 04:43:47 +04:00
/*
2020-08-09 17:14:02 +03:00
Unix SMB / CIFS Implementation .
2007-04-23 04:43:47 +04:00
DSDB replication service outgoing Pull - Replication
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"
2020-11-20 17:27:17 +03:00
# include "samba/service.h"
2007-04-23 04:43:47 +04:00
# include "lib/events/events.h"
# include "dsdb/repl/drepl_service.h"
2011-02-10 06:12:51 +03:00
# include <ldb_errors.h>
2008-10-11 23:31:42 +04:00
# include "../lib/util/dlinklist.h"
2007-04-23 04:43:47 +04:00
# 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"
2010-09-20 11:42:13 +04:00
# include "libcli/security/security.h"
2007-04-23 04:43:47 +04:00
2017-09-06 07:37:34 +03:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_DRS_REPL
2010-11-17 15:13:32 +03:00
/*
update repsFrom / repsTo error information
*/
void drepl_reps_update ( struct dreplsrv_service * s , const char * reps_attr ,
struct ldb_dn * dn ,
struct GUID * source_dsa_obj_guid , WERROR status )
{
struct repsFromToBlob * reps ;
uint32_t count , i ;
WERROR werr ;
TALLOC_CTX * tmp_ctx = talloc_new ( s ) ;
time_t t ;
NTTIME now ;
t = time ( NULL ) ;
unix_to_nt_time ( & now , t ) ;
werr = dsdb_loadreps ( s - > samdb , tmp_ctx , dn , reps_attr , & reps , & count ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
talloc_free ( tmp_ctx ) ;
return ;
}
for ( i = 0 ; i < count ; i + + ) {
2014-06-05 14:04:43 +04:00
if ( GUID_equal ( source_dsa_obj_guid ,
& reps [ i ] . ctr . ctr1 . source_dsa_obj_guid ) ) {
2010-11-17 15:13:32 +03:00
break ;
}
}
if ( i = = count ) {
/* no record to update */
talloc_free ( tmp_ctx ) ;
return ;
}
/* only update the status fields */
reps [ i ] . ctr . ctr1 . last_attempt = now ;
reps [ i ] . ctr . ctr1 . result_last_attempt = status ;
if ( W_ERROR_IS_OK ( status ) ) {
reps [ i ] . ctr . ctr1 . last_success = now ;
reps [ i ] . ctr . ctr1 . consecutive_sync_failures = 0 ;
} else {
reps [ i ] . ctr . ctr1 . consecutive_sync_failures + + ;
}
werr = dsdb_savereps ( s - > samdb , tmp_ctx , dn , reps_attr , reps , count ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 2 , ( " drepl_reps_update: Failed to save %s for %s: %s \n " ,
reps_attr , ldb_dn_get_linearized ( dn ) , win_errstr ( werr ) ) ) ;
}
talloc_free ( tmp_ctx ) ;
}
2010-01-06 06:54:12 +03:00
WERROR dreplsrv_schedule_partition_pull_source ( struct dreplsrv_service * s ,
struct dreplsrv_partition_source_dsa * source ,
2011-02-26 21:36:19 +03:00
uint32_t options ,
2010-01-06 09:16:58 +03:00
enum drsuapi_DsExtendedOperation extended_op ,
uint64_t fsmo_info ,
2010-09-15 12:59:17 +04:00
dreplsrv_extended_callback_t callback ,
2010-08-31 01:01:25 +04:00
void * cb_data )
2007-04-23 04:43:47 +04:00
{
struct dreplsrv_out_operation * op ;
2010-01-06 06:54:12 +03:00
op = talloc_zero ( s , struct dreplsrv_out_operation ) ;
2007-04-23 04:43:47 +04:00
W_ERROR_HAVE_NO_MEMORY ( op ) ;
op - > service = s ;
2012-06-22 03:42:02 +04:00
/*
* source may either be the long - term list of partners , or
* from dreplsrv_partition_source_dsa_temporary ( ) . Because it
* can be either , we can ' t talloc_steal ( ) it here , so we
* instead we reference it .
*
* We never talloc_free ( ) the p - > sources pointers - indeed we
* never remove them - and the temp source will otherwise go
* away with the msg it is allocated on .
*
* Finally the pointer created in drepl_request_extended_op ( )
* is removed with talloc_unlink ( ) .
*
*/
op - > source_dsa = talloc_reference ( op , source ) ;
if ( ! op - > source_dsa ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2012-06-22 03:42:02 +04:00
}
2011-02-26 21:36:19 +03:00
op - > options = options ;
2010-01-06 06:54:12 +03:00
op - > extended_op = extended_op ;
2010-01-06 09:16:58 +03:00
op - > fsmo_info = fsmo_info ;
op - > callback = callback ;
2010-08-31 01:01:25 +04:00
op - > cb_data = cb_data ;
2010-11-17 15:12:10 +03:00
op - > schedule_time = time ( NULL ) ;
2017-06-15 07:52:33 +03:00
op - > more_flags = 0 ;
2007-04-23 04:43:47 +04:00
2016-02-05 13:32:18 +03:00
DLIST_ADD_END ( s - > ops . pending , op ) ;
2010-01-06 06:54:12 +03:00
2007-04-23 04:43:47 +04:00
return WERR_OK ;
}
static WERROR dreplsrv_schedule_partition_pull ( struct dreplsrv_service * s ,
struct dreplsrv_partition * p ,
TALLOC_CTX * mem_ctx )
{
WERROR status ;
struct dreplsrv_partition_source_dsa * cur ;
for ( cur = p - > sources ; cur ; cur = cur - > next ) {
2010-08-31 01:01:25 +04:00
status = dreplsrv_schedule_partition_pull_source ( s , cur ,
2011-02-26 21:36:19 +03:00
0 , DRSUAPI_EXOP_NONE , 0 ,
2010-08-31 01:01:25 +04:00
NULL , NULL ) ;
2007-04-23 04:43:47 +04:00
W_ERROR_NOT_OK_RETURN ( status ) ;
}
return WERR_OK ;
}
WERROR dreplsrv_schedule_pull_replication ( struct dreplsrv_service * s , TALLOC_CTX * mem_ctx )
{
WERROR status ;
struct dreplsrv_partition * p ;
for ( p = s - > partitions ; p ; p = p - > next ) {
status = dreplsrv_schedule_partition_pull ( s , p , mem_ctx ) ;
W_ERROR_NOT_OK_RETURN ( status ) ;
}
return WERR_OK ;
}
2009-09-09 12:04:07 +04:00
2009-12-30 19:11:51 +03:00
static void dreplsrv_pending_op_callback ( struct tevent_req * subreq )
2007-04-23 04:43:47 +04:00
{
2009-12-30 19:11:51 +03:00
struct dreplsrv_out_operation * op = tevent_req_callback_data ( subreq ,
struct dreplsrv_out_operation ) ;
2007-04-23 04:43:47 +04:00
struct repsFromTo1 * rf = op - > source_dsa - > repsFrom1 ;
struct dreplsrv_service * s = op - > service ;
2010-11-17 15:13:32 +03:00
WERROR werr ;
2007-04-23 04:43:47 +04:00
2010-11-17 15:13:32 +03:00
werr = dreplsrv_op_pull_source_recv ( subreq ) ;
2009-12-30 19:11:51 +03:00
TALLOC_FREE ( subreq ) ;
2007-04-23 04:43:47 +04:00
2010-11-17 15:13:32 +03:00
DEBUG ( 4 , ( " dreplsrv_op_pull_source(%s) for %s \n " , win_errstr ( werr ) ,
ldb_dn_get_linearized ( op - > source_dsa - > partition - > dn ) ) ) ;
2007-04-23 04:43:47 +04:00
2010-11-17 15:13:32 +03:00
if ( op - > extended_op = = DRSUAPI_EXOP_NONE ) {
drepl_reps_update ( s , " repsFrom " , op - > source_dsa - > partition - > dn ,
& rf - > source_dsa_obj_guid , werr ) ;
}
2007-04-23 04:43:47 +04:00
2010-01-06 09:16:58 +03:00
if ( op - > callback ) {
2010-11-17 15:13:32 +03:00
op - > callback ( s , werr , op - > extended_ret , op - > cb_data ) ;
2010-01-06 09:16:58 +03:00
}
2007-04-23 04:43:47 +04:00
talloc_free ( op ) ;
s - > ops . current = NULL ;
dreplsrv_run_pending_ops ( s ) ;
}
2010-11-17 15:12:10 +03:00
void dreplsrv_run_pull_ops ( struct dreplsrv_service * s )
2007-04-23 04:43:47 +04:00
{
struct dreplsrv_out_operation * op ;
time_t t ;
NTTIME now ;
2009-12-30 19:11:51 +03:00
struct tevent_req * subreq ;
2011-02-26 22:00:46 +03:00
WERROR werr ;
2007-04-23 04:43:47 +04:00
2017-07-22 13:00:59 +03:00
if ( s - > ops . n_current | | s - > ops . current ) {
2007-04-23 04:43:47 +04:00
/* if there's still one running, we're done */
return ;
}
if ( ! s - > ops . pending ) {
/* if there're no pending operations, we're done */
return ;
}
t = time ( NULL ) ;
unix_to_nt_time ( & now , t ) ;
op = s - > ops . pending ;
s - > ops . current = op ;
DLIST_REMOVE ( s - > ops . pending , op ) ;
op - > source_dsa - > repsFrom1 - > last_attempt = now ;
2011-02-26 22:00:46 +03:00
/* check if inbound replication is enabled */
if ( ! ( op - > options & DRSUAPI_DRS_SYNC_FORCED ) ) {
uint32_t rep_options ;
if ( samdb_ntds_options ( op - > service - > samdb , & rep_options ) ! = LDB_SUCCESS ) {
werr = WERR_DS_DRA_INTERNAL_ERROR ;
goto failed ;
2010-11-17 15:13:32 +03:00
}
2011-02-26 22:00:46 +03:00
if ( ( rep_options & DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL ) ) {
werr = WERR_DS_DRA_SINK_DISABLED ;
goto failed ;
2010-09-08 02:07:44 +04:00
}
2007-04-23 04:43:47 +04:00
}
2011-02-26 22:00:46 +03:00
subreq = dreplsrv_op_pull_source_send ( op , s - > task - > event_ctx , op ) ;
if ( ! subreq ) {
2015-12-03 17:24:18 +03:00
werr = WERR_NOT_ENOUGH_MEMORY ;
2011-02-26 22:00:46 +03:00
goto failed ;
}
2009-12-30 19:11:51 +03:00
tevent_req_set_callback ( subreq , dreplsrv_pending_op_callback , op ) ;
2011-02-26 22:00:46 +03:00
return ;
failed :
if ( op - > extended_op = = DRSUAPI_EXOP_NONE ) {
drepl_reps_update ( s , " repsFrom " , op - > source_dsa - > partition - > dn ,
& op - > source_dsa - > repsFrom1 - > source_dsa_obj_guid , werr ) ;
}
/* unblock queue processing */
s - > ops . current = NULL ;
/*
* let the callback do its job just like in any other failure situation
*/
if ( op - > callback ) {
op - > callback ( s , werr , op - > extended_ret , op - > cb_data ) ;
}
2007-04-23 04:43:47 +04:00
}