2009-09-09 15:00:01 +04:00
/*
Unix SMB / CIFS implementation .
2010-09-27 08:12:02 +04:00
implement the DSGetNCChanges call
2009-09-09 15:00:01 +04:00
Copyright ( C ) Anatoliy Atanasov 2009
2016-03-04 03:12:12 +03:00
Copyright ( C ) Andrew Tridgell 2009 - 2010
Copyright ( C ) Andrew Bartlett 2010 - 2016
2009-09-09 15:00:01 +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 .
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"
# include "param/param.h"
# include "librpc/gen_ndr/ndr_drsblobs.h"
2009-12-19 16:12:35 +03:00
# include "librpc/gen_ndr/ndr_drsuapi.h"
2010-08-18 12:38:26 +04:00
# include "librpc/gen_ndr/ndr_security.h"
2010-11-27 21:42:31 +03:00
# include "libcli/security/security.h"
# include "libcli/security/session.h"
2009-09-09 15:00:01 +04:00
# include "rpc_server/drsuapi/dcesrv_drsuapi.h"
2009-09-10 11:46:30 +04:00
# include "rpc_server/dcerpc_server_proto.h"
2017-04-21 02:29:48 +03:00
# include "rpc_server/common/sid_helper.h"
2009-09-10 11:46:30 +04:00
# include "../libcli/drsuapi/drsuapi.h"
2010-01-09 05:11:27 +03:00
# include "lib/util/binsearch.h"
2010-02-13 05:00:55 +03:00
# include "lib/util/tsort.h"
2010-04-22 08:56:19 +04:00
# include "auth/session.h"
2010-08-18 12:38:26 +04:00
# include "dsdb/common/util.h"
2016-11-29 13:12:22 +03:00
# include "lib/dbwrap/dbwrap.h"
# include "lib/dbwrap/dbwrap_rbt.h"
# include "librpc/gen_ndr/ndr_misc.h"
2009-09-09 15:00:01 +04:00
2012-12-17 17:08:56 +04:00
/* state of a partially completed getncchanges call */
struct drsuapi_getncchanges_state {
2016-11-29 13:12:22 +03:00
struct db_context * anc_cache ;
2012-12-17 17:08:56 +04:00
struct GUID * guids ;
uint32_t num_records ;
uint32_t num_processed ;
struct ldb_dn * ncRoot_dn ;
2016-11-29 13:09:46 +03:00
struct GUID ncRoot_guid ;
2012-12-17 17:08:56 +04:00
bool is_schema_nc ;
uint64_t min_usn ;
2012-12-18 17:59:20 +04:00
uint64_t max_usn ;
2012-12-17 14:30:26 +04:00
struct drsuapi_DsReplicaHighWaterMark last_hwm ;
2012-12-17 17:08:56 +04:00
struct ldb_dn * last_dn ;
2012-12-18 17:59:20 +04:00
struct drsuapi_DsReplicaHighWaterMark final_hwm ;
struct drsuapi_DsReplicaCursor2CtrEx * final_udv ;
2012-12-17 17:08:56 +04:00
struct drsuapi_DsReplicaLinkedAttribute * la_list ;
uint32_t la_count ;
2016-06-13 07:41:08 +03:00
struct la_for_sorting * la_sorted ;
2012-12-17 17:08:56 +04:00
uint32_t la_idx ;
} ;
2016-06-09 08:03:18 +03:00
/* We must keep the GUIDs in NDR form for sorting */
2016-06-07 02:56:49 +03:00
struct la_for_sorting {
struct drsuapi_DsReplicaLinkedAttribute * link ;
2016-06-13 07:41:08 +03:00
uint8_t target_guid [ 16 ] ;
uint8_t source_guid [ 16 ] ;
2016-06-07 02:56:49 +03:00
} ;
2012-12-17 14:13:43 +04:00
static int drsuapi_DsReplicaHighWaterMark_cmp ( const struct drsuapi_DsReplicaHighWaterMark * h1 ,
const struct drsuapi_DsReplicaHighWaterMark * h2 )
{
if ( h1 - > highest_usn < h2 - > highest_usn ) {
return - 1 ;
} else if ( h1 - > highest_usn > h2 - > highest_usn ) {
return 1 ;
} else if ( h1 - > tmp_highest_usn < h2 - > tmp_highest_usn ) {
return - 1 ;
} else if ( h1 - > tmp_highest_usn > h2 - > tmp_highest_usn ) {
return 1 ;
} else if ( h1 - > reserved_usn < h2 - > reserved_usn ) {
return - 1 ;
} else if ( h1 - > reserved_usn > h2 - > reserved_usn ) {
return 1 ;
}
return 0 ;
}
2009-12-19 04:25:09 +03:00
/*
build a DsReplicaObjectIdentifier from a ldb msg
*/
static struct drsuapi_DsReplicaObjectIdentifier * get_object_identifier ( TALLOC_CTX * mem_ctx ,
2016-12-01 13:50:34 +03:00
const struct ldb_message * msg )
2009-12-19 04:25:09 +03:00
{
struct drsuapi_DsReplicaObjectIdentifier * identifier ;
struct dom_sid * sid ;
identifier = talloc ( mem_ctx , struct drsuapi_DsReplicaObjectIdentifier ) ;
if ( identifier = = NULL ) {
return NULL ;
}
identifier - > dn = ldb_dn_alloc_linearized ( identifier , msg - > dn ) ;
identifier - > guid = samdb_result_guid ( msg , " objectGUID " ) ;
sid = samdb_result_dom_sid ( identifier , msg , " objectSid " ) ;
if ( sid ) {
identifier - > sid = * sid ;
} else {
ZERO_STRUCT ( identifier - > sid ) ;
}
return identifier ;
}
2010-01-09 05:11:27 +03:00
static int udv_compare ( const struct GUID * guid1 , struct GUID guid2 )
{
return GUID_compare ( guid1 , & guid2 ) ;
}
/*
see if we can filter an attribute using the uptodateness_vector
*/
static bool udv_filter ( const struct drsuapi_DsReplicaCursorCtrEx * udv ,
const struct GUID * originating_invocation_id ,
uint64_t originating_usn )
{
const struct drsuapi_DsReplicaCursor * c ;
if ( udv = = NULL ) return false ;
2016-06-07 02:57:02 +03:00
BINARY_ARRAY_SEARCH ( udv - > cursors , udv - > count , source_dsa_invocation_id ,
2010-01-09 05:11:27 +03:00
originating_invocation_id , udv_compare , c ) ;
if ( c & & originating_usn < = c - > highest_usn ) {
return true ;
}
return false ;
}
2016-08-15 05:10:38 +03:00
static int uint32_t_cmp ( uint32_t a1 , uint32_t a2 )
2010-09-30 02:49:15 +04:00
{
if ( a1 = = a2 ) return 0 ;
2016-08-15 05:10:38 +03:00
return a1 > a2 ? 1 : - 1 ;
2010-09-30 02:49:15 +04:00
}
2016-08-15 05:10:38 +03:00
static int uint32_t_ptr_cmp ( uint32_t * a1 , uint32_t * a2 , void * unused )
2010-09-30 02:49:15 +04:00
{
2016-08-15 05:10:38 +03:00
if ( * a1 = = * a2 ) return 0 ;
return * a1 > * a2 ? 1 : - 1 ;
2010-09-30 02:49:15 +04:00
}
2016-08-15 05:10:38 +03:00
static WERROR getncchanges_attid_remote_to_local ( const struct dsdb_schema * schema ,
const struct dsdb_syntax_ctx * ctx ,
enum drsuapi_DsAttributeId remote_attid_as_enum ,
enum drsuapi_DsAttributeId * local_attid_as_enum ,
const struct dsdb_attribute * * _sa )
{
WERROR werr ;
const struct dsdb_attribute * sa = NULL ;
if ( ctx - > pfm_remote = = NULL ) {
DEBUG ( 7 , ( " No prefixMap supplied, falling back to local prefixMap. \n " ) ) ;
goto fail ;
}
werr = dsdb_attribute_drsuapi_remote_to_local ( ctx ,
remote_attid_as_enum ,
local_attid_as_enum ,
_sa ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 3 , ( " WARNING: Unable to resolve remote attid, falling back to local prefixMap. \n " ) ) ;
goto fail ;
}
return werr ;
fail :
sa = dsdb_attribute_by_attributeID_id ( schema , remote_attid_as_enum ) ;
if ( sa = = NULL ) {
return WERR_DS_DRA_SCHEMA_MISMATCH ;
} else {
if ( local_attid_as_enum ! = NULL ) {
* local_attid_as_enum = sa - > attributeID_id ;
}
if ( _sa ! = NULL ) {
* _sa = sa ;
}
return WERR_OK ;
}
}
2010-09-30 02:49:15 +04:00
2017-03-13 02:18:00 +03:00
/*
* Similar to function in repl_meta_data without the extra
* dependencies .
*/
static WERROR get_parsed_dns_trusted ( TALLOC_CTX * mem_ctx , struct ldb_message_element * el ,
struct parsed_dn * * pdn )
{
/* Here we get a list of 'struct parsed_dns' without the parsing */
int i ;
* pdn = talloc_zero_array ( mem_ctx , struct parsed_dn ,
el - > num_values ) ;
if ( ! * pdn ) {
return WERR_DS_DRA_INTERNAL_ERROR ;
}
for ( i = 0 ; i < el - > num_values ; i + + ) {
( * pdn ) [ i ] . v = & el - > values [ i ] ;
}
return WERR_OK ;
}
2017-03-03 06:21:12 +03:00
static WERROR getncchanges_update_revealed_list ( struct ldb_context * sam_ctx ,
TALLOC_CTX * mem_ctx ,
struct ldb_message * * msg ,
struct ldb_dn * object_dn ,
2017-03-13 02:18:00 +03:00
const struct GUID * object_guid ,
2017-03-03 06:21:12 +03:00
const struct dsdb_attribute * sa ,
struct replPropertyMetaData1 * meta_data ,
struct ldb_message * revealed_users )
{
enum ndr_err_code ndr_err ;
int ldb_err ;
char * attr_str = NULL ;
char * attr_hex = NULL ;
DATA_BLOB attr_blob ;
struct ldb_message_element * existing = NULL , * el_add = NULL , * el_del = NULL ;
const char * const * secret_attributes = ldb_get_opaque ( sam_ctx , " LDB_SECRET_ATTRIBUTE_LIST " ) ;
if ( ! ldb_attr_in_list ( secret_attributes ,
sa - > lDAPDisplayName ) ) {
return WERR_OK ;
}
ndr_err = ndr_push_struct_blob ( & attr_blob , mem_ctx , meta_data , ( ndr_push_flags_fn_t ) ndr_push_replPropertyMetaData1 ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return WERR_DS_DRA_INTERNAL_ERROR ;
}
attr_hex = hex_encode_talloc ( mem_ctx , attr_blob . data , attr_blob . length ) ;
if ( attr_hex = = NULL ) {
return WERR_NOT_ENOUGH_MEMORY ;
}
attr_str = talloc_asprintf ( mem_ctx , " B:%zd:%s:%s " , attr_blob . length * 2 , attr_hex , ldb_dn_get_linearized ( object_dn ) ) ;
if ( attr_str = = NULL ) {
return WERR_NOT_ENOUGH_MEMORY ;
}
existing = ldb_msg_find_element ( revealed_users , " msDS-RevealedUsers " ) ;
if ( existing ! = NULL ) {
/* Replace the old value (if one exists) with the current one */
2017-03-13 02:18:00 +03:00
struct parsed_dn * link_dns ;
struct parsed_dn * exact = NULL , * unused = NULL ;
WERROR werr ;
uint8_t attid [ 4 ] ;
DATA_BLOB partial_meta ;
werr = get_parsed_dns_trusted ( mem_ctx , existing , & link_dns ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
return werr ;
}
/* Construct a partial metadata blob to match on in the DB */
SIVAL ( attid , 0 , sa - > attributeID_id ) ;
partial_meta . length = 4 ;
partial_meta . data = attid ;
/* Binary search using GUID and attribute id for uniqueness */
ldb_err = parsed_dn_find ( sam_ctx , link_dns , existing - > num_values ,
object_guid , object_dn ,
partial_meta , 4 ,
& exact , & unused ,
DSDB_SYNTAX_BINARY_DN , true ) ;
if ( ldb_err ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed parsed DN find - %s \n " ,
ldb_errstring ( sam_ctx ) ) ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
if ( exact ! = NULL ) {
/* Perform some verification of the blob */
struct replPropertyMetaData1 existing_meta_data ;
ndr_err = ndr_pull_struct_blob_all_noalloc ( & exact - > dsdb_dn - > extra_part ,
& existing_meta_data ,
( ndr_pull_flags_fn_t ) ndr_pull_replPropertyMetaData1 ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return WERR_DS_DRA_INTERNAL_ERROR ;
}
if ( existing_meta_data . attid = = sa - > attributeID_id ) {
ldb_err = ldb_msg_add_empty ( * msg , " msDS-RevealedUsers " , LDB_FLAG_MOD_DELETE , & el_del ) ;
if ( ldb_err ! = LDB_SUCCESS ) {
2017-03-03 06:21:12 +03:00
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2017-03-13 02:18:00 +03:00
el_del - > values = talloc_array ( ( * msg ) - > elements , struct ldb_val , 1 ) ;
if ( el_del - > values = = NULL ) {
return WERR_NOT_ENOUGH_MEMORY ;
2017-03-03 06:21:12 +03:00
}
2017-03-13 02:18:00 +03:00
el_del - > values [ 0 ] = * exact - > v ;
el_del - > num_values = 1 ;
} else {
return WERR_DS_DRA_INTERNAL_ERROR ;
2017-03-03 06:21:12 +03:00
}
}
}
ldb_err = ldb_msg_add_empty ( * msg , " msDS-RevealedUsers " , LDB_FLAG_MOD_ADD , & el_add ) ;
if ( ldb_err ! = LDB_SUCCESS ) {
return WERR_DS_DRA_INTERNAL_ERROR ;
}
el_add - > values = talloc_array ( ( * msg ) - > elements , struct ldb_val , 1 ) ;
if ( el_add - > values = = NULL ) {
return WERR_NOT_ENOUGH_MEMORY ;
}
el_add - > values [ 0 ] = data_blob_string_const ( attr_str ) ;
el_add - > num_values = 1 ;
return WERR_OK ;
}
2017-03-03 01:18:33 +03:00
/*
* This function filter attributes for build_object based on the
* uptodatenessvector and partial attribute set .
*
* Any secret attributes are forced here for REPL_SECRET , and audited at this
* point with msDS - RevealedUsers .
*/
2017-03-03 01:01:36 +03:00
static WERROR get_nc_changes_filter_attrs ( struct drsuapi_DsReplicaObjectListItemEx * obj ,
struct replPropertyMetaDataBlob md ,
struct ldb_context * sam_ctx ,
const struct ldb_message * msg ,
2017-03-13 02:18:00 +03:00
const struct GUID * guid ,
2017-03-03 01:01:36 +03:00
uint32_t * count ,
uint64_t highest_usn ,
const struct dsdb_attribute * rdn_sa ,
struct dsdb_schema * schema ,
2017-03-03 01:18:33 +03:00
struct drsuapi_DsReplicaCursorCtrEx * uptodateness_vector ,
struct drsuapi_DsPartialAttributeSet * partial_attribute_set ,
uint32_t * local_pas ,
uint32_t * attids ,
2017-03-03 01:01:36 +03:00
bool exop_secret ,
struct ldb_message * * revealed_list_msg ,
2017-03-03 01:18:33 +03:00
struct ldb_message * existing_revealed_list_msg )
2017-03-03 01:01:36 +03:00
{
uint32_t i , n ;
WERROR werr ;
for ( n = i = 0 ; i < md . ctr . ctr1 . count ; i + + ) {
const struct dsdb_attribute * sa ;
bool force_attribute = false ;
/* if the attribute has not changed, and it is not the
instanceType then don ' t include it */
if ( md . ctr . ctr1 . array [ i ] . local_usn < highest_usn & &
! exop_secret & &
md . ctr . ctr1 . array [ i ] . attid ! = DRSUAPI_ATTID_instanceType ) continue ;
/* don't include the rDN */
if ( md . ctr . ctr1 . array [ i ] . attid = = rdn_sa - > attributeID_id ) continue ;
sa = dsdb_attribute_by_attributeID_id ( schema , md . ctr . ctr1 . array [ i ] . attid ) ;
if ( ! sa ) {
DEBUG ( 0 , ( __location__ " : Failed to find attribute in schema for attrid %u mentioned in replPropertyMetaData of %s \n " ,
( unsigned int ) md . ctr . ctr1 . array [ i ] . attid ,
ldb_dn_get_linearized ( msg - > dn ) ) ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
if ( sa - > linkID ) {
struct ldb_message_element * el ;
el = ldb_msg_find_element ( msg , sa - > lDAPDisplayName ) ;
if ( el & & el - > num_values & & dsdb_dn_is_upgraded_link_val ( & el - > values [ 0 ] ) ) {
/* don't send upgraded links inline */
continue ;
}
}
if ( exop_secret & &
! dsdb_attr_in_rodc_fas ( sa ) ) {
force_attribute = true ;
DEBUG ( 4 , ( " Forcing attribute %s in %s \n " ,
sa - > lDAPDisplayName , ldb_dn_get_linearized ( msg - > dn ) ) ) ;
werr = getncchanges_update_revealed_list ( sam_ctx , obj ,
revealed_list_msg ,
2017-03-13 02:18:00 +03:00
msg - > dn , guid , sa ,
2017-03-03 01:01:36 +03:00
& md . ctr . ctr1 . array [ i ] ,
existing_revealed_list_msg ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
return werr ;
}
}
/* filter by uptodateness_vector */
if ( md . ctr . ctr1 . array [ i ] . attid ! = DRSUAPI_ATTID_instanceType & &
! force_attribute & &
udv_filter ( uptodateness_vector ,
& md . ctr . ctr1 . array [ i ] . originating_invocation_id ,
md . ctr . ctr1 . array [ i ] . originating_usn ) ) {
continue ;
}
/* filter by partial_attribute_set */
if ( partial_attribute_set & & ! force_attribute ) {
uint32_t * result = NULL ;
BINARY_ARRAY_SEARCH_V ( local_pas , partial_attribute_set - > num_attids , sa - > attributeID_id ,
uint32_t_cmp , result ) ;
if ( result = = NULL ) {
continue ;
}
}
obj - > meta_data_ctr - > meta_data [ n ] . originating_change_time = md . ctr . ctr1 . array [ i ] . originating_change_time ;
obj - > meta_data_ctr - > meta_data [ n ] . version = md . ctr . ctr1 . array [ i ] . version ;
obj - > meta_data_ctr - > meta_data [ n ] . originating_invocation_id = md . ctr . ctr1 . array [ i ] . originating_invocation_id ;
obj - > meta_data_ctr - > meta_data [ n ] . originating_usn = md . ctr . ctr1 . array [ i ] . originating_usn ;
attids [ n ] = md . ctr . ctr1 . array [ i ] . attid ;
n + + ;
}
* count = n ;
return WERR_OK ;
}
2009-09-09 15:26:17 +04:00
/*
2009-09-10 11:46:30 +04:00
drsuapi_DsGetNCChanges for one object
2009-09-09 15:26:17 +04:00
*/
static WERROR get_nc_changes_build_object ( struct drsuapi_DsReplicaObjectListItemEx * obj ,
2016-12-01 13:50:34 +03:00
const struct ldb_message * msg ,
2009-09-09 15:26:17 +04:00
struct ldb_context * sam_ctx ,
struct ldb_dn * ncRoot_dn ,
2010-08-18 04:52:48 +04:00
bool is_schema_nc ,
2009-09-10 11:46:30 +04:00
struct dsdb_schema * schema ,
2009-09-12 05:14:29 +04:00
DATA_BLOB * session_key ,
s4: Handle DRSUAPI_DS_REPLICA_NEIGHBOUR_SPECIAL_SECRET_PROCESSING in getncchanges
When this flag is specified in the request these attributes are treated as
secret: currentValue, dBCSPwd, initialAuthIncoming, initialAuthOutgoing,
lmPwdHistory, ntPwdHistory, priorValue, supplementalCredentials,
trustAuthIncoming, trustAuthOutgoing, unicodePwd
Their value is changed to NULL and the meta_data.originating_change_time to 0
2009-09-24 03:51:55 +04:00
uint64_t highest_usn ,
2010-01-09 05:11:27 +03:00
uint32_t replica_flags ,
2010-09-30 02:49:15 +04:00
struct drsuapi_DsPartialAttributeSet * partial_attribute_set ,
2010-08-18 08:31:05 +04:00
struct drsuapi_DsReplicaCursorCtrEx * uptodateness_vector ,
2011-11-10 14:23:40 +04:00
enum drsuapi_DsExtendedOperation extended_op ,
2016-08-15 05:10:38 +03:00
bool force_object_return ,
2017-03-03 06:21:12 +03:00
uint32_t * local_pas ,
2017-03-13 02:18:00 +03:00
struct ldb_dn * machine_dn ,
const struct GUID * guid )
2009-09-09 15:26:17 +04:00
{
const struct ldb_val * md_value ;
2010-09-30 10:47:24 +04:00
uint32_t i , n ;
2009-09-09 17:38:51 +04:00
struct replPropertyMetaDataBlob md ;
2009-09-10 11:46:30 +04:00
uint32_t rid = 0 ;
2017-03-03 06:21:12 +03:00
int ldb_err ;
2009-09-12 05:14:29 +04:00
enum ndr_err_code ndr_err ;
uint32_t * attids ;
2009-09-24 00:56:10 +04:00
const char * rdn ;
const struct dsdb_attribute * rdn_sa ;
2017-02-07 14:28:33 +03:00
uint64_t uSNChanged ;
2010-01-09 10:50:30 +03:00
unsigned int instanceType ;
2010-08-18 04:52:48 +04:00
struct dsdb_syntax_ctx syntax_ctx ;
2017-03-03 06:21:12 +03:00
struct ldb_result * res = NULL ;
WERROR werr ;
int ret ;
2010-08-18 04:52:48 +04:00
/* make dsdb sytanx context for conversions */
dsdb_syntax_ctx_init ( & syntax_ctx , sam_ctx , schema ) ;
syntax_ctx . is_schema_nc = is_schema_nc ;
2009-09-09 15:26:17 +04:00
2017-02-07 14:28:33 +03:00
uSNChanged = ldb_msg_find_attr_as_uint64 ( msg , " uSNChanged " , 0 ) ;
2010-01-09 10:50:30 +03:00
instanceType = ldb_msg_find_attr_as_uint ( msg , " instanceType " , 0 ) ;
if ( instanceType & INSTANCE_TYPE_IS_NC_HEAD ) {
2009-09-09 15:26:17 +04:00
obj - > is_nc_prefix = true ;
obj - > parent_object_guid = NULL ;
} else {
2009-09-26 02:17:44 +04:00
obj - > is_nc_prefix = false ;
obj - > parent_object_guid = talloc ( obj , struct GUID ) ;
2009-12-09 06:38:25 +03:00
if ( obj - > parent_object_guid = = NULL ) {
2009-09-26 02:17:44 +04:00
return WERR_DS_DRA_INTERNAL_ERROR ;
2009-09-24 00:56:10 +04:00
}
2009-12-09 06:38:25 +03:00
* obj - > parent_object_guid = samdb_result_guid ( msg , " parentGUID " ) ;
if ( GUID_all_zero ( obj - > parent_object_guid ) ) {
DEBUG ( 0 , ( __location__ " : missing parentGUID for %s \n " ,
ldb_dn_get_linearized ( msg - > dn ) ) ) ;
2009-09-26 02:17:44 +04:00
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2009-09-09 15:26:17 +04:00
}
obj - > next_object = NULL ;
2016-06-07 02:57:02 +03:00
2009-09-09 15:26:17 +04:00
md_value = ldb_msg_find_ldb_val ( msg , " replPropertyMetaData " ) ;
2009-09-12 05:14:29 +04:00
if ( ! md_value ) {
/* nothing to send */
return WERR_OK ;
}
2010-04-26 11:02:25 +04:00
if ( instanceType & INSTANCE_TYPE_UNINSTANT ) {
/* don't send uninstantiated objects */
return WERR_OK ;
}
2017-02-07 14:28:33 +03:00
if ( uSNChanged < = highest_usn ) {
/* nothing to send */
return WERR_OK ;
}
2010-05-09 19:20:01 +04:00
ndr_err = ndr_pull_struct_blob ( md_value , obj , & md ,
2009-09-12 05:14:29 +04:00
( ndr_pull_flags_fn_t ) ndr_pull_replPropertyMetaDataBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2016-06-07 02:57:02 +03:00
2009-09-12 05:14:29 +04:00
if ( md . version ! = 1 ) {
return WERR_DS_DRA_INTERNAL_ERROR ;
2009-09-09 15:26:17 +04:00
}
2009-09-12 05:14:29 +04:00
2009-09-24 00:56:10 +04:00
rdn = ldb_dn_get_rdn_name ( msg - > dn ) ;
if ( rdn = = NULL ) {
DEBUG ( 0 , ( __location__ " : No rDN for %s \n " , ldb_dn_get_linearized ( msg - > dn ) ) ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
rdn_sa = dsdb_attribute_by_lDAPDisplayName ( schema , rdn ) ;
if ( rdn_sa = = NULL ) {
2016-06-07 02:57:02 +03:00
DEBUG ( 0 , ( __location__ " : Can't find dsds_attribute for rDN %s in %s \n " ,
2009-09-24 00:56:10 +04:00
rdn , ldb_dn_get_linearized ( msg - > dn ) ) ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2009-09-12 05:14:29 +04:00
obj - > meta_data_ctr = talloc ( obj , struct drsuapi_DsReplicaMetaDataCtr ) ;
attids = talloc_array ( obj , uint32_t , md . ctr . ctr1 . count ) ;
2009-12-03 01:19:55 +03:00
2009-12-19 04:25:09 +03:00
obj - > object . identifier = get_object_identifier ( obj , msg ) ;
if ( obj - > object . identifier = = NULL ) {
2015-12-03 17:24:19 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2009-12-03 01:19:55 +03:00
}
2009-12-19 04:25:09 +03:00
dom_sid_split_rid ( NULL , & obj - > object . identifier - > sid , NULL , & rid ) ;
2016-06-07 02:57:02 +03:00
2009-09-12 05:14:29 +04:00
obj - > meta_data_ctr - > meta_data = talloc_array ( obj , struct drsuapi_DsReplicaMetaData , md . ctr . ctr1 . count ) ;
2017-03-03 06:21:12 +03:00
if ( extended_op = = DRSUAPI_EXOP_REPL_SECRET ) {
/* Get the existing revealed users for the destination */
2017-03-03 01:18:33 +03:00
struct ldb_message * revealed_list_msg = NULL ;
struct ldb_message * existing_revealed_list_msg = NULL ;
const char * machine_attrs [ ] = {
" msDS-RevealedUsers " ,
NULL
} ;
2017-03-03 06:21:12 +03:00
revealed_list_msg = ldb_msg_new ( sam_ctx ) ;
if ( revealed_list_msg = = NULL ) {
return WERR_NOT_ENOUGH_MEMORY ;
}
revealed_list_msg - > dn = machine_dn ;
ret = ldb_transaction_start ( sam_ctx ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed transaction start - %s \n " ,
ldb_errstring ( sam_ctx ) ) ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2017-03-13 02:18:00 +03:00
ldb_err = dsdb_search_dn ( sam_ctx , obj , & res , machine_dn , machine_attrs , DSDB_SEARCH_SHOW_EXTENDED_DN ) ;
2017-03-03 01:14:24 +03:00
if ( ldb_err ! = LDB_SUCCESS | | res - > count ! = 1 ) {
2017-03-03 06:21:12 +03:00
ldb_transaction_cancel ( sam_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2017-03-03 01:14:24 +03:00
existing_revealed_list_msg = res - > msgs [ 0 ] ;
2017-03-13 02:18:00 +03:00
werr = get_nc_changes_filter_attrs ( obj , md , sam_ctx , msg ,
guid , & n , highest_usn ,
rdn_sa , schema ,
2017-03-03 01:14:24 +03:00
uptodateness_vector ,
partial_attribute_set , local_pas ,
2017-03-03 01:18:33 +03:00
attids ,
true ,
& revealed_list_msg ,
existing_revealed_list_msg ) ;
2017-03-03 01:14:24 +03:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
ldb_transaction_cancel ( sam_ctx ) ;
return werr ;
}
if ( revealed_list_msg ! = NULL ) {
ret = ldb_modify ( sam_ctx , revealed_list_msg ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to alter revealed links - %s \n " ,
ldb_errstring ( sam_ctx ) ) ) ;
ldb_transaction_cancel ( sam_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
}
2017-03-03 06:21:12 +03:00
ret = ldb_transaction_commit ( sam_ctx ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed transaction commit - %s \n " ,
ldb_errstring ( sam_ctx ) ) ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2017-03-03 01:14:24 +03:00
} else {
2017-03-13 02:18:00 +03:00
werr = get_nc_changes_filter_attrs ( obj , md , sam_ctx , msg , guid ,
& n , highest_usn , rdn_sa ,
schema , uptodateness_vector ,
2017-03-03 01:14:24 +03:00
partial_attribute_set , local_pas ,
2017-03-03 01:18:33 +03:00
attids ,
false ,
NULL ,
NULL ) ;
2017-03-03 01:14:24 +03:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
return werr ;
}
2017-03-03 06:21:12 +03:00
}
2010-01-09 05:11:27 +03:00
/* ignore it if its an empty change. Note that renames always
* change the ' name ' attribute , so they won ' t be ignored by
2011-11-10 14:23:40 +04:00
* this
* the force_object_return check is used to force an empty
* object return when we timeout in the getncchanges loop .
* This allows us to return an empty object , which keeps the
* client happy while preventing timeouts
*/
2010-01-09 05:11:27 +03:00
if ( n = = 0 | |
2011-11-10 14:23:40 +04:00
( n = = 1 & &
attids [ 0 ] = = DRSUAPI_ATTID_instanceType & &
! force_object_return ) ) {
2010-01-09 05:11:27 +03:00
talloc_free ( obj - > meta_data_ctr ) ;
obj - > meta_data_ctr = NULL ;
return WERR_OK ;
}
2009-09-15 00:12:32 +04:00
2009-09-12 05:14:29 +04:00
obj - > meta_data_ctr - > count = n ;
2009-09-24 00:56:10 +04:00
obj - > object . flags = DRSUAPI_DS_REPLICA_OBJECT_FROM_MASTER ;
2009-09-09 17:38:51 +04:00
obj - > object . attribute_ctr . num_attributes = obj - > meta_data_ctr - > count ;
obj - > object . attribute_ctr . attributes = talloc_array ( obj , struct drsuapi_DsReplicaAttribute ,
obj - > object . attribute_ctr . num_attributes ) ;
2011-11-15 14:47:42 +04:00
if ( obj - > object . attribute_ctr . attributes = = NULL ) {
2015-12-03 17:24:19 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2011-11-15 14:47:42 +04:00
}
2009-09-09 17:38:51 +04:00
/*
* Note that the meta_data array and the attributes array must
* be the same size and in the same order
*/
for ( i = 0 ; i < obj - > object . attribute_ctr . num_attributes ; i + + ) {
struct ldb_message_element * el ;
2009-09-24 00:56:10 +04:00
const struct dsdb_attribute * sa ;
2016-06-07 02:57:02 +03:00
2009-09-12 05:14:29 +04:00
sa = dsdb_attribute_by_attributeID_id ( schema , attids [ i ] ) ;
2009-09-09 17:38:51 +04:00
if ( ! sa ) {
2009-09-12 05:14:29 +04:00
DEBUG ( 0 , ( " Unable to find attributeID %u in schema \n " , attids [ i ] ) ) ;
2009-09-09 17:38:51 +04:00
return WERR_DS_DRA_INTERNAL_ERROR ;
}
el = ldb_msg_find_element ( msg , sa - > lDAPDisplayName ) ;
if ( el = = NULL ) {
2009-12-03 01:19:55 +03:00
/* this happens for attributes that have been removed */
DEBUG ( 5 , ( " No element '%s' for attributeID %u in message \n " ,
2009-09-12 05:14:29 +04:00
sa - > lDAPDisplayName , attids [ i ] ) ) ;
2009-09-09 19:27:12 +04:00
ZERO_STRUCT ( obj - > object . attribute_ctr . attributes [ i ] ) ;
2010-08-19 04:17:36 +04:00
obj - > object . attribute_ctr . attributes [ i ] . attid =
dsdb_attribute_get_attid ( sa , syntax_ctx . is_schema_nc ) ;
2009-09-09 19:27:12 +04:00
} else {
2010-08-18 04:52:48 +04:00
werr = sa - > syntax - > ldb_to_drsuapi ( & syntax_ctx , sa , el , obj ,
& obj - > object . attribute_ctr . attributes [ i ] ) ;
2009-09-09 19:27:12 +04:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
2013-04-02 09:10:03 +04:00
DEBUG ( 0 , ( " Unable to convert %s on %s to DRS object - %s \n " ,
sa - > lDAPDisplayName , ldb_dn_get_linearized ( msg - > dn ) ,
win_errstr ( werr ) ) ) ;
2009-09-09 19:27:12 +04:00
return werr ;
}
2009-10-14 13:29:39 +04:00
/* if DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING is set
s4: Handle DRSUAPI_DS_REPLICA_NEIGHBOUR_SPECIAL_SECRET_PROCESSING in getncchanges
When this flag is specified in the request these attributes are treated as
secret: currentValue, dBCSPwd, initialAuthIncoming, initialAuthOutgoing,
lmPwdHistory, ntPwdHistory, priorValue, supplementalCredentials,
trustAuthIncoming, trustAuthOutgoing, unicodePwd
Their value is changed to NULL and the meta_data.originating_change_time to 0
2009-09-24 03:51:55 +04:00
* check if attribute is secret and send a null value
*/
2009-10-14 13:29:39 +04:00
if ( replica_flags & DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING ) {
s4: Handle DRSUAPI_DS_REPLICA_NEIGHBOUR_SPECIAL_SECRET_PROCESSING in getncchanges
When this flag is specified in the request these attributes are treated as
secret: currentValue, dBCSPwd, initialAuthIncoming, initialAuthOutgoing,
lmPwdHistory, ntPwdHistory, priorValue, supplementalCredentials,
trustAuthIncoming, trustAuthOutgoing, unicodePwd
Their value is changed to NULL and the meta_data.originating_change_time to 0
2009-09-24 03:51:55 +04:00
drsuapi_process_secret_attribute ( & obj - > object . attribute_ctr . attributes [ i ] ,
& obj - > meta_data_ctr - > meta_data [ i ] ) ;
}
2009-09-10 11:46:30 +04:00
/* some attributes needs to be encrypted
before being sent */
werr = drsuapi_encrypt_attribute ( obj , session_key , rid ,
& obj - > object . attribute_ctr . attributes [ i ] ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
2013-04-02 09:10:03 +04:00
DEBUG ( 0 , ( " Unable to encrypt %s on %s in DRS object - %s \n " ,
sa - > lDAPDisplayName , ldb_dn_get_linearized ( msg - > dn ) ,
win_errstr ( werr ) ) ) ;
2009-09-10 11:46:30 +04:00
return werr ;
}
2009-09-09 15:26:17 +04:00
}
2015-12-22 09:39:31 +03:00
if ( attids [ i ] ! = obj - > object . attribute_ctr . attributes [ i ] . attid ) {
DEBUG ( 0 , ( " Unable to replicate attribute %s on %s via DRS, incorrect attributeID: "
" 0x%08x vs 0x%08x "
" Run dbcheck! \n " ,
sa - > lDAPDisplayName ,
ldb_dn_get_linearized ( msg - > dn ) ,
attids [ i ] ,
obj - > object . attribute_ctr . attributes [ i ] . attid ) ) ;
return WERR_DS_DATABASE_ERROR ;
}
2009-09-09 15:26:17 +04:00
}
return WERR_OK ;
}
2009-12-19 04:25:09 +03:00
/*
add one linked attribute from an object to the list of linked
attributes in a getncchanges request
*/
static WERROR get_nc_changes_add_la ( TALLOC_CTX * mem_ctx ,
struct ldb_context * sam_ctx ,
const struct dsdb_schema * schema ,
const struct dsdb_attribute * sa ,
2016-12-01 13:50:34 +03:00
const struct ldb_message * msg ,
2009-12-19 04:25:09 +03:00
struct dsdb_dn * dsdb_dn ,
struct drsuapi_DsReplicaLinkedAttribute * * la_list ,
2016-07-27 05:22:39 +03:00
uint32_t * la_count ,
bool is_schema_nc )
2009-12-19 04:25:09 +03:00
{
struct drsuapi_DsReplicaLinkedAttribute * la ;
bool active ;
NTSTATUS status ;
WERROR werr ;
( * la_list ) = talloc_realloc ( mem_ctx , * la_list , struct drsuapi_DsReplicaLinkedAttribute , ( * la_count ) + 1 ) ;
W_ERROR_HAVE_NO_MEMORY ( * la_list ) ;
la = & ( * la_list ) [ * la_count ] ;
la - > identifier = get_object_identifier ( * la_list , msg ) ;
W_ERROR_HAVE_NO_MEMORY ( la - > identifier ) ;
2010-01-02 00:14:52 +03:00
active = ( dsdb_dn_rmd_flags ( dsdb_dn - > dn ) & DSDB_RMD_FLAG_DELETED ) = = 0 ;
2009-12-19 04:25:09 +03:00
2011-07-08 02:06:04 +04:00
if ( ! active ) {
/* We have to check that the inactive link still point to an existing object */
struct GUID guid ;
struct ldb_dn * tdn ;
int ret ;
2011-07-19 00:59:20 +04:00
const char * v ;
2011-11-14 21:32:41 +04:00
v = ldb_msg_find_attr_as_string ( msg , " isDeleted " , " FALSE " ) ;
if ( strncmp ( v , " TRUE " , 4 ) = = 0 ) {
2011-07-19 00:59:20 +04:00
/*
2011-10-05 18:23:37 +04:00
* Note : we skip the transmition of the deleted link even if the other part used to
* know about it because when we transmit the deletion of the object , the link will
* be deleted too due to deletion of object where link points and Windows do so .
*/
if ( dsdb_functional_level ( sam_ctx ) > = DS_DOMAIN_FUNCTION_2008_R2 ) {
2011-11-15 15:42:22 +04:00
v = ldb_msg_find_attr_as_string ( msg , " isRecycled " , " FALSE " ) ;
2011-10-05 18:23:37 +04:00
/*
* On Windows 2008 R2 isRecycled is always present even if FL or DL are < FL 2 K8R2
* if it join an existing domain with deleted objets , it firsts impose to have a
* schema with the is - Recycled object and for all deleted objects it adds the isRecycled
* either during initial replication or after the getNCChanges .
* Behavior of samba has been changed to always have this attribute if it ' s present in the schema .
*
* So if FL < 2 K8R2 isRecycled might be here or not but we don ' t care , it ' s meaning less .
* If FL > = 2 K8R2 we are sure that this attribute will be here .
* For this kind of forest level we do not return the link if the object is recycled
* ( isRecycled = true ) .
*/
2011-11-14 21:32:41 +04:00
if ( strncmp ( v , " TRUE " , 4 ) = = 0 ) {
2011-10-05 18:23:37 +04:00
DEBUG ( 2 , ( " object %s is recycled, not returning linked attribute ! \n " ,
ldb_dn_get_linearized ( msg - > dn ) ) ) ;
return WERR_OK ;
}
} else {
2011-07-19 00:59:20 +04:00
return WERR_OK ;
}
}
2011-07-08 02:06:04 +04:00
status = dsdb_get_extended_dn_guid ( dsdb_dn - > dn , & guid , " GUID " ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( __location__ " Unable to extract GUID in linked attribute '%s' in '%s' \n " ,
sa - > lDAPDisplayName , ldb_dn_get_linearized ( msg - > dn ) ) ) ;
return ntstatus_to_werror ( status ) ;
}
2013-06-10 06:22:40 +04:00
ret = dsdb_find_dn_by_guid ( sam_ctx , mem_ctx , & guid , 0 , & tdn ) ;
2011-07-08 02:06:04 +04:00
if ( ret = = LDB_ERR_NO_SUCH_OBJECT ) {
DEBUG ( 2 , ( " Search of guid %s returned 0 objects, skipping it ! \n " ,
GUID_string ( mem_ctx , & guid ) ) ) ;
return WERR_OK ;
} else if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " Search of guid %s failed with error code %d \n " ,
GUID_string ( mem_ctx , & guid ) ,
ret ) ) ;
return WERR_OK ;
}
}
2016-07-27 05:22:39 +03:00
la - > attid = dsdb_attribute_get_attid ( sa , is_schema_nc ) ;
2009-12-19 04:25:09 +03:00
la - > flags = active ? DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE : 0 ;
status = dsdb_get_extended_dn_uint32 ( dsdb_dn - > dn , & la - > meta_data . version , " RMD_VERSION " ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-06-10 04:11:01 +04:00
DEBUG ( 0 , ( __location__ " No RMD_VERSION in linked attribute '%s' in '%s' \n " ,
sa - > lDAPDisplayName , ldb_dn_get_linearized ( msg - > dn ) ) ) ;
2009-12-19 04:25:09 +03:00
return ntstatus_to_werror ( status ) ;
}
status = dsdb_get_extended_dn_nttime ( dsdb_dn - > dn , & la - > meta_data . originating_change_time , " RMD_CHANGETIME " ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-06-10 04:11:01 +04:00
DEBUG ( 0 , ( __location__ " No RMD_CHANGETIME in linked attribute '%s' in '%s' \n " ,
sa - > lDAPDisplayName , ldb_dn_get_linearized ( msg - > dn ) ) ) ;
2009-12-19 04:25:09 +03:00
return ntstatus_to_werror ( status ) ;
}
status = dsdb_get_extended_dn_guid ( dsdb_dn - > dn , & la - > meta_data . originating_invocation_id , " RMD_INVOCID " ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-06-10 04:11:01 +04:00
DEBUG ( 0 , ( __location__ " No RMD_INVOCID in linked attribute '%s' in '%s' \n " ,
sa - > lDAPDisplayName , ldb_dn_get_linearized ( msg - > dn ) ) ) ;
2009-12-19 04:25:09 +03:00
return ntstatus_to_werror ( status ) ;
}
status = dsdb_get_extended_dn_uint64 ( dsdb_dn - > dn , & la - > meta_data . originating_usn , " RMD_ORIGINATING_USN " ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-06-10 04:11:01 +04:00
DEBUG ( 0 , ( __location__ " No RMD_ORIGINATING_USN in linked attribute '%s' in '%s' \n " ,
sa - > lDAPDisplayName , ldb_dn_get_linearized ( msg - > dn ) ) ) ;
2009-12-19 04:25:09 +03:00
return ntstatus_to_werror ( status ) ;
}
2011-06-10 03:10:09 +04:00
status = dsdb_get_extended_dn_nttime ( dsdb_dn - > dn , & la - > originating_add_time , " RMD_ADDTIME " ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
/* this is possible for upgraded links */
la - > originating_add_time = la - > meta_data . originating_change_time ;
}
2009-12-28 09:19:29 +03:00
werr = dsdb_dn_la_to_blob ( sam_ctx , sa , schema , * la_list , dsdb_dn , & la - > value . blob ) ;
2009-12-19 04:25:09 +03:00
W_ERROR_NOT_OK_RETURN ( werr ) ;
( * la_count ) + + ;
return WERR_OK ;
}
/*
add linked attributes from an object to the list of linked
attributes in a getncchanges request
*/
static WERROR get_nc_changes_add_links ( struct ldb_context * sam_ctx ,
TALLOC_CTX * mem_ctx ,
struct ldb_dn * ncRoot_dn ,
2016-07-27 05:22:39 +03:00
bool is_schema_nc ,
2009-12-19 04:25:09 +03:00
struct dsdb_schema * schema ,
uint64_t highest_usn ,
uint32_t replica_flags ,
2016-12-01 13:50:34 +03:00
const struct ldb_message * msg ,
2009-12-19 04:25:09 +03:00
struct drsuapi_DsReplicaLinkedAttribute * * la_list ,
2010-01-09 05:11:27 +03:00
uint32_t * la_count ,
struct drsuapi_DsReplicaCursorCtrEx * uptodateness_vector )
2009-12-19 04:25:09 +03:00
{
2009-11-21 20:57:24 +03:00
unsigned int i ;
2016-12-14 06:04:32 +03:00
TALLOC_CTX * tmp_ctx = NULL ;
2017-02-07 14:28:33 +03:00
uint64_t uSNChanged = ldb_msg_find_attr_as_uint64 ( msg , " uSNChanged " , 0 ) ;
2016-12-14 06:04:32 +03:00
bool is_critical = ldb_msg_find_attr_as_bool ( msg , " isCriticalSystemObject " , false ) ;
if ( replica_flags & DRSUAPI_DRS_CRITICAL_ONLY ) {
if ( ! is_critical ) {
return WERR_OK ;
}
}
2017-02-07 14:28:33 +03:00
if ( uSNChanged < = highest_usn ) {
return WERR_OK ;
}
2016-12-14 06:04:32 +03:00
tmp_ctx = talloc_new ( mem_ctx ) ;
if ( tmp_ctx = = NULL ) {
return WERR_NOT_ENOUGH_MEMORY ;
}
2009-12-19 04:25:09 +03:00
for ( i = 0 ; i < msg - > num_elements ; i + + ) {
struct ldb_message_element * el = & msg - > elements [ i ] ;
const struct dsdb_attribute * sa ;
2009-11-21 20:57:24 +03:00
unsigned int j ;
2009-12-19 04:25:09 +03:00
sa = dsdb_attribute_by_lDAPDisplayName ( schema , el - > name ) ;
if ( ! sa | | sa - > linkID = = 0 | | ( sa - > linkID & 1 ) ) {
/* we only want forward links */
continue ;
}
2009-12-19 12:59:04 +03:00
if ( el - > num_values & & ! dsdb_dn_is_upgraded_link_val ( & el - > values [ 0 ] ) ) {
/* its an old style link, it will have been
* sent in the main replication data */
continue ;
}
2009-12-19 04:25:09 +03:00
for ( j = 0 ; j < el - > num_values ; j + + ) {
struct dsdb_dn * dsdb_dn ;
uint64_t local_usn ;
2016-12-14 06:05:05 +03:00
uint64_t originating_usn ;
NTSTATUS status , status2 ;
2009-12-19 04:25:09 +03:00
WERROR werr ;
2016-12-14 06:05:05 +03:00
struct GUID originating_invocation_id ;
2009-12-19 04:25:09 +03:00
dsdb_dn = dsdb_dn_parse ( tmp_ctx , sam_ctx , & el - > values [ j ] , sa - > syntax - > ldap_oid ) ;
if ( dsdb_dn = = NULL ) {
DEBUG ( 1 , ( __location__ " : Failed to parse DN for %s in %s \n " ,
el - > name , ldb_dn_get_linearized ( msg - > dn ) ) ) ;
talloc_free ( tmp_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
status = dsdb_get_extended_dn_uint64 ( dsdb_dn - > dn , & local_usn , " RMD_LOCAL_USN " ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
/* this can happen for attributes
given to us with old style meta
data */
continue ;
}
2009-12-19 16:12:35 +03:00
if ( local_usn > uSNChanged ) {
DEBUG ( 1 , ( __location__ " : uSNChanged less than RMD_LOCAL_USN for %s on %s \n " ,
el - > name , ldb_dn_get_linearized ( msg - > dn ) ) ) ;
talloc_free ( tmp_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2017-02-07 14:34:45 +03:00
if ( local_usn < = highest_usn ) {
2009-12-19 04:25:09 +03:00
continue ;
}
2016-12-14 06:05:05 +03:00
status = dsdb_get_extended_dn_guid ( dsdb_dn - > dn ,
& originating_invocation_id ,
" RMD_INVOCID " ) ;
status2 = dsdb_get_extended_dn_uint64 ( dsdb_dn - > dn ,
& originating_usn ,
" RMD_ORIGINATING_USN " ) ;
if ( NT_STATUS_IS_OK ( status ) & & NT_STATUS_IS_OK ( status2 ) ) {
if ( udv_filter ( uptodateness_vector ,
& originating_invocation_id ,
originating_usn ) ) {
continue ;
}
}
2016-07-27 05:22:39 +03:00
werr = get_nc_changes_add_la ( mem_ctx , sam_ctx , schema ,
sa , msg , dsdb_dn , la_list ,
la_count , is_schema_nc ) ;
2009-12-19 04:25:09 +03:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
talloc_free ( tmp_ctx ) ;
return werr ;
}
}
}
talloc_free ( tmp_ctx ) ;
return WERR_OK ;
}
2009-09-12 05:14:29 +04:00
/*
fill in the cursors return based on the replUpToDateVector for the ncRoot_dn
*/
static WERROR get_nc_changes_udv ( struct ldb_context * sam_ctx ,
struct ldb_dn * ncRoot_dn ,
2010-01-16 03:49:09 +03:00
struct drsuapi_DsReplicaCursor2CtrEx * udv )
2009-09-12 05:14:29 +04:00
{
2010-01-16 03:49:09 +03:00
int ret ;
2009-09-12 05:14:29 +04:00
2010-01-09 06:28:00 +03:00
udv - > version = 2 ;
udv - > reserved1 = 0 ;
udv - > reserved2 = 0 ;
2010-01-16 03:08:59 +03:00
ret = dsdb_load_udv_v2 ( sam_ctx , ncRoot_dn , udv , & udv - > cursors , & udv - > count ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to load UDV for %s - %s \n " ,
ldb_dn_get_linearized ( ncRoot_dn ) , ldb_errstring ( sam_ctx ) ) ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
2009-09-12 05:14:29 +04:00
}
2016-06-07 02:57:02 +03:00
2009-09-10 13:41:48 +04:00
return WERR_OK ;
}
2009-12-28 09:22:40 +03:00
/* comparison function for linked attributes - see CompareLinks() in
* MS - DRSR section 4.1 .10 .5 .17 */
2016-06-07 02:56:49 +03:00
static int linked_attribute_compare ( const struct la_for_sorting * la1 ,
const struct la_for_sorting * la2 ,
void * opaque )
2009-12-28 09:22:40 +03:00
{
int c ;
2016-06-13 07:41:08 +03:00
c = memcmp ( la1 - > source_guid ,
la2 - > source_guid , sizeof ( la2 - > source_guid ) ) ;
2016-06-07 02:56:49 +03:00
if ( c ! = 0 ) {
return c ;
2009-12-28 09:22:40 +03:00
}
2016-06-07 02:56:49 +03:00
if ( la1 - > link - > attid ! = la2 - > link - > attid ) {
return la1 - > link - > attid < la2 - > link - > attid ? - 1 : 1 ;
2009-12-28 09:22:40 +03:00
}
2016-06-07 02:56:49 +03:00
if ( ( la1 - > link - > flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE ) ! =
( la2 - > link - > flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE ) ) {
return ( la1 - > link - > flags &
DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE ) ? 1 : - 1 ;
2009-12-28 09:22:40 +03:00
}
2016-06-13 07:41:08 +03:00
return memcmp ( la1 - > target_guid ,
la2 - > target_guid , sizeof ( la2 - > target_guid ) ) ;
2009-12-28 09:22:40 +03:00
}
2011-11-14 21:53:30 +04:00
struct drsuapi_changed_objects {
struct ldb_dn * dn ;
struct GUID guid ;
uint64_t usn ;
} ;
2009-12-28 09:22:40 +03:00
2009-12-21 13:10:41 +03:00
/*
sort the objects we send first by uSNChanged
*/
2012-12-18 18:16:28 +04:00
static int site_res_cmp_usn_order ( struct drsuapi_changed_objects * m1 ,
struct drsuapi_changed_objects * m2 ,
struct drsuapi_getncchanges_state * getnc_state )
2009-12-21 13:10:41 +03:00
{
2012-12-15 13:18:08 +04:00
int ret ;
2011-11-14 21:53:30 +04:00
2012-12-15 13:18:08 +04:00
ret = ldb_dn_compare ( getnc_state - > ncRoot_dn , m1 - > dn ) ;
if ( ret = = 0 ) {
return - 1 ;
2009-12-21 13:10:41 +03:00
}
2012-12-15 13:18:08 +04:00
ret = ldb_dn_compare ( getnc_state - > ncRoot_dn , m2 - > dn ) ;
if ( ret = = 0 ) {
return 1 ;
2009-12-21 13:10:41 +03:00
}
2012-12-15 13:18:08 +04:00
if ( m1 - > usn = = m2 - > usn ) {
return ldb_dn_compare ( m2 - > dn , m1 - > dn ) ;
}
if ( m1 - > usn < m2 - > usn ) {
return - 1 ;
}
return 1 ;
2009-12-21 13:10:41 +03:00
}
2010-01-06 11:35:05 +03:00
/*
handle a DRSUAPI_EXOP_FSMO_RID_ALLOC call
*/
static WERROR getncchanges_rid_alloc ( struct drsuapi_bind_state * b_state ,
TALLOC_CTX * mem_ctx ,
2010-09-30 10:30:18 +04:00
struct drsuapi_DsGetNCChangesRequest10 * req10 ,
2016-03-04 03:12:12 +03:00
struct drsuapi_DsGetNCChangesCtr6 * ctr6 ,
struct ldb_dn * * rid_manager_dn )
2010-01-06 11:35:05 +03:00
{
2016-03-14 01:06:39 +03:00
struct ldb_dn * req_dn , * ntds_dn = NULL ;
2010-01-06 11:35:05 +03:00
int ret ;
struct ldb_context * ldb = b_state - > sam_ctx ;
struct ldb_result * ext_res ;
struct dsdb_fsmo_extended_op * exop ;
2012-08-14 12:47:54 +04:00
bool is_us ;
2010-01-06 11:35:05 +03:00
/*
steps :
- verify that the DN being asked for is the RID Manager DN
- verify that we are the RID Manager
*/
2016-03-04 03:12:12 +03:00
/* work out who is the RID Manager, also return to caller */
ret = samdb_rid_manager_dn ( ldb , mem_ctx , rid_manager_dn ) ;
2010-01-06 11:35:05 +03:00
if ( ret ! = LDB_SUCCESS ) {
2010-01-07 10:38:39 +03:00
DEBUG ( 0 , ( __location__ " : Failed to find RID Manager object - %s \n " , ldb_errstring ( ldb ) ) ) ;
2010-01-06 11:35:05 +03:00
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2010-09-30 10:30:18 +04:00
req_dn = drs_ObjectIdentifier_to_dn ( mem_ctx , ldb , req10 - > naming_context ) ;
2011-03-04 12:44:22 +03:00
if ( ! ldb_dn_validate ( req_dn ) | |
2016-03-04 03:12:12 +03:00
ldb_dn_compare ( req_dn , * rid_manager_dn ) ! = 0 ) {
2010-01-06 11:35:05 +03:00
/* that isn't the RID Manager DN */
2010-01-07 10:38:39 +03:00
DEBUG ( 0 , ( __location__ " : RID Alloc request for wrong DN %s \n " ,
2010-09-30 10:30:18 +04:00
drs_ObjectIdentifier_to_string ( mem_ctx , req10 - > naming_context ) ) ) ;
2010-01-06 11:35:05 +03:00
ctr6 - > extended_ret = DRSUAPI_EXOP_ERR_MISMATCH ;
return WERR_OK ;
}
2016-03-14 01:06:39 +03:00
/* TODO: make sure ntds_dn is a valid nTDSDSA object */
ret = dsdb_find_dn_by_guid ( ldb , mem_ctx , & req10 - > destination_dsa_guid , 0 , & ntds_dn ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Unable to find NTDS object for guid %s - %s \n " ,
GUID_string ( mem_ctx , & req10 - > destination_dsa_guid ) , ldb_errstring ( ldb ) ) ) ;
ctr6 - > extended_ret = DRSUAPI_EXOP_ERR_UNKNOWN_CALLER ;
return WERR_OK ;
}
2010-01-06 11:35:05 +03:00
/* find the DN of the RID Manager */
2016-03-04 03:12:12 +03:00
ret = samdb_reference_dn_is_our_ntdsa ( ldb , * rid_manager_dn , " fSMORoleOwner " , & is_us ) ;
2010-01-06 11:35:05 +03:00
if ( ret ! = LDB_SUCCESS ) {
2012-08-14 12:47:54 +04:00
DEBUG ( 0 , ( " Failed to find fSMORoleOwner in RID Manager object \n " ) ) ;
2010-01-09 07:12:18 +03:00
ctr6 - > extended_ret = DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER ;
2010-01-06 11:35:05 +03:00
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2012-08-14 12:47:54 +04:00
if ( ! is_us ) {
2010-01-06 11:35:05 +03:00
/* we're not the RID Manager - go away */
2010-01-07 10:38:39 +03:00
DEBUG ( 0 , ( __location__ " : RID Alloc request when not RID Manager \n " ) ) ;
2010-01-06 11:35:05 +03:00
ctr6 - > extended_ret = DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER ;
return WERR_OK ;
}
exop = talloc ( mem_ctx , struct dsdb_fsmo_extended_op ) ;
W_ERROR_HAVE_NO_MEMORY ( exop ) ;
2010-09-30 10:30:18 +04:00
exop - > fsmo_info = req10 - > fsmo_info ;
exop - > destination_dsa_guid = req10 - > destination_dsa_guid ;
2010-01-06 11:35:05 +03:00
2010-01-07 10:38:39 +03:00
ret = ldb_transaction_start ( ldb ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed transaction start - %s \n " ,
ldb_errstring ( ldb ) ) ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2010-01-06 11:35:05 +03:00
ret = ldb_extended ( ldb , DSDB_EXTENDED_ALLOCATE_RID_POOL , exop , & ext_res ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed extended allocation RID pool operation - %s \n " ,
ldb_errstring ( ldb ) ) ) ;
2010-01-07 10:38:39 +03:00
ldb_transaction_cancel ( ldb ) ;
2010-01-06 11:35:05 +03:00
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2010-01-07 10:38:39 +03:00
ret = ldb_transaction_commit ( ldb ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed transaction commit - %s \n " ,
ldb_errstring ( ldb ) ) ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2010-01-06 11:35:05 +03:00
talloc_free ( ext_res ) ;
2010-01-06 12:56:19 +03:00
DEBUG ( 2 , ( " Allocated RID pool for server %s \n " ,
2010-09-30 10:30:18 +04:00
GUID_string ( mem_ctx , & req10 - > destination_dsa_guid ) ) ) ;
2010-01-06 12:56:19 +03:00
2010-01-09 07:12:18 +03:00
ctr6 - > extended_ret = DRSUAPI_EXOP_ERR_SUCCESS ;
2010-01-06 11:35:05 +03:00
return WERR_OK ;
}
2010-08-18 12:38:26 +04:00
/*
handle a DRSUAPI_EXOP_REPL_SECRET call
*/
static WERROR getncchanges_repl_secret ( struct drsuapi_bind_state * b_state ,
TALLOC_CTX * mem_ctx ,
2010-09-30 10:30:18 +04:00
struct drsuapi_DsGetNCChangesRequest10 * req10 ,
2010-08-18 12:38:26 +04:00
struct dom_sid * user_sid ,
2012-09-26 22:44:58 +04:00
struct drsuapi_DsGetNCChangesCtr6 * ctr6 ,
2017-02-28 06:21:25 +03:00
bool has_get_all_changes ,
struct ldb_dn * * machine_dn )
2010-08-18 12:38:26 +04:00
{
2010-09-30 10:30:18 +04:00
struct drsuapi_DsReplicaObjectIdentifier * ncRoot = req10 - > naming_context ;
2015-02-25 15:19:44 +03:00
struct ldb_dn * obj_dn = NULL ;
2017-02-28 06:21:25 +03:00
struct ldb_dn * ntds_dn = NULL , * server_dn = NULL ;
2015-02-25 15:19:44 +03:00
struct ldb_dn * rodc_dn , * krbtgt_link_dn ;
2010-08-18 12:38:26 +04:00
int ret ;
2017-02-28 06:21:25 +03:00
const char * rodc_attrs [ ] = { " msDS-KrbTgtLink " , " msDS-NeverRevealGroup " , " msDS-RevealOnDemandGroup " , " objectGUID " , NULL } ;
2010-08-18 12:38:26 +04:00
const char * obj_attrs [ ] = { " tokenGroups " , " objectSid " , " UserAccountControl " , " msDS-KrbTgtLinkBL " , NULL } ;
2017-03-21 05:02:50 +03:00
struct ldb_result * rodc_res = NULL , * obj_res = NULL ;
2010-08-18 12:38:26 +04:00
const struct dom_sid * * never_reveal_sids , * * reveal_sids , * * token_sids ;
2017-03-03 06:02:40 +03:00
const struct dom_sid * object_sid = NULL ;
2010-08-18 12:38:26 +04:00
WERROR werr ;
2017-03-10 04:25:21 +03:00
const struct dom_sid * additional_sids [ ] = { NULL , NULL } ;
2010-08-18 12:38:26 +04:00
2010-09-28 21:40:18 +04:00
DEBUG ( 3 , ( __location__ " : DRSUAPI_EXOP_REPL_SECRET extended op on %s \n " ,
drs_ObjectIdentifier_to_string ( mem_ctx , ncRoot ) ) ) ;
2010-08-18 12:38:26 +04:00
/*
2012-09-26 22:44:58 +04:00
* we need to work out if we will allow this DC to
2010-08-18 12:38:26 +04:00
* replicate the secrets for this object
*
* see 4.1 .10 .5 .14 GetRevealSecretsPolicyForUser for details
* of this function
*/
if ( b_state - > sam_ctx_system = = NULL ) {
/* this operation needs system level access */
ctr6 - > extended_ret = DRSUAPI_EXOP_ERR_ACCESS_DENIED ;
return WERR_DS_DRA_SOURCE_DISABLED ;
}
2017-02-28 06:21:25 +03:00
/*
* Before we accept or deny , fetch the machine DN for the destination
* DSA GUID .
*
* If we are the RODC , we will check that this matches the SID .
*/
ret = dsdb_find_dn_by_guid ( b_state - > sam_ctx_system , mem_ctx ,
& req10 - > destination_dsa_guid , 0 ,
& ntds_dn ) ;
if ( ret ! = LDB_SUCCESS ) {
goto failed ;
}
server_dn = ldb_dn_get_parent ( mem_ctx , ntds_dn ) ;
if ( server_dn = = NULL ) {
goto failed ;
}
ret = samdb_reference_dn ( b_state - > sam_ctx_system , mem_ctx , server_dn ,
" serverReference " , machine_dn ) ;
if ( ret ! = LDB_SUCCESS ) {
goto failed ;
}
2012-09-26 22:49:07 +04:00
/*
* In MS - DRSR . pdf 5.99 IsGetNCChangesPermissionGranted
*
* The pseudo code indicate
* revealsecrets = true
* if IsRevealSecretRequest ( msgIn ) then
* if AccessCheckCAR ( ncRoot , Ds - Replication - Get - Changes - All ) = false
* then
* if ( msgIn . ulExtendedOp = EXOP_REPL_SECRETS ) then
* < . . . check if this account is ok to be replicated on this DC . . . >
* < . . . and if not reveal secrets = no . . . >
* else
* reveal secrets = false
* endif
* endif
* endif
*
* Which basically means that if you have GET_ALL_CHANGES rights ( ~ = = RWDC )
* then you can do EXOP_REPL_SECRETS
*/
2017-03-21 05:02:50 +03:00
obj_dn = drs_ObjectIdentifier_to_dn ( mem_ctx , b_state - > sam_ctx_system , ncRoot ) ;
if ( ! ldb_dn_validate ( obj_dn ) ) goto failed ;
2012-09-26 22:49:07 +04:00
if ( has_get_all_changes ) {
goto allowed ;
}
2010-08-18 12:38:26 +04:00
rodc_dn = ldb_dn_new_fmt ( mem_ctx , b_state - > sam_ctx_system , " <SID=%s> " ,
dom_sid_string ( mem_ctx , user_sid ) ) ;
if ( ! ldb_dn_validate ( rodc_dn ) ) goto failed ;
/* do the two searches we need */
ret = dsdb_search_dn ( b_state - > sam_ctx_system , mem_ctx , & rodc_res , rodc_dn , rodc_attrs ,
DSDB_SEARCH_SHOW_EXTENDED_DN ) ;
if ( ret ! = LDB_SUCCESS | | rodc_res - > count ! = 1 ) goto failed ;
ret = dsdb_search_dn ( b_state - > sam_ctx_system , mem_ctx , & obj_res , obj_dn , obj_attrs , 0 ) ;
if ( ret ! = LDB_SUCCESS | | obj_res - > count ! = 1 ) goto failed ;
/* if the object SID is equal to the user_sid, allow */
2017-03-03 06:02:40 +03:00
object_sid = samdb_result_dom_sid ( mem_ctx , obj_res - > msgs [ 0 ] , " objectSid " ) ;
if ( dom_sid_equal ( user_sid , object_sid ) ) {
2010-08-18 12:38:26 +04:00
goto allowed ;
}
2017-03-10 04:25:21 +03:00
additional_sids [ 0 ] = object_sid ;
2017-02-28 06:21:25 +03:00
/*
* Must be an RODC account at this point , verify machine DN matches the
* SID account
*/
if ( ldb_dn_compare ( rodc_res - > msgs [ 0 ] - > dn , * machine_dn ) ! = 0 ) {
goto denied ;
}
2010-08-18 12:38:26 +04:00
/* an RODC is allowed to get its own krbtgt account secrets */
krbtgt_link_dn = samdb_result_dn ( b_state - > sam_ctx_system , mem_ctx ,
rodc_res - > msgs [ 0 ] , " msDS-KrbTgtLink " , NULL ) ;
if ( krbtgt_link_dn ! = NULL & &
ldb_dn_compare ( obj_dn , krbtgt_link_dn ) = = 0 ) {
goto allowed ;
}
/* but it isn't allowed to get anyone elses krbtgt secrets */
if ( samdb_result_dn ( b_state - > sam_ctx_system , mem_ctx ,
obj_res - > msgs [ 0 ] , " msDS-KrbTgtLinkBL " , NULL ) ) {
goto denied ;
}
2010-10-14 11:41:42 +04:00
if ( ldb_msg_find_attr_as_uint ( obj_res - > msgs [ 0 ] ,
" userAccountControl " , 0 ) &
2010-08-18 12:38:26 +04:00
UF_INTERDOMAIN_TRUST_ACCOUNT ) {
goto denied ;
}
werr = samdb_result_sid_array_dn ( b_state - > sam_ctx_system , rodc_res - > msgs [ 0 ] ,
mem_ctx , " msDS-NeverRevealGroup " , & never_reveal_sids ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
goto denied ;
}
werr = samdb_result_sid_array_dn ( b_state - > sam_ctx_system , rodc_res - > msgs [ 0 ] ,
mem_ctx , " msDS-RevealOnDemandGroup " , & reveal_sids ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
goto denied ;
}
2017-03-10 04:31:10 +03:00
/*
* The SID list needs to include itself as well as the tokenGroups .
*
* TODO determine if sIDHistory is required for this check
*/
2010-08-18 12:38:26 +04:00
werr = samdb_result_sid_array_ndr ( b_state - > sam_ctx_system , obj_res - > msgs [ 0 ] ,
2017-03-10 04:25:21 +03:00
mem_ctx , " tokenGroups " , & token_sids ,
additional_sids , 1 ) ;
2010-08-18 12:38:26 +04:00
if ( ! W_ERROR_IS_OK ( werr ) | | token_sids = = NULL ) {
goto denied ;
}
if ( never_reveal_sids & &
sid_list_match ( token_sids , never_reveal_sids ) ) {
goto denied ;
}
if ( reveal_sids & &
sid_list_match ( token_sids , reveal_sids ) ) {
goto allowed ;
}
/* default deny */
denied :
2012-09-26 22:44:58 +04:00
DEBUG ( 2 , ( __location__ " : Denied single object with secret replication for %s by RODC %s \n " ,
2010-09-28 21:40:18 +04:00
ldb_dn_get_linearized ( obj_dn ) , ldb_dn_get_linearized ( rodc_res - > msgs [ 0 ] - > dn ) ) ) ;
2010-08-19 07:06:08 +04:00
ctr6 - > extended_ret = DRSUAPI_EXOP_ERR_NONE ;
2017-02-27 04:40:40 +03:00
return WERR_DS_DRA_SECRETS_DENIED ;
2010-08-18 12:38:26 +04:00
allowed :
2012-09-26 22:44:58 +04:00
DEBUG ( 2 , ( __location__ " : Allowed single object with secret replication for %s by %s %s \n " ,
ldb_dn_get_linearized ( obj_dn ) , has_get_all_changes ? " RWDC " : " RODC " ,
2017-03-21 05:02:50 +03:00
ldb_dn_get_linearized ( * machine_dn ) ) ) ;
2010-08-18 12:38:26 +04:00
ctr6 - > extended_ret = DRSUAPI_EXOP_ERR_SUCCESS ;
2010-09-30 10:30:18 +04:00
req10 - > highwatermark . highest_usn = 0 ;
2010-08-18 12:38:26 +04:00
return WERR_OK ;
failed :
2012-09-26 22:44:58 +04:00
DEBUG ( 2 , ( __location__ " : Failed single secret replication for %s by RODC %s \n " ,
2010-09-28 21:40:18 +04:00
ldb_dn_get_linearized ( obj_dn ) , dom_sid_string ( mem_ctx , user_sid ) ) ) ;
2010-08-19 07:06:08 +04:00
ctr6 - > extended_ret = DRSUAPI_EXOP_ERR_NONE ;
return WERR_DS_DRA_BAD_DN ;
2010-08-18 12:38:26 +04:00
}
2010-09-28 21:48:38 +04:00
/*
handle a DRSUAPI_EXOP_REPL_OBJ call
*/
static WERROR getncchanges_repl_obj ( struct drsuapi_bind_state * b_state ,
TALLOC_CTX * mem_ctx ,
2010-09-30 10:30:18 +04:00
struct drsuapi_DsGetNCChangesRequest10 * req10 ,
2010-09-28 21:48:38 +04:00
struct dom_sid * user_sid ,
struct drsuapi_DsGetNCChangesCtr6 * ctr6 )
{
2010-09-30 10:30:18 +04:00
struct drsuapi_DsReplicaObjectIdentifier * ncRoot = req10 - > naming_context ;
2010-09-28 21:48:38 +04:00
DEBUG ( 3 , ( __location__ " : DRSUAPI_EXOP_REPL_OBJ extended op on %s \n " ,
drs_ObjectIdentifier_to_string ( mem_ctx , ncRoot ) ) ) ;
ctr6 - > extended_ret = DRSUAPI_EXOP_ERR_SUCCESS ;
return WERR_OK ;
}
2010-08-26 11:59:02 +04:00
/*
handle DRSUAPI_EXOP_FSMO_REQ_ROLE ,
DRSUAPI_EXOP_FSMO_RID_REQ_ROLE ,
and DRSUAPI_EXOP_FSMO_REQ_PDC calls
*/
static WERROR getncchanges_change_master ( struct drsuapi_bind_state * b_state ,
TALLOC_CTX * mem_ctx ,
2010-09-30 10:30:18 +04:00
struct drsuapi_DsGetNCChangesRequest10 * req10 ,
2010-08-26 11:59:02 +04:00
struct drsuapi_DsGetNCChangesCtr6 * ctr6 )
{
2012-08-14 12:47:54 +04:00
struct ldb_dn * req_dn , * ntds_dn ;
2010-09-10 21:17:25 +04:00
int ret ;
unsigned int i ;
2010-08-26 11:59:02 +04:00
struct ldb_context * ldb = b_state - > sam_ctx ;
struct ldb_message * msg ;
2012-08-14 12:47:54 +04:00
bool is_us ;
2010-08-26 11:59:02 +04:00
/*
steps :
- verify that the client dn exists
- verify that we are the current master
*/
2010-09-30 10:30:18 +04:00
req_dn = drs_ObjectIdentifier_to_dn ( mem_ctx , ldb , req10 - > naming_context ) ;
2011-03-04 12:44:22 +03:00
if ( ! ldb_dn_validate ( req_dn ) ) {
2010-08-26 11:59:02 +04:00
/* that is not a valid dn */
DEBUG ( 0 , ( __location__ " : FSMO role transfer request for invalid DN %s \n " ,
2010-09-30 10:30:18 +04:00
drs_ObjectIdentifier_to_string ( mem_ctx , req10 - > naming_context ) ) ) ;
2010-08-26 11:59:02 +04:00
ctr6 - > extended_ret = DRSUAPI_EXOP_ERR_MISMATCH ;
return WERR_OK ;
}
2013-06-28 03:19:48 +04:00
/* find the DN of the current role owner */
2012-08-14 12:47:54 +04:00
ret = samdb_reference_dn_is_our_ntdsa ( ldb , req_dn , " fSMORoleOwner " , & is_us ) ;
2010-08-26 11:59:02 +04:00
if ( ret ! = LDB_SUCCESS ) {
2012-08-14 12:47:54 +04:00
DEBUG ( 0 , ( " Failed to find fSMORoleOwner in RID Manager object \n " ) ) ;
2010-08-26 11:59:02 +04:00
ctr6 - > extended_ret = DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2012-08-14 12:47:54 +04:00
if ( ! is_us ) {
2013-06-28 03:19:48 +04:00
/* we're not the RID Manager or role owner - go away */
DEBUG ( 0 , ( __location__ " : FSMO role or RID manager transfer owner request when not role owner \n " ) ) ;
2010-08-26 11:59:02 +04:00
ctr6 - > extended_ret = DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER ;
return WERR_OK ;
}
/* change the current master */
msg = ldb_msg_new ( ldb ) ;
W_ERROR_HAVE_NO_MEMORY ( msg ) ;
2010-09-30 10:30:18 +04:00
msg - > dn = drs_ObjectIdentifier_to_dn ( msg , ldb , req10 - > naming_context ) ;
2010-08-26 11:59:02 +04:00
W_ERROR_HAVE_NO_MEMORY ( msg - > dn ) ;
2011-05-09 21:09:49 +04:00
/* TODO: make sure ntds_dn is a valid nTDSDSA object */
2013-06-10 06:22:40 +04:00
ret = dsdb_find_dn_by_guid ( ldb , msg , & req10 - > destination_dsa_guid , 0 , & ntds_dn ) ;
2010-08-26 11:59:02 +04:00
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Unable to find NTDS object for guid %s - %s \n " ,
2010-09-30 10:30:18 +04:00
GUID_string ( mem_ctx , & req10 - > destination_dsa_guid ) , ldb_errstring ( ldb ) ) ) ;
2010-08-26 11:59:02 +04:00
talloc_free ( msg ) ;
2011-05-09 21:09:49 +04:00
ctr6 - > extended_ret = DRSUAPI_EXOP_ERR_UNKNOWN_CALLER ;
return WERR_OK ;
2010-08-26 11:59:02 +04:00
}
ret = ldb_msg_add_string ( msg , " fSMORoleOwner " , ldb_dn_get_linearized ( ntds_dn ) ) ;
if ( ret ! = 0 ) {
talloc_free ( msg ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2010-01-06 11:35:05 +03:00
2010-08-26 11:59:02 +04:00
for ( i = 0 ; i < msg - > num_elements ; i + + ) {
msg - > elements [ i ] . flags = LDB_FLAG_MOD_REPLACE ;
}
ret = ldb_transaction_start ( ldb ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed transaction start - %s \n " ,
ldb_errstring ( ldb ) ) ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
ret = ldb_modify ( ldb , msg ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to change current owner - %s \n " ,
ldb_errstring ( ldb ) ) ) ;
ldb_transaction_cancel ( ldb ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
ret = ldb_transaction_commit ( ldb ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed transaction commit - %s \n " ,
ldb_errstring ( ldb ) ) ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
ctr6 - > extended_ret = DRSUAPI_EXOP_ERR_SUCCESS ;
return WERR_OK ;
}
2010-01-06 11:35:05 +03:00
2010-09-30 02:49:15 +04:00
/*
see if this getncchanges request includes a request to reveal secret information
*/
static WERROR dcesrv_drsuapi_is_reveal_secrets_request ( struct drsuapi_bind_state * b_state ,
2010-09-30 10:30:18 +04:00
struct drsuapi_DsGetNCChangesRequest10 * req10 ,
2016-08-15 05:10:38 +03:00
struct dsdb_schema_prefixmap * pfm_remote ,
2010-09-30 02:49:15 +04:00
bool * is_secret_request )
{
enum drsuapi_DsExtendedOperation exop ;
2010-09-30 10:47:24 +04:00
uint32_t i ;
2010-09-30 02:49:15 +04:00
struct dsdb_schema * schema ;
2016-08-15 05:10:38 +03:00
struct dsdb_syntax_ctx syntax_ctx ;
2010-09-30 02:49:15 +04:00
* is_secret_request = true ;
2010-09-30 10:30:18 +04:00
exop = req10 - > extended_op ;
2010-09-30 02:49:15 +04:00
switch ( exop ) {
case DRSUAPI_EXOP_FSMO_REQ_ROLE :
case DRSUAPI_EXOP_FSMO_RID_ALLOC :
case DRSUAPI_EXOP_FSMO_RID_REQ_ROLE :
case DRSUAPI_EXOP_FSMO_REQ_PDC :
case DRSUAPI_EXOP_FSMO_ABANDON_ROLE :
/* FSMO exops can reveal secrets */
* is_secret_request = true ;
return WERR_OK ;
case DRSUAPI_EXOP_REPL_SECRET :
case DRSUAPI_EXOP_REPL_OBJ :
case DRSUAPI_EXOP_NONE :
break ;
}
2010-09-30 10:30:18 +04:00
if ( req10 - > replica_flags & DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING ) {
2010-09-30 02:49:15 +04:00
* is_secret_request = false ;
return WERR_OK ;
}
if ( exop = = DRSUAPI_EXOP_REPL_SECRET | |
2010-09-30 10:30:18 +04:00
req10 - > partial_attribute_set = = NULL ) {
2010-09-30 02:49:15 +04:00
/* they want secrets */
* is_secret_request = true ;
return WERR_OK ;
}
schema = dsdb_get_schema ( b_state - > sam_ctx , NULL ) ;
2016-08-15 05:10:38 +03:00
dsdb_syntax_ctx_init ( & syntax_ctx , b_state - > sam_ctx , schema ) ;
syntax_ctx . pfm_remote = pfm_remote ;
2010-09-30 02:49:15 +04:00
/* check the attributes they asked for */
2010-09-30 10:30:18 +04:00
for ( i = 0 ; i < req10 - > partial_attribute_set - > num_attids ; i + + ) {
2010-09-30 02:49:15 +04:00
const struct dsdb_attribute * sa ;
2016-08-15 05:10:38 +03:00
WERROR werr = getncchanges_attid_remote_to_local ( schema ,
& syntax_ctx ,
req10 - > partial_attribute_set - > attids [ i ] ,
NULL ,
& sa ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 0 , ( __location__ " : attid 0x%08X not found: %s \n " ,
req10 - > partial_attribute_set - > attids [ i ] , win_errstr ( werr ) ) ) ;
return werr ;
2010-09-30 02:49:15 +04:00
}
2016-08-15 05:10:38 +03:00
2010-09-30 02:49:15 +04:00
if ( ! dsdb_attr_in_rodc_fas ( sa ) ) {
* is_secret_request = true ;
return WERR_OK ;
}
}
2011-09-20 09:15:36 +04:00
if ( req10 - > partial_attribute_set_ex ) {
/* check the extended attributes they asked for */
for ( i = 0 ; i < req10 - > partial_attribute_set_ex - > num_attids ; i + + ) {
const struct dsdb_attribute * sa ;
2016-08-15 05:10:38 +03:00
WERROR werr = getncchanges_attid_remote_to_local ( schema ,
& syntax_ctx ,
req10 - > partial_attribute_set_ex - > attids [ i ] ,
NULL ,
& sa ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 0 , ( __location__ " : attid 0x%08X not found: %s \n " ,
req10 - > partial_attribute_set_ex - > attids [ i ] , win_errstr ( werr ) ) ) ;
return werr ;
2011-09-20 09:15:36 +04:00
}
2016-08-15 05:10:38 +03:00
2011-09-20 09:15:36 +04:00
if ( ! dsdb_attr_in_rodc_fas ( sa ) ) {
* is_secret_request = true ;
return WERR_OK ;
}
}
}
* is_secret_request = false ;
return WERR_OK ;
}
/*
see if this getncchanges request is only for attributes in the GC
partial attribute set
*/
static WERROR dcesrv_drsuapi_is_gc_pas_request ( struct drsuapi_bind_state * b_state ,
struct drsuapi_DsGetNCChangesRequest10 * req10 ,
2016-08-15 05:10:38 +03:00
struct dsdb_schema_prefixmap * pfm_remote ,
2011-09-20 09:15:36 +04:00
bool * is_gc_pas_request )
{
enum drsuapi_DsExtendedOperation exop ;
uint32_t i ;
struct dsdb_schema * schema ;
2016-08-15 05:10:38 +03:00
struct dsdb_syntax_ctx syntax_ctx ;
2011-09-20 09:15:36 +04:00
exop = req10 - > extended_op ;
switch ( exop ) {
case DRSUAPI_EXOP_FSMO_REQ_ROLE :
case DRSUAPI_EXOP_FSMO_RID_ALLOC :
case DRSUAPI_EXOP_FSMO_RID_REQ_ROLE :
case DRSUAPI_EXOP_FSMO_REQ_PDC :
case DRSUAPI_EXOP_FSMO_ABANDON_ROLE :
case DRSUAPI_EXOP_REPL_SECRET :
* is_gc_pas_request = false ;
return WERR_OK ;
case DRSUAPI_EXOP_REPL_OBJ :
case DRSUAPI_EXOP_NONE :
break ;
}
if ( req10 - > partial_attribute_set = = NULL ) {
/* they want it all */
* is_gc_pas_request = false ;
return WERR_OK ;
}
schema = dsdb_get_schema ( b_state - > sam_ctx , NULL ) ;
2016-08-15 05:10:38 +03:00
dsdb_syntax_ctx_init ( & syntax_ctx , b_state - > sam_ctx , schema ) ;
syntax_ctx . pfm_remote = pfm_remote ;
2011-09-20 09:15:36 +04:00
2010-09-30 02:49:15 +04:00
/* check the attributes they asked for */
2011-09-20 09:15:36 +04:00
for ( i = 0 ; i < req10 - > partial_attribute_set - > num_attids ; i + + ) {
2010-09-30 02:49:15 +04:00
const struct dsdb_attribute * sa ;
2016-08-15 05:10:38 +03:00
WERROR werr = getncchanges_attid_remote_to_local ( schema ,
& syntax_ctx ,
req10 - > partial_attribute_set - > attids [ i ] ,
NULL ,
& sa ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 0 , ( __location__ " : attid 0x%08X not found: %s \n " ,
req10 - > partial_attribute_set - > attids [ i ] , win_errstr ( werr ) ) ) ;
return werr ;
2010-09-30 02:49:15 +04:00
}
2016-08-15 05:10:38 +03:00
2011-09-20 09:15:36 +04:00
if ( ! sa - > isMemberOfPartialAttributeSet ) {
* is_gc_pas_request = false ;
2010-09-30 02:49:15 +04:00
return WERR_OK ;
}
}
2011-09-20 09:15:36 +04:00
if ( req10 - > partial_attribute_set_ex ) {
/* check the extended attributes they asked for */
for ( i = 0 ; i < req10 - > partial_attribute_set_ex - > num_attids ; i + + ) {
const struct dsdb_attribute * sa ;
2016-08-15 05:10:38 +03:00
WERROR werr = getncchanges_attid_remote_to_local ( schema ,
& syntax_ctx ,
req10 - > partial_attribute_set_ex - > attids [ i ] ,
NULL ,
& sa ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 0 , ( __location__ " : attid 0x%08X not found: %s \n " ,
req10 - > partial_attribute_set_ex - > attids [ i ] , win_errstr ( werr ) ) ) ;
return werr ;
2011-09-20 09:15:36 +04:00
}
2016-08-15 05:10:38 +03:00
2011-09-20 09:15:36 +04:00
if ( ! sa - > isMemberOfPartialAttributeSet ) {
* is_gc_pas_request = false ;
return WERR_OK ;
}
}
}
* is_gc_pas_request = true ;
2010-09-30 02:49:15 +04:00
return WERR_OK ;
}
2010-09-30 10:30:18 +04:00
/*
map from req8 to req10
*/
static struct drsuapi_DsGetNCChangesRequest10 *
getncchanges_map_req8 ( TALLOC_CTX * mem_ctx ,
struct drsuapi_DsGetNCChangesRequest8 * req8 )
{
struct drsuapi_DsGetNCChangesRequest10 * req10 = talloc_zero ( mem_ctx ,
struct drsuapi_DsGetNCChangesRequest10 ) ;
if ( req10 = = NULL ) {
return NULL ;
}
req10 - > destination_dsa_guid = req8 - > destination_dsa_guid ;
req10 - > source_dsa_invocation_id = req8 - > source_dsa_invocation_id ;
req10 - > naming_context = req8 - > naming_context ;
req10 - > highwatermark = req8 - > highwatermark ;
req10 - > uptodateness_vector = req8 - > uptodateness_vector ;
req10 - > replica_flags = req8 - > replica_flags ;
req10 - > max_object_count = req8 - > max_object_count ;
req10 - > max_ndr_size = req8 - > max_ndr_size ;
req10 - > extended_op = req8 - > extended_op ;
req10 - > fsmo_info = req8 - > fsmo_info ;
req10 - > partial_attribute_set = req8 - > partial_attribute_set ;
req10 - > partial_attribute_set_ex = req8 - > partial_attribute_set_ex ;
req10 - > mapping_ctr = req8 - > mapping_ctr ;
return req10 ;
}
2016-03-04 03:12:12 +03:00
static const char * collect_objects_attrs [ ] = { " uSNChanged " ,
" objectGUID " ,
NULL } ;
2010-09-30 02:49:15 +04:00
2011-05-11 21:48:53 +04:00
/**
* Collects object for normal replication cycle .
*/
static WERROR getncchanges_collect_objects ( struct drsuapi_bind_state * b_state ,
TALLOC_CTX * mem_ctx ,
struct drsuapi_DsGetNCChangesRequest10 * req10 ,
struct ldb_dn * search_dn ,
const char * extra_filter ,
struct ldb_result * * search_res )
{
int ret ;
char * search_filter ;
enum ldb_scope scope = LDB_SCOPE_SUBTREE ;
struct drsuapi_getncchanges_state * getnc_state = b_state - > getncchanges_state ;
2016-11-30 11:11:31 +03:00
bool critical_only = false ;
if ( req10 - > replica_flags & DRSUAPI_DRS_CRITICAL_ONLY ) {
critical_only = true ;
}
2011-05-11 21:48:53 +04:00
if ( req10 - > extended_op = = DRSUAPI_EXOP_REPL_OBJ | |
req10 - > extended_op = = DRSUAPI_EXOP_REPL_SECRET ) {
scope = LDB_SCOPE_BASE ;
2016-11-30 11:11:31 +03:00
critical_only = false ;
2011-05-11 21:48:53 +04:00
}
/* Construct response. */
search_filter = talloc_asprintf ( mem_ctx ,
" (uSNChanged>=%llu) " ,
( unsigned long long ) ( getnc_state - > min_usn + 1 ) ) ;
if ( extra_filter ) {
search_filter = talloc_asprintf ( mem_ctx , " (&%s(%s)) " , search_filter , extra_filter ) ;
}
2016-11-30 11:11:31 +03:00
if ( critical_only ) {
2011-05-11 21:48:53 +04:00
search_filter = talloc_asprintf ( mem_ctx ,
" (&%s(isCriticalSystemObject=TRUE)) " ,
search_filter ) ;
}
if ( req10 - > replica_flags & DRSUAPI_DRS_ASYNC_REP ) {
scope = LDB_SCOPE_BASE ;
}
if ( ! search_dn ) {
search_dn = getnc_state - > ncRoot_dn ;
}
DEBUG ( 2 , ( __location__ " : getncchanges on %s using filter %s \n " ,
ldb_dn_get_linearized ( getnc_state - > ncRoot_dn ) , search_filter ) ) ;
ret = drsuapi_search_with_extended_dn ( b_state - > sam_ctx , getnc_state , search_res ,
2016-03-04 03:12:12 +03:00
search_dn , scope ,
collect_objects_attrs ,
2011-05-11 21:48:53 +04:00
search_filter ) ;
if ( ret ! = LDB_SUCCESS ) {
return WERR_DS_DRA_INTERNAL_ERROR ;
}
return WERR_OK ;
}
2011-05-11 21:49:42 +04:00
/**
* Collects object for normal replication cycle .
*/
static WERROR getncchanges_collect_objects_exop ( struct drsuapi_bind_state * b_state ,
TALLOC_CTX * mem_ctx ,
struct drsuapi_DsGetNCChangesRequest10 * req10 ,
struct drsuapi_DsGetNCChangesCtr6 * ctr6 ,
struct ldb_dn * search_dn ,
const char * extra_filter ,
struct ldb_result * * search_res )
{
/* we have nothing to do in case of ex-op failure */
if ( ctr6 - > extended_ret ! = DRSUAPI_EXOP_ERR_SUCCESS ) {
return WERR_OK ;
}
2016-03-04 03:12:12 +03:00
switch ( req10 - > extended_op ) {
case DRSUAPI_EXOP_FSMO_RID_ALLOC :
{
int ret ;
struct ldb_dn * ntds_dn = NULL ;
struct ldb_dn * server_dn = NULL ;
struct ldb_dn * machine_dn = NULL ;
struct ldb_dn * rid_set_dn = NULL ;
struct ldb_result * search_res2 = NULL ;
struct ldb_result * search_res3 = NULL ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
/* get RID manager, RID set and server DN (in that order) */
/* This first search will get the RID Manager */
2016-03-14 01:09:02 +03:00
ret = drsuapi_search_with_extended_dn ( b_state - > sam_ctx , frame ,
2016-03-04 03:12:12 +03:00
search_res ,
search_dn , LDB_SCOPE_BASE ,
collect_objects_attrs ,
NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 1 , ( " DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to get RID Manager object %s - %s " ,
ldb_dn_get_linearized ( search_dn ) ,
ldb_errstring ( b_state - > sam_ctx ) ) ) ;
TALLOC_FREE ( frame ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
if ( ( * search_res ) - > count ! = 1 ) {
DEBUG ( 1 , ( " DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to get RID Manager object %s - %u objects returned " ,
ldb_dn_get_linearized ( search_dn ) ,
( * search_res ) - > count ) ) ;
TALLOC_FREE ( frame ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
/* Now extend it to the RID set */
/* Find the computer account DN for the destination
* dsa GUID specified */
ret = dsdb_find_dn_by_guid ( b_state - > sam_ctx , frame ,
& req10 - > destination_dsa_guid , 0 ,
& ntds_dn ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 1 , ( " DRSUAPI_EXOP_FSMO_RID_ALLOC: Unable to find NTDS object for guid %s - %s \n " ,
GUID_string ( frame ,
& req10 - > destination_dsa_guid ) ,
ldb_errstring ( b_state - > sam_ctx ) ) ) ;
TALLOC_FREE ( frame ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
server_dn = ldb_dn_get_parent ( frame , ntds_dn ) ;
if ( ! server_dn ) {
TALLOC_FREE ( frame ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
ret = samdb_reference_dn ( b_state - > sam_ctx , frame , server_dn ,
" serverReference " , & machine_dn ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 1 , ( " DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to find serverReference in %s - %s " ,
ldb_dn_get_linearized ( server_dn ) ,
ldb_errstring ( b_state - > sam_ctx ) ) ) ;
TALLOC_FREE ( frame ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
ret = samdb_reference_dn ( b_state - > sam_ctx , frame , machine_dn ,
" rIDSetReferences " , & rid_set_dn ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 1 , ( " DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to find rIDSetReferences in %s - %s " ,
ldb_dn_get_linearized ( server_dn ) ,
ldb_errstring ( b_state - > sam_ctx ) ) ) ;
TALLOC_FREE ( frame ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
/* This first search will get the RID Manager, now get the RID set */
ret = drsuapi_search_with_extended_dn ( b_state - > sam_ctx , frame ,
& search_res2 ,
rid_set_dn , LDB_SCOPE_BASE ,
collect_objects_attrs ,
NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 1 , ( " DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to get RID Set object %s - %s " ,
ldb_dn_get_linearized ( rid_set_dn ) ,
ldb_errstring ( b_state - > sam_ctx ) ) ) ;
TALLOC_FREE ( frame ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
if ( search_res2 - > count ! = 1 ) {
DEBUG ( 1 , ( " DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to get RID Set object %s - %u objects returned " ,
ldb_dn_get_linearized ( rid_set_dn ) ,
search_res2 - > count ) ) ;
TALLOC_FREE ( frame ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
/* Finally get the server DN */
ret = drsuapi_search_with_extended_dn ( b_state - > sam_ctx , frame ,
& search_res3 ,
machine_dn , LDB_SCOPE_BASE ,
collect_objects_attrs ,
NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 1 , ( " DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to get server object %s - %s " ,
ldb_dn_get_linearized ( server_dn ) ,
ldb_errstring ( b_state - > sam_ctx ) ) ) ;
TALLOC_FREE ( frame ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
if ( search_res3 - > count ! = 1 ) {
DEBUG ( 1 , ( " DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to get server object %s - %u objects returned " ,
ldb_dn_get_linearized ( server_dn ) ,
search_res3 - > count ) ) ;
TALLOC_FREE ( frame ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2016-03-14 01:09:02 +03:00
/* Now extend the original search_res with these answers */
2016-03-04 03:12:12 +03:00
( * search_res ) - > count = 3 ;
2016-03-14 01:09:02 +03:00
( * search_res ) - > msgs = talloc_realloc ( frame , ( * search_res ) - > msgs ,
2016-03-04 03:12:12 +03:00
struct ldb_message * ,
( * search_res ) - > count ) ;
if ( ( * search_res ) - > msgs = = NULL ) {
TALLOC_FREE ( frame ) ;
2015-12-03 17:24:19 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2016-03-04 03:12:12 +03:00
}
2016-03-14 01:09:02 +03:00
talloc_steal ( mem_ctx , * search_res ) ;
2016-03-04 03:12:12 +03:00
( * search_res ) - > msgs [ 1 ] =
talloc_steal ( ( * search_res ) - > msgs , search_res2 - > msgs [ 0 ] ) ;
( * search_res ) - > msgs [ 2 ] =
talloc_steal ( ( * search_res ) - > msgs , search_res3 - > msgs [ 0 ] ) ;
TALLOC_FREE ( frame ) ;
return WERR_OK ;
}
default :
/* TODO: implement extended op specific collection
* of objects . Right now we just normal procedure
* for collecting objects */
return getncchanges_collect_objects ( b_state , mem_ctx , req10 , search_dn , extra_filter , search_res ) ;
}
2011-05-11 21:49:42 +04:00
}
2016-11-29 13:12:22 +03:00
static void dcesrv_drsuapi_update_highwatermark ( const struct ldb_message * msg ,
uint64_t max_usn ,
struct drsuapi_DsReplicaHighWaterMark * hwm )
{
uint64_t uSN = ldb_msg_find_attr_as_uint64 ( msg , " uSNChanged " , 0 ) ;
if ( uSN > max_usn ) {
/*
* Only report the max_usn we had at the start
* of the replication cycle .
*
* If this object has changed lately we better
* let the destination dsa refetch the change .
* This is better than the risk of loosing some
* objects or linked attributes .
*/
return ;
}
if ( uSN < = hwm - > tmp_highest_usn ) {
return ;
}
hwm - > tmp_highest_usn = uSN ;
hwm - > reserved_usn = 0 ;
}
static WERROR dcesrv_drsuapi_anc_cache_add ( struct db_context * anc_cache ,
const struct GUID * guid )
{
enum ndr_err_code ndr_err ;
uint8_t guid_buf [ 16 ] = { 0 , } ;
DATA_BLOB b = {
. data = guid_buf ,
. length = sizeof ( guid_buf ) ,
} ;
TDB_DATA key = {
. dptr = b . data ,
. dsize = b . length ,
} ;
TDB_DATA val = {
. dptr = NULL ,
. dsize = 0 ,
} ;
NTSTATUS status ;
ndr_err = ndr_push_struct_into_fixed_blob ( & b , guid ,
( ndr_push_flags_fn_t ) ndr_push_GUID ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return WERR_DS_DRA_INTERNAL_ERROR ;
}
status = dbwrap_store ( anc_cache , key , val , TDB_REPLACE ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return WERR_DS_DRA_INTERNAL_ERROR ;
}
return WERR_OK ;
}
static WERROR dcesrv_drsuapi_anc_cache_exists ( struct db_context * anc_cache ,
const struct GUID * guid )
{
enum ndr_err_code ndr_err ;
uint8_t guid_buf [ 16 ] = { 0 , } ;
DATA_BLOB b = {
. data = guid_buf ,
. length = sizeof ( guid_buf ) ,
} ;
TDB_DATA key = {
. dptr = b . data ,
. dsize = b . length ,
} ;
bool exists ;
ndr_err = ndr_push_struct_into_fixed_blob ( & b , guid ,
( ndr_push_flags_fn_t ) ndr_push_GUID ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return WERR_DS_DRA_INTERNAL_ERROR ;
}
exists = dbwrap_exists ( anc_cache , key ) ;
if ( ! exists ) {
return WERR_OBJECT_NOT_FOUND ;
}
return WERR_OBJECT_NAME_EXISTS ;
}
2009-09-09 15:00:01 +04:00
/*
drsuapi_DsGetNCChanges
2009-10-13 12:49:08 +04:00
see MS - DRSR 4.1 .10 .5 .2 for basic logic of this function
2009-09-09 15:00:01 +04:00
*/
WERROR dcesrv_drsuapi_DsGetNCChanges ( struct dcesrv_call_state * dce_call , TALLOC_CTX * mem_ctx ,
struct drsuapi_DsGetNCChanges * r )
{
struct drsuapi_DsReplicaObjectIdentifier * ncRoot ;
int ret ;
2016-06-13 07:41:08 +03:00
uint32_t i , k ;
2009-09-09 15:00:01 +04:00
struct dsdb_schema * schema ;
struct drsuapi_DsReplicaOIDMapping_Ctr * ctr ;
2009-09-12 05:14:29 +04:00
struct drsuapi_DsReplicaObjectListItemEx * * currentObject ;
2009-09-10 11:46:30 +04:00
NTSTATUS status ;
DATA_BLOB session_key ;
2009-09-12 05:14:29 +04:00
WERROR werr ;
2009-09-26 02:17:44 +04:00
struct dcesrv_handle * h ;
2016-08-15 07:19:20 +03:00
struct drsuapi_bind_state * b_state ;
2009-09-26 02:17:44 +04:00
struct drsuapi_getncchanges_state * getnc_state ;
2010-09-30 10:30:18 +04:00
struct drsuapi_DsGetNCChangesRequest10 * req10 ;
2009-10-13 12:49:08 +04:00
uint32_t options ;
2009-12-19 16:12:35 +03:00
uint32_t max_objects ;
2010-07-09 14:52:11 +04:00
uint32_t max_links ;
uint32_t link_count = 0 ;
uint32_t link_total = 0 ;
uint32_t link_given = 0 ;
2010-01-09 02:12:54 +03:00
struct ldb_dn * search_dn = NULL ;
2010-08-18 12:38:26 +04:00
bool am_rodc , null_scope = false ;
2010-04-22 08:56:19 +04:00
enum security_user_level security_level ;
2010-08-18 08:31:05 +04:00
struct ldb_context * sam_ctx ;
2010-08-18 12:38:26 +04:00
struct dom_sid * user_sid ;
2010-09-30 02:49:15 +04:00
bool is_secret_request ;
2011-09-20 09:15:36 +04:00
bool is_gc_pas_request ;
2011-11-14 21:53:30 +04:00
struct drsuapi_changed_objects * changes ;
2011-11-10 14:23:40 +04:00
time_t max_wait ;
time_t start = time ( NULL ) ;
bool max_wait_reached = false ;
2012-09-26 22:44:58 +04:00
bool has_get_all_changes = false ;
2012-12-18 16:40:33 +04:00
struct GUID invocation_id ;
2016-03-14 01:10:04 +03:00
static const struct drsuapi_DsReplicaLinkedAttribute no_linked_attr ;
2016-08-15 05:10:38 +03:00
struct dsdb_schema_prefixmap * pfm_remote = NULL ;
bool full = true ;
uint32_t * local_pas = NULL ;
2017-02-28 06:21:25 +03:00
struct ldb_dn * machine_dn = NULL ; /* Only used for REPL SECRET EXOP */
2009-09-26 02:17:44 +04:00
DCESRV_PULL_HANDLE_WERR ( h , r - > in . bind_handle , DRSUAPI_BIND_HANDLE ) ;
b_state = h - > data ;
2009-09-24 02:47:14 +04:00
2010-08-18 08:31:05 +04:00
sam_ctx = b_state - > sam_ctx_system ? b_state - > sam_ctx_system : b_state - > sam_ctx ;
2012-12-18 16:40:33 +04:00
invocation_id = * ( samdb_ntds_invocation_id ( sam_ctx ) ) ;
2009-09-16 06:26:33 +04:00
* r - > out . level_out = 6 ;
/* TODO: linked attributes*/
r - > out . ctr - > ctr6 . linked_attributes_count = 0 ;
2016-03-14 01:10:04 +03:00
r - > out . ctr - > ctr6 . linked_attributes = discard_const_p ( struct drsuapi_DsReplicaLinkedAttribute , & no_linked_attr ) ;
2009-09-09 15:26:17 +04:00
2009-09-16 06:26:33 +04:00
r - > out . ctr - > ctr6 . object_count = 0 ;
2009-09-26 02:17:44 +04:00
r - > out . ctr - > ctr6 . nc_object_count = 0 ;
2009-09-16 06:26:33 +04:00
r - > out . ctr - > ctr6 . more_data = false ;
r - > out . ctr - > ctr6 . uptodateness_vector = NULL ;
2016-03-14 01:10:04 +03:00
r - > out . ctr - > ctr6 . source_dsa_guid = * ( samdb_ntds_objectGUID ( sam_ctx ) ) ;
r - > out . ctr - > ctr6 . source_dsa_invocation_id = * ( samdb_ntds_invocation_id ( sam_ctx ) ) ;
r - > out . ctr - > ctr6 . first_object = NULL ;
2009-09-09 15:00:01 +04:00
2009-10-13 12:49:08 +04:00
/* a RODC doesn't allow for any replication */
2010-08-18 08:31:05 +04:00
ret = samdb_rodc ( sam_ctx , & am_rodc ) ;
2010-04-16 00:37:40 +04:00
if ( ret = = LDB_SUCCESS & & am_rodc ) {
2009-10-13 12:49:08 +04:00
DEBUG ( 0 , ( __location__ " : DsGetNCChanges attempt on RODC \n " ) ) ;
return WERR_DS_DRA_SOURCE_DISABLED ;
}
/* Check request revision.
*/
2010-09-30 10:30:18 +04:00
switch ( r - > in . level ) {
case 8 :
req10 = getncchanges_map_req8 ( mem_ctx , & r - > in . req - > req8 ) ;
if ( req10 = = NULL ) {
2015-12-03 17:24:19 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2010-09-30 10:30:18 +04:00
}
break ;
case 10 :
req10 = & r - > in . req - > req10 ;
break ;
default :
2009-10-13 12:49:08 +04:00
DEBUG ( 0 , ( __location__ " : Request for DsGetNCChanges with unsupported level %u \n " ,
r - > in . level ) ) ;
2009-09-09 15:00:01 +04:00
return WERR_REVISION_MISMATCH ;
}
2009-10-13 12:49:08 +04:00
2009-09-09 15:00:01 +04:00
/* Perform access checks. */
2009-12-03 01:19:55 +03:00
/* TODO: we need to support a sync on a specific non-root
* DN . We ' ll need to find the real partition root here */
2010-09-30 10:30:18 +04:00
ncRoot = req10 - > naming_context ;
2009-10-13 12:49:08 +04:00
if ( ncRoot = = NULL ) {
DEBUG ( 0 , ( __location__ " : Request for DsGetNCChanges with no NC \n " ) ) ;
2009-09-09 15:00:01 +04:00
return WERR_DS_DRA_INVALID_PARAMETER ;
}
2010-08-18 08:31:05 +04:00
if ( samdb_ntds_options ( sam_ctx , & options ) ! = LDB_SUCCESS ) {
2009-10-13 12:49:08 +04:00
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2016-08-15 07:19:20 +03:00
2009-10-13 12:49:08 +04:00
if ( ( options & DS_NTDSDSA_OPT_DISABLE_OUTBOUND_REPL ) & &
2010-09-30 10:30:18 +04:00
! ( req10 - > replica_flags & DRSUAPI_DRS_SYNC_FORCED ) ) {
2009-10-13 12:49:08 +04:00
return WERR_DS_DRA_SOURCE_DISABLED ;
2009-09-09 15:00:01 +04:00
}
2010-09-30 02:49:15 +04:00
user_sid = & dce_call - > conn - > auth_state . session_info - > security_token - > sids [ PRIMARY_USER_SID_INDEX ] ;
2011-09-20 09:15:36 +04:00
/* all clients must have GUID_DRS_GET_CHANGES */
2010-09-30 02:49:15 +04:00
werr = drs_security_access_check_nc_root ( b_state - > sam_ctx ,
mem_ctx ,
dce_call - > conn - > auth_state . session_info - > security_token ,
2010-09-30 10:30:18 +04:00
req10 - > naming_context ,
2010-09-30 02:49:15 +04:00
GUID_DRS_GET_CHANGES ) ;
2010-04-22 10:56:40 +04:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
return werr ;
2010-04-22 08:56:19 +04:00
}
2016-08-15 05:10:38 +03:00
if ( dsdb_functional_level ( sam_ctx ) > = DS_DOMAIN_FUNCTION_2008 ) {
full = req10 - > partial_attribute_set = = NULL & &
req10 - > partial_attribute_set_ex = = NULL ;
} else {
full = ( options & DRSUAPI_DRS_WRIT_REP ) ! = 0 ;
}
werr = dsdb_schema_pfm_from_drsuapi_pfm ( & req10 - > mapping_ctr , true ,
mem_ctx , & pfm_remote , NULL ) ;
/* We were supplied a partial attribute set, without the prefix map! */
if ( ! full & & ! W_ERROR_IS_OK ( werr ) ) {
if ( req10 - > mapping_ctr . num_mappings = = 0 ) {
/*
* Despite the fact MS - DRSR specifies that this shouldn ' t
* happen , Windows RODCs will in fact not provide a prefixMap .
*/
DEBUG ( 5 , ( __location__ " : Failed to provide a remote prefixMap, "
" falling back to local prefixMap \n " ) ) ;
} else {
DEBUG ( 0 , ( __location__ " : Failed to decode remote prefixMap: %s \n " ,
win_errstr ( werr ) ) ) ;
return werr ;
}
}
2011-09-20 09:15:36 +04:00
/* allowed if the GC PAS and client has
GUID_DRS_GET_FILTERED_ATTRIBUTES */
2016-08-15 05:10:38 +03:00
werr = dcesrv_drsuapi_is_gc_pas_request ( b_state , req10 , pfm_remote , & is_gc_pas_request ) ;
2011-09-20 09:15:36 +04:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
return werr ;
}
if ( is_gc_pas_request ) {
werr = drs_security_access_check_nc_root ( b_state - > sam_ctx ,
mem_ctx ,
dce_call - > conn - > auth_state . session_info - > security_token ,
req10 - > naming_context ,
GUID_DRS_GET_FILTERED_ATTRIBUTES ) ;
if ( W_ERROR_IS_OK ( werr ) ) {
goto allowed ;
}
}
2016-08-15 05:10:38 +03:00
werr = dcesrv_drsuapi_is_reveal_secrets_request ( b_state , req10 ,
pfm_remote ,
& is_secret_request ) ;
2010-09-30 02:49:15 +04:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
return werr ;
}
2017-03-08 07:12:27 +03:00
if ( is_secret_request ) {
2010-09-30 02:49:15 +04:00
werr = drs_security_access_check_nc_root ( b_state - > sam_ctx ,
mem_ctx ,
dce_call - > conn - > auth_state . session_info - > security_token ,
2010-09-30 10:30:18 +04:00
req10 - > naming_context ,
2010-09-30 02:49:15 +04:00
GUID_DRS_GET_ALL_CHANGES ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
2017-03-08 07:12:27 +03:00
/* Only bail if this is not a EXOP_REPL_SECRET */
if ( req10 - > extended_op ! = DRSUAPI_EXOP_REPL_SECRET ) {
return werr ;
}
2012-09-26 22:44:58 +04:00
} else {
has_get_all_changes = true ;
2010-09-30 02:49:15 +04:00
}
}
2010-08-18 12:38:26 +04:00
2011-09-20 09:15:36 +04:00
allowed :
2010-04-22 10:56:40 +04:00
/* for non-administrator replications, check that they have
given the correct source_dsa_invocation_id */
security_level = security_session_user_level ( dce_call - > conn - > auth_state . session_info ,
2010-08-18 08:31:05 +04:00
samdb_domain_sid ( sam_ctx ) ) ;
2010-09-30 02:49:15 +04:00
if ( security_level = = SECURITY_RO_DOMAIN_CONTROLLER ) {
2010-09-30 10:30:18 +04:00
if ( req10 - > replica_flags & DRSUAPI_DRS_WRIT_REP ) {
2010-09-30 02:49:15 +04:00
/* we rely on this flag being unset for RODC requests */
2010-09-30 10:30:18 +04:00
req10 - > replica_flags & = ~ DRSUAPI_DRS_WRIT_REP ;
2010-09-30 02:49:15 +04:00
}
2010-04-16 00:37:40 +04:00
}
2010-09-30 10:30:18 +04:00
if ( req10 - > replica_flags & DRSUAPI_DRS_FULL_SYNC_PACKET ) {
2009-09-24 03:58:58 +04:00
/* Ignore the _in_ uptpdateness vector*/
2010-09-30 10:30:18 +04:00
req10 - > uptodateness_vector = NULL ;
2016-06-07 02:57:02 +03:00
}
2009-09-24 03:58:58 +04:00
2012-12-18 16:40:33 +04:00
if ( GUID_all_zero ( & req10 - > source_dsa_invocation_id ) ) {
req10 - > source_dsa_invocation_id = invocation_id ;
}
if ( ! GUID_equal ( & req10 - > source_dsa_invocation_id , & invocation_id ) ) {
/*
* The given highwatermark is only valid relative to the
* specified source_dsa_invocation_id .
*/
ZERO_STRUCT ( req10 - > highwatermark ) ;
}
2009-09-26 02:17:44 +04:00
getnc_state = b_state - > getncchanges_state ;
2009-12-03 01:19:55 +03:00
/* see if a previous replication has been abandoned */
if ( getnc_state ) {
2010-09-28 21:40:18 +04:00
struct ldb_dn * new_dn = drs_ObjectIdentifier_to_dn ( getnc_state , sam_ctx , ncRoot ) ;
2009-12-03 01:19:55 +03:00
if ( ldb_dn_compare ( new_dn , getnc_state - > ncRoot_dn ) ! = 0 ) {
2009-12-19 16:12:35 +03:00
DEBUG ( 0 , ( __location__ " : DsGetNCChanges 2nd replication on different DN %s %s (last_dn %s) \n " ,
2009-12-03 01:19:55 +03:00
ldb_dn_get_linearized ( new_dn ) ,
2009-12-19 16:12:35 +03:00
ldb_dn_get_linearized ( getnc_state - > ncRoot_dn ) ,
ldb_dn_get_linearized ( getnc_state - > last_dn ) ) ) ;
2009-12-03 01:19:55 +03:00
talloc_free ( getnc_state ) ;
getnc_state = NULL ;
}
}
2012-12-17 14:30:26 +04:00
if ( getnc_state ) {
ret = drsuapi_DsReplicaHighWaterMark_cmp ( & getnc_state - > last_hwm ,
& req10 - > highwatermark ) ;
if ( ret ! = 0 ) {
DEBUG ( 0 , ( __location__ " : DsGetNCChanges 2nd replication "
" on DN %s %s highwatermark (last_dn %s) \n " ,
ldb_dn_get_linearized ( getnc_state - > ncRoot_dn ) ,
( ret > 0 ) ? " older " : " newer " ,
ldb_dn_get_linearized ( getnc_state - > last_dn ) ) ) ;
talloc_free ( getnc_state ) ;
getnc_state = NULL ;
}
}
2009-09-26 02:17:44 +04:00
if ( getnc_state = = NULL ) {
getnc_state = talloc_zero ( b_state , struct drsuapi_getncchanges_state ) ;
if ( getnc_state = = NULL ) {
2015-12-03 17:24:19 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2009-09-26 02:17:44 +04:00
}
b_state - > getncchanges_state = getnc_state ;
2010-09-28 21:40:18 +04:00
getnc_state - > ncRoot_dn = drs_ObjectIdentifier_to_dn ( getnc_state , sam_ctx , ncRoot ) ;
2016-11-29 13:09:46 +03:00
if ( getnc_state - > ncRoot_dn = = NULL ) {
return WERR_NOT_ENOUGH_MEMORY ;
}
ret = dsdb_find_guid_by_dn ( b_state - > sam_ctx_system ,
getnc_state - > ncRoot_dn ,
& getnc_state - > ncRoot_guid ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to find GUID of ncRoot_dn %s \n " ,
ldb_dn_get_linearized ( getnc_state - > ncRoot_dn ) ) ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
ncRoot - > guid = getnc_state - > ncRoot_guid ;
2010-08-18 04:52:48 +04:00
/* find out if we are to replicate Schema NC */
2016-07-27 06:51:47 +03:00
ret = ldb_dn_compare_base ( ldb_get_schema_basedn ( b_state - > sam_ctx ) ,
getnc_state - > ncRoot_dn ) ;
2010-08-18 04:52:48 +04:00
getnc_state - > is_schema_nc = ( 0 = = ret ) ;
2010-09-10 03:02:56 +04:00
2011-05-11 22:09:34 +04:00
if ( req10 - > extended_op ! = DRSUAPI_EXOP_NONE ) {
r - > out . ctr - > ctr6 . extended_ret = DRSUAPI_EXOP_ERR_SUCCESS ;
}
2010-09-10 03:02:56 +04:00
/*
* This is the first replication cycle and it is
* a good place to handle extended operations
*
* FIXME : we don ' t fully support extended operations yet
*/
2010-09-30 10:30:18 +04:00
switch ( req10 - > extended_op ) {
2010-09-10 03:02:56 +04:00
case DRSUAPI_EXOP_NONE :
break ;
case DRSUAPI_EXOP_FSMO_RID_ALLOC :
2016-03-04 03:12:12 +03:00
werr = getncchanges_rid_alloc ( b_state , mem_ctx , req10 , & r - > out . ctr - > ctr6 , & search_dn ) ;
2010-09-10 03:02:56 +04:00
W_ERROR_NOT_OK_RETURN ( werr ) ;
2016-03-14 01:06:39 +03:00
if ( r - > out . ctr - > ctr6 . extended_ret ! = DRSUAPI_EXOP_ERR_SUCCESS ) {
return WERR_OK ;
}
2010-09-10 03:02:56 +04:00
break ;
case DRSUAPI_EXOP_REPL_SECRET :
2012-09-26 22:44:58 +04:00
werr = getncchanges_repl_secret ( b_state , mem_ctx , req10 ,
user_sid ,
& r - > out . ctr - > ctr6 ,
2017-02-28 06:21:25 +03:00
has_get_all_changes ,
& machine_dn ) ;
2010-09-10 03:02:56 +04:00
r - > out . result = werr ;
W_ERROR_NOT_OK_RETURN ( werr ) ;
break ;
case DRSUAPI_EXOP_FSMO_REQ_ROLE :
2010-09-30 10:30:18 +04:00
werr = getncchanges_change_master ( b_state , mem_ctx , req10 , & r - > out . ctr - > ctr6 ) ;
2010-09-10 03:02:56 +04:00
W_ERROR_NOT_OK_RETURN ( werr ) ;
2016-03-14 01:06:39 +03:00
if ( r - > out . ctr - > ctr6 . extended_ret ! = DRSUAPI_EXOP_ERR_SUCCESS ) {
return WERR_OK ;
}
2010-09-10 03:02:56 +04:00
break ;
case DRSUAPI_EXOP_FSMO_RID_REQ_ROLE :
2010-09-30 10:30:18 +04:00
werr = getncchanges_change_master ( b_state , mem_ctx , req10 , & r - > out . ctr - > ctr6 ) ;
2010-09-10 03:02:56 +04:00
W_ERROR_NOT_OK_RETURN ( werr ) ;
2016-03-14 01:06:39 +03:00
if ( r - > out . ctr - > ctr6 . extended_ret ! = DRSUAPI_EXOP_ERR_SUCCESS ) {
return WERR_OK ;
}
2010-09-10 03:02:56 +04:00
break ;
case DRSUAPI_EXOP_FSMO_REQ_PDC :
2010-09-30 10:30:18 +04:00
werr = getncchanges_change_master ( b_state , mem_ctx , req10 , & r - > out . ctr - > ctr6 ) ;
2010-09-10 03:02:56 +04:00
W_ERROR_NOT_OK_RETURN ( werr ) ;
2016-03-14 01:06:39 +03:00
if ( r - > out . ctr - > ctr6 . extended_ret ! = DRSUAPI_EXOP_ERR_SUCCESS ) {
return WERR_OK ;
}
2010-09-10 03:02:56 +04:00
break ;
case DRSUAPI_EXOP_REPL_OBJ :
2010-09-30 10:30:18 +04:00
werr = getncchanges_repl_obj ( b_state , mem_ctx , req10 , user_sid , & r - > out . ctr - > ctr6 ) ;
2010-09-28 21:48:38 +04:00
r - > out . result = werr ;
W_ERROR_NOT_OK_RETURN ( werr ) ;
break ;
case DRSUAPI_EXOP_FSMO_ABANDON_ROLE :
2010-09-10 03:02:56 +04:00
DEBUG ( 0 , ( __location__ " : Request for DsGetNCChanges unsupported extended op 0x%x \n " ,
2010-09-30 10:30:18 +04:00
( unsigned ) req10 - > extended_op ) ) ;
2010-09-10 03:02:56 +04:00
return WERR_DS_DRA_NOT_SUPPORTED ;
}
2009-12-09 06:39:05 +03:00
}
if ( ! ldb_dn_validate ( getnc_state - > ncRoot_dn ) | |
ldb_dn_is_null ( getnc_state - > ncRoot_dn ) ) {
2010-09-28 21:40:18 +04:00
DEBUG ( 0 , ( __location__ " : Bad DN '%s' \n " ,
drs_ObjectIdentifier_to_string ( mem_ctx , ncRoot ) ) ) ;
2009-12-09 06:39:05 +03:00
return WERR_DS_DRA_INVALID_PARAMETER ;
2009-09-16 06:26:33 +04:00
}
2016-11-29 13:09:46 +03:00
ncRoot - > guid = getnc_state - > ncRoot_guid ;
2009-09-10 11:46:30 +04:00
/* we need the session key for encrypting password attributes */
status = dcesrv_inherited_session_key ( dce_call - > conn , & session_key ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( __location__ " : Failed to get session key \n " ) ) ;
2016-06-07 02:57:02 +03:00
return WERR_DS_DRA_INTERNAL_ERROR ;
2009-09-10 11:46:30 +04:00
}
2009-10-13 12:49:08 +04:00
/*
TODO : MS - DRSR section 4.1 .10 .1 .1
Work out if this is the start of a new cycle */
2010-11-05 10:28:04 +03:00
if ( getnc_state - > guids = = NULL ) {
2009-12-19 16:12:35 +03:00
const char * extra_filter ;
2011-05-11 21:49:42 +04:00
struct ldb_result * search_res = NULL ;
2017-02-07 14:37:16 +03:00
static const struct drsuapi_DsReplicaCursorCtrEx empty_udv ;
const struct drsuapi_DsReplicaCursorCtrEx * udv = NULL ;
2009-12-19 16:12:35 +03:00
2010-07-16 08:32:42 +04:00
extra_filter = lpcfg_parm_string ( dce_call - > conn - > dce_ctx - > lp_ctx , NULL , " drs " , " object filter " ) ;
2009-09-24 02:47:14 +04:00
2017-05-22 04:59:22 +03:00
if ( req10 - > extended_op = = DRSUAPI_EXOP_NONE ) {
if ( req10 - > uptodateness_vector ! = NULL ) {
udv = req10 - > uptodateness_vector ;
} else {
udv = & empty_udv ;
}
2017-02-07 14:37:16 +03:00
2017-05-22 04:59:22 +03:00
getnc_state - > min_usn = req10 - > highwatermark . highest_usn ;
for ( i = 0 ; i < udv - > count ; i + + ) {
bool match ;
const struct drsuapi_DsReplicaCursor * cur =
& udv - > cursors [ i ] ;
2017-02-07 14:37:16 +03:00
2017-05-22 04:59:22 +03:00
match = GUID_equal ( & invocation_id ,
& cur - > source_dsa_invocation_id ) ;
if ( ! match ) {
continue ;
}
if ( cur - > highest_usn > getnc_state - > min_usn ) {
getnc_state - > min_usn = cur - > highest_usn ;
}
break ;
2017-02-07 14:37:16 +03:00
}
2017-05-22 04:59:22 +03:00
} else {
/* We do not want REPL_SECRETS or REPL_SINGLE to return empty-handed */
udv = & empty_udv ;
getnc_state - > min_usn = 0 ;
2017-02-07 14:37:16 +03:00
}
2017-05-22 04:59:22 +03:00
2012-12-18 17:59:20 +04:00
getnc_state - > max_usn = getnc_state - > min_usn ;
getnc_state - > final_udv = talloc_zero ( getnc_state ,
struct drsuapi_DsReplicaCursor2CtrEx ) ;
if ( getnc_state - > final_udv = = NULL ) {
2015-12-03 17:24:19 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2012-12-18 17:59:20 +04:00
}
werr = get_nc_changes_udv ( sam_ctx , getnc_state - > ncRoot_dn ,
getnc_state - > final_udv ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
return werr ;
}
2009-09-24 03:52:34 +04:00
2011-05-11 21:49:42 +04:00
if ( req10 - > extended_op = = DRSUAPI_EXOP_NONE ) {
werr = getncchanges_collect_objects ( b_state , mem_ctx , req10 ,
search_dn , extra_filter ,
& search_res ) ;
} else {
werr = getncchanges_collect_objects_exop ( b_state , mem_ctx , req10 ,
& r - > out . ctr - > ctr6 ,
search_dn , extra_filter ,
& search_res ) ;
}
2011-05-11 21:48:53 +04:00
W_ERROR_NOT_OK_RETURN ( werr ) ;
2009-12-21 13:10:41 +03:00
2010-11-05 10:28:04 +03:00
/* extract out the GUIDs list */
2011-05-11 21:49:42 +04:00
getnc_state - > num_records = search_res ? search_res - > count : 0 ;
2010-11-05 10:28:04 +03:00
getnc_state - > guids = talloc_array ( getnc_state , struct GUID , getnc_state - > num_records ) ;
W_ERROR_HAVE_NO_MEMORY ( getnc_state - > guids ) ;
2011-11-14 21:53:30 +04:00
changes = talloc_array ( getnc_state ,
struct drsuapi_changed_objects ,
getnc_state - > num_records ) ;
W_ERROR_HAVE_NO_MEMORY ( changes ) ;
2010-11-05 10:28:04 +03:00
for ( i = 0 ; i < getnc_state - > num_records ; i + + ) {
2011-11-14 21:53:30 +04:00
changes [ i ] . dn = search_res - > msgs [ i ] - > dn ;
changes [ i ] . guid = samdb_result_guid ( search_res - > msgs [ i ] , " objectGUID " ) ;
changes [ i ] . usn = ldb_msg_find_attr_as_uint64 ( search_res - > msgs [ i ] , " uSNChanged " , 0 ) ;
2012-12-18 17:59:20 +04:00
if ( changes [ i ] . usn > getnc_state - > max_usn ) {
getnc_state - > max_usn = changes [ i ] . usn ;
}
2010-11-05 10:28:04 +03:00
}
2016-03-04 03:12:12 +03:00
/* RID_ALLOC returns 3 objects in a fixed order */
if ( req10 - > extended_op = = DRSUAPI_EXOP_FSMO_RID_ALLOC ) {
/* Do nothing */
2011-11-14 21:53:30 +04:00
} else {
2012-12-18 18:16:28 +04:00
LDB_TYPESAFE_QSORT ( changes ,
getnc_state - > num_records ,
getnc_state ,
site_res_cmp_usn_order ) ;
2011-11-14 21:53:30 +04:00
}
2010-11-05 10:28:04 +03:00
2011-11-14 21:53:30 +04:00
for ( i = 0 ; i < getnc_state - > num_records ; i + + ) {
getnc_state - > guids [ i ] = changes [ i ] . guid ;
if ( GUID_all_zero ( & getnc_state - > guids [ i ] ) ) {
DEBUG ( 2 , ( " getncchanges: bad objectGUID from %s \n " ,
ldb_dn_get_linearized ( search_res - > msgs [ i ] - > dn ) ) ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
}
2012-12-18 17:59:20 +04:00
getnc_state - > final_hwm . tmp_highest_usn = getnc_state - > max_usn ;
getnc_state - > final_hwm . reserved_usn = 0 ;
getnc_state - > final_hwm . highest_usn = getnc_state - > max_usn ;
2011-11-14 21:53:30 +04:00
talloc_free ( search_res ) ;
talloc_free ( changes ) ;
2016-11-29 13:12:22 +03:00
if ( req10 - > extended_op ! = DRSUAPI_EXOP_NONE ) {
/* Do nothing */
} else if ( req10 - > replica_flags & DRSUAPI_DRS_GET_ANC ) {
getnc_state - > anc_cache = db_open_rbt ( getnc_state ) ;
if ( getnc_state - > anc_cache = = NULL ) {
return WERR_NOT_ENOUGH_MEMORY ;
}
}
2009-09-09 15:00:01 +04:00
}
2012-12-17 19:34:25 +04:00
if ( req10 - > uptodateness_vector ) {
/* make sure its sorted */
TYPESAFE_QSORT ( req10 - > uptodateness_vector - > cursors ,
req10 - > uptodateness_vector - > count ,
drsuapi_DsReplicaCursor_compare ) ;
}
2009-09-09 15:00:01 +04:00
/* Prefix mapping */
2010-08-18 08:31:05 +04:00
schema = dsdb_get_schema ( sam_ctx , mem_ctx ) ;
2009-09-09 15:00:01 +04:00
if ( ! schema ) {
2009-09-09 15:26:17 +04:00
DEBUG ( 0 , ( " No schema in sam_ctx \n " ) ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
2009-09-09 15:00:01 +04:00
}
2009-09-16 06:26:33 +04:00
r - > out . ctr - > ctr6 . naming_context = talloc ( mem_ctx , struct drsuapi_DsReplicaObjectIdentifier ) ;
2016-11-29 13:09:46 +03:00
if ( r - > out . ctr - > ctr6 . naming_context = = NULL ) {
return WERR_NOT_ENOUGH_MEMORY ;
2009-09-24 00:56:10 +04:00
}
2016-11-29 13:09:46 +03:00
* r - > out . ctr - > ctr6 . naming_context = * ncRoot ;
2009-09-24 00:56:10 +04:00
/* find the SID if there is one */
2010-08-18 08:31:05 +04:00
dsdb_find_sid_by_dn ( sam_ctx , getnc_state - > ncRoot_dn , & r - > out . ctr - > ctr6 . naming_context - > sid ) ;
2009-09-24 00:56:10 +04:00
2009-09-09 15:00:01 +04:00
dsdb_get_oid_mappings_drsuapi ( schema , true , mem_ctx , & ctr ) ;
r - > out . ctr - > ctr6 . mapping_ctr = * ctr ;
2010-08-18 08:31:05 +04:00
r - > out . ctr - > ctr6 . source_dsa_guid = * ( samdb_ntds_objectGUID ( sam_ctx ) ) ;
r - > out . ctr - > ctr6 . source_dsa_invocation_id = * ( samdb_ntds_invocation_id ( sam_ctx ) ) ;
2009-09-09 15:00:01 +04:00
2010-09-30 10:30:18 +04:00
r - > out . ctr - > ctr6 . old_highwatermark = req10 - > highwatermark ;
r - > out . ctr - > ctr6 . new_highwatermark = req10 - > highwatermark ;
2009-09-09 15:00:01 +04:00
2009-09-12 05:14:29 +04:00
currentObject = & r - > out . ctr - > ctr6 . first_object ;
2009-09-09 15:00:01 +04:00
2010-07-16 08:32:42 +04:00
max_objects = lpcfg_parm_int ( dce_call - > conn - > dce_ctx - > lp_ctx , NULL , " drs " , " max object sync " , 1000 ) ;
2016-03-04 03:12:12 +03:00
/*
* The client control here only applies in normal replication , not extended
* operations , which return a fixed set , even if the caller
* sets max_object_count = = 0
*/
if ( req10 - > extended_op = = DRSUAPI_EXOP_NONE ) {
/* use this to force single objects at a time, which is useful
* for working out what object is giving problems
*/
if ( req10 - > max_object_count < max_objects ) {
max_objects = req10 - > max_object_count ;
}
2009-12-19 16:12:35 +03:00
}
2010-07-09 14:52:11 +04:00
/*
* TODO : work out how the maximum should be calculated
*/
2010-07-16 08:32:42 +04:00
max_links = lpcfg_parm_int ( dce_call - > conn - > dce_ctx - > lp_ctx , NULL , " drs " , " max link sync " , 1500 ) ;
2009-12-19 04:25:09 +03:00
2011-11-10 14:23:40 +04:00
/*
* Maximum time that we can spend in a getncchanges
* in order to avoid timeout of the other part .
* 10 seconds by default .
*/
max_wait = lpcfg_parm_int ( dce_call - > conn - > dce_ctx - > lp_ctx , NULL , " drs " , " max work time " , 10 ) ;
2016-08-15 05:10:38 +03:00
if ( req10 - > partial_attribute_set ! = NULL ) {
struct dsdb_syntax_ctx syntax_ctx ;
uint32_t j = 0 ;
dsdb_syntax_ctx_init ( & syntax_ctx , b_state - > sam_ctx , schema ) ;
syntax_ctx . pfm_remote = pfm_remote ;
local_pas = talloc_array ( b_state , uint32_t , req10 - > partial_attribute_set - > num_attids ) ;
for ( j = 0 ; j < req10 - > partial_attribute_set - > num_attids ; j + + ) {
getncchanges_attid_remote_to_local ( schema ,
& syntax_ctx ,
req10 - > partial_attribute_set - > attids [ j ] ,
( enum drsuapi_DsAttributeId * ) & local_pas [ j ] ,
NULL ) ;
}
LDB_TYPESAFE_QSORT ( local_pas ,
req10 - > partial_attribute_set - > num_attids ,
NULL ,
uint32_t_ptr_cmp ) ;
}
2011-02-15 10:41:23 +03:00
for ( i = getnc_state - > num_processed ;
2010-11-05 10:28:04 +03:00
i < getnc_state - > num_records & &
2010-08-18 12:38:26 +04:00
! null_scope & &
2011-11-10 14:23:40 +04:00
( r - > out . ctr - > ctr6 . object_count < max_objects )
& & ! max_wait_reached ;
2009-09-26 02:17:44 +04:00
i + + ) {
2016-11-29 13:12:22 +03:00
struct drsuapi_DsReplicaObjectListItemEx * new_objs = NULL ;
2009-09-12 05:14:29 +04:00
struct drsuapi_DsReplicaObjectListItemEx * obj ;
2010-11-05 10:28:04 +03:00
struct ldb_message * msg ;
2010-11-09 21:52:49 +03:00
static const char * const msg_attrs [ ] = {
" * " ,
2010-11-05 10:28:04 +03:00
" nTSecurityDescriptor " ,
" parentGUID " ,
" replPropertyMetaData " ,
2010-11-09 21:45:31 +03:00
DSDB_SECRET_ATTRIBUTES ,
2010-11-05 10:28:04 +03:00
NULL } ;
struct ldb_result * msg_res ;
struct ldb_dn * msg_dn ;
2016-11-29 13:12:22 +03:00
const struct GUID * next_anc_guid = NULL ;
2009-12-19 04:25:09 +03:00
2009-09-12 05:14:29 +04:00
obj = talloc_zero ( mem_ctx , struct drsuapi_DsReplicaObjectListItemEx ) ;
2010-11-05 10:28:04 +03:00
W_ERROR_HAVE_NO_MEMORY ( obj ) ;
msg_dn = ldb_dn_new_fmt ( obj , sam_ctx , " <GUID=%s> " , GUID_string ( obj , & getnc_state - > guids [ i ] ) ) ;
W_ERROR_HAVE_NO_MEMORY ( msg_dn ) ;
/* by re-searching here we avoid having a lot of full
* records in memory between calls to getncchanges
*/
ret = drsuapi_search_with_extended_dn ( sam_ctx , obj , & msg_res ,
msg_dn ,
LDB_SCOPE_BASE , msg_attrs , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
if ( ret ! = LDB_ERR_NO_SUCH_OBJECT ) {
DEBUG ( 1 , ( " getncchanges: failed to fetch DN %s - %s \n " ,
ldb_dn_get_extended_linearized ( obj , msg_dn , 1 ) , ldb_errstring ( sam_ctx ) ) ) ;
}
talloc_free ( obj ) ;
continue ;
}
msg = msg_res - > msgs [ 0 ] ;
2009-09-09 15:26:17 +04:00
2016-11-29 13:12:22 +03:00
/*
* If it has already been added as an ancestor of
* an object , we don ' t need to do anything more ,
* as we ' ve already added the links .
*/
if ( getnc_state - > anc_cache ! = NULL ) {
werr = dcesrv_drsuapi_anc_cache_exists ( getnc_state - > anc_cache ,
& getnc_state - > guids [ i ] ) ;
if ( W_ERROR_EQUAL ( werr , WERR_OBJECT_NAME_EXISTS ) ) {
dcesrv_drsuapi_update_highwatermark ( msg ,
getnc_state - > max_usn ,
& r - > out . ctr - > ctr6 . new_highwatermark ) ;
/* no attributes to send */
talloc_free ( obj ) ;
continue ;
}
}
2011-11-10 14:23:40 +04:00
max_wait_reached = ( time ( NULL ) - start > max_wait ) ;
2009-12-19 04:25:09 +03:00
werr = get_nc_changes_build_object ( obj , msg ,
2010-08-18 08:31:05 +04:00
sam_ctx , getnc_state - > ncRoot_dn ,
2010-08-18 04:52:48 +04:00
getnc_state - > is_schema_nc ,
2009-09-26 02:17:44 +04:00
schema , & session_key , getnc_state - > min_usn ,
2010-09-30 10:30:18 +04:00
req10 - > replica_flags ,
req10 - > partial_attribute_set ,
2012-12-17 19:34:25 +04:00
req10 - > uptodateness_vector ,
2011-11-10 14:23:40 +04:00
req10 - > extended_op ,
2016-08-15 05:10:38 +03:00
max_wait_reached ,
2017-03-13 02:18:00 +03:00
local_pas , machine_dn ,
& getnc_state - > guids [ i ] ) ;
2009-09-09 15:26:17 +04:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
return werr ;
2009-09-09 15:00:01 +04:00
}
2009-09-10 13:41:48 +04:00
2010-08-18 08:31:05 +04:00
werr = get_nc_changes_add_links ( sam_ctx , getnc_state ,
2009-12-19 04:25:09 +03:00
getnc_state - > ncRoot_dn ,
2016-07-27 05:22:39 +03:00
getnc_state - > is_schema_nc ,
2009-12-19 04:25:09 +03:00
schema , getnc_state - > min_usn ,
2010-09-30 10:30:18 +04:00
req10 - > replica_flags ,
2009-12-19 04:25:09 +03:00
msg ,
2009-12-21 13:13:59 +03:00
& getnc_state - > la_list ,
2010-01-09 05:11:27 +03:00
& getnc_state - > la_count ,
2012-12-17 19:34:25 +04:00
req10 - > uptodateness_vector ) ;
2009-12-19 04:25:09 +03:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
return werr ;
}
2016-11-29 13:12:22 +03:00
dcesrv_drsuapi_update_highwatermark ( msg ,
getnc_state - > max_usn ,
& r - > out . ctr - > ctr6 . new_highwatermark ) ;
2009-12-21 13:16:35 +03:00
2009-09-12 05:14:29 +04:00
if ( obj - > meta_data_ctr = = NULL ) {
2010-01-09 06:28:00 +03:00
DEBUG ( 8 , ( __location__ " : getncchanges skipping send of object %s \n " ,
2009-12-19 04:25:09 +03:00
ldb_dn_get_linearized ( msg - > dn ) ) ) ;
2009-09-12 05:14:29 +04:00
/* no attributes to send */
talloc_free ( obj ) ;
continue ;
2009-09-10 13:41:48 +04:00
}
2016-11-29 13:12:22 +03:00
new_objs = obj ;
if ( getnc_state - > anc_cache ! = NULL ) {
werr = dcesrv_drsuapi_anc_cache_add ( getnc_state - > anc_cache ,
& getnc_state - > guids [ i ] ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
return werr ;
}
next_anc_guid = obj - > parent_object_guid ;
}
while ( next_anc_guid ! = NULL ) {
struct drsuapi_DsReplicaObjectListItemEx * anc_obj = NULL ;
struct ldb_message * anc_msg = NULL ;
struct ldb_result * anc_res = NULL ;
struct ldb_dn * anc_dn = NULL ;
werr = dcesrv_drsuapi_anc_cache_exists ( getnc_state - > anc_cache ,
next_anc_guid ) ;
if ( W_ERROR_EQUAL ( werr , WERR_OBJECT_NAME_EXISTS ) ) {
/*
* We don ' t need to send it twice .
*/
break ;
}
if ( W_ERROR_IS_OK ( werr ) ) {
return WERR_INTERNAL_ERROR ;
}
if ( ! W_ERROR_EQUAL ( werr , WERR_OBJECT_NOT_FOUND ) ) {
return werr ;
}
werr = WERR_OK ;
anc_obj = talloc_zero ( mem_ctx ,
struct drsuapi_DsReplicaObjectListItemEx ) ;
if ( anc_obj = = NULL ) {
return WERR_NOT_ENOUGH_MEMORY ;
}
anc_dn = ldb_dn_new_fmt ( anc_obj , sam_ctx , " <GUID=%s> " ,
GUID_string ( anc_obj , next_anc_guid ) ) ;
if ( anc_dn = = NULL ) {
return WERR_NOT_ENOUGH_MEMORY ;
}
ret = drsuapi_search_with_extended_dn ( sam_ctx , anc_obj ,
& anc_res , anc_dn ,
LDB_SCOPE_BASE ,
msg_attrs , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
const char * anc_str = NULL ;
const char * obj_str = NULL ;
anc_str = ldb_dn_get_extended_linearized ( anc_obj ,
anc_dn ,
1 ) ;
obj_str = ldb_dn_get_extended_linearized ( anc_obj ,
msg - > dn ,
1 ) ,
DBG_ERR ( " getncchanges: failed to fetch ANC "
" DN %s for DN %s - %s \n " ,
anc_str , obj_str ,
ldb_errstring ( sam_ctx ) ) ;
return WERR_DS_DRA_INCONSISTENT_DIT ;
}
2016-06-07 02:57:02 +03:00
2016-11-29 13:12:22 +03:00
anc_msg = anc_res - > msgs [ 0 ] ;
werr = get_nc_changes_build_object ( anc_obj , anc_msg ,
sam_ctx ,
getnc_state - > ncRoot_dn ,
getnc_state - > is_schema_nc ,
schema , & session_key ,
getnc_state - > min_usn ,
req10 - > replica_flags ,
req10 - > partial_attribute_set ,
req10 - > uptodateness_vector ,
req10 - > extended_op ,
false , /* force_object_return */
2017-03-03 06:21:12 +03:00
local_pas ,
2017-03-13 02:18:00 +03:00
machine_dn ,
next_anc_guid ) ;
2016-11-29 13:12:22 +03:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
return werr ;
}
werr = get_nc_changes_add_links ( sam_ctx , getnc_state ,
getnc_state - > ncRoot_dn ,
getnc_state - > is_schema_nc ,
schema , getnc_state - > min_usn ,
req10 - > replica_flags ,
anc_msg ,
& getnc_state - > la_list ,
& getnc_state - > la_count ,
req10 - > uptodateness_vector ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
return werr ;
}
/*
* Regardless of if we actually use it or not ,
* we add it to the cache so we don ' t look at it again
*/
werr = dcesrv_drsuapi_anc_cache_add ( getnc_state - > anc_cache ,
next_anc_guid ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
return werr ;
}
/*
* Any ancestors which are below the highwatermark
* or uptodateness_vector shouldn ' t be added ,
* but we still look further up the
* tree for ones which have been changed recently .
*/
if ( anc_obj - > meta_data_ctr ! = NULL ) {
/*
* prepend it to the list
*/
anc_obj - > next_object = new_objs ;
new_objs = anc_obj ;
}
anc_msg = NULL ;
TALLOC_FREE ( anc_res ) ;
TALLOC_FREE ( anc_dn ) ;
/*
* We may need to resolve more . . .
*/
next_anc_guid = anc_obj - > parent_object_guid ;
}
* currentObject = new_objs ;
while ( new_objs ! = NULL ) {
r - > out . ctr - > ctr6 . object_count + = 1 ;
if ( new_objs - > next_object = = NULL ) {
currentObject = & new_objs - > next_object ;
}
new_objs = new_objs - > next_object ;
}
2009-12-19 04:25:09 +03:00
DEBUG ( 8 , ( __location__ " : replicating object %s \n " , ldb_dn_get_linearized ( msg - > dn ) ) ) ;
2010-11-05 10:28:04 +03:00
2012-12-18 15:44:43 +04:00
talloc_free ( getnc_state - > last_dn ) ;
getnc_state - > last_dn = talloc_move ( getnc_state , & msg - > dn ) ;
2010-11-05 10:28:04 +03:00
talloc_free ( msg_res ) ;
talloc_free ( msg_dn ) ;
2009-09-09 15:00:01 +04:00
}
2011-02-15 10:41:23 +03:00
getnc_state - > num_processed = i ;
2009-09-12 05:14:29 +04:00
2009-10-14 13:29:39 +04:00
/* the client can us to call UpdateRefs on its behalf to
re - establish monitoring of the NC */
2010-09-30 10:30:18 +04:00
if ( ( req10 - > replica_flags & ( DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_REF_GCSPN ) ) & &
! GUID_all_zero ( & req10 - > destination_dsa_guid ) ) {
2009-10-14 13:29:39 +04:00
struct drsuapi_DsReplicaUpdateRefsRequest1 ureq ;
2010-04-26 15:49:37 +04:00
DEBUG ( 3 , ( " UpdateRefs on getncchanges for %s \n " ,
2010-09-30 10:30:18 +04:00
GUID_string ( mem_ctx , & req10 - > destination_dsa_guid ) ) ) ;
2009-10-14 13:29:39 +04:00
ureq . naming_context = ncRoot ;
2011-08-24 07:51:49 +04:00
ureq . dest_dsa_dns_name = samdb_ntds_msdcs_dns_name ( b_state - > sam_ctx , mem_ctx ,
& req10 - > destination_dsa_guid ) ;
2009-10-14 13:29:39 +04:00
if ( ! ureq . dest_dsa_dns_name ) {
2015-12-03 17:24:19 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2009-10-14 13:29:39 +04:00
}
2010-09-30 10:30:18 +04:00
ureq . dest_dsa_guid = req10 - > destination_dsa_guid ;
2010-01-14 06:38:00 +03:00
ureq . options = DRSUAPI_DRS_ADD_REF |
DRSUAPI_DRS_ASYNC_OP |
DRSUAPI_DRS_GETCHG_CHECK ;
2010-09-30 23:43:45 +04:00
/* we also need to pass through the
DRSUAPI_DRS_REF_GCSPN bit so that repsTo gets flagged
to send notifies using the GC SPN */
ureq . options | = ( req10 - > replica_flags & DRSUAPI_DRS_REF_GCSPN ) ;
2017-03-29 01:24:50 +03:00
werr = drsuapi_UpdateRefs ( dce_call - > msg_ctx ,
dce_call - > event_ctx , b_state ,
mem_ctx , & ureq ) ;
2009-10-14 13:29:39 +04:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
2012-11-20 07:59:17 +04:00
DEBUG ( 0 , ( __location__ " : Failed UpdateRefs on %s for %s in DsGetNCChanges - %s \n " ,
drs_ObjectIdentifier_to_string ( mem_ctx , ncRoot ) , ureq . dest_dsa_dns_name ,
2009-10-14 13:29:39 +04:00
win_errstr ( werr ) ) ) ;
}
}
2010-07-09 14:52:11 +04:00
/*
* TODO :
* This is just a guess , how to calculate the
* number of linked attributes to send , we need to
* find out how to do this right .
*/
if ( r - > out . ctr - > ctr6 . object_count > = max_links ) {
max_links = 0 ;
} else {
max_links - = r - > out . ctr - > ctr6 . object_count ;
}
link_total = getnc_state - > la_count ;
2010-11-05 10:28:04 +03:00
if ( i < getnc_state - > num_records ) {
2009-09-26 02:17:44 +04:00
r - > out . ctr - > ctr6 . more_data = true ;
} else {
2010-07-09 14:52:11 +04:00
/* sort the whole array the first time */
2016-06-13 07:41:08 +03:00
if ( getnc_state - > la_sorted = = NULL ) {
2016-06-07 02:56:49 +03:00
int j ;
2016-06-13 07:41:08 +03:00
struct la_for_sorting * guid_array = talloc_array ( getnc_state , struct la_for_sorting , getnc_state - > la_count ) ;
if ( guid_array = = NULL ) {
DEBUG ( 0 , ( " Out of memory allocating %u linked attributes for sorting " , getnc_state - > la_count ) ) ;
2015-12-03 17:24:19 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2016-06-13 07:41:08 +03:00
}
2016-06-07 02:56:49 +03:00
for ( j = 0 ; j < getnc_state - > la_count ; j + + ) {
/* we need to get the target GUIDs to compare */
struct dsdb_dn * dn ;
const struct drsuapi_DsReplicaLinkedAttribute * la = & getnc_state - > la_list [ j ] ;
const struct dsdb_attribute * schema_attrib ;
2016-06-09 08:03:18 +03:00
const struct ldb_val * target_guid ;
DATA_BLOB source_guid ;
2016-06-13 07:41:08 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2016-06-07 02:56:49 +03:00
schema_attrib = dsdb_attribute_by_attributeID_id ( schema , la - > attid ) ;
2016-06-13 07:41:08 +03:00
werr = dsdb_dn_la_from_blob ( sam_ctx , schema_attrib , schema , frame , la - > value . blob , & dn ) ;
2016-06-07 02:56:49 +03:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 0 , ( __location__ " : Bad la blob in sort \n " ) ) ;
2016-06-13 07:41:08 +03:00
TALLOC_FREE ( frame ) ;
2016-06-07 02:56:49 +03:00
return werr ;
}
2016-06-09 08:03:18 +03:00
/* Extract the target GUID in NDR form */
target_guid = ldb_dn_get_extended_component ( dn - > dn , " GUID " ) ;
2016-06-13 07:41:08 +03:00
if ( target_guid = = NULL
| | target_guid - > length ! = sizeof ( guid_array [ 0 ] . target_guid ) ) {
2016-06-09 08:03:18 +03:00
status = NT_STATUS_OBJECT_NAME_NOT_FOUND ;
} else {
/* Repack the source GUID as NDR for sorting */
status = GUID_to_ndr_blob ( & la - > identifier - > guid ,
2016-06-13 07:41:08 +03:00
frame ,
2016-06-09 08:03:18 +03:00
& source_guid ) ;
}
2016-06-13 07:41:08 +03:00
if ( ! NT_STATUS_IS_OK ( status )
| | source_guid . length ! = sizeof ( guid_array [ 0 ] . source_guid ) ) {
2016-06-07 02:56:49 +03:00
DEBUG ( 0 , ( __location__ " : Bad la guid in sort \n " ) ) ;
2016-06-13 07:41:08 +03:00
TALLOC_FREE ( frame ) ;
2016-06-07 02:56:49 +03:00
return ntstatus_to_werror ( status ) ;
}
2016-06-13 07:41:08 +03:00
guid_array [ j ] . link = & getnc_state - > la_list [ j ] ;
memcpy ( guid_array [ j ] . target_guid , target_guid - > data ,
sizeof ( guid_array [ j ] . target_guid ) ) ;
memcpy ( guid_array [ j ] . source_guid , source_guid . data ,
sizeof ( guid_array [ j ] . source_guid ) ) ;
TALLOC_FREE ( frame ) ;
2016-06-07 02:56:49 +03:00
}
LDB_TYPESAFE_QSORT ( guid_array , getnc_state - > la_count , NULL , linked_attribute_compare ) ;
2016-06-13 07:41:08 +03:00
getnc_state - > la_sorted = guid_array ;
2010-07-09 14:52:11 +04:00
}
link_count = getnc_state - > la_count - getnc_state - > la_idx ;
link_count = MIN ( max_links , link_count ) ;
r - > out . ctr - > ctr6 . linked_attributes_count = link_count ;
2016-06-13 07:41:08 +03:00
r - > out . ctr - > ctr6 . linked_attributes = talloc_array ( r - > out . ctr , struct drsuapi_DsReplicaLinkedAttribute , link_count ) ;
if ( r - > out . ctr - > ctr6 . linked_attributes = = NULL ) {
DEBUG ( 0 , ( " Out of memory allocating %u linked attributes for output " , link_count ) ) ;
2015-12-03 17:24:19 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2016-06-13 07:41:08 +03:00
}
for ( k = 0 ; k < link_count ; k + + ) {
r - > out . ctr - > ctr6 . linked_attributes [ k ]
= * getnc_state - > la_sorted [ getnc_state - > la_idx + k ] . link ;
}
2010-07-09 14:52:11 +04:00
getnc_state - > la_idx + = link_count ;
link_given = getnc_state - > la_idx ;
2009-12-28 09:22:40 +03:00
2010-07-09 14:52:11 +04:00
if ( getnc_state - > la_idx < getnc_state - > la_count ) {
r - > out . ctr - > ctr6 . more_data = true ;
}
}
2016-11-29 15:23:23 +03:00
if ( req10 - > replica_flags & DRSUAPI_DRS_GET_NC_SIZE ) {
/*
* TODO : This implementation is wrong
* we should find out the total number of
* objects and links in the whole naming context
* at the start of the cycle and return these
* values in each message .
*
* For now we keep our current strategy and return
* the number of objects for this cycle and the number
* of links we found so far during the cycle .
*/
r - > out . ctr - > ctr6 . nc_object_count = getnc_state - > num_records ;
r - > out . ctr - > ctr6 . nc_linked_attributes_count = getnc_state - > la_count ;
}
2010-07-09 14:52:11 +04:00
if ( ! r - > out . ctr - > ctr6 . more_data ) {
talloc_steal ( mem_ctx , getnc_state - > la_list ) ;
2009-12-28 09:22:40 +03:00
2012-12-18 17:59:20 +04:00
r - > out . ctr - > ctr6 . new_highwatermark = getnc_state - > final_hwm ;
r - > out . ctr - > ctr6 . uptodateness_vector = talloc_move ( mem_ctx ,
& getnc_state - > final_udv ) ;
2009-09-26 02:17:44 +04:00
talloc_free ( getnc_state ) ;
b_state - > getncchanges_state = NULL ;
2012-12-17 14:30:26 +04:00
} else {
ret = drsuapi_DsReplicaHighWaterMark_cmp ( & r - > out . ctr - > ctr6 . old_highwatermark ,
& r - > out . ctr - > ctr6 . new_highwatermark ) ;
if ( ret = = 0 ) {
/*
* We need to make sure that we never return the
* same highwatermark within the same replication
* cycle more than once . Otherwise we cannot detect
* when the client uses an unexptected highwatermark .
*
* This is a HACK which is needed because our
* object ordering is wrong and set tmp_highest_usn
* to a value that is higher than what we already
* sent to the client ( destination dsa ) .
*/
r - > out . ctr - > ctr6 . new_highwatermark . reserved_usn + = 1 ;
}
getnc_state - > last_hwm = r - > out . ctr - > ctr6 . new_highwatermark ;
2009-09-26 02:17:44 +04:00
}
2009-09-12 05:14:29 +04:00
2010-09-30 10:30:18 +04:00
if ( req10 - > extended_op ! = DRSUAPI_EXOP_NONE ) {
2010-01-09 02:12:54 +03:00
r - > out . ctr - > ctr6 . uptodateness_vector = NULL ;
r - > out . ctr - > ctr6 . nc_object_count = 0 ;
ZERO_STRUCT ( r - > out . ctr - > ctr6 . new_highwatermark ) ;
}
2010-09-24 21:05:07 +04:00
DEBUG ( r - > out . ctr - > ctr6 . more_data ? 4 : 2 ,
2010-08-23 05:33:19 +04:00
( " DsGetNCChanges with uSNChanged >= %llu flags 0x%08x on %s gave %u objects (done %u/%u) %u links (done %u/%u (as %s)) \n " ,
2010-09-30 10:30:18 +04:00
( unsigned long long ) ( req10 - > highwatermark . highest_usn + 1 ) ,
req10 - > replica_flags , drs_ObjectIdentifier_to_string ( mem_ctx , ncRoot ) ,
2010-07-09 14:52:11 +04:00
r - > out . ctr - > ctr6 . object_count ,
2010-11-05 10:28:04 +03:00
i , r - > out . ctr - > ctr6 . more_data ? getnc_state - > num_records : i ,
2010-07-09 14:52:11 +04:00
r - > out . ctr - > ctr6 . linked_attributes_count ,
2010-08-23 05:33:19 +04:00
link_given , link_total ,
dom_sid_string ( mem_ctx , user_sid ) ) ) ;
2009-12-19 16:12:35 +03:00
#if 0
2010-09-30 10:30:18 +04:00
if ( ! r - > out . ctr - > ctr6 . more_data & & req10 - > extended_op ! = DRSUAPI_EXOP_NONE ) {
2009-12-19 16:12:35 +03:00
NDR_PRINT_FUNCTION_DEBUG ( drsuapi_DsGetNCChanges , NDR_BOTH , r ) ;
}
# endif
2009-09-12 05:14:29 +04:00
2009-09-09 15:00:01 +04:00
return WERR_OK ;
}