2010-01-06 06:54:12 +03:00
/*
Unix SMB / CIFS mplementation .
DSDB replication service - RID allocation code
Copyright ( C ) Andrew Tridgell 2010
Copyright ( C ) Andrew Bartlett 2010
based on drepl_notify . c
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 "dsdb/samdb/samdb.h"
# include "smbd/service.h"
# include "dsdb/repl/drepl_service.h"
# include "param/param.h"
/*
create the RID manager source dsa structure
*/
static WERROR drepl_create_rid_manager_source_dsa ( struct dreplsrv_service * service ,
struct ldb_dn * rid_manager_dn , struct ldb_dn * fsmo_role_dn )
{
struct dreplsrv_partition_source_dsa * sdsa ;
struct ldb_context * ldb = service - > samdb ;
int ret ;
WERROR werr ;
sdsa = talloc_zero ( service , struct dreplsrv_partition_source_dsa ) ;
W_ERROR_HAVE_NO_MEMORY ( sdsa ) ;
sdsa - > partition = talloc_zero ( sdsa , struct dreplsrv_partition ) ;
if ( ! sdsa - > partition ) {
talloc_free ( sdsa ) ;
return WERR_NOMEM ;
}
sdsa - > partition - > dn = samdb_base_dn ( ldb ) ;
sdsa - > partition - > nc . dn = ldb_dn_alloc_linearized ( sdsa - > partition , rid_manager_dn ) ;
ret = dsdb_find_guid_by_dn ( ldb , rid_manager_dn , & sdsa - > partition - > nc . guid ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to find GUID for %s \n " ,
ldb_dn_get_linearized ( rid_manager_dn ) ) ) ;
talloc_free ( sdsa ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
sdsa - > repsFrom1 = & sdsa - > _repsFromBlob . ctr . ctr1 ;
ret = dsdb_find_guid_attr_by_dn ( ldb , fsmo_role_dn , " objectGUID " , & sdsa - > repsFrom1 - > source_dsa_obj_guid ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to find objectGUID for %s \n " ,
ldb_dn_get_linearized ( fsmo_role_dn ) ) ) ;
talloc_free ( sdsa ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
sdsa - > repsFrom1 - > other_info = talloc_zero ( sdsa , struct repsFromTo1OtherInfo ) ;
if ( ! sdsa - > repsFrom1 - > other_info ) {
talloc_free ( sdsa ) ;
return WERR_NOMEM ;
}
sdsa - > repsFrom1 - > other_info - > dns_name =
talloc_asprintf ( sdsa - > repsFrom1 - > other_info , " %s._msdcs.%s " ,
GUID_string ( sdsa - > repsFrom1 - > other_info , & sdsa - > repsFrom1 - > source_dsa_obj_guid ) ,
lp_dnsdomain ( service - > task - > lp_ctx ) ) ;
if ( ! sdsa - > repsFrom1 - > other_info - > dns_name ) {
talloc_free ( sdsa ) ;
return WERR_NOMEM ;
}
werr = dreplsrv_out_connection_attach ( service , sdsa - > repsFrom1 , & sdsa - > conn ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 0 , ( __location__ " : Failed to attach to RID manager connection \n " ) ) ;
talloc_free ( sdsa ) ;
return werr ;
}
service - > ridalloc . rid_manager_source_dsa = sdsa ;
return WERR_OK ;
}
2010-01-06 09:18:42 +03:00
/*
called when a rid allocation request has completed
*/
static void drepl_new_rid_pool_callback ( struct dreplsrv_service * service , WERROR werr )
{
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 0 , ( __location__ " : RID Manager failed RID allocation - %s \n " ,
win_errstr ( werr ) ) ) ;
} else {
DEBUG ( 3 , ( __location__ " : RID Manager completed RID allocation OK \n " ) ) ;
}
/* don't keep the connection open to the RID Manager */
talloc_free ( service - > ridalloc . rid_manager_source_dsa ) ;
service - > ridalloc . rid_manager_source_dsa = NULL ;
service - > ridalloc . in_progress = false ;
}
2010-01-06 06:54:12 +03:00
/*
schedule a getncchanges request to the RID Manager to ask for a new
set of RIDs using DRSUAPI_EXOP_FSMO_RID_ALLOC
*/
static WERROR drepl_request_new_rid_pool ( struct dreplsrv_service * service ,
2010-01-06 09:18:42 +03:00
struct ldb_dn * rid_manager_dn , struct ldb_dn * fsmo_role_dn ,
uint64_t alloc_pool )
2010-01-06 06:54:12 +03:00
{
WERROR werr ;
if ( service - > ridalloc . rid_manager_source_dsa = = NULL ) {
/* we need to establish a connection to the RID
Manager */
werr = drepl_create_rid_manager_source_dsa ( service , rid_manager_dn , fsmo_role_dn ) ;
W_ERROR_NOT_OK_RETURN ( werr ) ;
}
2010-01-06 09:18:42 +03:00
service - > ridalloc . in_progress = true ;
2010-01-06 06:54:12 +03:00
werr = dreplsrv_schedule_partition_pull_source ( service , service - > ridalloc . rid_manager_source_dsa ,
2010-01-06 09:18:42 +03:00
DRSUAPI_EXOP_FSMO_RID_ALLOC , alloc_pool ,
drepl_new_rid_pool_callback ) ;
2010-01-06 06:54:12 +03:00
return werr ;
}
/*
see if we are on the last pool we have
*/
2010-01-06 09:18:42 +03:00
static int drepl_ridalloc_pool_exhausted ( struct ldb_context * ldb , bool * exhausted , uint64_t * alloc_pool )
2010-01-06 06:54:12 +03:00
{
struct ldb_dn * server_dn , * machine_dn , * rid_set_dn ;
TALLOC_CTX * tmp_ctx = talloc_new ( ldb ) ;
2010-01-06 09:18:42 +03:00
uint64_t prev_alloc_pool ;
2010-01-06 06:54:12 +03:00
const char * attrs [ ] = { " rIDPreviousAllocationPool " , " rIDAllocationPool " , NULL } ;
int ret ;
struct ldb_result * res ;
server_dn = ldb_dn_get_parent ( tmp_ctx , samdb_ntds_settings_dn ( ldb ) ) ;
if ( ! server_dn ) {
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
ret = samdb_reference_dn ( ldb , tmp_ctx , server_dn , " serverReference " , & machine_dn ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to find serverReference in %s - %s " ,
ldb_dn_get_linearized ( server_dn ) , ldb_errstring ( ldb ) ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
ret = samdb_reference_dn ( ldb , tmp_ctx , machine_dn , " rIDSetReferences " , & rid_set_dn ) ;
if ( ret = = LDB_ERR_NO_SUCH_ATTRIBUTE ) {
* exhausted = true ;
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to find rIDSetReferences in %s - %s " ,
ldb_dn_get_linearized ( machine_dn ) , ldb_errstring ( ldb ) ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
ret = ldb_search ( ldb , tmp_ctx , & res , rid_set_dn , LDB_SCOPE_BASE , attrs , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to load RID Set attrs from %s - %s " ,
ldb_dn_get_linearized ( rid_set_dn ) , ldb_errstring ( ldb ) ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
2010-01-06 09:18:42 +03:00
* alloc_pool = ldb_msg_find_attr_as_uint64 ( res - > msgs [ 0 ] , " rIDAllocationPool " , 0 ) ;
2010-01-06 06:54:12 +03:00
prev_alloc_pool = ldb_msg_find_attr_as_uint64 ( res - > msgs [ 0 ] , " rIDPreviousAllocationPool " , 0 ) ;
2010-01-06 09:18:42 +03:00
if ( * alloc_pool ! = prev_alloc_pool ) {
2010-01-06 06:54:12 +03:00
* exhausted = false ;
} else {
* exhausted = true ;
}
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
/*
see if we are low on RIDs in the RID Set rIDAllocationPool . If we
are , then schedule a replication call with DRSUAPI_EXOP_FSMO_RID_ALLOC
to the RID Manager
*/
WERROR dreplsrv_ridalloc_check_rid_pool ( struct dreplsrv_service * service )
{
struct ldb_dn * rid_manager_dn , * fsmo_role_dn ;
TALLOC_CTX * tmp_ctx = talloc_new ( service ) ;
struct ldb_context * ldb = service - > samdb ;
bool exhausted ;
WERROR werr ;
int ret ;
2010-01-06 09:18:42 +03:00
uint64_t alloc_pool ;
if ( service - > ridalloc . in_progress ) {
talloc_free ( tmp_ctx ) ;
return WERR_OK ;
}
2010-01-06 06:54:12 +03:00
/*
steps :
- find who the RID Manager is
- if we are the RID Manager then nothing to do
- find our RID Set object
- load rIDAllocationPool and rIDPreviousAllocationPool
- if rIDAllocationPool ! = rIDPreviousAllocationPool then
nothing to do
- schedule a getncchanges with DRSUAPI_EXOP_FSMO_RID_ALLOC
to the RID Manager
*/
/* work out who is the RID Manager */
ret = samdb_rid_manager_dn ( ldb , tmp_ctx , & rid_manager_dn ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to find RID Manager object - %s " , ldb_errstring ( ldb ) ) ) ;
talloc_free ( tmp_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
/* find the DN of the RID Manager */
ret = samdb_reference_dn ( ldb , tmp_ctx , rid_manager_dn , " fSMORoleOwner " , & fsmo_role_dn ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to find fSMORoleOwner in RID Manager object - %s " ,
ldb_errstring ( ldb ) ) ) ;
talloc_free ( tmp_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
if ( ldb_dn_compare ( samdb_ntds_settings_dn ( ldb ) , fsmo_role_dn ) = = 0 ) {
/* we are the RID Manager - no need to do a
DRSUAPI_EXOP_FSMO_RID_ALLOC */
talloc_free ( tmp_ctx ) ;
return WERR_OK ;
}
2010-01-06 09:18:42 +03:00
ret = drepl_ridalloc_pool_exhausted ( ldb , & exhausted , & alloc_pool ) ;
2010-01-06 06:54:12 +03:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2010-01-06 09:18:42 +03:00
DEBUG ( 2 , ( __location__ " : Requesting more RIDs from RID Manager \n " ) ) ;
2010-01-06 06:54:12 +03:00
2010-01-06 09:18:42 +03:00
werr = drepl_request_new_rid_pool ( service , rid_manager_dn , fsmo_role_dn , alloc_pool ) ;
2010-01-06 06:54:12 +03:00
talloc_free ( tmp_ctx ) ;
return werr ;
}
2010-01-06 09:18:42 +03:00
/* called by the samldb ldb module to tell us to ask for a new RID
pool */
void dreplsrv_allocate_rid ( struct messaging_context * msg , void * private_data ,
uint32_t msg_type ,
struct server_id server_id , DATA_BLOB * data )
{
struct dreplsrv_service * service = talloc_get_type ( private_data , struct dreplsrv_service ) ;
dreplsrv_ridalloc_check_rid_pool ( service ) ;
}