2009-09-09 15:00:01 +04:00
/*
Unix SMB / CIFS implementation .
implement the DRSUpdateRefs call
Copyright ( C ) Anatoliy Atanasov 2009
Copyright ( C ) Andrew Tridgell 2009
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
# include "librpc/gen_ndr/ndr_drsuapi.h"
# include "rpc_server/dcerpc_server.h"
# include "rpc_server/common/common.h"
# include "dsdb/samdb/samdb.h"
# include "lib/ldb/include/ldb_errors.h"
# include "param/param.h"
# include "librpc/gen_ndr/ndr_drsblobs.h"
# include "auth/auth.h"
# include "rpc_server/drsuapi/dcesrv_drsuapi.h"
2009-09-10 11:46:30 +04:00
# include "rpc_server/dcerpc_server_proto.h"
# include "../libcli/drsuapi/drsuapi.h"
# include "../libcli/security/dom_sid.h"
2009-09-09 15:00:01 +04:00
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 ,
struct ldb_message * msg ,
struct ldb_context * sam_ctx ,
struct ldb_dn * ncRoot_dn ,
2009-09-10 11:46:30 +04:00
struct dsdb_schema * schema ,
2009-09-12 05:14:29 +04:00
DATA_BLOB * session_key ,
uint64_t highest_usn )
2009-09-09 15:26:17 +04:00
{
const struct ldb_val * md_value ;
2009-09-12 05:14:29 +04:00
int i , n ;
2009-09-09 15:26:17 +04:00
struct ldb_dn * obj_dn ;
2009-09-09 17:38:51 +04:00
struct replPropertyMetaDataBlob md ;
2009-09-10 11:46:30 +04:00
struct dom_sid * sid ;
uint32_t rid = 0 ;
2009-09-12 05:14:29 +04:00
enum ndr_err_code ndr_err ;
uint32_t * attids ;
2009-09-09 15:26:17 +04:00
if ( ldb_dn_compare ( ncRoot_dn , msg - > dn ) = = 0 ) {
obj - > is_nc_prefix = true ;
obj - > parent_object_guid = NULL ;
} else {
obj - > is_nc_prefix = false ;
obj - > parent_object_guid = talloc ( obj , struct GUID ) ;
* obj - > parent_object_guid = samdb_result_guid ( msg , " parentGUID " ) ;
}
obj - > next_object = NULL ;
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 ;
}
ndr_err = ndr_pull_struct_blob ( md_value , obj ,
lp_iconv_convenience ( ldb_get_opaque ( sam_ctx , " loadparm " ) ) , & md ,
( ndr_pull_flags_fn_t ) ndr_pull_replPropertyMetaDataBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return WERR_DS_DRA_INTERNAL_ERROR ;
}
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
obj - > meta_data_ctr = talloc ( obj , struct drsuapi_DsReplicaMetaDataCtr ) ;
attids = talloc_array ( obj , uint32_t , md . ctr . ctr1 . count ) ;
obj - > meta_data_ctr - > meta_data = talloc_array ( obj , struct drsuapi_DsReplicaMetaData , md . ctr . ctr1 . count ) ;
for ( n = i = 0 ; i < md . ctr . ctr1 . count ; i + + ) {
2009-09-15 22:47:42 +04:00
if ( md . ctr . ctr1 . array [ i ] . local_usn < highest_usn ) continue ;
2009-09-12 05:14:29 +04:00
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 + + ;
}
2009-09-15 00:12:32 +04:00
/*
note that if n = = 0 we still need to send the change , as it
could be a rename , which changes the uSNChanged , but not any
of the replicated attributes
*/
2009-09-12 05:14:29 +04:00
obj - > meta_data_ctr - > count = n ;
2009-09-09 15:26:17 +04:00
obj - > object . identifier = talloc ( obj , struct drsuapi_DsReplicaObjectIdentifier ) ;
obj_dn = ldb_msg_find_attr_as_dn ( sam_ctx , obj , msg , " distinguishedName " ) ;
obj - > object . identifier - > dn = ldb_dn_get_linearized ( obj_dn ) ;
2009-09-10 07:51:08 +04:00
obj - > object . identifier - > guid = samdb_result_guid ( msg , " objectGUID " ) ;
2009-09-10 11:46:30 +04:00
sid = samdb_result_dom_sid ( obj , msg , " objectSid " ) ;
if ( sid ) {
dom_sid_split_rid ( NULL , sid , NULL , & rid ) ;
obj - > object . identifier - > sid = * sid ;
} else {
ZERO_STRUCT ( obj - > object . identifier - > sid ) ;
}
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 ) ;
/*
* 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 + + ) {
2009-09-09 15:26:17 +04:00
const struct dsdb_attribute * sa ;
2009-09-09 17:38:51 +04:00
struct ldb_message_element * el ;
WERROR werr ;
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 ) {
DEBUG ( 0 , ( " 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 ] ) ;
2009-09-12 05:14:29 +04:00
obj - > object . attribute_ctr . attributes [ i ] . attid = attids [ i ] ;
2009-09-09 19:27:12 +04:00
} else {
werr = dsdb_attribute_ldb_to_drsuapi ( sam_ctx , schema , el , obj ,
& obj - > object . attribute_ctr . attributes [ i ] ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 0 , ( " Unable to convert %s to DRS object - %s \n " ,
sa - > lDAPDisplayName , win_errstr ( werr ) ) ) ;
return werr ;
}
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 ) ) {
DEBUG ( 0 , ( " Unable to encrypt %s in DRS object - %s \n " ,
sa - > lDAPDisplayName , win_errstr ( werr ) ) ) ;
return werr ;
}
2009-09-09 15:26:17 +04:00
}
}
return WERR_OK ;
}
2009-09-10 13:41:48 +04:00
static int replmd_drsuapi_DsReplicaCursor2_compare ( const struct drsuapi_DsReplicaCursor2 * c1 ,
const struct drsuapi_DsReplicaCursor2 * c2 )
{
return GUID_compare ( & c1 - > source_dsa_invocation_id , & c2 - > source_dsa_invocation_id ) ;
}
2009-09-12 05:14:29 +04:00
/*
load replUpToDateVector from a DN
*/
static WERROR load_udv ( struct ldb_context * sam_ctx , TALLOC_CTX * mem_ctx ,
struct ldb_dn * dn , struct replUpToDateVectorBlob * ouv )
2009-09-10 13:41:48 +04:00
{
2009-09-12 05:14:29 +04:00
const char * attrs [ ] = { " replUpToDateVector " , NULL } ;
struct ldb_result * res = NULL ;
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
struct ldb_message_element * el ;
enum ndr_err_code ndr_err ;
ZERO_STRUCTP ( ouv ) ;
if ( ldb_search ( sam_ctx , tmp_ctx , & res , dn , LDB_SCOPE_BASE , attrs , NULL ) ! = LDB_SUCCESS | |
res - > count < 1 ) {
DEBUG ( 0 , ( " load_udv: failed to read partition object \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2009-09-10 13:41:48 +04:00
2009-09-12 05:14:29 +04:00
el = ldb_msg_find_element ( res - > msgs [ 0 ] , " replUpToDateVector " ) ;
if ( el = = NULL | | el - > num_values < 1 ) {
talloc_free ( tmp_ctx ) ;
ouv - > version = 2 ;
return WERR_OK ;
}
2009-09-10 13:41:48 +04:00
2009-09-12 05:14:29 +04:00
ndr_err = ndr_pull_struct_blob ( & el - > values [ 0 ] ,
mem_ctx , lp_iconv_convenience ( ldb_get_opaque ( sam_ctx , " loadparm " ) ) ,
ouv ,
( ndr_pull_flags_fn_t ) ndr_pull_replUpToDateVectorBlob ) ;
talloc_free ( tmp_ctx ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DEBUG ( 0 , ( __location__ " : Failed to parse replUpToDateVector for %s \n " ,
ldb_dn_get_linearized ( dn ) ) ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
return WERR_OK ;
}
/*
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 ,
struct drsuapi_DsReplicaCursor2CtrEx * udv )
{
WERROR werr ;
struct drsuapi_DsReplicaCursor2 * tmp_cursor ;
uint64_t highest_commited_usn ;
NTTIME now ;
time_t t = time ( NULL ) ;
int ret ;
struct replUpToDateVectorBlob ouv ;
werr = load_udv ( sam_ctx , udv , ncRoot_dn , & ouv ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
return werr ;
}
ret = ldb_sequence_number ( sam_ctx , LDB_SEQ_HIGHEST_SEQ , & highest_commited_usn ) ;
if ( ret ! = LDB_SUCCESS ) {
return WERR_DS_DRA_INTERNAL_ERROR ;
2009-09-10 13:41:48 +04:00
}
2009-09-12 05:14:29 +04:00
tmp_cursor = talloc ( udv , struct drsuapi_DsReplicaCursor2 ) ;
tmp_cursor - > source_dsa_invocation_id = * ( samdb_ntds_invocation_id ( sam_ctx ) ) ;
tmp_cursor - > highest_usn = highest_commited_usn ;
unix_to_nt_time ( & now , t ) ;
tmp_cursor - > last_sync_success = now ;
udv - > count = ouv . ctr . ctr2 . count + 1 ;
udv - > cursors = talloc_steal ( udv , ouv . ctr . ctr2 . cursors ) ;
udv - > cursors = talloc_realloc ( udv , udv - > cursors , struct drsuapi_DsReplicaCursor2 , udv - > count ) ;
if ( ! udv - > cursors ) {
return WERR_DS_DRA_INTERNAL_ERROR ;
}
udv - > cursors [ udv - > count - 1 ] = * tmp_cursor ;
qsort ( udv - > cursors , udv - > count ,
sizeof ( struct drsuapi_DsReplicaCursor2 ) ,
( comparison_fn_t ) replmd_drsuapi_DsReplicaCursor2_compare ) ;
2009-09-10 13:41:48 +04:00
return WERR_OK ;
}
2009-09-09 15:00:01 +04:00
/*
drsuapi_DsGetNCChanges
*/
WERROR dcesrv_drsuapi_DsGetNCChanges ( struct dcesrv_call_state * dce_call , TALLOC_CTX * mem_ctx ,
struct drsuapi_DsGetNCChanges * r )
{
struct ldb_result * site_res ;
struct drsuapi_DsReplicaObjectIdentifier * ncRoot ;
2009-09-09 15:26:17 +04:00
struct ldb_context * sam_ctx ;
2009-09-09 15:00:01 +04:00
struct ldb_dn * ncRoot_dn ;
int ret ;
int i ;
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-10 17:03:07 +04:00
const char * attrs [ ] = { " * " , " parentGUID " , NULL } ;
2009-09-12 05:14:29 +04:00
WERROR werr ;
2009-09-09 15:26:17 +04:00
2009-09-09 15:00:01 +04:00
/*
2009-09-10 11:46:30 +04:00
* connect to the samdb . TODO : We need to check that the caller
* has the rights to do this . This exposes all attributes ,
* including all passwords .
2009-09-09 15:00:01 +04:00
*/
2009-09-10 11:46:30 +04:00
sam_ctx = samdb_connect ( mem_ctx , dce_call - > event_ctx , dce_call - > conn - > dce_ctx - > lp_ctx ,
system_session ( mem_ctx , dce_call - > conn - > dce_ctx - > lp_ctx ) ) ;
2009-09-09 15:26:17 +04:00
if ( ! sam_ctx ) {
2009-09-09 15:00:01 +04:00
return WERR_FOOBAR ;
}
/* Check request revision. */
if ( r - > in . level ! = 8 ) {
return WERR_REVISION_MISMATCH ;
}
/* Perform access checks. */
if ( r - > in . req - > req8 . naming_context = = NULL ) {
return WERR_DS_DRA_INVALID_PARAMETER ;
}
ncRoot = r - > in . req - > req8 . naming_context ;
if ( ncRoot = = NULL ) {
return WERR_DS_DRA_BAD_NC ;
}
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 " ) ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2009-09-09 15:00:01 +04:00
/* Construct response. */
2009-09-09 15:26:17 +04:00
ncRoot_dn = ldb_dn_new ( mem_ctx , sam_ctx , ncRoot - > dn ) ;
ret = drsuapi_search_with_extended_dn ( sam_ctx , mem_ctx , & site_res ,
2009-09-10 17:03:07 +04:00
ncRoot_dn , LDB_SCOPE_SUBTREE , attrs ,
2009-09-13 12:14:35 +04:00
" (uSNChanged>=%llu) " ,
2009-09-12 06:42:40 +04:00
( unsigned long long ) ( r - > in . req - > req8 . highwatermark . highest_usn + 1 ) ) ;
2009-09-09 15:00:01 +04:00
if ( ret ! = LDB_SUCCESS ) {
return WERR_DS_DRA_INTERNAL_ERROR ;
}
* r - > out . level_out = 6 ;
r - > out . ctr - > ctr6 . naming_context = talloc ( mem_ctx , struct drsuapi_DsReplicaObjectIdentifier ) ;
* r - > out . ctr - > ctr6 . naming_context = * ncRoot ;
/* TODO: linked attributes*/
r - > out . ctr - > ctr6 . linked_attributes_count = 0 ;
r - > out . ctr - > ctr6 . linked_attributes = NULL ;
r - > out . ctr - > ctr6 . object_count = 0 ;
r - > out . ctr - > ctr6 . more_data = false ;
r - > out . ctr - > ctr6 . uptodateness_vector = NULL ;
/* Prefix mapping */
2009-09-09 15:26:17 +04:00
schema = dsdb_get_schema ( sam_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
}
dsdb_get_oid_mappings_drsuapi ( schema , true , mem_ctx , & ctr ) ;
r - > out . ctr - > ctr6 . mapping_ctr = * ctr ;
2009-09-09 15:26:17 +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
r - > out . ctr - > ctr6 . old_highwatermark = r - > in . req - > req8 . highwatermark ;
r - > out . ctr - > ctr6 . new_highwatermark = r - > in . req - > req8 . highwatermark ;
2009-09-10 13:41:48 +04:00
r - > out . ctr - > ctr6 . uptodateness_vector = talloc ( mem_ctx , struct drsuapi_DsReplicaCursor2CtrEx ) ;
r - > out . ctr - > ctr6 . uptodateness_vector - > version = 2 ;
r - > out . ctr - > ctr6 . uptodateness_vector - > reserved1 = 0 ;
r - > out . ctr - > ctr6 . uptodateness_vector - > reserved2 = 0 ;
2009-09-12 05:14:29 +04:00
r - > out . ctr - > ctr6 . first_object = NULL ;
currentObject = & r - > out . ctr - > ctr6 . first_object ;
2009-09-09 15:00:01 +04:00
for ( i = 0 ; i < site_res - > count ; i + + ) {
2009-09-09 15:26:17 +04:00
int uSN ;
2009-09-12 05:14:29 +04:00
struct drsuapi_DsReplicaObjectListItemEx * obj ;
obj = talloc_zero ( mem_ctx , struct drsuapi_DsReplicaObjectListItemEx ) ;
2009-09-09 15:26:17 +04:00
uSN = ldb_msg_find_attr_as_int ( site_res - > msgs [ i ] , " uSNChanged " , - 1 ) ;
2009-09-09 15:00:01 +04:00
if ( uSN > r - > out . ctr - > ctr6 . new_highwatermark . highest_usn ) {
2009-09-12 07:06:32 +04:00
r - > out . ctr - > ctr6 . new_highwatermark . tmp_highest_usn = uSN ;
2009-09-09 15:00:01 +04:00
r - > out . ctr - > ctr6 . new_highwatermark . highest_usn = uSN ;
}
2009-09-12 05:14:29 +04:00
werr = get_nc_changes_build_object ( obj , site_res - > msgs [ i ] , sam_ctx , ncRoot_dn ,
schema , & session_key , r - > in . req - > req8 . highwatermark . highest_usn ) ;
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
2009-09-12 05:14:29 +04:00
if ( obj - > meta_data_ctr = = NULL ) {
/* no attributes to send */
talloc_free ( obj ) ;
continue ;
2009-09-10 13:41:48 +04:00
}
2009-09-12 05:14:29 +04:00
r - > out . ctr - > ctr6 . object_count + + ;
* currentObject = obj ;
currentObject = & obj - > next_object ;
2009-09-09 15:00:01 +04:00
}
2009-09-12 05:14:29 +04:00
werr = get_nc_changes_udv ( sam_ctx , ncRoot_dn , r - > out . ctr - > ctr6 . uptodateness_vector ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
return werr ;
}
2009-09-12 09:23:30 +04:00
DEBUG ( 3 , ( " DsGetNCChanges with uSNChanged >= %llu on %s gave %u objects \n " ,
2009-09-12 06:42:40 +04:00
( unsigned long long ) ( r - > in . req - > req8 . highwatermark . highest_usn + 1 ) ,
2009-09-12 05:14:29 +04:00
ncRoot - > dn , r - > out . ctr - > ctr6 . object_count ) ) ;
2009-09-12 06:42:40 +04:00
if ( r - > out . ctr - > ctr6 . object_count < = 10 & & DEBUGLVL ( 6 ) ) {
NDR_PRINT_FUNCTION_DEBUG ( drsuapi_DsGetNCChanges , NDR_IN | NDR_OUT , r ) ;
}
2009-09-09 15:00:01 +04:00
return WERR_OK ;
}