2024-08-02 02:26:49 +03:00
/*
2020-08-09 17:14:02 +03:00
Unix SMB / CIFS Implementation .
2009-09-11 15:46:58 +04:00
KCC service periodic handling
2024-08-02 02:26:49 +03:00
2009-09-11 15:46:58 +04:00
Copyright ( C ) Andrew Tridgell 2009
based on repl service code
2024-08-02 02:26:49 +03:00
2009-09-11 15:46:58 +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 3 of the License , or
( at your option ) any later version .
2024-08-02 02:26:49 +03:00
2009-09-11 15:46:58 +04:00
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 .
2024-08-02 02:26:49 +03:00
2009-09-11 15:46:58 +04:00
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2024-08-02 02:26:49 +03:00
2009-09-11 15:46:58 +04:00
*/
# include "includes.h"
# include "lib/events/events.h"
# include "dsdb/samdb/samdb.h"
# include "auth/auth.h"
2020-11-20 17:27:17 +03:00
# include "samba/service.h"
2009-09-11 15:46:58 +04:00
# include "lib/messaging/irpc.h"
2009-11-30 12:12:24 +03:00
# include "dsdb/kcc/kcc_connection.h"
2009-09-11 15:46:58 +04:00
# include "dsdb/kcc/kcc_service.h"
2011-02-10 06:12:51 +03:00
# include <ldb_errors.h>
2009-09-11 15:46:58 +04:00
# 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"
2010-09-03 13:34:17 +04:00
# include "librpc/gen_ndr/ndr_irpc_c.h"
2009-09-11 15:46:58 +04:00
# include "param/param.h"
2011-09-28 10:45:17 +04:00
# include "dsdb/common/util.h"
2009-09-11 15:46:58 +04:00
2010-09-30 09:03:35 +04:00
/*
* see if two repsFromToBlob blobs are for the same source DSA
*/
static bool kccsrv_same_source_dsa ( struct repsFromToBlob * r1 , struct repsFromToBlob * r2 )
{
2014-06-05 14:04:43 +04:00
return GUID_equal ( & r1 - > ctr . ctr1 . source_dsa_obj_guid ,
& r2 - > ctr . ctr1 . source_dsa_obj_guid ) ;
2010-09-30 09:03:35 +04:00
}
2009-09-11 15:46:58 +04:00
/*
2009-09-12 05:09:10 +04:00
* see if a repsFromToBlob is in a list
2009-09-11 15:46:58 +04:00
*/
2009-09-12 05:09:10 +04:00
static bool reps_in_list ( struct repsFromToBlob * r , struct repsFromToBlob * reps , uint32_t count )
{
2010-03-16 10:49:22 +03:00
uint32_t i ;
2009-09-12 05:09:10 +04:00
for ( i = 0 ; i < count ; i + + ) {
2010-09-30 09:03:35 +04:00
if ( kccsrv_same_source_dsa ( r , & reps [ i ] ) ) {
2009-09-12 05:09:10 +04:00
return true ;
}
}
return false ;
}
2009-09-11 15:46:58 +04:00
2010-04-26 16:51:11 +04:00
/*
make sure we only add repsFrom entries for DCs who are masters for
the partition
*/
2016-07-18 04:10:23 +03:00
static bool check_MasterNC ( struct kccsrv_service * service , struct dsdb_ldb_dn_list_node * p , struct repsFromToBlob * r ,
2010-04-26 16:51:11 +04:00
struct ldb_result * res )
{
2010-08-27 18:25:56 +04:00
struct repsFromTo1 * r1 = & r - > ctr . ctr1 ;
2010-04-26 16:51:11 +04:00
struct GUID invocation_id = r1 - > source_dsa_invocation_id ;
2010-04-27 10:19:10 +04:00
unsigned int i , j ;
2012-08-17 16:47:44 +04:00
TALLOC_CTX * tmp_ctx ;
2010-04-26 16:51:11 +04:00
2010-08-27 18:25:56 +04:00
/* we are expecting only version 1 */
SMB_ASSERT ( r - > version = = 1 ) ;
2012-08-17 16:47:44 +04:00
tmp_ctx = talloc_new ( p ) ;
if ( ! tmp_ctx ) {
return false ;
}
2010-04-26 16:51:11 +04:00
for ( i = 0 ; i < res - > count ; i + + ) {
struct ldb_message * msg = res - > msgs [ i ] ;
struct ldb_message_element * el ;
struct ldb_dn * dn ;
struct GUID id2 = samdb_result_guid ( msg , " invocationID " ) ;
2010-09-20 08:48:35 +04:00
if ( GUID_all_zero ( & id2 ) | |
! GUID_equal ( & invocation_id , & id2 ) ) {
2010-04-26 16:51:11 +04:00
continue ;
}
2010-10-01 00:16:19 +04:00
el = ldb_msg_find_element ( msg , " msDS-hasMasterNCs " ) ;
2010-04-26 16:51:11 +04:00
if ( ! el | | el - > num_values = = 0 ) {
2010-10-01 00:16:19 +04:00
el = ldb_msg_find_element ( msg , " hasMasterNCs " ) ;
if ( ! el | | el - > num_values = = 0 ) {
continue ;
}
2010-04-26 16:51:11 +04:00
}
for ( j = 0 ; j < el - > num_values ; j + + ) {
2016-07-18 04:10:23 +03:00
dn = ldb_dn_from_ldb_val ( tmp_ctx , service - > samdb , & el - > values [ j ] ) ;
2010-04-26 16:51:11 +04:00
if ( ! ldb_dn_validate ( dn ) ) {
talloc_free ( dn ) ;
continue ;
}
if ( ldb_dn_compare ( dn , p - > dn ) = = 0 ) {
2010-10-01 00:16:19 +04:00
DEBUG ( 5 , ( " %s %s match on %s in %s \n " ,
r1 - > other_info - > dns_name ,
el - > name ,
ldb_dn_get_linearized ( dn ) ,
2010-09-20 08:48:35 +04:00
ldb_dn_get_linearized ( msg - > dn ) ) ) ;
2012-08-17 16:47:44 +04:00
talloc_free ( tmp_ctx ) ;
2010-04-26 16:51:11 +04:00
return true ;
}
talloc_free ( dn ) ;
}
}
2012-08-17 16:47:44 +04:00
talloc_free ( tmp_ctx ) ;
2010-04-26 16:51:11 +04:00
return false ;
}
2010-09-03 13:34:17 +04:00
struct kccsrv_notify_drepl_server_state {
struct dreplsrv_refresh r ;
} ;
static void kccsrv_notify_drepl_server_done ( struct tevent_req * subreq ) ;
2009-09-11 15:46:58 +04:00
2010-08-28 21:02:13 +04:00
/**
* Force dreplsrv to update its state as topology is changed
*/
static void kccsrv_notify_drepl_server ( struct kccsrv_service * s ,
TALLOC_CTX * mem_ctx )
{
2010-09-03 13:34:17 +04:00
struct kccsrv_notify_drepl_server_state * state ;
struct dcerpc_binding_handle * irpc_handle ;
struct tevent_req * subreq ;
2010-08-28 21:02:13 +04:00
2010-09-09 02:43:01 +04:00
state = talloc_zero ( s , struct kccsrv_notify_drepl_server_state ) ;
2010-09-03 13:34:17 +04:00
if ( state = = NULL ) {
return ;
}
irpc_handle = irpc_binding_handle_by_name ( state , s - > task - > msg_ctx ,
" dreplsrv " , & ndr_table_irpc ) ;
if ( irpc_handle = = NULL ) {
2010-08-28 21:02:13 +04:00
/* dreplsrv is not running yet */
2010-09-03 13:34:17 +04:00
TALLOC_FREE ( state ) ;
2010-08-28 21:02:13 +04:00
return ;
}
2010-09-03 13:34:17 +04:00
subreq = dcerpc_dreplsrv_refresh_r_send ( state , s - > task - > event_ctx ,
irpc_handle , & state - > r ) ;
if ( subreq = = NULL ) {
TALLOC_FREE ( state ) ;
return ;
}
tevent_req_set_callback ( subreq , kccsrv_notify_drepl_server_done , state ) ;
}
static void kccsrv_notify_drepl_server_done ( struct tevent_req * subreq )
{
struct kccsrv_notify_drepl_server_state * state =
tevent_req_callback_data ( subreq ,
struct kccsrv_notify_drepl_server_state ) ;
2013-05-17 16:22:15 +04:00
dcerpc_dreplsrv_refresh_r_recv ( subreq , state ) ;
2010-09-03 13:34:17 +04:00
TALLOC_FREE ( subreq ) ;
/* we don't care about errors */
TALLOC_FREE ( state ) ;
2010-08-28 21:02:13 +04:00
}
2011-07-06 06:31:45 +04:00
uint32_t kccsrv_replica_flags ( struct kccsrv_service * s )
2010-09-30 09:03:35 +04:00
{
if ( s - > am_rodc ) {
return DRSUAPI_DRS_INIT_SYNC |
DRSUAPI_DRS_PER_SYNC |
DRSUAPI_DRS_ADD_REF |
DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING |
DRSUAPI_DRS_NONGC_RO_REP ;
}
return DRSUAPI_DRS_INIT_SYNC |
DRSUAPI_DRS_PER_SYNC |
DRSUAPI_DRS_ADD_REF |
DRSUAPI_DRS_WRIT_REP ;
}
2009-09-12 05:09:10 +04:00
/*
* add any missing repsFrom structures to our partitions
*/
2011-07-06 06:31:45 +04:00
NTSTATUS kccsrv_add_repsFrom ( struct kccsrv_service * s , TALLOC_CTX * mem_ctx ,
struct repsFromToBlob * reps , uint32_t count ,
struct ldb_result * res )
2009-09-12 05:09:10 +04:00
{
2016-07-18 04:10:23 +03:00
struct dsdb_ldb_dn_list_node * p ;
2010-08-28 21:02:13 +04:00
bool notify_dreplsrv = false ;
2010-09-30 09:03:35 +04:00
uint32_t replica_flags = kccsrv_replica_flags ( s ) ;
2009-09-12 05:09:10 +04:00
/* update the repsFrom on all partitions */
for ( p = s - > partitions ; p ; p = p - > next ) {
2010-09-30 09:03:35 +04:00
struct repsFromToBlob * our_reps ;
uint32_t our_count ;
2009-09-12 05:09:10 +04:00
WERROR werr ;
2010-09-30 09:03:35 +04:00
uint32_t i , j ;
2009-09-12 05:09:10 +04:00
bool modified = false ;
2010-09-30 09:03:35 +04:00
werr = dsdb_loadreps ( s - > samdb , mem_ctx , p - > dn , " repsFrom " , & our_reps , & our_count ) ;
2009-09-12 05:09:10 +04:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
2024-08-02 02:26:49 +03:00
DEBUG ( 0 , ( __location__ " : Failed to load repsFrom from %s - %s \n " ,
2009-09-12 05:09:10 +04:00
ldb_dn_get_linearized ( p - > dn ) , ldb_errstring ( s - > samdb ) ) ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
2010-09-30 09:03:35 +04:00
/* see if the entry already exists */
2009-09-12 05:09:10 +04:00
for ( i = 0 ; i < count ; i + + ) {
2010-09-30 09:03:35 +04:00
for ( j = 0 ; j < our_count ; j + + ) {
if ( kccsrv_same_source_dsa ( & reps [ i ] , & our_reps [ j ] ) ) {
/* we already have this one -
check the replica_flags are right */
if ( replica_flags ! = our_reps [ j ] . ctr . ctr1 . replica_flags ) {
/* we need to update the old one with
* the new flags
*/
our_reps [ j ] . ctr . ctr1 . replica_flags = replica_flags ;
modified = true ;
}
break ;
}
}
if ( j = = our_count ) {
/* we don't have the new one - add it
* if it is a master
*/
2016-07-18 04:10:23 +03:00
if ( res & & ! check_MasterNC ( s , p , & reps [ i ] , res ) ) {
2010-09-30 09:03:35 +04:00
/* its not a master, we don't
want to pull from it */
continue ;
}
/* we need to add it to our repsFrom */
our_reps = talloc_realloc ( mem_ctx , our_reps , struct repsFromToBlob , our_count + 1 ) ;
NT_STATUS_HAVE_NO_MEMORY ( our_reps ) ;
our_reps [ our_count ] = reps [ i ] ;
our_reps [ our_count ] . ctr . ctr1 . replica_flags = replica_flags ;
our_count + + ;
2009-09-12 05:09:10 +04:00
modified = true ;
2010-09-30 09:03:35 +04:00
DEBUG ( 4 , ( __location__ " : Added repsFrom for %s \n " ,
reps [ i ] . ctr . ctr1 . other_info - > dns_name ) ) ;
2009-09-12 05:09:10 +04:00
}
}
2009-09-28 07:10:13 +04:00
/* remove any stale ones */
2010-09-30 09:03:35 +04:00
for ( i = 0 ; i < our_count ; i + + ) {
if ( ! reps_in_list ( & our_reps [ i ] , reps , count ) | |
2016-07-18 04:10:23 +03:00
( res & & ! check_MasterNC ( s , p , & our_reps [ i ] , res ) ) ) {
2010-09-30 09:03:35 +04:00
DEBUG ( 4 , ( __location__ " : Removed repsFrom for %s \n " ,
our_reps [ i ] . ctr . ctr1 . other_info - > dns_name ) ) ;
memmove ( & our_reps [ i ] , & our_reps [ i + 1 ] , ( our_count - ( i + 1 ) ) * sizeof ( our_reps [ 0 ] ) ) ;
our_count - - ;
2009-09-28 07:10:13 +04:00
i - - ;
modified = true ;
}
}
2010-09-30 09:03:35 +04:00
2009-09-12 05:09:10 +04:00
if ( modified ) {
2010-09-30 09:03:35 +04:00
werr = dsdb_savereps ( s - > samdb , mem_ctx , p - > dn , " repsFrom " , our_reps , our_count ) ;
2009-09-12 05:09:10 +04:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
2024-08-02 02:26:49 +03:00
DEBUG ( 0 , ( __location__ " : Failed to save repsFrom to %s - %s \n " ,
2009-09-12 05:09:10 +04:00
ldb_dn_get_linearized ( p - > dn ) , ldb_errstring ( s - > samdb ) ) ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
2010-08-28 21:02:13 +04:00
/* dreplsrv should refresh its state */
notify_dreplsrv = true ;
2009-09-12 05:09:10 +04:00
}
2010-10-02 01:20:57 +04:00
/* remove stale repsTo entries */
modified = false ;
werr = dsdb_loadreps ( s - > samdb , mem_ctx , p - > dn , " repsTo " , & our_reps , & our_count ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
2024-08-02 02:26:49 +03:00
DEBUG ( 0 , ( __location__ " : Failed to load repsTo from %s - %s \n " ,
2010-10-02 01:20:57 +04:00
ldb_dn_get_linearized ( p - > dn ) , ldb_errstring ( s - > samdb ) ) ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
/* remove any stale ones */
for ( i = 0 ; i < our_count ; i + + ) {
if ( ! reps_in_list ( & our_reps [ i ] , reps , count ) ) {
DEBUG ( 4 , ( __location__ " : Removed repsTo for %s \n " ,
our_reps [ i ] . ctr . ctr1 . other_info - > dns_name ) ) ;
memmove ( & our_reps [ i ] , & our_reps [ i + 1 ] , ( our_count - ( i + 1 ) ) * sizeof ( our_reps [ 0 ] ) ) ;
our_count - - ;
i - - ;
modified = true ;
}
}
if ( modified ) {
werr = dsdb_savereps ( s - > samdb , mem_ctx , p - > dn , " repsTo " , our_reps , our_count ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
2024-08-02 02:26:49 +03:00
DEBUG ( 0 , ( __location__ " : Failed to save repsTo to %s - %s \n " ,
2010-10-02 01:20:57 +04:00
ldb_dn_get_linearized ( p - > dn ) , ldb_errstring ( s - > samdb ) ) ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
/* dreplsrv should refresh its state */
notify_dreplsrv = true ;
}
2009-09-12 05:09:10 +04:00
}
2010-08-28 21:02:13 +04:00
/* notify dreplsrv toplogy has changed */
if ( notify_dreplsrv ) {
kccsrv_notify_drepl_server ( s , mem_ctx ) ;
}
2009-09-12 05:09:10 +04:00
return NT_STATUS_OK ;
}
2011-09-28 10:45:17 +04:00
/*
form a unique list of DNs from a search result and a given set of attributes
*/
static int kccsrv_dn_list ( struct ldb_context * ldb , struct ldb_result * res ,
TALLOC_CTX * mem_ctx ,
const char * * attrs ,
struct ldb_dn * * * dn_list , int * dn_count )
{
int i ;
struct ldb_dn * * nc_list = NULL ;
int nc_count = 0 ;
nc_list = talloc_array ( mem_ctx , struct ldb_dn * , 0 ) ;
if ( nc_list = = NULL ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
/* gather up a list of all NCs in this forest */
for ( i = 0 ; i < res - > count ; i + + ) {
struct ldb_message * msg = res - > msgs [ i ] ;
int j ;
for ( j = 0 ; attrs [ j ] ; j + + ) {
struct ldb_message_element * el ;
int k ;
el = ldb_msg_find_element ( msg , attrs [ j ] ) ;
if ( el = = NULL ) continue ;
for ( k = 0 ; k < el - > num_values ; k + + ) {
struct ldb_dn * dn ;
dn = ldb_dn_from_ldb_val ( nc_list , ldb , & el - > values [ k ] ) ;
if ( dn ! = NULL ) {
int l ;
for ( l = 0 ; l < nc_count ; l + + ) {
if ( ldb_dn_compare ( nc_list [ l ] , dn ) = = 0 ) break ;
}
if ( l < nc_count ) continue ;
nc_list = talloc_realloc ( mem_ctx , nc_list , struct ldb_dn * , nc_count + 1 ) ;
if ( nc_list = = NULL ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
nc_list [ nc_count ] = dn ;
nc_count + + ;
}
}
}
}
( * dn_list ) = nc_list ;
( * dn_count ) = nc_count ;
return LDB_SUCCESS ;
}
/*
look for any additional global catalog partitions that we should be
replicating ( by looking for msDS - HasDomainNCs ) , and add them to our
hasPartialReplicaNCs NTDS attribute
*/
static int kccsrv_gc_update ( struct kccsrv_service * s , struct ldb_result * res )
{
int i ;
struct ldb_dn * * nc_list = NULL ;
int nc_count = 0 ;
struct ldb_dn * * our_nc_list = NULL ;
int our_nc_count = 0 ;
const char * attrs1 [ ] = { " msDS-hasMasterNCs " , " hasMasterNCs " , " msDS-HasDomainNCs " , NULL } ;
const char * attrs2 [ ] = { " msDS-hasMasterNCs " , " hasMasterNCs " , " msDS-HasDomainNCs " , " hasPartialReplicaNCs " , NULL } ;
int ret ;
TALLOC_CTX * tmp_ctx = talloc_new ( res ) ;
struct ldb_result * res2 ;
struct ldb_message * msg ;
/* get a complete list of NCs for the forest */
ret = kccsrv_dn_list ( s - > samdb , res , tmp_ctx , attrs1 , & nc_list , & nc_count ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 1 , ( " Failed to get NC list for GC update - %s \n " , ldb_errstring ( s - > samdb ) ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
/* get a list of what NCs we are already replicating */
2012-08-14 10:08:47 +04:00
ret = dsdb_search_dn ( s - > samdb , tmp_ctx , & res2 , samdb_ntds_settings_dn ( s - > samdb , tmp_ctx ) , attrs2 , 0 ) ;
2011-09-28 10:45:17 +04:00
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 1 , ( " Failed to get our NC list attributes for GC update - %s \n " , ldb_errstring ( s - > samdb ) ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
ret = kccsrv_dn_list ( s - > samdb , res2 , tmp_ctx , attrs2 , & our_nc_list , & our_nc_count ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 1 , ( " Failed to get our NC list for GC update - %s \n " , ldb_errstring ( s - > samdb ) ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
msg = ldb_msg_new ( tmp_ctx ) ;
if ( msg = = NULL ) {
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
msg - > dn = res2 - > msgs [ 0 ] - > dn ;
/* see if we are missing any */
for ( i = 0 ; i < nc_count ; i + + ) {
int j ;
for ( j = 0 ; j < our_nc_count ; j + + ) {
if ( ldb_dn_compare ( nc_list [ i ] , our_nc_list [ j ] ) = = 0 ) break ;
}
if ( j = = our_nc_count ) {
/* its a new one */
ret = ldb_msg_add_string ( msg , " hasPartialReplicaNCs " ,
ldb_dn_get_extended_linearized ( msg , nc_list [ i ] , 1 ) ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
}
}
if ( msg - > num_elements = = 0 ) {
/* none to add */
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2012-04-19 12:51:24 +04:00
if ( s - > am_rodc ) {
DEBUG ( 5 , ( " %d partial replica should be added but we are RODC so we skip \n " , msg - > num_elements ) ) ;
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2011-09-28 10:45:17 +04:00
msg - > elements [ 0 ] . flags = LDB_FLAG_MOD_ADD ;
ret = dsdb_modify ( s - > samdb , msg , 0 ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( " Failed to add hasPartialReplicaNCs - %s \n " ,
ldb_errstring ( s - > samdb ) ) ) ;
}
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-09-11 15:46:58 +04:00
/*
this is the core of our initial simple KCC
We just add a repsFrom entry for all DCs we find that have nTDSDSA
objects , except for ourselves
*/
2009-11-11 23:25:13 +03:00
NTSTATUS kccsrv_simple_update ( struct kccsrv_service * s , TALLOC_CTX * mem_ctx )
2009-09-11 15:46:58 +04:00
{
struct ldb_result * res ;
2009-11-06 22:14:41 +03:00
unsigned int i ;
int ret ;
2011-09-28 10:45:17 +04:00
const char * attrs [ ] = { " objectGUID " , " invocationID " , " msDS-hasMasterNCs " , " hasMasterNCs " , " msDS-HasDomainNCs " , NULL } ;
2009-09-12 05:09:10 +04:00
struct repsFromToBlob * reps = NULL ;
uint32_t count = 0 ;
2009-11-30 12:12:24 +03:00
struct kcc_connection_list * ntds_conn , * dsa_conn ;
2009-09-11 15:46:58 +04:00
2011-09-28 10:45:17 +04:00
ret = dsdb_search ( s - > samdb , mem_ctx , & res , s - > config_dn , LDB_SCOPE_SUBTREE ,
attrs , DSDB_SEARCH_SHOW_EXTENDED_DN , " objectClass=nTDSDSA " ) ;
2009-09-11 15:46:58 +04:00
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed nTDSDSA search - %s \n " , ldb_errstring ( s - > samdb ) ) ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
2011-09-28 10:45:17 +04:00
if ( samdb_is_gc ( s - > samdb ) ) {
kccsrv_gc_update ( s , res ) ;
}
2009-11-30 12:12:24 +03:00
/* get the current list of connections */
ntds_conn = kccsrv_find_connections ( s , mem_ctx ) ;
dsa_conn = talloc_zero ( mem_ctx , struct kcc_connection_list ) ;
2009-09-11 15:46:58 +04:00
for ( i = 0 ; i < res - > count ; i + + ) {
struct repsFromTo1 * r1 ;
struct GUID ntds_guid , invocation_id ;
ntds_guid = samdb_result_guid ( res - > msgs [ i ] , " objectGUID " ) ;
2014-06-05 14:04:43 +04:00
if ( GUID_equal ( & ntds_guid , & s - > ntds_guid ) ) {
2009-09-11 15:46:58 +04:00
/* don't replicate with ourselves */
continue ;
}
invocation_id = samdb_result_guid ( res - > msgs [ i ] , " invocationID " ) ;
2009-09-12 05:09:10 +04:00
reps = talloc_realloc ( mem_ctx , reps , struct repsFromToBlob , count + 1 ) ;
NT_STATUS_HAVE_NO_MEMORY ( reps ) ;
ZERO_STRUCT ( reps [ count ] ) ;
reps [ count ] . version = 1 ;
r1 = & reps [ count ] . ctr . ctr1 ;
2009-09-11 15:46:58 +04:00
2009-09-28 09:16:06 +04:00
r1 - > other_info = talloc_zero ( reps , struct repsFromTo1OtherInfo ) ;
2011-08-22 11:29:54 +04:00
r1 - > other_info - > dns_name = samdb_ntds_msdcs_dns_name ( s - > samdb , reps , & ntds_guid ) ;
2009-09-11 15:46:58 +04:00
r1 - > source_dsa_obj_guid = ntds_guid ;
r1 - > source_dsa_invocation_id = invocation_id ;
2010-09-30 09:03:35 +04:00
r1 - > replica_flags = kccsrv_replica_flags ( s ) ;
2009-09-11 15:46:58 +04:00
memset ( r1 - > schedule , 0x11 , sizeof ( r1 - > schedule ) ) ;
2009-11-30 12:12:24 +03:00
dsa_conn - > servers = talloc_realloc ( dsa_conn , dsa_conn - > servers ,
struct kcc_connection ,
dsa_conn - > count + 1 ) ;
NT_STATUS_HAVE_NO_MEMORY ( dsa_conn - > servers ) ;
dsa_conn - > servers [ dsa_conn - > count ] . dsa_guid = r1 - > source_dsa_obj_guid ;
dsa_conn - > count + + ;
2009-09-12 05:09:10 +04:00
count + + ;
2009-09-11 15:46:58 +04:00
}
2009-11-30 12:12:24 +03:00
kccsrv_apply_connections ( s , ntds_conn , dsa_conn ) ;
2009-11-30 12:11:27 +03:00
2010-04-26 16:51:11 +04:00
return kccsrv_add_repsFrom ( s , mem_ctx , reps , count , res ) ;
2009-09-11 15:46:58 +04:00
}
static void kccsrv_periodic_run ( struct kccsrv_service * service ) ;
static void kccsrv_periodic_handler_te ( struct tevent_context * ev , struct tevent_timer * te ,
struct timeval t , void * ptr )
{
struct kccsrv_service * service = talloc_get_type ( ptr , struct kccsrv_service ) ;
WERROR status ;
service - > periodic . te = NULL ;
kccsrv_periodic_run ( service ) ;
status = kccsrv_periodic_schedule ( service , service - > periodic . interval ) ;
if ( ! W_ERROR_IS_OK ( status ) ) {
2009-09-19 05:05:55 +04:00
task_server_terminate ( service - > task , win_errstr ( status ) , true ) ;
2009-09-11 15:46:58 +04:00
return ;
}
}
WERROR kccsrv_periodic_schedule ( struct kccsrv_service * service , uint32_t next_interval )
{
TALLOC_CTX * tmp_mem ;
struct tevent_timer * new_te ;
struct timeval next_time ;
/* prevent looping */
if ( next_interval = = 0 ) next_interval = 1 ;
next_time = timeval_current_ofs ( next_interval , 50 ) ;
if ( service - > periodic . te ) {
/*
* if the timestamp of the new event is higher ,
* as current next we don ' t need to reschedule
*/
if ( timeval_compare ( & next_time , & service - > periodic . next_event ) > 0 ) {
return WERR_OK ;
}
}
/* reset the next scheduled timestamp */
service - > periodic . next_event = next_time ;
2010-05-25 23:26:00 +04:00
new_te = tevent_add_timer ( service - > task - > event_ctx , service ,
2009-09-11 15:46:58 +04:00
service - > periodic . next_event ,
kccsrv_periodic_handler_te , service ) ;
W_ERROR_HAVE_NO_MEMORY ( new_te ) ;
tmp_mem = talloc_new ( service ) ;
2010-11-08 08:02:21 +03:00
DEBUG ( 4 , ( " kccsrv_periodic_schedule(%u) %sscheduled for: %s \n " ,
2009-09-11 15:46:58 +04:00
next_interval ,
( service - > periodic . te ? " re " : " " ) ,
nt_time_string ( tmp_mem , timeval_to_nttime ( & next_time ) ) ) ) ;
talloc_free ( tmp_mem ) ;
talloc_free ( service - > periodic . te ) ;
service - > periodic . te = new_te ;
return WERR_OK ;
}
2018-05-29 06:50:19 +03:00
/*
2021-04-10 05:08:09 +03:00
* Check to see if any dns entries need scavenging . This only occurs if aging
* is enabled in general ( " zone scavenging " lpcfg ) and on the zone
* ( zone - > fAging is true ) .
2018-05-29 06:50:19 +03:00
*/
static NTSTATUS kccsrv_dns_zone_scavenging (
struct kccsrv_service * s ,
TALLOC_CTX * mem_ctx )
{
time_t current_time = time ( NULL ) ;
time_t dns_scavenge_interval ;
NTSTATUS status ;
char * error_string = NULL ;
/*
* Only perform zone scavenging if it ' s been enabled .
2021-04-10 05:08:09 +03:00
* ( it still might be disabled on all zones ) .
2018-05-29 06:50:19 +03:00
*/
if ( ! lpcfg_dns_zone_scavenging ( s - > task - > lp_ctx ) ) {
2023-03-07 00:38:27 +03:00
DBG_INFO ( " DNS scavenging not enabled \n " ) ;
2018-05-29 06:50:19 +03:00
return NT_STATUS_OK ;
}
dns_scavenge_interval = lpcfg_parm_int ( s - > task - > lp_ctx ,
NULL ,
" dnsserver " ,
" scavenging_interval " ,
2 * 60 * 60 ) ;
if ( ( current_time - s - > last_dns_scavenge ) > dns_scavenge_interval ) {
s - > last_dns_scavenge = current_time ;
status = dns_tombstone_records ( mem_ctx , s - > samdb ,
& error_string ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
const char * err = NULL ;
if ( error_string ! = NULL ) {
err = error_string ;
} else {
err = nt_errstr ( status ) ;
}
2023-03-07 00:38:27 +03:00
DBG_ERR ( " DNS record scavenging process failed: %s \n " ,
2018-05-29 06:50:19 +03:00
err ) ;
return status ;
}
}
2023-03-07 00:38:27 +03:00
DBG_INFO ( " Successfully tombstoned stale DNS records \n " ) ;
2021-04-10 05:08:09 +03:00
return NT_STATUS_OK ;
}
/*
* check to see if any dns tombstones should be deleted . This is not optional
* ( [ MS - DNSP ] " DsTombstoneInterval " ) - - stale tombstones are useless clutter .
*
* Windows does it daily at 2 am ; we do it roughly daily at an uncontrolled
* time .
*/
static NTSTATUS kccsrv_dns_zone_tombstone_deletion ( struct kccsrv_service * s ,
TALLOC_CTX * mem_ctx )
{
time_t current_time = time ( NULL ) ;
NTSTATUS status ;
char * error_string = NULL ;
time_t dns_collection_interval =
lpcfg_parm_int ( s - > task - > lp_ctx ,
NULL ,
" dnsserver " ,
" tombstone_collection_interval " ,
24 * 60 * 60 ) ;
2018-05-29 06:50:19 +03:00
if ( ( current_time - s - > last_dns_tombstone_collection ) >
dns_collection_interval ) {
s - > last_dns_tombstone_collection = current_time ;
status = dns_delete_tombstones ( mem_ctx , s - > samdb ,
& error_string ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
const char * err = NULL ;
if ( error_string ! = NULL ) {
err = error_string ;
} else {
err = nt_errstr ( status ) ;
}
2023-03-07 00:38:27 +03:00
DBG_ERR ( " DNS tombstone deletion failed: %s \n " , err ) ;
2018-05-29 06:50:19 +03:00
return status ;
}
}
2023-03-07 00:38:27 +03:00
DBG_INFO ( " Successfully deleted DNS tombstones \n " ) ;
2018-05-29 06:50:19 +03:00
return NT_STATUS_OK ;
}
2016-07-18 04:10:23 +03:00
/*
check to see if any deleted objects need scavenging
*/
static NTSTATUS kccsrv_check_deleted ( struct kccsrv_service * s , TALLOC_CTX * mem_ctx )
{
2016-07-18 04:17:52 +03:00
time_t current_time = time ( NULL ) ;
2018-07-10 04:37:18 +03:00
time_t interval = lpcfg_parm_int (
s - > task - > lp_ctx , NULL , " kccsrv " , " check_deleted_interval " , 86400 ) ;
2016-07-18 04:17:52 +03:00
uint32_t tombstoneLifetime ;
int ret ;
unsigned int num_objects_removed = 0 ;
unsigned int num_links_removed = 0 ;
NTSTATUS status ;
2016-08-30 01:22:47 +03:00
char * error_string = NULL ;
2016-08-29 09:56:10 +03:00
2016-07-18 04:17:52 +03:00
if ( current_time - s - > last_deleted_check < interval ) {
2016-08-29 09:56:10 +03:00
return NT_STATUS_OK ;
}
2016-08-29 10:02:39 +03:00
ret = dsdb_tombstone_lifetime ( s - > samdb , & tombstoneLifetime ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 1 , ( __location__ " : Failed to get tombstone lifetime \n " ) ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
2016-07-18 04:17:52 +03:00
s - > last_deleted_check = current_time ;
status = dsdb_garbage_collect_tombstones ( mem_ctx , s - > samdb ,
s - > partitions ,
current_time , tombstoneLifetime ,
& num_objects_removed ,
2016-08-30 01:22:47 +03:00
& num_links_removed ,
& error_string ) ;
2016-07-18 04:17:52 +03:00
if ( NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 5 , ( " garbage_collect_tombstones: Removed %u tombstone objects "
" and %u tombstone links successfully \n " ,
num_objects_removed , num_links_removed ) ) ;
} else {
DEBUG ( 2 , ( " garbage_collect_tombstones: Failure removing tombstone "
" objects and links after removing %u tombstone objects "
" and %u tombstone links successfully: %s \n " ,
num_objects_removed , num_links_removed ,
2016-08-30 01:22:47 +03:00
error_string ? error_string : nt_errstr ( status ) ) ) ;
2016-07-18 04:17:52 +03:00
}
return status ;
2016-07-18 04:10:23 +03:00
}
2009-09-11 15:46:58 +04:00
static void kccsrv_periodic_run ( struct kccsrv_service * service )
{
TALLOC_CTX * mem_ctx ;
NTSTATUS status ;
2011-12-04 21:06:47 +04:00
DEBUG ( 4 , ( " kccsrv_periodic_run(): update \n " ) ) ;
2009-09-11 15:46:58 +04:00
mem_ctx = talloc_new ( service ) ;
2011-12-04 21:06:47 +04:00
2024-07-30 04:53:57 +03:00
if ( service - > samba_kcc_code ) {
2015-02-18 06:42:09 +03:00
status = kccsrv_samba_kcc ( service ) ;
2024-07-30 04:53:57 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " kccsrv_samba_kcc failed - %s \n " ,
nt_errstr ( status ) ) ;
}
} else {
2011-12-04 21:06:47 +04:00
status = kccsrv_simple_update ( service , mem_ctx ) ;
if ( ! NT_STATUS_IS_OK ( status ) )
DEBUG ( 0 , ( " kccsrv_simple_update failed - %s \n " ,
nt_errstr ( status ) ) ) ;
2009-09-11 15:46:58 +04:00
}
2009-12-30 13:40:17 +03:00
status = kccsrv_check_deleted ( service , mem_ctx ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " kccsrv_check_deleted failed - %s \n " , nt_errstr ( status ) ) ) ;
}
2018-05-29 06:50:19 +03:00
status = kccsrv_dns_zone_scavenging ( service , mem_ctx ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2021-04-10 05:08:09 +03:00
DBG_ERR ( " kccsrv_dns_zone_aging failed - %s \n " ,
nt_errstr ( status ) ) ;
}
status = kccsrv_dns_zone_tombstone_deletion ( service , mem_ctx ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " kccsrv_dns_zone_tombstone_scavenging failed - %s \n " ,
2018-05-29 06:50:19 +03:00
nt_errstr ( status ) ) ;
}
2009-09-11 15:46:58 +04:00
talloc_free ( mem_ctx ) ;
}
2011-12-04 21:06:47 +04:00
/* Called when samba_kcc script has finished
*/
static void samba_kcc_done ( struct tevent_req * subreq )
{
struct kccsrv_service * service =
tevent_req_callback_data ( subreq , struct kccsrv_service ) ;
int rc ;
int sys_errno ;
service - > periodic . subreq = NULL ;
rc = samba_runcmd_recv ( subreq , & sys_errno ) ;
TALLOC_FREE ( subreq ) ;
if ( rc ! = 0 )
service - > periodic . status =
map_nt_error_from_unix_common ( sys_errno ) ;
else
service - > periodic . status = NT_STATUS_OK ;
if ( ! NT_STATUS_IS_OK ( service - > periodic . status ) )
DEBUG ( 0 , ( __location__ " : Failed samba_kcc - %s \n " ,
nt_errstr ( service - > periodic . status ) ) ) ;
else
DEBUG ( 3 , ( " Completed samba_kcc OK \n " ) ) ;
}
/* Invocation of the samba_kcc python script for replication
* topology generation .
*/
2015-02-18 06:42:09 +03:00
NTSTATUS kccsrv_samba_kcc ( struct kccsrv_service * service )
2011-12-04 21:06:47 +04:00
{
NTSTATUS status = NT_STATUS_OK ;
const char * const * samba_kcc_command =
lpcfg_samba_kcc_command ( service - > task - > lp_ctx ) ;
/* kill any existing child */
TALLOC_FREE ( service - > periodic . subreq ) ;
2014-09-27 18:28:27 +04:00
DEBUG ( 2 , ( " Calling samba_kcc script \n " ) ) ;
2011-12-04 21:06:47 +04:00
service - > periodic . subreq = samba_runcmd_send ( service ,
service - > task - > event_ctx ,
timeval_current_ofs ( 40 , 0 ) ,
2 , 0 , samba_kcc_command , NULL ) ;
if ( service - > periodic . subreq = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto xerror ;
}
tevent_req_set_callback ( service - > periodic . subreq ,
samba_kcc_done , service ) ;
xerror :
if ( ! NT_STATUS_IS_OK ( status ) )
DEBUG ( 0 , ( __location__ " : failed - %s \n " , nt_errstr ( status ) ) ) ;
return status ;
}