2009-09-11 15:46:58 +04:00
/*
Unix SMB / CIFS mplementation .
KCC service periodic handling
Copyright ( C ) Andrew Tridgell 2009
based on repl service code
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"
# include "lib/events/events.h"
# include "dsdb/samdb/samdb.h"
# include "auth/auth.h"
# include "smbd/service.h"
# 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"
# 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"
2010-08-28 21:02:13 +04:00
# include "librpc/gen_ndr/ndr_irpc.h"
2009-09-11 15:46:58 +04:00
# include "param/param.h"
/*
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 + + ) {
if ( strcmp ( r - > ctr . ctr1 . other_info - > dns_name ,
reps [ i ] . ctr . ctr1 . other_info - > dns_name ) = = 0 & &
GUID_compare ( & r - > ctr . ctr1 . source_dsa_obj_guid ,
& reps [ i ] . ctr . ctr1 . source_dsa_obj_guid ) = = 0 ) {
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
*/
static bool check_MasterNC ( struct kccsrv_partition * p , struct repsFromToBlob * r ,
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 ;
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 ) ;
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 " ) ;
if ( ! GUID_equal ( & invocation_id , & id2 ) ) {
continue ;
}
el = ldb_msg_find_element ( msg , " hasMasterNCs " ) ;
if ( ! el | | el - > num_values = = 0 ) {
continue ;
}
for ( j = 0 ; j < el - > num_values ; j + + ) {
dn = ldb_dn_from_ldb_val ( p , p - > service - > samdb , & el - > values [ j ] ) ;
if ( ! ldb_dn_validate ( dn ) ) {
talloc_free ( dn ) ;
continue ;
}
if ( ldb_dn_compare ( dn , p - > dn ) = = 0 ) {
talloc_free ( dn ) ;
return true ;
}
talloc_free ( dn ) ;
}
}
return false ;
}
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 )
{
struct dreplsrv_refresh r ;
struct server_id * drepl_srv ;
drepl_srv = irpc_servers_byname ( s - > task - > msg_ctx , mem_ctx , " dreplsrv " ) ;
if ( ! drepl_srv ) {
/* dreplsrv is not running yet */
return ;
}
IRPC_CALL ( s - > task - > msg_ctx , drepl_srv [ 0 ] , irpc , DREPLSRV_REFRESH , & r , mem_ctx ) ;
}
2009-09-12 05:09:10 +04:00
/*
* add any missing repsFrom structures to our partitions
*/
static NTSTATUS kccsrv_add_repsFrom ( struct kccsrv_service * s , TALLOC_CTX * mem_ctx ,
2010-04-26 16:51:11 +04:00
struct repsFromToBlob * reps , uint32_t count ,
struct ldb_result * res )
2009-09-12 05:09:10 +04:00
{
struct kccsrv_partition * p ;
2010-08-28 21:02:13 +04:00
bool notify_dreplsrv = false ;
2009-09-12 05:09:10 +04:00
/* update the repsFrom on all partitions */
for ( p = s - > partitions ; p ; p = p - > next ) {
2010-04-26 17:21:10 +04:00
struct repsFromToBlob * old_reps , * reps_to ;
uint32_t old_count , to_count ;
2009-09-12 05:09:10 +04:00
WERROR werr ;
2010-03-16 10:49:22 +03:00
uint32_t i ;
2009-09-12 05:09:10 +04:00
bool modified = false ;
werr = dsdb_loadreps ( s - > samdb , mem_ctx , p - > dn , " repsFrom " , & old_reps , & old_count ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 0 , ( __location__ " : Failed to load repsFrom from %s - %s \n " ,
ldb_dn_get_linearized ( p - > dn ) , ldb_errstring ( s - > samdb ) ) ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
2009-09-28 07:10:13 +04:00
/* add any new ones */
2009-09-12 05:09:10 +04:00
for ( i = 0 ; i < count ; i + + ) {
2010-04-26 16:51:11 +04:00
if ( ! reps_in_list ( & reps [ i ] , old_reps , old_count ) & &
check_MasterNC ( p , & reps [ i ] , res ) ) {
2009-09-12 05:09:10 +04:00
old_reps = talloc_realloc ( mem_ctx , old_reps , struct repsFromToBlob , old_count + 1 ) ;
NT_STATUS_HAVE_NO_MEMORY ( old_reps ) ;
old_reps [ old_count ] = reps [ i ] ;
old_count + + ;
modified = true ;
}
}
2009-09-28 07:10:13 +04:00
/* remove any stale ones */
for ( i = 0 ; i < old_count ; i + + ) {
2010-04-26 16:51:11 +04:00
if ( ! reps_in_list ( & old_reps [ i ] , reps , count ) | |
! check_MasterNC ( p , & old_reps [ i ] , res ) ) {
2009-09-28 07:10:13 +04:00
memmove ( & old_reps [ i ] , & old_reps [ i + 1 ] , ( old_count - ( i + 1 ) ) * sizeof ( old_reps [ 0 ] ) ) ;
old_count - - ;
i - - ;
modified = true ;
}
}
2009-09-12 05:09:10 +04:00
if ( modified ) {
werr = dsdb_savereps ( s - > samdb , mem_ctx , p - > dn , " repsFrom " , old_reps , old_count ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 0 , ( __location__ " : Failed to save repsFrom to %s - %s \n " ,
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-04-26 17:21:10 +04:00
werr = dsdb_loadreps ( s - > samdb , mem_ctx , p - > dn , " repsTo " , & reps_to , & to_count ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 0 , ( __location__ " : Failed to load repsTo from %s - %s \n " ,
ldb_dn_get_linearized ( p - > dn ) , ldb_errstring ( s - > samdb ) ) ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
modified = false ;
/* add any new ones */
for ( i = 0 ; i < old_count ; i + + ) {
if ( ! reps_in_list ( & old_reps [ i ] , reps_to , to_count ) ) {
reps_to = talloc_realloc ( mem_ctx , reps_to , struct repsFromToBlob , to_count + 1 ) ;
NT_STATUS_HAVE_NO_MEMORY ( reps_to ) ;
reps_to [ to_count ] = old_reps [ i ] ;
to_count + + ;
modified = true ;
}
}
if ( modified ) {
werr = dsdb_savereps ( s - > samdb , mem_ctx , p - > dn , " repsTo " , reps_to , to_count ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 0 , ( __location__ " : Failed to save repsTo to %s - %s \n " ,
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 ;
2010-04-26 17:21:10 +04:00
}
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 ;
}
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 ;
2010-04-26 16:51:11 +04:00
const char * attrs [ ] = { " objectGUID " , " invocationID " , " hasMasterNCs " , 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
ret = ldb_search ( s - > samdb , mem_ctx , & res , s - > config_dn , LDB_SCOPE_SUBTREE ,
attrs , " objectClass=nTDSDSA " ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed nTDSDSA search - %s \n " , ldb_errstring ( s - > samdb ) ) ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
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 " ) ;
if ( GUID_compare ( & ntds_guid , & s - > ntds_guid ) = = 0 ) {
/* 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 ) ;
r1 - > other_info - > dns_name = talloc_asprintf ( r1 - > other_info , " %s._msdcs.%s " ,
2009-09-11 15:46:58 +04:00
GUID_string ( mem_ctx , & ntds_guid ) ,
2010-07-16 08:32:42 +04:00
lpcfg_dnsdomain ( s - > task - > lp_ctx ) ) ;
2009-09-11 15:46:58 +04:00
r1 - > source_dsa_obj_guid = ntds_guid ;
r1 - > source_dsa_invocation_id = invocation_id ;
r1 - > replica_flags =
2010-01-17 13:59:56 +03:00
DRSUAPI_DRS_WRIT_REP |
DRSUAPI_DRS_INIT_SYNC |
DRSUAPI_DRS_PER_SYNC ;
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 ;
new_te = event_add_timed ( service - > task - > event_ctx , service ,
service - > periodic . next_event ,
kccsrv_periodic_handler_te , service ) ;
W_ERROR_HAVE_NO_MEMORY ( new_te ) ;
tmp_mem = talloc_new ( service ) ;
DEBUG ( 2 , ( " kccsrv_periodic_schedule(%u) %sscheduled for: %s \n " ,
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 ;
}
static void kccsrv_periodic_run ( struct kccsrv_service * service )
{
TALLOC_CTX * mem_ctx ;
NTSTATUS status ;
DEBUG ( 2 , ( " kccsrv_periodic_run(): simple update \n " ) ) ;
mem_ctx = talloc_new ( service ) ;
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-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 ) ) ) ;
}
2009-09-11 15:46:58 +04:00
talloc_free ( mem_ctx ) ;
}