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"
2010-04-22 10:48:01 +04:00
# include "libcli/security/security.h"
2010-11-27 21:42:31 +03:00
# include "libcli/security/session.h"
# include "rpc_server/drsuapi/dcesrv_drsuapi.h"
2010-04-22 10:48:01 +04:00
# include "auth/session.h"
2010-09-16 07:02:43 +04:00
# include "librpc/gen_ndr/ndr_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-11-21 20:57:24 +03:00
unsigned 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 + + ) {
2014-06-05 14:04:43 +04:00
if ( GUID_equal ( & dest - > source_dsa_obj_guid ,
& reps . r [ i ] . ctr . ctr1 . source_dsa_obj_guid ) ) {
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 ;
2010-09-30 23:43:45 +04:00
/* add the GCSPN flag if the client asked for it */
reps . r [ reps . count ] . ctr . ctr1 . replica_flags | = ( options & DRSUAPI_DRS_REF_GCSPN ) ;
2009-09-09 06:29:01 +04:00
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 ;
2009-11-21 20:57:24 +03:00
unsigned 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 + + ) {
2014-06-05 14:04:43 +04:00
if ( GUID_equal ( dest_guid ,
& reps . r [ i ] . ctr . ctr1 . source_dsa_obj_guid ) ) {
2009-09-09 06:29:01 +04:00
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 ;
}
2012-10-14 12:04:51 +04:00
/**
* @ brief Update the references for the given NC and the destination DSA object
*
* This function is callable from non RPC functions ( ie . getncchanges ) , it
* will validate the request to update reference and then will add / del a repsTo
* to the specified server referenced by its DSA GUID in the request .
*
* @ param [ in ] b_state A bind_state object
*
* @ param [ in ] mem_ctx A talloc context for memory allocation
*
* @ param [ in ] req A drsuapi_DsReplicaUpdateRefsRequest1
* object which NC , which server and which
* action ( add / delete ) should be performed
*
* @ return WERR_OK is success , different error
* otherwise .
*/
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 ;
2012-09-28 02:02:06 +04:00
int ret ;
2009-09-10 08:27:47 +04:00
struct ldb_dn * dn ;
2012-09-28 02:02:06 +04:00
struct ldb_dn * nc_root ;
2010-09-26 04:53:14 +04:00
struct ldb_context * sam_ctx = b_state - > sam_ctx_system ? b_state - > sam_ctx_system : b_state - > sam_ctx ;
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 ) ) ) ;
2012-09-28 02:22:00 +04:00
/*
* 4.1 .26 .2 Server Behavior of the IDL_DRSUpdateRefs Method
* Implements the input validation checks
*/
if ( GUID_all_zero ( & req - > dest_dsa_guid ) ) {
return WERR_DS_DRA_INVALID_PARAMETER ;
}
2013-06-28 10:58:41 +04:00
/* FIXME it seems that we should check the length of the stuff too*/
2012-09-28 02:22:00 +04:00
if ( req - > dest_dsa_dns_name = = NULL ) {
return WERR_DS_DRA_INVALID_PARAMETER ;
}
if ( ! ( req - > options & ( DRSUAPI_DRS_DEL_REF | DRSUAPI_DRS_ADD_REF ) ) ) {
return WERR_DS_DRA_INVALID_PARAMETER ;
}
2012-09-28 02:02:06 +04:00
dn = drs_ObjectIdentifier_to_dn ( mem_ctx , sam_ctx , req - > naming_context ) ;
W_ERROR_HAVE_NO_MEMORY ( dn ) ;
ret = dsdb_find_nc_root ( sam_ctx , dn , dn , & nc_root ) ;
if ( ret ! = LDB_SUCCESS ) {
2013-01-12 08:05:39 +04:00
DEBUG ( 2 , ( " Didn't find a nc for %s \n " , ldb_dn_get_linearized ( dn ) ) ) ;
2012-09-28 02:02:06 +04:00
return WERR_DS_DRA_BAD_NC ;
}
if ( ldb_dn_compare ( dn , nc_root ) ! = 0 ) {
2013-01-12 08:05:39 +04:00
DEBUG ( 2 , ( " dn %s is not equal to %s \n " , ldb_dn_get_linearized ( dn ) , ldb_dn_get_linearized ( nc_root ) ) ) ;
2012-09-28 02:02:06 +04:00
return WERR_DS_DRA_BAD_NC ;
2009-09-10 08:27:47 +04:00
}
2010-09-26 04:53:14 +04:00
if ( ldb_transaction_start ( sam_ctx ) ! = LDB_SUCCESS ) {
2010-09-06 15:33:14 +04:00
DEBUG ( 0 , ( __location__ " : Failed to start transaction on samdb: %s \n " ,
2010-09-26 04:53:14 +04:00
ldb_errstring ( sam_ctx ) ) ) ;
2012-09-28 02:02:06 +04:00
return WERR_DS_DRA_INTERNAL_ERROR ;
2009-09-08 05:49:28 +04:00
}
2010-01-14 06:38:00 +03:00
if ( req - > options & DRSUAPI_DRS_DEL_REF ) {
2010-09-26 04:53:14 +04:00
werr = uref_del_dest ( 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 ) ) {
2010-09-06 15:33:14 +04:00
DEBUG ( 0 , ( " Failed to delete repsTo for %s: %s \n " ,
GUID_string ( mem_ctx , & req - > dest_dsa_guid ) ,
win_errstr ( werr ) ) ) ;
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
2010-09-26 04:53:14 +04:00
werr = uref_add_dest ( sam_ctx , mem_ctx , dn , & dest , req - > options ) ;
2009-09-08 05:49:28 +04:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
2010-09-06 15:33:14 +04:00
DEBUG ( 0 , ( " Failed to add repsTo for %s: %s \n " ,
GUID_string ( mem_ctx , & dest . source_dsa_obj_guid ) ,
win_errstr ( werr ) ) ) ;
2009-09-08 05:49:28 +04:00
goto failed ;
}
}
2010-09-26 04:53:14 +04:00
if ( ldb_transaction_commit ( sam_ctx ) ! = LDB_SUCCESS ) {
2010-09-06 15:33:14 +04:00
DEBUG ( 0 , ( __location__ " : Failed to commit transaction on samdb: %s \n " ,
2010-09-26 04:53:14 +04:00
ldb_errstring ( sam_ctx ) ) ) ;
2009-09-08 05:49:28 +04:00
return WERR_DS_DRA_INTERNAL_ERROR ;
}
return WERR_OK ;
failed :
2010-09-26 04:53:14 +04:00
ldb_transaction_cancel ( 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 ;
2010-04-22 10:48:01 +04:00
int ret ;
enum security_user_level security_level ;
2009-10-14 13:25:48 +04:00
DCESRV_PULL_HANDLE_WERR ( h , r - > in . bind_handle , DRSUAPI_BIND_HANDLE ) ;
b_state = h - > data ;
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 ;
2010-09-27 08:16:47 +04:00
werr = drs_security_access_check ( b_state - > sam_ctx ,
mem_ctx ,
dce_call - > conn - > auth_state . session_info - > security_token ,
req - > naming_context ,
GUID_DRS_MANAGE_TOPOLOGY ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
return werr ;
}
2009-10-14 13:25:48 +04:00
2010-04-22 10:48:01 +04:00
security_level = security_session_user_level ( dce_call - > conn - > auth_state . session_info , NULL ) ;
if ( security_level < SECURITY_ADMINISTRATOR ) {
2010-04-26 01:22:53 +04:00
/* check that they are using an DSA objectGUID that they own */
ret = dsdb_validate_dsa_guid ( b_state - > sam_ctx ,
& req - > dest_dsa_guid ,
2010-08-20 06:15:15 +04:00
& dce_call - > conn - > auth_state . session_info - > security_token - > sids [ PRIMARY_USER_SID_INDEX ] ) ;
2010-04-22 10:48:01 +04:00
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Refusing DsReplicaUpdateRefs for sid %s with GUID %s \n " ,
dom_sid_string ( mem_ctx ,
2010-08-20 06:15:15 +04:00
& dce_call - > conn - > auth_state . session_info - > security_token - > sids [ PRIMARY_USER_SID_INDEX ] ) ,
2010-04-22 10:48:01 +04:00
GUID_string ( mem_ctx , & req - > dest_dsa_guid ) ) ) ;
return WERR_DS_DRA_ACCESS_DENIED ;
}
}
2010-09-16 07:02:43 +04:00
werr = drsuapi_UpdateRefs ( b_state , mem_ctx , req ) ;
#if 0
NDR_PRINT_FUNCTION_DEBUG ( drsuapi_DsReplicaUpdateRefs , NDR_BOTH , r ) ;
# endif
return werr ;
2009-10-14 13:25:48 +04:00
}