2009-09-08 05:49:28 +04:00
/*
Unix SMB / CIFS implementation .
implement the DRSUpdateRefs call
Copyright ( C ) Andrew Tridgell 2009
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 "rpc_server/dcerpc_server.h"
# include "dsdb/samdb/samdb.h"
2009-09-09 15:00:01 +04:00
# include "rpc_server/drsuapi/dcesrv_drsuapi.h"
2009-09-08 05:49:28 +04:00
2009-09-09 06:29:01 +04:00
struct repsTo {
uint32_t count ;
struct repsFromToBlob * r ;
} ;
2009-09-08 05:49:28 +04:00
/*
add a replication destination for a given partition GUID
*/
static WERROR uref_add_dest ( struct ldb_context * sam_ctx , TALLOC_CTX * mem_ctx ,
2009-10-14 13:25:48 +04:00
struct ldb_dn * dn , struct repsFromTo1 * dest ,
uint32_t options )
2009-09-08 05:49:28 +04:00
{
struct repsTo reps ;
WERROR werr ;
2009-10-14 13:25:48 +04:00
int i ;
2009-09-08 05:49:28 +04:00
2009-09-12 05:12:05 +04:00
werr = dsdb_loadreps ( sam_ctx , mem_ctx , dn , " repsTo " , & reps . r , & reps . count ) ;
2009-09-08 05:49:28 +04:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
return werr ;
}
2009-10-14 13:25:48 +04:00
for ( i = 0 ; i < reps . count ; i + + ) {
if ( GUID_compare ( & dest - > source_dsa_obj_guid ,
& reps . r [ i ] . ctr . ctr1 . source_dsa_obj_guid ) = = 0 ) {
2010-01-14 06:38:00 +03:00
if ( options & DRSUAPI_DRS_GETCHG_CHECK ) {
2009-10-14 13:25:48 +04:00
return WERR_OK ;
} else {
return WERR_DS_DRA_REF_ALREADY_EXISTS ;
}
}
}
2009-09-09 06:29:01 +04:00
reps . r = talloc_realloc ( mem_ctx , reps . r , struct repsFromToBlob , reps . count + 1 ) ;
if ( reps . r = = NULL ) {
2009-09-08 05:49:28 +04:00
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2009-09-09 06:29:01 +04:00
ZERO_STRUCT ( reps . r [ reps . count ] ) ;
reps . r [ reps . count ] . version = 1 ;
reps . r [ reps . count ] . ctr . ctr1 = * dest ;
reps . count + + ;
2009-09-08 05:49:28 +04:00
2009-09-12 05:12:05 +04:00
werr = dsdb_savereps ( sam_ctx , mem_ctx , dn , " repsTo " , reps . r , reps . count ) ;
2009-09-08 05:49:28 +04:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
return werr ;
}
return WERR_OK ;
}
/*
delete a replication destination for a given partition GUID
*/
static WERROR uref_del_dest ( struct ldb_context * sam_ctx , TALLOC_CTX * mem_ctx ,
2009-10-14 13:25:48 +04:00
struct ldb_dn * dn , struct GUID * dest_guid ,
uint32_t options )
2009-09-08 05:49:28 +04:00
{
struct repsTo reps ;
WERROR werr ;
int i ;
2009-10-14 13:25:48 +04:00
bool found = false ;
2009-09-08 05:49:28 +04:00
2009-09-12 05:12:05 +04:00
werr = dsdb_loadreps ( sam_ctx , mem_ctx , dn , " repsTo " , & reps . r , & reps . count ) ;
2009-09-08 05:49:28 +04:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
return werr ;
}
2009-09-09 06:29:01 +04:00
for ( i = 0 ; i < reps . count ; i + + ) {
if ( GUID_compare ( dest_guid , & reps . r [ i ] . ctr . ctr1 . source_dsa_obj_guid ) = = 0 ) {
if ( i + 1 < reps . count ) {
memmove ( & reps . r [ i ] , & reps . r [ i + 1 ] , sizeof ( reps . r [ i ] ) * ( reps . count - ( i + 1 ) ) ) ;
2009-09-08 05:49:28 +04:00
}
2009-09-09 06:29:01 +04:00
reps . count - - ;
2009-10-14 13:25:48 +04:00
found = true ;
2009-09-08 05:49:28 +04:00
}
}
2009-09-12 05:12:05 +04:00
werr = dsdb_savereps ( sam_ctx , mem_ctx , dn , " repsTo " , reps . r , reps . count ) ;
2009-09-08 05:49:28 +04:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
return werr ;
}
2010-01-02 08:51:30 +03:00
if ( ! found & &
2010-01-14 06:38:00 +03:00
! ( options & DRSUAPI_DRS_GETCHG_CHECK ) & &
! ( options & DRSUAPI_DRS_ADD_REF ) ) {
2009-10-14 13:25:48 +04:00
return WERR_DS_DRA_REF_NOT_FOUND ;
}
2009-09-08 05:49:28 +04:00
return WERR_OK ;
}
/*
2009-10-14 13:25:48 +04:00
drsuapi_DsReplicaUpdateRefs - a non RPC version callable from getncchanges
2009-09-08 05:49:28 +04:00
*/
2009-10-14 13:25:48 +04:00
WERROR drsuapi_UpdateRefs ( struct drsuapi_bind_state * b_state , TALLOC_CTX * mem_ctx ,
struct drsuapi_DsReplicaUpdateRefsRequest1 * req )
2009-09-08 05:49:28 +04:00
{
WERROR werr ;
2009-09-10 08:27:47 +04:00
struct ldb_dn * dn ;
2009-09-16 06:26:33 +04:00
2009-09-10 07:50:46 +04:00
DEBUG ( 4 , ( " DsReplicaUpdateRefs for host '%s' with GUID %s options 0x%08x nc=%s \n " ,
2009-09-08 05:49:28 +04:00
req - > dest_dsa_dns_name , GUID_string ( mem_ctx , & req - > dest_dsa_guid ) ,
req - > options ,
drs_ObjectIdentifier_to_string ( mem_ctx , req - > naming_context ) ) ) ;
2009-10-06 11:59:30 +04:00
dn = ldb_dn_new ( mem_ctx , b_state - > sam_ctx , req - > naming_context - > dn ) ;
2009-09-10 08:27:47 +04:00
if ( dn = = NULL ) {
return WERR_DS_INVALID_DN_SYNTAX ;
}
2009-10-06 11:59:30 +04:00
if ( ldb_transaction_start ( b_state - > sam_ctx ) ! = LDB_SUCCESS ) {
2009-09-08 05:49:28 +04:00
DEBUG ( 0 , ( __location__ " : Failed to start transaction on samdb \n " ) ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2010-01-14 06:38:00 +03:00
if ( req - > options & DRSUAPI_DRS_DEL_REF ) {
2009-10-14 13:25:48 +04:00
werr = uref_del_dest ( b_state - > sam_ctx , mem_ctx , dn , & req - > dest_dsa_guid , req - > options ) ;
2009-09-08 05:49:28 +04:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 0 , ( " Failed to delete repsTo for %s \n " ,
2009-10-14 13:25:48 +04:00
GUID_string ( mem_ctx , & req - > dest_dsa_guid ) ) ) ;
2009-09-08 05:49:28 +04:00
goto failed ;
}
}
2010-01-14 06:38:00 +03:00
if ( req - > options & DRSUAPI_DRS_ADD_REF ) {
2009-09-09 06:29:01 +04:00
struct repsFromTo1 dest ;
struct repsFromTo1OtherInfo oi ;
ZERO_STRUCT ( dest ) ;
ZERO_STRUCT ( oi ) ;
2009-09-08 05:49:28 +04:00
2009-09-09 06:29:01 +04:00
oi . dns_name = req - > dest_dsa_dns_name ;
dest . other_info = & oi ;
dest . source_dsa_obj_guid = req - > dest_dsa_guid ;
dest . replica_flags = req - > options ;
2009-09-08 05:49:28 +04:00
2009-10-14 13:25:48 +04:00
werr = uref_add_dest ( b_state - > sam_ctx , mem_ctx , dn , & dest , req - > options ) ;
2009-09-08 05:49:28 +04:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
2009-10-14 13:25:48 +04:00
DEBUG ( 0 , ( " Failed to add repsTo for %s \n " ,
GUID_string ( mem_ctx , & dest . source_dsa_obj_guid ) ) ) ;
2009-09-08 05:49:28 +04:00
goto failed ;
}
}
2009-10-06 11:59:30 +04:00
if ( ldb_transaction_commit ( b_state - > sam_ctx ) ! = LDB_SUCCESS ) {
2009-09-08 05:49:28 +04:00
DEBUG ( 0 , ( __location__ " : Failed to commit transaction on samdb \n " ) ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
return WERR_OK ;
failed :
2009-10-06 11:59:30 +04:00
ldb_transaction_cancel ( b_state - > sam_ctx ) ;
2009-09-08 05:49:28 +04:00
return werr ;
}
2009-10-14 13:25:48 +04:00
/*
drsuapi_DsReplicaUpdateRefs
*/
WERROR dcesrv_drsuapi_DsReplicaUpdateRefs ( struct dcesrv_call_state * dce_call , TALLOC_CTX * mem_ctx ,
struct drsuapi_DsReplicaUpdateRefs * r )
{
struct dcesrv_handle * h ;
struct drsuapi_bind_state * b_state ;
struct drsuapi_DsReplicaUpdateRefsRequest1 * req ;
WERROR werr ;
DCESRV_PULL_HANDLE_WERR ( h , r - > in . bind_handle , DRSUAPI_BIND_HANDLE ) ;
b_state = h - > data ;
werr = drs_security_level_check ( dce_call , " DsReplicaUpdateRefs " ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
return werr ;
}
if ( r - > in . level ! = 1 ) {
DEBUG ( 0 , ( " DrReplicUpdateRefs - unsupported level %u \n " , r - > in . level ) ) ;
return WERR_DS_DRA_INVALID_PARAMETER ;
}
req = & r - > in . req . req1 ;
return drsuapi_UpdateRefs ( b_state , mem_ctx , req ) ;
}