2007-01-04 12:10:55 +00:00
/*
ldb database library
2008-09-11 18:36:28 -04:00
Copyright ( C ) Simo Sorce 2004 - 2008
2007-01-04 12:10:55 +00:00
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2005
Copyright ( C ) Andrew Tridgell 2005
2007-03-14 19:10:21 +00:00
Copyright ( C ) Stefan Metzmacher < metze @ samba . org > 2007
2007-01-04 12:10:55 +00:00
2009-09-12 11:21:21 +10: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 .
2007-01-04 12:10:55 +00:00
2009-09-12 11:21:21 +10:00
This program is distributed in the hope that it will be useful ,
2007-01-04 12:10:55 +00:00
but WITHOUT ANY WARRANTY ; without even the implied warranty of
2009-09-12 11:21:21 +10:00
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/>.
2007-01-04 12:10:55 +00:00
*/
/*
* Name : ldb
*
* Component : ldb repl_meta_data module
*
* Description : - add a unique objectGUID onto every new record ,
* - handle whenCreated , whenChanged timestamps
* - handle uSNCreated , uSNChanged numbers
* - handle replPropertyMetaData attribute
*
* Author : Simo Sorce
* Author : Stefan Metzmacher
*/
# include "includes.h"
2009-01-30 16:31:19 -05:00
# include "ldb_module.h"
2007-01-06 01:13:59 +00:00
# include "dsdb/samdb/samdb.h"
2009-09-03 12:55:57 +10:00
# include "dsdb/common/proto.h"
2009-06-12 14:27:19 +02:00
# include "../libds/common/flags.h"
2007-01-11 09:54:10 +00:00
# include "librpc/gen_ndr/ndr_misc.h"
2007-01-12 13:17:25 +00:00
# include "librpc/gen_ndr/ndr_drsuapi.h"
2007-01-11 09:54:10 +00:00
# include "librpc/gen_ndr/ndr_drsblobs.h"
2008-01-01 22:05:05 -06:00
# include "param/param.h"
2009-09-03 12:55:57 +10:00
# include "libcli/security/dom_sid.h"
2009-09-12 00:49:51 +02:00
# include "lib/util/dlinklist.h"
2009-12-09 14:35:46 +11:00
# include "dsdb/samdb/ldb_modules/util.h"
2009-12-10 23:48:30 +11:00
# include "lib/util/binsearch.h"
# define W2K3_LINKED_ATTRIBUTES 1
2009-09-03 12:55:57 +10:00
struct replmd_private {
2009-09-14 03:44:10 -07:00
TALLOC_CTX * la_ctx ;
2009-09-03 12:55:57 +10:00
struct la_entry * la_list ;
2009-12-16 11:34:33 +11:00
TALLOC_CTX * bl_ctx ;
struct la_backlink * la_backlinks ;
2009-09-13 14:24:08 +10:00
struct nc_entry {
2009-10-16 16:20:15 +11:00
struct nc_entry * prev , * next ;
2009-09-13 14:24:08 +10:00
struct ldb_dn * dn ;
uint64_t mod_usn ;
} * ncs ;
2009-09-03 12:55:57 +10:00
} ;
struct la_entry {
struct la_entry * next , * prev ;
struct drsuapi_DsReplicaLinkedAttribute * la ;
} ;
2007-01-11 09:54:10 +00:00
struct replmd_replicated_request {
struct ldb_module * module ;
2008-09-11 18:36:28 -04:00
struct ldb_request * req ;
2007-01-11 09:54:10 +00:00
2007-01-23 10:21:14 +00:00
const struct dsdb_schema * schema ;
2008-09-27 02:27:54 +02:00
/* the controls we pass down */
struct ldb_control * * controls ;
2009-10-16 16:20:15 +11:00
/* details for the mode where we apply a bunch of inbound replication meessages */
bool apply_mode ;
2007-01-11 09:54:10 +00:00
uint32_t index_current ;
2009-10-16 16:20:15 +11:00
struct dsdb_extended_replicated_objects * objs ;
2007-01-11 09:54:10 +00:00
2008-09-11 18:36:28 -04:00
struct ldb_message * search_msg ;
2009-10-10 09:36:44 +11:00
uint64_t seq_num ;
2009-10-16 16:20:15 +11:00
2007-01-11 09:54:10 +00:00
} ;
2009-10-16 16:20:15 +11:00
static int replmd_replicated_apply_next ( struct replmd_replicated_request * ar ) ;
2009-09-13 14:24:08 +10:00
2009-12-16 11:34:33 +11:00
2009-09-13 14:24:08 +10:00
/*
initialise the module
allocate the private structure and build the list
of partition DNs for use by replmd_notify ( )
*/
static int replmd_init ( struct ldb_module * module )
{
struct replmd_private * replmd_private ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
replmd_private = talloc_zero ( module , struct replmd_private ) ;
if ( replmd_private = = NULL ) {
ldb_oom ( ldb ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
ldb_module_set_private ( module , replmd_private ) ;
return ldb_next_init ( module ) ;
}
2009-12-16 11:34:33 +11:00
/*
cleanup our per - transaction contexts
*/
static void replmd_txn_cleanup ( struct replmd_private * replmd_private )
{
talloc_free ( replmd_private - > la_ctx ) ;
replmd_private - > la_list = NULL ;
replmd_private - > la_ctx = NULL ;
talloc_free ( replmd_private - > bl_ctx ) ;
replmd_private - > la_backlinks = NULL ;
replmd_private - > bl_ctx = NULL ;
}
struct la_backlink {
struct la_backlink * next , * prev ;
const char * attr_name ;
struct GUID forward_guid , target_guid ;
bool active ;
} ;
/*
2009-12-17 10:50:34 +11:00
process a backlinks we accumulated during a transaction , adding and
deleting the backlinks from the target objects
2009-12-16 11:34:33 +11:00
*/
static int replmd_process_backlink ( struct ldb_module * module , struct la_backlink * bl )
{
struct ldb_dn * target_dn , * source_dn ;
int ret ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
struct ldb_message * msg ;
TALLOC_CTX * tmp_ctx = talloc_new ( bl ) ;
char * dn_string ;
/*
- find DN of target
- find DN of source
- construct ldb_message
- either an add or a delete
*/
ret = dsdb_module_dn_by_guid ( module , tmp_ctx , & bl - > target_guid , & target_dn ) ;
if ( ret ! = LDB_SUCCESS ) {
ldb_asprintf_errstring ( ldb , " Failed to find target DN for linked attribute with GUID %s \n " ,
GUID_string ( bl , & bl - > target_guid ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
ret = dsdb_module_dn_by_guid ( module , tmp_ctx , & bl - > forward_guid , & source_dn ) ;
if ( ret ! = LDB_SUCCESS ) {
ldb_asprintf_errstring ( ldb , " Failed to find source DN for linked attribute with GUID %s \n " ,
GUID_string ( bl , & bl - > forward_guid ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
msg = ldb_msg_new ( tmp_ctx ) ;
if ( msg = = NULL ) {
ldb_module_oom ( module ) ;
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
/* construct a ldb_message for adding/deleting the backlink */
msg - > dn = target_dn ;
dn_string = ldb_dn_get_extended_linearized ( tmp_ctx , source_dn , 1 ) ;
if ( ! dn_string ) {
ldb_module_oom ( module ) ;
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
ret = ldb_msg_add_steal_string ( msg , bl - > attr_name , dn_string ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
msg - > elements [ 0 ] . flags = bl - > active ? LDB_FLAG_MOD_ADD : LDB_FLAG_MOD_DELETE ;
ret = dsdb_module_modify ( module , msg , 0 ) ;
if ( ret ! = LDB_SUCCESS ) {
ldb_asprintf_errstring ( ldb , " Failed to %s backlink from %s to %s - %s " ,
bl - > active ? " add " : " remove " ,
ldb_dn_get_linearized ( source_dn ) ,
ldb_dn_get_linearized ( target_dn ) ,
ldb_errstring ( ldb ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-12-17 10:50:34 +11:00
/*
add a backlink to the list of backlinks to add / delete in the prepare
commit
*/
static int replmd_add_backlink ( struct ldb_module * module , const struct dsdb_schema * schema ,
struct GUID * forward_guid , struct GUID * target_guid ,
bool active , const struct dsdb_attribute * schema_attr , bool immediate )
{
const struct dsdb_attribute * target_attr ;
struct la_backlink * bl ;
struct replmd_private * replmd_private =
talloc_get_type_abort ( ldb_module_get_private ( module ) , struct replmd_private ) ;
2009-12-20 11:53:09 +11:00
target_attr = dsdb_attribute_by_linkID ( schema , schema_attr - > linkID ^ 1 ) ;
2009-12-17 10:50:34 +11:00
if ( ! target_attr ) {
/*
* windows 2003 has a broken schema where the
* definition of msDS - IsDomainFor is missing ( which is
* supposed to be the backlink of the
* msDS - HasDomainNCs attribute
*/
return LDB_SUCCESS ;
}
/* see if its already in the list */
for ( bl = replmd_private - > la_backlinks ; bl ; bl = bl - > next ) {
if ( GUID_equal ( forward_guid , & bl - > forward_guid ) & &
GUID_equal ( target_guid , & bl - > target_guid ) & &
( target_attr - > lDAPDisplayName = = bl - > attr_name | |
strcmp ( target_attr - > lDAPDisplayName , bl - > attr_name ) = = 0 ) ) {
break ;
}
}
if ( bl ) {
/* we found an existing one */
if ( bl - > active = = active ) {
return LDB_SUCCESS ;
}
DLIST_REMOVE ( replmd_private - > la_backlinks , bl ) ;
talloc_free ( bl ) ;
return LDB_SUCCESS ;
}
if ( replmd_private - > bl_ctx = = NULL ) {
replmd_private - > bl_ctx = talloc_new ( replmd_private ) ;
if ( replmd_private - > bl_ctx = = NULL ) {
ldb_module_oom ( module ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
}
/* its a new one */
bl = talloc ( replmd_private - > bl_ctx , struct la_backlink ) ;
if ( bl = = NULL ) {
ldb_module_oom ( module ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
bl - > attr_name = target_attr - > lDAPDisplayName ;
bl - > forward_guid = * forward_guid ;
bl - > target_guid = * target_guid ;
bl - > active = active ;
/* the caller may ask for this backlink to be processed
immediately */
if ( immediate ) {
int ret = replmd_process_backlink ( module , bl ) ;
talloc_free ( bl ) ;
return ret ;
}
DLIST_ADD ( replmd_private - > la_backlinks , bl ) ;
return LDB_SUCCESS ;
}
2009-09-13 14:24:08 +10:00
/*
2009-10-16 16:20:15 +11:00
* Callback for most write operations in this module :
*
* notify the repl task that a object has changed . The notifies are
* gathered up in the replmd_private structure then written to the
* @ REPLCHANGED object in each partition during the prepare_commit
2009-09-13 14:24:08 +10:00
*/
2009-10-16 16:20:15 +11:00
static int replmd_op_callback ( struct ldb_request * req , struct ldb_reply * ares )
2009-09-13 14:24:08 +10:00
{
2009-10-16 16:20:15 +11:00
int ret ;
struct replmd_replicated_request * ac =
talloc_get_type_abort ( req - > context , struct replmd_replicated_request ) ;
2009-09-13 14:24:08 +10:00
struct replmd_private * replmd_private =
2009-10-16 16:20:15 +11:00
talloc_get_type_abort ( ldb_module_get_private ( ac - > module ) , struct replmd_private ) ;
struct nc_entry * modified_partition ;
struct ldb_control * partition_ctrl ;
const struct dsdb_control_current_partition * partition ;
2009-09-13 14:24:08 +10:00
2009-10-21 15:21:21 +11:00
struct ldb_control * * controls ;
partition_ctrl = ldb_reply_get_control ( ares , DSDB_CONTROL_CURRENT_PARTITION_OID ) ;
/* Remove the 'partition' control from what we pass up the chain */
controls = controls_except_specified ( ares - > controls , ares , partition_ctrl ) ;
2009-10-16 16:20:15 +11:00
if ( ares - > error ! = LDB_SUCCESS ) {
2009-10-21 15:21:21 +11:00
return ldb_module_done ( ac - > req , controls ,
2009-10-16 16:20:15 +11:00
ares - > response , ares - > error ) ;
2009-09-13 14:24:08 +10:00
}
2009-10-16 16:20:15 +11:00
if ( ares - > type ! = LDB_REPLY_DONE ) {
ldb_set_errstring ( ldb_module_get_ctx ( ac - > module ) , " Invalid reply type for notify \n ! " ) ;
return ldb_module_done ( ac - > req , NULL ,
NULL , LDB_ERR_OPERATIONS_ERROR ) ;
2009-09-13 14:24:08 +10:00
}
2009-10-16 16:20:15 +11:00
if ( ! partition_ctrl ) {
2009-12-21 21:19:55 +11:00
ldb_set_errstring ( ldb_module_get_ctx ( ac - > module ) , " No partition control on reply " ) ;
2009-10-16 16:20:15 +11:00
return ldb_module_done ( ac - > req , NULL ,
NULL , LDB_ERR_OPERATIONS_ERROR ) ;
2009-09-13 14:24:08 +10:00
}
2009-10-21 15:21:21 +11:00
2009-10-16 16:20:15 +11:00
partition = talloc_get_type_abort ( partition_ctrl - > data ,
struct dsdb_control_current_partition ) ;
2009-09-13 14:24:08 +10:00
2009-10-16 16:20:15 +11:00
if ( ac - > seq_num > 0 ) {
for ( modified_partition = replmd_private - > ncs ; modified_partition ;
modified_partition = modified_partition - > next ) {
if ( ldb_dn_compare ( modified_partition - > dn , partition - > dn ) = = 0 ) {
break ;
}
}
if ( modified_partition = = NULL ) {
modified_partition = talloc_zero ( replmd_private , struct nc_entry ) ;
if ( ! modified_partition ) {
ldb_oom ( ldb_module_get_ctx ( ac - > module ) ) ;
return ldb_module_done ( ac - > req , NULL ,
NULL , LDB_ERR_OPERATIONS_ERROR ) ;
}
modified_partition - > dn = ldb_dn_copy ( modified_partition , partition - > dn ) ;
if ( ! modified_partition - > dn ) {
ldb_oom ( ldb_module_get_ctx ( ac - > module ) ) ;
return ldb_module_done ( ac - > req , NULL ,
NULL , LDB_ERR_OPERATIONS_ERROR ) ;
}
DLIST_ADD ( replmd_private - > ncs , modified_partition ) ;
}
2009-09-13 14:24:08 +10:00
2009-10-16 16:20:15 +11:00
if ( ac - > seq_num > modified_partition - > mod_usn ) {
modified_partition - > mod_usn = ac - > seq_num ;
2009-09-13 14:24:08 +10:00
}
}
2009-10-16 16:20:15 +11:00
if ( ac - > apply_mode ) {
talloc_free ( ares ) ;
ac - > index_current + + ;
ret = replmd_replicated_apply_next ( ac ) ;
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_done ( ac - > req , NULL , NULL , ret ) ;
}
return ret ;
} else {
2009-10-21 15:21:21 +11:00
/* free the partition control container here, for the
* common path . Other cases will have it cleaned up
* eventually with the ares */
talloc_free ( partition_ctrl ) ;
return ldb_module_done ( ac - > req ,
controls_except_specified ( controls , ares , partition_ctrl ) ,
2009-10-16 16:20:15 +11:00
ares - > response , LDB_SUCCESS ) ;
2009-09-13 14:24:08 +10:00
}
}
/*
* update a @ REPLCHANGED record in each partition if there have been
* any writes of replicated data in the partition
*/
static int replmd_notify_store ( struct ldb_module * module )
{
struct replmd_private * replmd_private =
talloc_get_type ( ldb_module_get_private ( module ) , struct replmd_private ) ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
2009-11-20 12:09:24 +11:00
while ( replmd_private - > ncs ) {
2009-09-13 18:13:56 +10:00
int ret ;
2009-11-20 12:09:24 +11:00
struct nc_entry * modified_partition = replmd_private - > ncs ;
2009-09-13 14:24:08 +10:00
2009-10-16 16:20:15 +11:00
ret = dsdb_save_partition_usn ( ldb , modified_partition - > dn , modified_partition - > mod_usn ) ;
2009-09-13 14:24:08 +10:00
if ( ret ! = LDB_SUCCESS ) {
2009-09-13 18:13:56 +10:00
DEBUG ( 0 , ( __location__ " : Failed to save partition uSN for %s \n " ,
2009-10-16 16:20:15 +11:00
ldb_dn_get_linearized ( modified_partition - > dn ) ) ) ;
2009-09-13 14:24:08 +10:00
return ret ;
}
2009-11-20 12:09:24 +11:00
DLIST_REMOVE ( replmd_private - > ncs , modified_partition ) ;
talloc_free ( modified_partition ) ;
2009-09-13 14:24:08 +10:00
}
return LDB_SUCCESS ;
}
2009-09-03 12:55:57 +10:00
/*
created a replmd_replicated_request context
*/
2008-09-11 18:36:28 -04:00
static struct replmd_replicated_request * replmd_ctx_init ( struct ldb_module * module ,
2009-09-03 12:55:57 +10:00
struct ldb_request * req )
2007-01-11 09:54:10 +00:00
{
2009-01-30 16:31:19 -05:00
struct ldb_context * ldb ;
2008-09-11 18:36:28 -04:00
struct replmd_replicated_request * ac ;
2007-01-11 09:54:10 +00:00
2009-01-30 16:31:19 -05:00
ldb = ldb_module_get_ctx ( module ) ;
2008-09-11 18:36:28 -04:00
ac = talloc_zero ( req , struct replmd_replicated_request ) ;
if ( ac = = NULL ) {
2009-01-30 16:31:19 -05:00
ldb_oom ( ldb ) ;
2007-01-11 09:54:10 +00:00
return NULL ;
}
2008-09-11 18:36:28 -04:00
ac - > module = module ;
ac - > req = req ;
2009-10-16 16:20:15 +11:00
ac - > schema = dsdb_get_schema ( ldb ) ;
if ( ! ac - > schema ) {
ldb_debug_set ( ldb , LDB_DEBUG_FATAL ,
" replmd_modify: no dsdb_schema loaded " ) ;
DEBUG ( 0 , ( __location__ " : %s \n " , ldb_errstring ( ldb ) ) ) ;
return NULL ;
}
2008-09-11 18:36:28 -04:00
return ac ;
2007-01-11 09:54:10 +00:00
}
2007-01-04 12:10:55 +00:00
/*
add a time element to a record
*/
static int add_time_element ( struct ldb_message * msg , const char * attr , time_t t )
{
struct ldb_message_element * el ;
char * s ;
if ( ldb_msg_find_element ( msg , attr ) ! = NULL ) {
2008-09-09 15:06:13 +02:00
return LDB_SUCCESS ;
2007-01-04 12:10:55 +00:00
}
s = ldb_timestring ( msg , t ) ;
if ( s = = NULL ) {
2008-09-09 15:06:13 +02:00
return LDB_ERR_OPERATIONS_ERROR ;
2007-01-04 12:10:55 +00:00
}
2008-09-25 12:21:28 +02:00
if ( ldb_msg_add_string ( msg , attr , s ) ! = LDB_SUCCESS ) {
2008-09-09 15:06:13 +02:00
return LDB_ERR_OPERATIONS_ERROR ;
2007-01-04 12:10:55 +00:00
}
el = ldb_msg_find_element ( msg , attr ) ;
/* always set as replace. This works because on add ops, the flag
is ignored */
el - > flags = LDB_FLAG_MOD_REPLACE ;
2008-09-09 15:06:13 +02:00
return LDB_SUCCESS ;
2007-01-04 12:10:55 +00:00
}
/*
add a uint64_t element to a record
*/
static int add_uint64_element ( struct ldb_message * msg , const char * attr , uint64_t v )
{
struct ldb_message_element * el ;
if ( ldb_msg_find_element ( msg , attr ) ! = NULL ) {
2008-09-09 15:06:13 +02:00
return LDB_SUCCESS ;
2007-01-04 12:10:55 +00:00
}
2008-09-25 12:21:28 +02:00
if ( ldb_msg_add_fmt ( msg , attr , " %llu " , ( unsigned long long ) v ) ! = LDB_SUCCESS ) {
2008-09-09 15:06:13 +02:00
return LDB_ERR_OPERATIONS_ERROR ;
2007-01-04 12:10:55 +00:00
}
el = ldb_msg_find_element ( msg , attr ) ;
/* always set as replace. This works because on add ops, the flag
is ignored */
el - > flags = LDB_FLAG_MOD_REPLACE ;
2008-09-09 15:06:13 +02:00
return LDB_SUCCESS ;
2007-01-04 12:10:55 +00:00
}
2007-01-23 10:21:14 +00:00
static int replmd_replPropertyMetaData1_attid_sort ( const struct replPropertyMetaData1 * m1 ,
const struct replPropertyMetaData1 * m2 ,
const uint32_t * rdn_attid )
{
if ( m1 - > attid = = m2 - > attid ) {
return 0 ;
}
/*
* the rdn attribute should be at the end !
* so we need to return a value greater than zero
* which means m1 is greater than m2
*/
if ( m1 - > attid = = * rdn_attid ) {
return 1 ;
}
/*
* the rdn attribute should be at the end !
* so we need to return a value less than zero
* which means m2 is greater than m1
*/
if ( m2 - > attid = = * rdn_attid ) {
return - 1 ;
}
2009-12-20 10:26:06 +11:00
return m1 - > attid > m2 - > attid ? 1 : - 1 ;
2007-01-23 10:21:14 +00:00
}
2009-09-24 16:50:59 -07:00
static int replmd_replPropertyMetaDataCtr1_sort ( struct replPropertyMetaDataCtr1 * ctr1 ,
const struct dsdb_schema * schema ,
struct ldb_dn * dn )
2007-01-23 10:21:14 +00:00
{
2009-09-24 16:50:59 -07:00
const char * rdn_name ;
const struct dsdb_attribute * rdn_sa ;
rdn_name = ldb_dn_get_rdn_name ( dn ) ;
if ( ! rdn_name ) {
DEBUG ( 0 , ( __location__ " : No rDN for %s? \n " , ldb_dn_get_linearized ( dn ) ) ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
rdn_sa = dsdb_attribute_by_lDAPDisplayName ( schema , rdn_name ) ;
if ( rdn_sa = = NULL ) {
DEBUG ( 0 , ( __location__ " : No sa found for rDN %s for %s \n " , rdn_name , ldb_dn_get_linearized ( dn ) ) ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
DEBUG ( 6 , ( " Sorting rpmd with attid exception %u rDN=%s DN=%s \n " ,
rdn_sa - > attributeID_id , rdn_name , ldb_dn_get_linearized ( dn ) ) ) ;
2007-01-23 10:21:14 +00:00
ldb_qsort ( ctr1 - > array , ctr1 - > count , sizeof ( struct replPropertyMetaData1 ) ,
2009-09-24 16:50:59 -07:00
discard_const_p ( void , & rdn_sa - > attributeID_id ) ,
( ldb_qsort_cmp_fn_t ) replmd_replPropertyMetaData1_attid_sort ) ;
return LDB_SUCCESS ;
2007-01-23 10:21:14 +00:00
}
static int replmd_ldb_message_element_attid_sort ( const struct ldb_message_element * e1 ,
const struct ldb_message_element * e2 ,
const struct dsdb_schema * schema )
{
const struct dsdb_attribute * a1 ;
const struct dsdb_attribute * a2 ;
/*
* TODO : make this faster by caching the dsdb_attribute pointer
* on the ldb_messag_element
*/
a1 = dsdb_attribute_by_lDAPDisplayName ( schema , e1 - > name ) ;
a2 = dsdb_attribute_by_lDAPDisplayName ( schema , e2 - > name ) ;
/*
* TODO : remove this check , we should rely on e1 and e2 having valid attribute names
* in the schema
*/
if ( ! a1 | | ! a2 ) {
return strcasecmp ( e1 - > name , e2 - > name ) ;
}
2009-12-20 10:26:06 +11:00
if ( a1 - > attributeID_id = = a2 - > attributeID_id ) {
return 0 ;
}
return a1 - > attributeID_id > a2 - > attributeID_id ? 1 : - 1 ;
2007-01-23 10:21:14 +00:00
}
static void replmd_ldb_message_sort ( struct ldb_message * msg ,
const struct dsdb_schema * schema )
{
ldb_qsort ( msg - > elements , msg - > num_elements , sizeof ( struct ldb_message_element ) ,
discard_const_p ( void , schema ) , ( ldb_qsort_cmp_fn_t ) replmd_ldb_message_element_attid_sort ) ;
}
2009-12-17 10:42:15 +11:00
static int replmd_build_la_val ( TALLOC_CTX * mem_ctx , struct ldb_val * v , struct dsdb_dn * dsdb_dn ,
2009-12-18 20:57:21 +11:00
const struct GUID * invocation_id , uint64_t seq_num ,
2009-12-20 00:10:40 +11:00
uint64_t local_usn , NTTIME nttime , uint32_t version , bool deleted ) ;
2009-12-18 20:57:21 +11:00
2009-12-17 10:42:15 +11:00
/*
fix up linked attributes in replmd_add .
This involves setting up the right meta - data in extended DN
components , and creating backlinks to the object
*/
static int replmd_add_fix_la ( struct ldb_module * module , struct ldb_message_element * el ,
uint64_t seq_num , const struct GUID * invocationId , time_t t ,
struct GUID * guid , const struct dsdb_attribute * sa )
{
int i ;
TALLOC_CTX * tmp_ctx = talloc_new ( el - > values ) ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
struct dsdb_schema * schema = dsdb_get_schema ( ldb ) ;
2009-12-18 20:57:21 +11:00
NTTIME now ;
unix_to_nt_time ( & now , t ) ;
2009-12-17 10:42:15 +11:00
for ( i = 0 ; i < el - > num_values ; i + + ) {
struct ldb_val * v = & el - > values [ i ] ;
struct dsdb_dn * dsdb_dn = dsdb_dn_parse ( tmp_ctx , ldb , v , sa - > syntax - > ldap_oid ) ;
struct GUID target_guid ;
NTSTATUS status ;
int ret ;
2009-12-18 20:57:21 +11:00
ret = replmd_build_la_val ( el - > values , v , dsdb_dn , invocationId ,
2009-12-20 00:10:40 +11:00
seq_num , seq_num , now , 0 , false ) ;
2009-12-17 10:42:15 +11:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
/* note that the DN already has the extended
components from the extended_dn_store module */
2009-12-18 20:57:21 +11:00
status = dsdb_get_extended_dn_guid ( dsdb_dn - > dn , & target_guid , " GUID " ) ;
2009-12-21 21:18:31 +11:00
if ( ! NT_STATUS_IS_OK ( status ) | | GUID_all_zero ( & target_guid ) ) {
ret = dsdb_module_guid_by_dn ( module , dsdb_dn - > dn , & target_guid ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-12-17 10:42:15 +11:00
}
2009-12-17 23:00:16 +11:00
ret = replmd_add_backlink ( module , schema , guid , & target_guid , true , sa , false ) ;
2009-12-17 10:42:15 +11:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
}
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
/*
intercept add requests
*/
2008-09-11 18:36:28 -04:00
static int replmd_add ( struct ldb_module * module , struct ldb_request * req )
2007-01-04 12:10:55 +00:00
{
2009-01-30 16:31:19 -05:00
struct ldb_context * ldb ;
2009-09-23 13:36:40 +04:00
struct ldb_control * control ;
2008-09-11 18:36:28 -04:00
struct replmd_replicated_request * ac ;
2007-11-09 19:24:51 +01:00
enum ndr_err_code ndr_err ;
2007-01-04 12:10:55 +00:00
struct ldb_request * down_req ;
struct ldb_message * msg ;
2009-09-23 13:36:40 +04:00
const DATA_BLOB * guid_blob ;
2007-01-04 12:10:55 +00:00
struct GUID guid ;
2007-01-23 16:18:45 +00:00
struct replPropertyMetaDataBlob nmd ;
struct ldb_val nmd_value ;
const struct GUID * our_invocation_id ;
2007-01-04 12:10:55 +00:00
time_t t = time ( NULL ) ;
2007-01-23 16:18:45 +00:00
NTTIME now ;
char * time_str ;
int ret ;
uint32_t i , ni = 0 ;
2009-10-03 10:52:53 +02:00
bool allow_add_guid = false ;
bool remove_current_guid = false ;
2009-09-23 13:36:40 +04:00
2009-10-03 10:52:53 +02:00
/* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
2009-09-23 13:36:40 +04:00
control = ldb_request_get_control ( req , LDB_CONTROL_RELAX_OID ) ;
if ( control ) {
allow_add_guid = 1 ;
}
2007-01-04 12:10:55 +00:00
2008-09-11 18:36:28 -04:00
/* do not manipulate our control entries */
if ( ldb_dn_is_special ( req - > op . add . message - > dn ) ) {
return ldb_next_request ( module , req ) ;
}
2009-01-31 09:44:27 +01:00
ldb = ldb_module_get_ctx ( module ) ;
2009-01-30 16:31:19 -05:00
ldb_debug ( ldb , LDB_DEBUG_TRACE , " replmd_add \n " ) ;
2008-09-11 18:36:28 -04:00
ac = replmd_ctx_init ( module , req ) ;
if ( ! ac ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-09-23 13:36:40 +04:00
guid_blob = ldb_msg_find_ldb_val ( req - > op . add . message , " objectGUID " ) ;
if ( guid_blob ! = NULL ) {
if ( ! allow_add_guid ) {
ldb_debug_set ( ldb , LDB_DEBUG_ERROR ,
2008-09-11 18:36:28 -04:00
" replmd_add: it's not allowed to add an object with objectGUID \n " ) ;
2009-10-02 23:26:35 +02:00
talloc_free ( ac ) ;
2009-09-23 13:36:40 +04:00
return LDB_ERR_UNWILLING_TO_PERFORM ;
} else {
NTSTATUS status = GUID_from_data_blob ( guid_blob , & guid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
ldb_debug_set ( ldb , LDB_DEBUG_ERROR ,
" replmd_add: Unable to parse as a GUID the attribute objectGUID \n " ) ;
2009-10-02 23:26:35 +02:00
talloc_free ( ac ) ;
2009-09-23 13:36:40 +04:00
return LDB_ERR_UNWILLING_TO_PERFORM ;
}
/* we remove this attribute as it can be a string and will not be treated
correctly and then we will readd it latter on in the good format */
2009-10-03 10:52:53 +02:00
remove_current_guid = true ;
2009-09-23 13:36:40 +04:00
}
} else {
/* a new GUID */
guid = GUID_random ( ) ;
2007-01-23 16:18:45 +00:00
}
/* Get a sequence number from the backend */
2009-10-10 09:36:44 +11:00
ret = ldb_sequence_number ( ldb , LDB_SEQ_NEXT , & ac - > seq_num ) ;
2007-01-23 16:18:45 +00:00
if ( ret ! = LDB_SUCCESS ) {
2009-10-02 23:26:35 +02:00
talloc_free ( ac ) ;
2007-01-23 16:18:45 +00:00
return ret ;
2007-01-04 12:10:55 +00:00
}
2009-09-03 12:55:57 +10:00
/* get our invocationId */
2009-01-30 16:31:19 -05:00
our_invocation_id = samdb_ntds_invocation_id ( ldb ) ;
2007-01-23 16:18:45 +00:00
if ( ! our_invocation_id ) {
2009-01-30 16:31:19 -05:00
ldb_debug_set ( ldb , LDB_DEBUG_ERROR ,
2008-09-11 18:36:28 -04:00
" replmd_add: unable to find invocationId \n " ) ;
2009-10-02 23:26:35 +02:00
talloc_free ( ac ) ;
2007-01-04 12:10:55 +00:00
return LDB_ERR_OPERATIONS_ERROR ;
}
/* we have to copy the message as the caller might have it as a const */
2008-09-11 18:36:28 -04:00
msg = ldb_msg_copy_shallow ( ac , req - > op . add . message ) ;
2007-01-04 12:10:55 +00:00
if ( msg = = NULL ) {
2009-01-30 16:31:19 -05:00
ldb_oom ( ldb ) ;
2009-10-02 23:26:35 +02:00
talloc_free ( ac ) ;
2007-01-04 12:10:55 +00:00
return LDB_ERR_OPERATIONS_ERROR ;
}
2007-01-23 16:18:45 +00:00
/* generated times */
unix_to_nt_time ( & now , t ) ;
time_str = ldb_timestring ( msg , t ) ;
if ( ! time_str ) {
2009-10-02 23:26:35 +02:00
ldb_oom ( ldb ) ;
talloc_free ( ac ) ;
2007-01-23 16:18:45 +00:00
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-09-23 13:36:40 +04:00
if ( remove_current_guid ) {
ldb_msg_remove_attr ( msg , " objectGUID " ) ;
}
2007-01-04 12:10:55 +00:00
2007-01-23 16:18:45 +00:00
/*
* remove autogenerated attributes
*/
ldb_msg_remove_attr ( msg , " whenCreated " ) ;
ldb_msg_remove_attr ( msg , " whenChanged " ) ;
ldb_msg_remove_attr ( msg , " uSNCreated " ) ;
ldb_msg_remove_attr ( msg , " uSNChanged " ) ;
ldb_msg_remove_attr ( msg , " replPropertyMetaData " ) ;
/*
* readd replicated attributes
*/
ret = ldb_msg_add_string ( msg , " whenCreated " , time_str ) ;
if ( ret ! = LDB_SUCCESS ) {
2009-01-30 16:31:19 -05:00
ldb_oom ( ldb ) ;
2009-10-02 23:26:35 +02:00
talloc_free ( ac ) ;
return ret ;
2007-01-23 16:18:45 +00:00
}
/* build the replication meta_data */
ZERO_STRUCT ( nmd ) ;
nmd . version = 1 ;
nmd . ctr . ctr1 . count = msg - > num_elements ;
nmd . ctr . ctr1 . array = talloc_array ( msg ,
struct replPropertyMetaData1 ,
nmd . ctr . ctr1 . count ) ;
if ( ! nmd . ctr . ctr1 . array ) {
2009-01-30 16:31:19 -05:00
ldb_oom ( ldb ) ;
2009-10-02 23:26:35 +02:00
talloc_free ( ac ) ;
2007-01-23 16:18:45 +00:00
return LDB_ERR_OPERATIONS_ERROR ;
}
for ( i = 0 ; i < msg - > num_elements ; i + + ) {
struct ldb_message_element * e = & msg - > elements [ i ] ;
struct replPropertyMetaData1 * m = & nmd . ctr . ctr1 . array [ ni ] ;
const struct dsdb_attribute * sa ;
2007-05-18 08:09:51 +00:00
if ( e - > name [ 0 ] = = ' @ ' ) continue ;
2009-10-16 16:20:15 +11:00
sa = dsdb_attribute_by_lDAPDisplayName ( ac - > schema , e - > name ) ;
2007-01-23 16:18:45 +00:00
if ( ! sa ) {
2009-01-30 16:31:19 -05:00
ldb_debug_set ( ldb , LDB_DEBUG_ERROR ,
2008-09-11 18:36:28 -04:00
" replmd_add: attribute '%s' not defined in schema \n " ,
2007-01-23 16:18:45 +00:00
e - > name ) ;
2009-10-02 23:26:35 +02:00
talloc_free ( ac ) ;
2007-01-23 16:18:45 +00:00
return LDB_ERR_NO_SUCH_ATTRIBUTE ;
}
2009-09-24 07:19:01 -07:00
if ( ( sa - > systemFlags & DS_FLAG_ATTR_NOT_REPLICATED ) | | ( sa - > systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED ) ) {
2007-03-14 12:07:56 +00:00
/* if the attribute is not replicated (0x00000001)
* or constructed ( 0x00000004 ) it has no metadata
*/
2007-01-23 16:18:45 +00:00
continue ;
2007-01-04 12:10:55 +00:00
}
2007-01-23 16:18:45 +00:00
2009-12-17 10:42:15 +11:00
# if W2K3_LINKED_ATTRIBUTES
if ( sa - > linkID ! = 0 & & dsdb_functional_level ( ldb ) > DS_DOMAIN_FUNCTION_2000 ) {
ret = replmd_add_fix_la ( module , e , ac - > seq_num , our_invocation_id , t , & guid , sa ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( ac ) ;
return ret ;
}
/* linked attributes are not stored in
replPropertyMetaData in FL above w2k */
continue ;
}
# endif
2007-01-23 16:18:45 +00:00
m - > attid = sa - > attributeID_id ;
m - > version = 1 ;
2007-03-09 10:09:37 +00:00
m - > originating_change_time = now ;
m - > originating_invocation_id = * our_invocation_id ;
2009-10-10 09:36:44 +11:00
m - > originating_usn = ac - > seq_num ;
m - > local_usn = ac - > seq_num ;
2007-01-23 16:18:45 +00:00
ni + + ;
}
/* fix meta data count */
nmd . ctr . ctr1 . count = ni ;
/*
* sort meta data array , and move the rdn attribute entry to the end
*/
2009-10-16 16:20:15 +11:00
ret = replmd_replPropertyMetaDataCtr1_sort ( & nmd . ctr . ctr1 , ac - > schema , msg - > dn ) ;
2009-09-24 16:50:59 -07:00
if ( ret ! = LDB_SUCCESS ) {
2009-10-02 23:26:35 +02:00
talloc_free ( ac ) ;
2009-09-24 16:50:59 -07:00
return ret ;
}
2007-01-23 16:18:45 +00:00
/* generated NDR encoded values */
2008-01-01 22:05:05 -06:00
ndr_err = ndr_push_struct_blob ( & nmd_value , msg ,
2009-01-30 16:31:19 -05:00
lp_iconv_convenience ( ldb_get_opaque ( ldb , " loadparm " ) ) ,
2008-01-01 22:05:05 -06:00
& nmd ,
2007-11-09 19:24:51 +01:00
( ndr_push_flags_fn_t ) ndr_push_replPropertyMetaDataBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2009-01-30 16:31:19 -05:00
ldb_oom ( ldb ) ;
2009-10-02 23:26:35 +02:00
talloc_free ( ac ) ;
2007-01-23 16:18:45 +00:00
return LDB_ERR_OPERATIONS_ERROR ;
2007-01-04 12:10:55 +00:00
}
2007-01-23 16:18:45 +00:00
/*
* add the autogenerated values
*/
2009-11-25 17:01:55 -03:00
ret = dsdb_msg_add_guid ( msg , & guid , " objectGUID " ) ;
2007-01-23 16:18:45 +00:00
if ( ret ! = LDB_SUCCESS ) {
2009-01-30 16:31:19 -05:00
ldb_oom ( ldb ) ;
2009-10-02 23:26:35 +02:00
talloc_free ( ac ) ;
2009-09-23 21:13:22 -07:00
return ret ;
2007-01-23 16:18:45 +00:00
}
ret = ldb_msg_add_string ( msg , " whenChanged " , time_str ) ;
if ( ret ! = LDB_SUCCESS ) {
2009-01-30 16:31:19 -05:00
ldb_oom ( ldb ) ;
2009-10-02 23:26:35 +02:00
talloc_free ( ac ) ;
2009-09-23 21:13:22 -07:00
return ret ;
2007-01-23 16:18:45 +00:00
}
2009-10-10 09:36:44 +11:00
ret = samdb_msg_add_uint64 ( ldb , msg , msg , " uSNCreated " , ac - > seq_num ) ;
2007-01-23 16:18:45 +00:00
if ( ret ! = LDB_SUCCESS ) {
2009-01-30 16:31:19 -05:00
ldb_oom ( ldb ) ;
2009-10-02 23:26:35 +02:00
talloc_free ( ac ) ;
2009-09-23 21:13:22 -07:00
return ret ;
2007-01-23 16:18:45 +00:00
}
2009-10-10 09:36:44 +11:00
ret = samdb_msg_add_uint64 ( ldb , msg , msg , " uSNChanged " , ac - > seq_num ) ;
2007-01-23 16:18:45 +00:00
if ( ret ! = LDB_SUCCESS ) {
2009-01-30 16:31:19 -05:00
ldb_oom ( ldb ) ;
2009-10-02 23:26:35 +02:00
talloc_free ( ac ) ;
2009-09-23 21:13:22 -07:00
return ret ;
2007-01-23 16:18:45 +00:00
}
ret = ldb_msg_add_value ( msg , " replPropertyMetaData " , & nmd_value , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
2009-01-30 16:31:19 -05:00
ldb_oom ( ldb ) ;
2009-10-02 23:26:35 +02:00
talloc_free ( ac ) ;
2009-09-23 21:13:22 -07:00
return ret ;
2007-01-23 16:18:45 +00:00
}
/*
* sort the attributes by attid before storing the object
*/
2009-10-16 16:20:15 +11:00
replmd_ldb_message_sort ( msg , ac - > schema ) ;
2007-01-23 16:18:45 +00:00
2009-01-30 16:31:19 -05:00
ret = ldb_build_add_req ( & down_req , ldb , ac ,
2008-09-11 18:36:28 -04:00
msg ,
req - > controls ,
ac , replmd_op_callback ,
req ) ;
if ( ret ! = LDB_SUCCESS ) {
2009-10-02 23:26:35 +02:00
talloc_free ( ac ) ;
2008-09-11 18:36:28 -04:00
return ret ;
2007-01-04 12:10:55 +00:00
}
2009-12-16 20:45:40 +11:00
/* mark the control done */
if ( control ) {
control - > critical = 0 ;
2009-09-23 13:36:40 +04:00
}
2008-09-11 18:36:28 -04:00
/* go on with the call chain */
return ldb_next_request ( module , down_req ) ;
2007-01-06 01:13:59 +00:00
}
2009-09-11 19:07:38 +10:00
/*
* update the replPropertyMetaData for one element
*/
static int replmd_update_rpmd_element ( struct ldb_context * ldb ,
struct ldb_message * msg ,
struct ldb_message_element * el ,
struct replPropertyMetaDataBlob * omd ,
2009-10-16 16:20:15 +11:00
const struct dsdb_schema * schema ,
2009-09-12 11:10:19 +10:00
uint64_t * seq_num ,
2009-09-11 19:07:38 +10:00
const struct GUID * our_invocation_id ,
2009-09-12 11:10:19 +10:00
NTTIME now )
2009-09-11 19:07:38 +10:00
{
int i ;
const struct dsdb_attribute * a ;
struct replPropertyMetaData1 * md1 ;
a = dsdb_attribute_by_lDAPDisplayName ( schema , el - > name ) ;
if ( a = = NULL ) {
DEBUG ( 0 , ( __location__ " : Unable to find attribute %s in schema \n " ,
el - > name ) ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-09-24 07:19:01 -07:00
if ( ( a - > systemFlags & DS_FLAG_ATTR_NOT_REPLICATED ) | | ( a - > systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED ) ) {
2009-09-11 21:45:35 +10:00
return LDB_SUCCESS ;
}
2009-09-11 19:07:38 +10:00
for ( i = 0 ; i < omd - > ctr . ctr1 . count ; i + + ) {
if ( a - > attributeID_id = = omd - > ctr . ctr1 . array [ i ] . attid ) break ;
}
2009-12-10 23:48:30 +11:00
# if W2K3_LINKED_ATTRIBUTES
if ( a - > linkID ! = 0 & & dsdb_functional_level ( ldb ) > DS_DOMAIN_FUNCTION_2000 ) {
/* linked attributes are not stored in
replPropertyMetaData in FL above w2k , but we do
raise the seqnum for the object */
if ( * seq_num = = 0 & &
ldb_sequence_number ( ldb , LDB_SEQ_NEXT , seq_num ) ! = LDB_SUCCESS ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
return LDB_SUCCESS ;
}
# endif
2009-09-11 19:07:38 +10:00
if ( i = = omd - > ctr . ctr1 . count ) {
/* we need to add a new one */
omd - > ctr . ctr1 . array = talloc_realloc ( msg , omd - > ctr . ctr1 . array ,
struct replPropertyMetaData1 , omd - > ctr . ctr1 . count + 1 ) ;
if ( omd - > ctr . ctr1 . array = = NULL ) {
ldb_oom ( ldb ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
omd - > ctr . ctr1 . count + + ;
2009-09-12 09:32:24 +02:00
ZERO_STRUCT ( omd - > ctr . ctr1 . array [ i ] ) ;
2009-09-11 19:07:38 +10:00
}
2009-09-12 11:10:19 +10:00
/* Get a new sequence number from the backend. We only do this
* if we have a change that requires a new
* replPropertyMetaData element
*/
if ( * seq_num = = 0 ) {
int ret = ldb_sequence_number ( ldb , LDB_SEQ_NEXT , seq_num ) ;
if ( ret ! = LDB_SUCCESS ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
}
2009-09-11 19:07:38 +10:00
md1 = & omd - > ctr . ctr1 . array [ i ] ;
2009-09-12 09:32:24 +02:00
md1 - > version + + ;
2009-09-11 19:07:38 +10:00
md1 - > attid = a - > attributeID_id ;
md1 - > originating_change_time = now ;
md1 - > originating_invocation_id = * our_invocation_id ;
2009-09-12 11:10:19 +10:00
md1 - > originating_usn = * seq_num ;
md1 - > local_usn = * seq_num ;
2009-09-11 19:07:38 +10:00
return LDB_SUCCESS ;
}
/*
* update the replPropertyMetaData object each time we modify an
* object . This is needed for DRS replication , as the merge on the
* client is based on this object
*/
2009-09-13 14:24:08 +10:00
static int replmd_update_rpmd ( struct ldb_module * module ,
2009-10-16 16:20:15 +11:00
const struct dsdb_schema * schema ,
2009-12-10 23:48:30 +11:00
struct ldb_message * msg , uint64_t * seq_num ,
time_t t )
2009-09-11 19:07:38 +10:00
{
const struct ldb_val * omd_value ;
enum ndr_err_code ndr_err ;
struct replPropertyMetaDataBlob omd ;
int i ;
NTTIME now ;
const struct GUID * our_invocation_id ;
int ret ;
const char * attrs [ ] = { " replPropertyMetaData " , NULL } ;
struct ldb_result * res ;
2009-09-13 14:24:08 +10:00
struct ldb_context * ldb ;
ldb = ldb_module_get_ctx ( module ) ;
2009-09-11 19:07:38 +10:00
our_invocation_id = samdb_ntds_invocation_id ( ldb ) ;
if ( ! our_invocation_id ) {
2009-09-11 23:26:39 +10:00
/* this happens during an initial vampire while
updating the schema */
DEBUG ( 5 , ( " No invocationID - skipping replPropertyMetaData update \n " ) ) ;
return LDB_SUCCESS ;
2009-09-11 19:07:38 +10:00
}
unix_to_nt_time ( & now , t ) ;
/* search for the existing replPropertyMetaDataBlob */
2009-09-24 16:50:59 -07:00
ret = dsdb_search_dn_with_deleted ( ldb , msg , & res , msg - > dn , attrs ) ;
2009-10-02 23:26:35 +02:00
if ( ret ! = LDB_SUCCESS | | res - > count ! = 1 ) {
2009-09-11 19:07:38 +10:00
DEBUG ( 0 , ( __location__ " : Object %s failed to find replPropertyMetaData \n " ,
ldb_dn_get_linearized ( msg - > dn ) ) ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
omd_value = ldb_msg_find_ldb_val ( res - > msgs [ 0 ] , " replPropertyMetaData " ) ;
if ( ! omd_value ) {
DEBUG ( 0 , ( __location__ " : Object %s does not have a replPropertyMetaData attribute \n " ,
ldb_dn_get_linearized ( msg - > dn ) ) ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
ndr_err = ndr_pull_struct_blob ( omd_value , msg ,
lp_iconv_convenience ( ldb_get_opaque ( ldb , " loadparm " ) ) , & omd ,
( ndr_pull_flags_fn_t ) ndr_pull_replPropertyMetaDataBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DEBUG ( 0 , ( __location__ " : Failed to parse replPropertyMetaData for %s \n " ,
ldb_dn_get_linearized ( msg - > dn ) ) ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
if ( omd . version ! = 1 ) {
DEBUG ( 0 , ( __location__ " : bad version %u in replPropertyMetaData for %s \n " ,
omd . version , ldb_dn_get_linearized ( msg - > dn ) ) ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
for ( i = 0 ; i < msg - > num_elements ; i + + ) {
ret = replmd_update_rpmd_element ( ldb , msg , & msg - > elements [ i ] , & omd , schema , seq_num ,
2009-09-12 11:10:19 +10:00
our_invocation_id , now ) ;
2009-09-11 19:07:38 +10:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
2009-09-12 11:10:19 +10:00
/*
* replmd_update_rpmd_element has done an update if the
* seq_num is set
*/
if ( * seq_num ! = 0 ) {
2009-09-11 19:07:38 +10:00
struct ldb_val * md_value ;
struct ldb_message_element * el ;
md_value = talloc ( msg , struct ldb_val ) ;
if ( md_value = = NULL ) {
ldb_oom ( ldb ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-09-24 16:50:59 -07:00
ret = replmd_replPropertyMetaDataCtr1_sort ( & omd . ctr . ctr1 , schema , msg - > dn ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2009-09-24 07:18:21 -07:00
2009-09-11 19:07:38 +10:00
ndr_err = ndr_push_struct_blob ( md_value , msg ,
lp_iconv_convenience ( ldb_get_opaque ( ldb , " loadparm " ) ) ,
& omd ,
( ndr_push_flags_fn_t ) ndr_push_replPropertyMetaDataBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DEBUG ( 0 , ( __location__ " : Failed to marshall replPropertyMetaData for %s \n " ,
ldb_dn_get_linearized ( msg - > dn ) ) ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
ret = ldb_msg_add_empty ( msg , " replPropertyMetaData " , LDB_FLAG_MOD_REPLACE , & el ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to add updated replPropertyMetaData %s \n " ,
ldb_dn_get_linearized ( msg - > dn ) ) ) ;
return ret ;
}
el - > num_values = 1 ;
el - > values = md_value ;
}
return LDB_SUCCESS ;
}
2009-12-10 23:48:30 +11:00
struct parsed_dn {
struct dsdb_dn * dsdb_dn ;
struct GUID * guid ;
struct ldb_val * v ;
} ;
static int parsed_dn_compare ( struct parsed_dn * pdn1 , struct parsed_dn * pdn2 )
{
return GUID_compare ( pdn1 - > guid , pdn2 - > guid ) ;
}
2009-12-21 21:21:55 +11:00
static struct parsed_dn * parsed_dn_find ( struct parsed_dn * pdn , int count , struct GUID * guid , struct ldb_dn * dn )
2009-12-10 23:48:30 +11:00
{
struct parsed_dn * ret ;
2009-12-21 21:21:55 +11:00
if ( dn & & GUID_all_zero ( guid ) ) {
/* when updating a link using DRS, we sometimes get a
NULL GUID . We then need to try and match by DN */
int i ;
for ( i = 0 ; i < count ; i + + ) {
if ( ldb_dn_compare ( pdn [ i ] . dsdb_dn - > dn , dn ) = = 0 ) {
dsdb_get_extended_dn_guid ( pdn [ i ] . dsdb_dn - > dn , guid , " GUID " ) ;
return & pdn [ i ] ;
}
}
return NULL ;
}
2009-12-10 23:48:30 +11:00
BINARY_ARRAY_SEARCH ( pdn , count , guid , guid , GUID_compare , ret ) ;
return ret ;
}
/*
get a series of message element values as an array of DNs and GUIDs
the result is sorted by GUID
*/
static int get_parsed_dns ( struct ldb_module * module , TALLOC_CTX * mem_ctx ,
struct ldb_message_element * el , struct parsed_dn * * pdn ,
const char * ldap_oid )
{
int i ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
if ( el = = NULL ) {
* pdn = NULL ;
return LDB_SUCCESS ;
}
( * pdn ) = talloc_array ( mem_ctx , struct parsed_dn , el - > num_values ) ;
if ( ! * pdn ) {
ldb_module_oom ( module ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
for ( i = 0 ; i < el - > num_values ; i + + ) {
struct ldb_val * v = & el - > values [ i ] ;
NTSTATUS status ;
struct ldb_dn * dn ;
struct parsed_dn * p ;
p = & ( * pdn ) [ i ] ;
p - > dsdb_dn = dsdb_dn_parse ( * pdn , ldb , v , ldap_oid ) ;
if ( p - > dsdb_dn = = NULL ) {
return LDB_ERR_INVALID_DN_SYNTAX ;
}
dn = p - > dsdb_dn - > dn ;
p - > guid = talloc ( * pdn , struct GUID ) ;
if ( p - > guid = = NULL ) {
ldb_module_oom ( module ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-12-18 20:57:21 +11:00
status = dsdb_get_extended_dn_guid ( dn , p - > guid , " GUID " ) ;
2009-12-10 23:48:30 +11:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ) {
/* we got a DN without a GUID - go find the GUID */
2009-12-21 21:23:18 +11:00
int ret = dsdb_module_guid_by_dn ( module , dn , p - > guid ) ;
2009-12-10 23:48:30 +11:00
if ( ret ! = LDB_SUCCESS ) {
ldb_asprintf_errstring ( ldb , " Unable to find GUID for DN %s \n " ,
ldb_dn_get_linearized ( dn ) ) ;
return ret ;
}
} else if ( ! NT_STATUS_IS_OK ( status ) ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
/* keep a pointer to the original ldb_val */
p - > v = v ;
}
qsort ( * pdn , el - > num_values , sizeof ( ( * pdn ) [ 0 ] ) , ( comparison_fn_t ) parsed_dn_compare ) ;
return LDB_SUCCESS ;
}
/*
build a new extended DN , including all meta data fields
2009-12-18 12:47:31 +11:00
DELETED = 1 or missing
RMD_ADDTIME = originating_add_time
RMD_INVOCID = originating_invocation_id
RMD_CHANGETIME = originating_change_time
RMD_ORIGINATING_USN = originating_usn
RMD_LOCAL_USN = local_usn
RMD_VERSION = version
2009-12-10 23:48:30 +11:00
*/
2009-12-17 10:42:15 +11:00
static int replmd_build_la_val ( TALLOC_CTX * mem_ctx , struct ldb_val * v , struct dsdb_dn * dsdb_dn ,
2009-12-18 20:57:21 +11:00
const struct GUID * invocation_id , uint64_t seq_num ,
2009-12-20 00:10:40 +11:00
uint64_t local_usn , NTTIME nttime , uint32_t version , bool deleted )
2009-12-10 23:48:30 +11:00
{
2009-12-17 10:42:15 +11:00
struct ldb_dn * dn = dsdb_dn - > dn ;
2009-12-10 23:48:30 +11:00
const char * tstring , * usn_string ;
struct ldb_val tval ;
struct ldb_val iid ;
2009-12-18 20:57:21 +11:00
struct ldb_val usnv , local_usnv ;
2009-12-10 23:48:30 +11:00
struct ldb_val vers ;
NTSTATUS status ;
int ret ;
const char * dnstring ;
2009-12-20 00:10:40 +11:00
char * vstring ;
2009-12-10 23:48:30 +11:00
2009-12-18 20:57:21 +11:00
tstring = talloc_asprintf ( mem_ctx , " %llu " , ( unsigned long long ) nttime ) ;
2009-12-10 23:48:30 +11:00
if ( ! tstring ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
tval = data_blob_string_const ( tstring ) ;
usn_string = talloc_asprintf ( mem_ctx , " %llu " , ( unsigned long long ) seq_num ) ;
if ( ! usn_string ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
usnv = data_blob_string_const ( usn_string ) ;
2009-12-18 20:57:21 +11:00
usn_string = talloc_asprintf ( mem_ctx , " %llu " , ( unsigned long long ) local_usn ) ;
if ( ! usn_string ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
local_usnv = data_blob_string_const ( usn_string ) ;
2009-12-20 00:10:40 +11:00
vstring = talloc_asprintf ( mem_ctx , " %lu " , ( unsigned long ) version ) ;
vers = data_blob_string_const ( vstring ) ;
2009-12-10 23:48:30 +11:00
status = GUID_to_ndr_blob ( invocation_id , dn , & iid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-12-18 20:57:21 +11:00
if ( deleted ) {
struct ldb_val dv ;
dv = data_blob_string_const ( " 1 " ) ;
ret = ldb_dn_set_extended_component ( dn , " DELETED " , & dv ) ;
} else {
ret = ldb_dn_set_extended_component ( dn , " DELETED " , NULL ) ;
}
2009-12-10 23:48:30 +11:00
if ( ret ! = LDB_SUCCESS ) return ret ;
ret = ldb_dn_set_extended_component ( dn , " RMD_ADDTIME " , & tval ) ;
if ( ret ! = LDB_SUCCESS ) return ret ;
ret = ldb_dn_set_extended_component ( dn , " RMD_INVOCID " , & iid ) ;
if ( ret ! = LDB_SUCCESS ) return ret ;
ret = ldb_dn_set_extended_component ( dn , " RMD_CHANGETIME " , & tval ) ;
if ( ret ! = LDB_SUCCESS ) return ret ;
2009-12-18 20:57:21 +11:00
ret = ldb_dn_set_extended_component ( dn , " RMD_LOCAL_USN " , & local_usnv ) ;
2009-12-18 12:47:31 +11:00
if ( ret ! = LDB_SUCCESS ) return ret ;
ret = ldb_dn_set_extended_component ( dn , " RMD_ORIGINATING_USN " , & usnv ) ;
2009-12-10 23:48:30 +11:00
if ( ret ! = LDB_SUCCESS ) return ret ;
ret = ldb_dn_set_extended_component ( dn , " RMD_VERSION " , & vers ) ;
if ( ret ! = LDB_SUCCESS ) return ret ;
2009-12-17 10:42:15 +11:00
dnstring = dsdb_dn_get_extended_linearized ( mem_ctx , dsdb_dn , 1 ) ;
2009-12-10 23:48:30 +11:00
if ( dnstring = = NULL ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
* v = data_blob_string_const ( dnstring ) ;
return LDB_SUCCESS ;
}
2009-12-19 19:57:37 +11:00
static int replmd_update_la_val ( TALLOC_CTX * mem_ctx , struct ldb_val * v , struct dsdb_dn * dsdb_dn ,
struct dsdb_dn * old_dsdb_dn , const struct GUID * invocation_id ,
2009-12-20 00:10:40 +11:00
uint64_t seq_num , uint64_t local_usn , NTTIME nttime ,
uint32_t version , bool deleted ) ;
2009-12-19 19:57:37 +11:00
/*
check if any links need upgrading from w2k format
*/
static int replmd_check_upgrade_links ( struct parsed_dn * dns , uint32_t count , const struct GUID * invocation_id )
{
int i ;
for ( i = 0 ; i < count ; i + + ) {
NTSTATUS status ;
uint32_t version ;
int ret ;
status = dsdb_get_extended_dn_uint32 ( dns [ i ] . dsdb_dn - > dn , & version , " RMD_VERSION " ) ;
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ) {
continue ;
}
/* it's an old one that needs upgrading */
ret = replmd_update_la_val ( dns , dns [ i ] . v , dns [ i ] . dsdb_dn , dns [ i ] . dsdb_dn , invocation_id ,
2009-12-20 00:10:40 +11:00
1 , 1 , 0 , 0 , false ) ;
2009-12-19 19:57:37 +11:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
return LDB_SUCCESS ;
}
2009-12-10 23:48:30 +11:00
/*
update an extended DN , including all meta data fields
see replmd_build_la_val for value names
*/
2009-12-17 10:42:15 +11:00
static int replmd_update_la_val ( TALLOC_CTX * mem_ctx , struct ldb_val * v , struct dsdb_dn * dsdb_dn ,
struct dsdb_dn * old_dsdb_dn , const struct GUID * invocation_id ,
2009-12-20 00:10:40 +11:00
uint64_t seq_num , uint64_t local_usn , NTTIME nttime ,
uint32_t version , bool deleted )
2009-12-10 23:48:30 +11:00
{
2009-12-17 10:42:15 +11:00
struct ldb_dn * dn = dsdb_dn - > dn ;
2009-12-10 23:48:30 +11:00
const char * tstring , * usn_string ;
struct ldb_val tval ;
struct ldb_val iid ;
2009-12-18 20:57:21 +11:00
struct ldb_val usnv , local_usnv ;
2009-12-10 23:48:30 +11:00
struct ldb_val vers ;
2009-12-20 00:10:40 +11:00
const struct ldb_val * old_addtime ;
uint32_t old_version ;
2009-12-10 23:48:30 +11:00
NTSTATUS status ;
int ret ;
const char * dnstring ;
2009-12-20 00:10:40 +11:00
char * vstring ;
2009-12-10 23:48:30 +11:00
2009-12-18 20:57:21 +11:00
tstring = talloc_asprintf ( mem_ctx , " %llu " , ( unsigned long long ) nttime ) ;
2009-12-10 23:48:30 +11:00
if ( ! tstring ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
tval = data_blob_string_const ( tstring ) ;
usn_string = talloc_asprintf ( mem_ctx , " %llu " , ( unsigned long long ) seq_num ) ;
if ( ! usn_string ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
usnv = data_blob_string_const ( usn_string ) ;
2009-12-18 20:57:21 +11:00
usn_string = talloc_asprintf ( mem_ctx , " %llu " , ( unsigned long long ) local_usn ) ;
if ( ! usn_string ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
local_usnv = data_blob_string_const ( usn_string ) ;
2009-12-10 23:48:30 +11:00
status = GUID_to_ndr_blob ( invocation_id , dn , & iid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
if ( deleted ) {
struct ldb_val dv ;
dv = data_blob_string_const ( " 1 " ) ;
ret = ldb_dn_set_extended_component ( dn , " DELETED " , & dv ) ;
} else {
ret = ldb_dn_set_extended_component ( dn , " DELETED " , NULL ) ;
}
if ( ret ! = LDB_SUCCESS ) return ret ;
/* get the ADDTIME from the original */
2009-12-17 10:42:15 +11:00
old_addtime = ldb_dn_get_extended_component ( old_dsdb_dn - > dn , " RMD_ADDTIME " ) ;
2009-12-10 23:48:30 +11:00
if ( old_addtime = = NULL ) {
old_addtime = & tval ;
}
2009-12-17 10:42:15 +11:00
if ( dsdb_dn ! = old_dsdb_dn ) {
2009-12-10 23:48:30 +11:00
ret = ldb_dn_set_extended_component ( dn , " RMD_ADDTIME " , old_addtime ) ;
if ( ret ! = LDB_SUCCESS ) return ret ;
}
/* use our invocation id */
ret = ldb_dn_set_extended_component ( dn , " RMD_INVOCID " , & iid ) ;
if ( ret ! = LDB_SUCCESS ) return ret ;
/* changetime is the current time */
ret = ldb_dn_set_extended_component ( dn , " RMD_CHANGETIME " , & tval ) ;
if ( ret ! = LDB_SUCCESS ) return ret ;
/* update the USN */
2009-12-18 12:47:31 +11:00
ret = ldb_dn_set_extended_component ( dn , " RMD_ORIGINATING_USN " , & usnv ) ;
if ( ret ! = LDB_SUCCESS ) return ret ;
2009-12-18 20:57:21 +11:00
ret = ldb_dn_set_extended_component ( dn , " RMD_LOCAL_USN " , & local_usnv ) ;
2009-12-10 23:48:30 +11:00
if ( ret ! = LDB_SUCCESS ) return ret ;
/* increase the version by 1 */
2009-12-20 00:10:40 +11:00
status = dsdb_get_extended_dn_uint32 ( old_dsdb_dn - > dn , & old_version , " RMD_VERSION " ) ;
if ( NT_STATUS_IS_OK ( status ) & & old_version > = version ) {
version = old_version + 1 ;
2009-12-10 23:48:30 +11:00
}
2009-12-20 00:10:40 +11:00
vstring = talloc_asprintf ( dn , " %lu " , ( unsigned long ) version ) ;
vers = data_blob_string_const ( vstring ) ;
2009-12-10 23:48:30 +11:00
ret = ldb_dn_set_extended_component ( dn , " RMD_VERSION " , & vers ) ;
if ( ret ! = LDB_SUCCESS ) return ret ;
2009-12-17 10:42:15 +11:00
dnstring = dsdb_dn_get_extended_linearized ( mem_ctx , dsdb_dn , 1 ) ;
2009-12-10 23:48:30 +11:00
if ( dnstring = = NULL ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
* v = data_blob_string_const ( dnstring ) ;
return LDB_SUCCESS ;
}
/*
handle adding a linked attribute
*/
static int replmd_modify_la_add ( struct ldb_module * module ,
2009-12-16 11:34:33 +11:00
struct dsdb_schema * schema ,
2009-12-10 23:48:30 +11:00
struct ldb_message * msg ,
struct ldb_message_element * el ,
struct ldb_message_element * old_el ,
const struct dsdb_attribute * schema_attr ,
uint64_t seq_num ,
2009-12-16 11:34:33 +11:00
time_t t ,
struct GUID * msg_guid )
2009-12-10 23:48:30 +11:00
{
int i ;
struct parsed_dn * dns , * old_dns ;
TALLOC_CTX * tmp_ctx = talloc_new ( msg ) ;
int ret ;
struct ldb_val * new_values = NULL ;
unsigned int num_new_values = 0 ;
unsigned old_num_values = old_el ? old_el - > num_values : 0 ;
const struct GUID * invocation_id ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
2009-12-18 20:57:21 +11:00
NTTIME now ;
unix_to_nt_time ( & now , t ) ;
2009-12-10 23:48:30 +11:00
ret = get_parsed_dns ( module , tmp_ctx , el , & dns , schema_attr - > syntax - > ldap_oid ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
ret = get_parsed_dns ( module , tmp_ctx , old_el , & old_dns , schema_attr - > syntax - > ldap_oid ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
invocation_id = samdb_ntds_invocation_id ( ldb ) ;
if ( ! invocation_id ) {
2009-12-19 19:57:37 +11:00
talloc_free ( tmp_ctx ) ;
2009-12-10 23:48:30 +11:00
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-12-19 19:57:37 +11:00
ret = replmd_check_upgrade_links ( old_dns , old_num_values , invocation_id ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-12-10 23:48:30 +11:00
/* for each new value, see if it exists already with the same GUID */
for ( i = 0 ; i < el - > num_values ; i + + ) {
2009-12-21 21:21:55 +11:00
struct parsed_dn * p = parsed_dn_find ( old_dns , old_num_values , dns [ i ] . guid , NULL ) ;
2009-12-10 23:48:30 +11:00
if ( p = = NULL ) {
/* this is a new linked attribute value */
new_values = talloc_realloc ( tmp_ctx , new_values , struct ldb_val , num_new_values + 1 ) ;
if ( new_values = = NULL ) {
ldb_module_oom ( module ) ;
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-12-17 10:42:15 +11:00
ret = replmd_build_la_val ( new_values , & new_values [ num_new_values ] , dns [ i ] . dsdb_dn ,
2009-12-20 00:10:40 +11:00
invocation_id , seq_num , seq_num , now , 0 , false ) ;
2009-12-10 23:48:30 +11:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
num_new_values + + ;
} else {
/* this is only allowed if the GUID was
previously deleted . */
const struct ldb_val * v ;
v = ldb_dn_get_extended_component ( p - > dsdb_dn - > dn , " DELETED " ) ;
if ( v = = NULL ) {
ldb_asprintf_errstring ( ldb , " Attribute %s already exists for target GUID %s " ,
el - > name , GUID_string ( tmp_ctx , p - > guid ) ) ;
talloc_free ( tmp_ctx ) ;
return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS ;
}
2009-12-17 10:42:15 +11:00
ret = replmd_update_la_val ( old_el - > values , p - > v , dns [ i ] . dsdb_dn , p - > dsdb_dn ,
2009-12-20 00:10:40 +11:00
invocation_id , seq_num , seq_num , now , 0 , false ) ;
2009-12-10 23:48:30 +11:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
}
2009-12-16 11:34:33 +11:00
2009-12-17 10:50:34 +11:00
ret = replmd_add_backlink ( module , schema , msg_guid , dns [ i ] . guid , true , schema_attr , true ) ;
2009-12-16 11:34:33 +11:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-12-10 23:48:30 +11:00
}
/* add the new ones on to the end of the old values, constructing a new el->values */
el - > values = talloc_realloc ( msg - > elements , old_el ? old_el - > values : NULL ,
2009-12-14 21:54:41 +11:00
struct ldb_val ,
old_num_values + num_new_values ) ;
2009-12-10 23:48:30 +11:00
if ( el - > values = = NULL ) {
ldb_module_oom ( module ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
memcpy ( & el - > values [ old_num_values ] , new_values , num_new_values * sizeof ( struct ldb_val ) ) ;
el - > num_values = old_num_values + num_new_values ;
talloc_steal ( msg - > elements , el - > values ) ;
talloc_steal ( el - > values , new_values ) ;
talloc_free ( tmp_ctx ) ;
/* we now tell the backend to replace all existing values
with the one we have constructed */
el - > flags = LDB_FLAG_MOD_REPLACE ;
return LDB_SUCCESS ;
}
/*
handle deleting all active linked attributes
*/
static int replmd_modify_la_delete ( struct ldb_module * module ,
2009-12-16 11:34:33 +11:00
struct dsdb_schema * schema ,
2009-12-10 23:48:30 +11:00
struct ldb_message * msg ,
struct ldb_message_element * el ,
struct ldb_message_element * old_el ,
const struct dsdb_attribute * schema_attr ,
uint64_t seq_num ,
2009-12-16 11:34:33 +11:00
time_t t ,
struct GUID * msg_guid )
2009-12-10 23:48:30 +11:00
{
int i ;
struct parsed_dn * dns , * old_dns ;
TALLOC_CTX * tmp_ctx = talloc_new ( msg ) ;
int ret ;
const struct GUID * invocation_id ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
2009-12-18 20:57:21 +11:00
NTTIME now ;
unix_to_nt_time ( & now , t ) ;
2009-12-10 23:48:30 +11:00
/* check if there is nothing to delete */
if ( ( ! old_el | | old_el - > num_values = = 0 ) & &
el - > num_values = = 0 ) {
return LDB_SUCCESS ;
}
if ( ! old_el | | old_el - > num_values = = 0 ) {
return LDB_ERR_NO_SUCH_ATTRIBUTE ;
}
ret = get_parsed_dns ( module , tmp_ctx , el , & dns , schema_attr - > syntax - > ldap_oid ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
ret = get_parsed_dns ( module , tmp_ctx , old_el , & old_dns , schema_attr - > syntax - > ldap_oid ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
invocation_id = samdb_ntds_invocation_id ( ldb ) ;
if ( ! invocation_id ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-12-19 19:57:37 +11:00
ret = replmd_check_upgrade_links ( old_dns , old_el - > num_values , invocation_id ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-12-10 23:48:30 +11:00
el - > values = NULL ;
/* see if we are being asked to delete any links that
don ' t exist or are already deleted */
for ( i = 0 ; i < el - > num_values ; i + + ) {
struct parsed_dn * p = & dns [ i ] ;
struct parsed_dn * p2 ;
const struct ldb_val * v ;
2009-12-21 21:21:55 +11:00
p2 = parsed_dn_find ( old_dns , old_el - > num_values , p - > guid , NULL ) ;
2009-12-10 23:48:30 +11:00
if ( ! p2 ) {
ldb_asprintf_errstring ( ldb , " Attribute %s doesn't exist for target GUID %s " ,
el - > name , GUID_string ( tmp_ctx , p - > guid ) ) ;
return LDB_ERR_NO_SUCH_ATTRIBUTE ;
}
2009-12-14 21:54:41 +11:00
v = ldb_dn_get_extended_component ( p2 - > dsdb_dn - > dn , " DELETED " ) ;
2009-12-10 23:48:30 +11:00
if ( v ) {
ldb_asprintf_errstring ( ldb , " Attribute %s already deleted for target GUID %s " ,
el - > name , GUID_string ( tmp_ctx , p - > guid ) ) ;
return LDB_ERR_NO_SUCH_ATTRIBUTE ;
}
}
/* for each new value, see if it exists already with the same GUID
if it is not already deleted and matches the delete list then delete it
*/
for ( i = 0 ; i < old_el - > num_values ; i + + ) {
struct parsed_dn * p = & old_dns [ i ] ;
const struct ldb_val * v ;
2009-12-21 21:21:55 +11:00
if ( el - > num_values & & parsed_dn_find ( dns , el - > num_values , p - > guid , NULL ) = = NULL ) {
2009-12-10 23:48:30 +11:00
continue ;
}
v = ldb_dn_get_extended_component ( p - > dsdb_dn - > dn , " DELETED " ) ;
if ( v ! = NULL ) continue ;
2009-12-17 10:42:15 +11:00
ret = replmd_update_la_val ( old_el - > values , p - > v , p - > dsdb_dn , p - > dsdb_dn ,
2009-12-20 00:10:40 +11:00
invocation_id , seq_num , seq_num , now , 0 , true ) ;
2009-12-10 23:48:30 +11:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-12-16 11:34:33 +11:00
2009-12-17 10:50:34 +11:00
ret = replmd_add_backlink ( module , schema , msg_guid , old_dns [ i ] . guid , false , schema_attr , true ) ;
2009-12-16 11:34:33 +11:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-12-10 23:48:30 +11:00
}
el - > values = talloc_steal ( msg - > elements , old_el - > values ) ;
el - > num_values = old_el - > num_values ;
talloc_free ( tmp_ctx ) ;
/* we now tell the backend to replace all existing values
with the one we have constructed */
el - > flags = LDB_FLAG_MOD_REPLACE ;
return LDB_SUCCESS ;
}
2009-12-14 21:54:41 +11:00
/*
handle replacing a linked attribute
*/
static int replmd_modify_la_replace ( struct ldb_module * module ,
2009-12-16 11:34:33 +11:00
struct dsdb_schema * schema ,
2009-12-14 21:54:41 +11:00
struct ldb_message * msg ,
struct ldb_message_element * el ,
struct ldb_message_element * old_el ,
const struct dsdb_attribute * schema_attr ,
uint64_t seq_num ,
2009-12-16 11:34:33 +11:00
time_t t ,
struct GUID * msg_guid )
2009-12-14 21:54:41 +11:00
{
int i ;
struct parsed_dn * dns , * old_dns ;
TALLOC_CTX * tmp_ctx = talloc_new ( msg ) ;
int ret ;
const struct GUID * invocation_id ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
struct ldb_val * new_values = NULL ;
uint32_t num_new_values = 0 ;
unsigned old_num_values = old_el ? old_el - > num_values : 0 ;
2009-12-18 20:57:21 +11:00
NTTIME now ;
unix_to_nt_time ( & now , t ) ;
2009-12-14 21:54:41 +11:00
/* check if there is nothing to replace */
if ( ( ! old_el | | old_el - > num_values = = 0 ) & &
el - > num_values = = 0 ) {
return LDB_SUCCESS ;
}
ret = get_parsed_dns ( module , tmp_ctx , el , & dns , schema_attr - > syntax - > ldap_oid ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
ret = get_parsed_dns ( module , tmp_ctx , old_el , & old_dns , schema_attr - > syntax - > ldap_oid ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
invocation_id = samdb_ntds_invocation_id ( ldb ) ;
if ( ! invocation_id ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-12-19 19:57:37 +11:00
ret = replmd_check_upgrade_links ( old_dns , old_num_values , invocation_id ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-12-14 21:54:41 +11:00
/* mark all the old ones as deleted */
for ( i = 0 ; i < old_num_values ; i + + ) {
struct parsed_dn * old_p = & old_dns [ i ] ;
struct parsed_dn * p ;
const struct ldb_val * v ;
2009-12-16 11:34:33 +11:00
v = ldb_dn_get_extended_component ( old_p - > dsdb_dn - > dn , " DELETED " ) ;
if ( v ) continue ;
2009-12-17 10:50:34 +11:00
ret = replmd_add_backlink ( module , schema , msg_guid , old_dns [ i ] . guid , false , schema_attr , false ) ;
2009-12-16 11:34:33 +11:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-12-21 21:21:55 +11:00
p = parsed_dn_find ( dns , el - > num_values , old_p - > guid , NULL ) ;
2009-12-14 21:54:41 +11:00
if ( p ) {
/* we don't delete it if we are re-adding it */
continue ;
}
2009-12-17 10:42:15 +11:00
ret = replmd_update_la_val ( old_el - > values , old_p - > v , old_p - > dsdb_dn , old_p - > dsdb_dn ,
2009-12-20 00:10:40 +11:00
invocation_id , seq_num , seq_num , now , 0 , true ) ;
2009-12-14 21:54:41 +11:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
}
/* for each new value, either update its meta-data, or add it
* to old_el
*/
for ( i = 0 ; i < el - > num_values ; i + + ) {
struct parsed_dn * p = & dns [ i ] , * old_p ;
if ( old_dns & &
( old_p = parsed_dn_find ( old_dns ,
2009-12-21 21:21:55 +11:00
old_num_values , p - > guid , NULL ) ) ! = NULL ) {
2009-12-14 21:54:41 +11:00
/* update in place */
2009-12-17 10:42:15 +11:00
ret = replmd_update_la_val ( old_el - > values , old_p - > v , old_p - > dsdb_dn ,
old_p - > dsdb_dn , invocation_id ,
2009-12-20 00:10:40 +11:00
seq_num , seq_num , now , 0 , false ) ;
2009-12-14 21:54:41 +11:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
} else {
/* add a new one */
new_values = talloc_realloc ( tmp_ctx , new_values , struct ldb_val ,
num_new_values + 1 ) ;
if ( new_values = = NULL ) {
ldb_module_oom ( module ) ;
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-12-17 10:42:15 +11:00
ret = replmd_build_la_val ( new_values , & new_values [ num_new_values ] , dns [ i ] . dsdb_dn ,
2009-12-20 00:10:40 +11:00
invocation_id , seq_num , seq_num , now , 0 , false ) ;
2009-12-14 21:54:41 +11:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
num_new_values + + ;
}
2009-12-16 11:34:33 +11:00
2009-12-17 10:50:34 +11:00
ret = replmd_add_backlink ( module , schema , msg_guid , dns [ i ] . guid , true , schema_attr , false ) ;
2009-12-16 11:34:33 +11:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-12-14 21:54:41 +11:00
}
/* add the new values to the end of old_el */
if ( num_new_values ! = 0 ) {
el - > values = talloc_realloc ( msg - > elements , old_el ? old_el - > values : NULL ,
struct ldb_val , old_num_values + num_new_values ) ;
if ( el - > values = = NULL ) {
ldb_module_oom ( module ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
memcpy ( & el - > values [ old_num_values ] , & new_values [ 0 ] ,
sizeof ( struct ldb_val ) * num_new_values ) ;
el - > num_values = old_num_values + num_new_values ;
talloc_steal ( msg - > elements , new_values ) ;
} else {
el - > values = old_el - > values ;
el - > num_values = old_el - > num_values ;
talloc_steal ( msg - > elements , el - > values ) ;
}
talloc_free ( tmp_ctx ) ;
/* we now tell the backend to replace all existing values
with the one we have constructed */
el - > flags = LDB_FLAG_MOD_REPLACE ;
return LDB_SUCCESS ;
}
2009-12-10 23:48:30 +11:00
/*
handle linked attributes in modify requests
*/
static int replmd_modify_handle_linked_attribs ( struct ldb_module * module ,
struct ldb_message * msg ,
uint64_t seq_num , time_t t )
{
struct ldb_result * res ;
int ret , i ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
struct ldb_message * old_msg ;
struct dsdb_schema * schema = dsdb_get_schema ( ldb ) ;
2009-12-16 11:34:33 +11:00
struct GUID old_guid ;
2009-12-10 23:48:30 +11:00
if ( seq_num = = 0 ) {
/* there the replmd_update_rpmd code has already
* checked and saw that there are no linked
* attributes */
return LDB_SUCCESS ;
}
# if !W2K3_LINKED_ATTRIBUTES
return LDB_SUCCESS ;
# endif
if ( dsdb_functional_level ( ldb ) = = DS_DOMAIN_FUNCTION_2000 ) {
/* don't do anything special for linked attributes */
return LDB_SUCCESS ;
}
ret = dsdb_module_search_dn ( module , msg , & res , msg - > dn , NULL ,
DSDB_SEARCH_SHOW_DELETED |
2009-12-14 21:54:41 +11:00
DSDB_SEARCH_REVEAL_INTERNALS |
2009-12-10 23:48:30 +11:00
DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
old_msg = res - > msgs [ 0 ] ;
2009-12-16 11:34:33 +11:00
old_guid = samdb_result_guid ( old_msg , " objectGUID " ) ;
2009-12-10 23:48:30 +11:00
for ( i = 0 ; i < msg - > num_elements ; i + + ) {
struct ldb_message_element * el = & msg - > elements [ i ] ;
2009-12-14 21:54:41 +11:00
struct ldb_message_element * old_el , * new_el ;
2009-12-10 23:48:30 +11:00
const struct dsdb_attribute * schema_attr
= dsdb_attribute_by_lDAPDisplayName ( schema , el - > name ) ;
if ( ! schema_attr ) {
ldb_asprintf_errstring ( ldb ,
" attribute %s is not a valid attribute in schema " , el - > name ) ;
return LDB_ERR_OBJECT_CLASS_VIOLATION ;
}
if ( schema_attr - > linkID = = 0 ) {
continue ;
}
if ( ( schema_attr - > linkID & 1 ) = = 1 ) {
/* Odd is for the target. Illegal to modify */
ldb_asprintf_errstring ( ldb ,
" attribute %s must not be modified directly, it is a linked attribute " , el - > name ) ;
return LDB_ERR_UNWILLING_TO_PERFORM ;
}
old_el = ldb_msg_find_element ( old_msg , el - > name ) ;
2009-12-14 21:54:41 +11:00
switch ( el - > flags & LDB_FLAG_MOD_MASK ) {
2009-12-10 23:48:30 +11:00
case LDB_FLAG_MOD_REPLACE :
2009-12-16 11:34:33 +11:00
ret = replmd_modify_la_replace ( module , schema , msg , el , old_el , schema_attr , seq_num , t , & old_guid ) ;
2009-12-10 23:48:30 +11:00
break ;
case LDB_FLAG_MOD_DELETE :
2009-12-16 11:34:33 +11:00
ret = replmd_modify_la_delete ( module , schema , msg , el , old_el , schema_attr , seq_num , t , & old_guid ) ;
2009-12-10 23:48:30 +11:00
break ;
case LDB_FLAG_MOD_ADD :
2009-12-16 11:34:33 +11:00
ret = replmd_modify_la_add ( module , schema , msg , el , old_el , schema_attr , seq_num , t , & old_guid ) ;
2009-12-10 23:48:30 +11:00
break ;
default :
ldb_asprintf_errstring ( ldb ,
" invalid flags 0x%x for %s linked attribute " ,
el - > flags , el - > name ) ;
return LDB_ERR_UNWILLING_TO_PERFORM ;
}
2009-12-14 21:54:41 +11:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
if ( old_el ) {
ldb_msg_remove_attr ( old_msg , el - > name ) ;
}
ldb_msg_add_empty ( old_msg , el - > name , 0 , & new_el ) ;
new_el - > num_values = el - > num_values ;
2009-12-22 12:21:02 +11:00
new_el - > values = talloc_steal ( msg - > elements , el - > values ) ;
2009-12-14 21:54:41 +11:00
/* TODO: this relises a bit too heavily on the exact
behaviour of ldb_msg_find_element and
ldb_msg_remove_element */
old_el = ldb_msg_find_element ( msg , el - > name ) ;
if ( old_el ! = el ) {
ldb_msg_remove_element ( msg , old_el ) ;
i - - ;
}
2009-12-10 23:48:30 +11:00
}
talloc_free ( res ) ;
return ret ;
}
2008-09-11 18:36:28 -04:00
static int replmd_modify ( struct ldb_module * module , struct ldb_request * req )
2007-01-04 12:10:55 +00:00
{
2009-01-30 16:31:19 -05:00
struct ldb_context * ldb ;
2008-09-11 18:36:28 -04:00
struct replmd_replicated_request * ac ;
2007-01-04 12:10:55 +00:00
struct ldb_request * down_req ;
struct ldb_message * msg ;
time_t t = time ( NULL ) ;
2009-10-02 23:26:35 +02:00
int ret ;
2007-01-04 12:10:55 +00:00
2008-09-11 18:36:28 -04:00
/* do not manipulate our control entries */
if ( ldb_dn_is_special ( req - > op . mod . message - > dn ) ) {
return ldb_next_request ( module , req ) ;
}
2009-01-30 16:31:19 -05:00
ldb = ldb_module_get_ctx ( module ) ;
ldb_debug ( ldb , LDB_DEBUG_TRACE , " replmd_modify \n " ) ;
2008-09-11 18:36:28 -04:00
ac = replmd_ctx_init ( module , req ) ;
if ( ! ac ) {
2007-01-04 12:10:55 +00:00
return LDB_ERR_OPERATIONS_ERROR ;
}
/* we have to copy the message as the caller might have it as a const */
2008-09-11 18:36:28 -04:00
msg = ldb_msg_copy_shallow ( ac , req - > op . mod . message ) ;
2007-01-04 12:10:55 +00:00
if ( msg = = NULL ) {
2009-10-02 23:26:35 +02:00
ldb_oom ( ldb ) ;
2008-09-11 18:36:28 -04:00
talloc_free ( ac ) ;
2007-01-04 12:10:55 +00:00
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-12-10 23:48:30 +11:00
ret = replmd_update_rpmd ( module , ac - > schema , msg , & ac - > seq_num , t ) ;
2009-10-02 23:26:35 +02:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( ac ) ;
return ret ;
}
2009-12-10 23:48:30 +11:00
ret = replmd_modify_handle_linked_attribs ( module , msg , ac - > seq_num , t ) ;
2009-09-11 19:07:38 +10:00
if ( ret ! = LDB_SUCCESS ) {
2009-10-02 23:26:35 +02:00
talloc_free ( ac ) ;
2009-09-11 19:07:38 +10:00
return ret ;
}
2008-01-25 08:08:33 +01:00
/* TODO:
* - replace the old object with the newly constructed one
*/
2009-01-30 16:31:19 -05:00
ret = ldb_build_mod_req ( & down_req , ldb , ac ,
2008-09-11 18:36:28 -04:00
msg ,
req - > controls ,
ac , replmd_op_callback ,
req ) ;
if ( ret ! = LDB_SUCCESS ) {
2009-10-02 23:26:35 +02:00
talloc_free ( ac ) ;
2008-09-11 18:36:28 -04:00
return ret ;
2007-01-11 09:54:10 +00:00
}
2008-09-11 18:36:28 -04:00
talloc_steal ( down_req , msg ) ;
2007-01-11 09:54:10 +00:00
2009-09-12 11:10:19 +10:00
/* we only change whenChanged and uSNChanged if the seq_num
has changed */
2009-12-02 17:14:40 +11:00
if ( ac - > seq_num ! = 0 ) {
2009-09-12 11:10:19 +10:00
if ( add_time_element ( msg , " whenChanged " , t ) ! = LDB_SUCCESS ) {
talloc_free ( ac ) ;
2009-10-02 23:26:35 +02:00
return ret ;
2009-09-12 11:10:19 +10:00
}
2009-12-02 17:14:40 +11:00
if ( add_uint64_element ( msg , " uSNChanged " , ac - > seq_num ) ! = LDB_SUCCESS ) {
2009-09-12 11:10:19 +10:00
talloc_free ( ac ) ;
2009-10-02 23:26:35 +02:00
return ret ;
2009-09-12 11:10:19 +10:00
}
}
2008-09-11 18:36:28 -04:00
/* go on with the call chain */
return ldb_next_request ( module , down_req ) ;
2007-01-11 09:54:10 +00:00
}
2009-10-16 16:20:15 +11:00
static int replmd_rename_callback ( struct ldb_request * req , struct ldb_reply * ares ) ;
2009-09-14 13:13:12 -07:00
/*
handle a rename request
On a rename we need to do an extra ldb_modify which sets the
2009-10-16 16:20:15 +11:00
whenChanged and uSNChanged attributes . We do this in a callback after the success .
2009-09-14 13:13:12 -07:00
*/
static int replmd_rename ( struct ldb_module * module , struct ldb_request * req )
{
struct ldb_context * ldb ;
2009-10-16 16:20:15 +11:00
struct replmd_replicated_request * ac ;
int ret ;
struct ldb_request * down_req ;
2009-09-14 13:13:12 -07:00
/* do not manipulate our control entries */
if ( ldb_dn_is_special ( req - > op . mod . message - > dn ) ) {
return ldb_next_request ( module , req ) ;
}
ldb = ldb_module_get_ctx ( module ) ;
ldb_debug ( ldb , LDB_DEBUG_TRACE , " replmd_rename \n " ) ;
2009-10-16 16:20:15 +11:00
ac = replmd_ctx_init ( module , req ) ;
if ( ! ac ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
ret = ldb_build_rename_req ( & down_req , ldb , ac ,
ac - > req - > op . rename . olddn ,
ac - > req - > op . rename . newdn ,
ac - > req - > controls ,
ac , replmd_rename_callback ,
ac - > req ) ;
2009-09-14 13:13:12 -07:00
if ( ret ! = LDB_SUCCESS ) {
2009-10-16 16:20:15 +11:00
talloc_free ( ac ) ;
2009-09-14 13:13:12 -07:00
return ret ;
}
2009-10-16 16:20:15 +11:00
/* go on with the call chain */
return ldb_next_request ( module , down_req ) ;
}
2009-09-14 13:13:12 -07:00
2009-10-16 16:20:15 +11:00
/* After the rename is compleated, update the whenchanged etc */
static int replmd_rename_callback ( struct ldb_request * req , struct ldb_reply * ares )
{
struct ldb_context * ldb ;
struct replmd_replicated_request * ac ;
struct ldb_request * down_req ;
struct ldb_message * msg ;
time_t t = time ( NULL ) ;
int ret ;
2009-09-14 13:13:12 -07:00
2009-10-16 16:20:15 +11:00
ac = talloc_get_type ( req - > context , struct replmd_replicated_request ) ;
ldb = ldb_module_get_ctx ( ac - > module ) ;
if ( ares - > error ! = LDB_SUCCESS ) {
return ldb_module_done ( ac - > req , ares - > controls ,
ares - > response , ares - > error ) ;
2009-09-14 13:13:12 -07:00
}
2009-10-16 16:20:15 +11:00
if ( ares - > type ! = LDB_REPLY_DONE ) {
ldb_set_errstring ( ldb ,
" invalid ldb_reply_type in callback " ) ;
talloc_free ( ares ) ;
return ldb_module_done ( ac - > req , NULL , NULL ,
LDB_ERR_OPERATIONS_ERROR ) ;
2009-09-14 13:13:12 -07:00
}
2009-10-16 16:20:15 +11:00
/* Get a sequence number from the backend */
ret = ldb_sequence_number ( ldb , LDB_SEQ_NEXT , & ac - > seq_num ) ;
2009-09-14 13:13:12 -07:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2009-10-16 16:20:15 +11:00
/* TODO:
* - replace the old object with the newly constructed one
*/
2009-09-14 13:13:12 -07:00
2009-10-16 16:20:15 +11:00
msg = ldb_msg_new ( ac ) ;
if ( msg = = NULL ) {
ldb_oom ( ldb ) ;
2009-09-14 13:13:12 -07:00
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-10-16 16:20:15 +11:00
msg - > dn = ac - > req - > op . rename . newdn ;
ret = ldb_build_mod_req ( & down_req , ldb , ac ,
msg ,
req - > controls ,
ac , replmd_op_callback ,
req ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( ac ) ;
return ret ;
2009-09-14 13:13:12 -07:00
}
2009-10-16 16:20:15 +11:00
talloc_steal ( down_req , msg ) ;
if ( add_time_element ( msg , " whenChanged " , t ) ! = LDB_SUCCESS ) {
talloc_free ( ac ) ;
return ret ;
2009-09-14 13:13:12 -07:00
}
2009-10-16 16:20:15 +11:00
if ( add_uint64_element ( msg , " uSNChanged " , ac - > seq_num ) ! = LDB_SUCCESS ) {
talloc_free ( ac ) ;
return ret ;
}
/* go on with the call chain - do the modify after the rename */
return ldb_next_request ( ac - > module , down_req ) ;
2009-09-14 13:13:12 -07:00
}
2009-12-21 21:25:27 +11:00
/*
remove links from objects that point at this object when an object
is deleted
*/
2009-12-16 17:24:21 +11:00
static int replmd_delete_remove_link ( struct ldb_module * module ,
struct dsdb_schema * schema ,
struct ldb_dn * dn ,
struct ldb_message_element * el ,
const struct dsdb_attribute * sa )
{
int i ;
TALLOC_CTX * tmp_ctx = talloc_new ( module ) ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
for ( i = 0 ; i < el - > num_values ; i + + ) {
struct dsdb_dn * dsdb_dn ;
NTSTATUS status ;
int ret ;
struct GUID guid2 ;
struct ldb_message * msg ;
const struct dsdb_attribute * target_attr ;
struct ldb_message_element * el2 ;
struct ldb_val dn_val ;
if ( dsdb_dn_is_deleted_val ( & el - > values [ i ] ) ) {
continue ;
}
dsdb_dn = dsdb_dn_parse ( tmp_ctx , ldb , & el - > values [ i ] , sa - > syntax - > ldap_oid ) ;
if ( ! dsdb_dn ) {
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-12-18 20:57:21 +11:00
status = dsdb_get_extended_dn_guid ( dsdb_dn - > dn , & guid2 , " GUID " ) ;
2009-12-16 17:24:21 +11:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
/* remove the link */
msg = ldb_msg_new ( tmp_ctx ) ;
if ( ! msg ) {
ldb_module_oom ( module ) ;
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
msg - > dn = dsdb_dn - > dn ;
2009-12-17 23:50:41 +11:00
target_attr = dsdb_attribute_by_linkID ( schema , sa - > linkID ^ 1 ) ;
if ( target_attr = = NULL ) {
continue ;
2009-12-16 17:24:21 +11:00
}
ret = ldb_msg_add_empty ( msg , target_attr - > lDAPDisplayName , LDB_FLAG_MOD_DELETE , & el2 ) ;
if ( ret ! = LDB_SUCCESS ) {
ldb_module_oom ( module ) ;
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
dn_val = data_blob_string_const ( ldb_dn_get_linearized ( dn ) ) ;
el2 - > values = & dn_val ;
el2 - > num_values = 1 ;
2009-12-21 21:26:15 +11:00
ret = dsdb_module_modify ( module , msg , DSDB_FLAG_OWN_MODULE ) ;
2009-12-16 17:24:21 +11:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
}
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
/*
handle update of replication meta data for deletion of objects
This also handles the mapping of delete to a rename operation
to allow deletes to be replicated .
*/
static int replmd_delete ( struct ldb_module * module , struct ldb_request * req )
{
int ret = LDB_ERR_OTHER ;
bool retb ;
struct ldb_dn * old_dn , * new_dn ;
const char * rdn_name ;
const struct ldb_val * rdn_value , * new_rdn_value ;
struct GUID guid ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
struct dsdb_schema * schema = dsdb_get_schema ( ldb ) ;
struct ldb_message * msg , * old_msg ;
struct ldb_message_element * el ;
TALLOC_CTX * tmp_ctx ;
struct ldb_result * res , * parent_res ;
const char * preserved_attrs [ ] = {
/* yes, this really is a hard coded list. See MS-ADTS
section 3.1 .1 .5 .5 .1 .1 */
" nTSecurityDescriptor " , " attributeID " , " attributeSyntax " , " dNReferenceUpdate " , " dNSHostName " ,
" flatName " , " governsID " , " groupType " , " instanceType " , " lDAPDisplayName " , " legacyExchangeDN " ,
" isDeleted " , " isRecycled " , " lastKnownParent " , " msDS-LastKnownRDN " , " mS-DS-CreatorSID " ,
" mSMQOwnerID " , " nCName " , " objectClass " , " distinguishedName " , " objectGUID " , " objectSid " ,
" oMSyntax " , " proxiedObjectName " , " name " , " replPropertyMetaData " , " sAMAccountName " ,
" securityIdentifier " , " sIDHistory " , " subClassOf " , " systemFlags " , " trustPartner " , " trustDirection " ,
2009-12-21 21:24:18 +11:00
" trustType " , " trustAttributes " , " userAccountControl " , " uSNChanged " , " uSNCreated " , " whenCreated " ,
2009-12-16 17:24:21 +11:00
NULL } ;
uint32_t el_count = 0 ;
int i ;
tmp_ctx = talloc_new ( ldb ) ;
old_dn = ldb_dn_copy ( tmp_ctx , req - > op . del . dn ) ;
/* we need the complete msg off disk, so we can work out which
attributes need to be removed */
ret = dsdb_module_search_dn ( module , tmp_ctx , & res , old_dn , NULL ,
DSDB_SEARCH_SHOW_DELETED |
DSDB_SEARCH_REVEAL_INTERNALS |
DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
old_msg = res - > msgs [ 0 ] ;
/* work out where we will be renaming this object to */
ret = dsdb_get_deleted_objects_dn ( ldb , tmp_ctx , old_dn , & new_dn ) ;
if ( ret ! = LDB_SUCCESS ) {
/* this is probably an attempted delete on a partition
* that doesn ' t allow delete operations , such as the
* schema partition */
ldb_asprintf_errstring ( ldb , " No Deleted Objects container for DN %s " ,
ldb_dn_get_linearized ( old_dn ) ) ;
talloc_free ( tmp_ctx ) ;
return LDB_ERR_UNWILLING_TO_PERFORM ;
}
rdn_name = ldb_dn_get_rdn_name ( old_dn ) ;
rdn_value = ldb_dn_get_rdn_val ( old_dn ) ;
/* get the objects GUID from the search we just did */
guid = samdb_result_guid ( old_msg , " objectGUID " ) ;
/* Add a formatted child */
retb = ldb_dn_add_child_fmt ( new_dn , " %s=%s \\ 0ADEL:%s " ,
rdn_name ,
rdn_value - > data ,
GUID_string ( tmp_ctx , & guid ) ) ;
if ( ! retb ) {
DEBUG ( 0 , ( __location__ " : Unable to add a formatted child to dn: %s " ,
ldb_dn_get_linearized ( new_dn ) ) ) ;
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
/*
now we need to modify the object in the following ways :
- add isDeleted = TRUE
- update rDN and name , with new rDN
- remove linked attributes
- remove objectCategory and sAMAccountType
- remove attribs not on the preserved list
- preserved if in above list , or is rDN
- remove all linked attribs from this object
- remove all links from other objects to this object
- add lastKnownParent
- update replPropertyMetaData ?
see MS - ADTS " Tombstone Requirements " section 3.1 .1 .5 .5 .1 .1
*/
msg = ldb_msg_new ( tmp_ctx ) ;
if ( msg = = NULL ) {
ldb_module_oom ( module ) ;
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-12-17 23:00:16 +11:00
msg - > dn = old_dn ;
2009-12-16 17:24:21 +11:00
ret = ldb_msg_add_string ( msg , " isDeleted " , " TRUE " ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to add isDeleted string to the msg \n " ) ) ;
ldb_module_oom ( module ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
msg - > elements [ el_count + + ] . flags = LDB_FLAG_MOD_ADD ;
2009-12-21 21:27:16 +11:00
/* we also mark it as recycled, meaning this object can't be
recovered ( we are stripping its attributes ) */
if ( dsdb_functional_level ( ldb ) > = DS_DOMAIN_FUNCTION_2008_R2 ) {
ret = ldb_msg_add_string ( msg , " isRecycled " , " TRUE " ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to add isRecycled string to the msg \n " ) ) ;
ldb_module_oom ( module ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
msg - > elements [ el_count + + ] . flags = LDB_FLAG_MOD_ADD ;
}
2009-12-16 17:24:21 +11:00
/* we need the storage form of the parent GUID */
ret = dsdb_module_search_dn ( module , tmp_ctx , & parent_res ,
ldb_dn_get_parent ( tmp_ctx , old_dn ) , NULL ,
2009-12-18 20:57:21 +11:00
DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
DSDB_SEARCH_REVEAL_INTERNALS ) ;
2009-12-16 17:24:21 +11:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
ret = ldb_msg_add_steal_string ( msg , " lastKnownParent " ,
ldb_dn_get_extended_linearized ( tmp_ctx , parent_res - > msgs [ 0 ] - > dn , 1 ) ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to add lastKnownParent string to the msg \n " ) ) ;
ldb_module_oom ( module ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
msg - > elements [ el_count + + ] . flags = LDB_FLAG_MOD_ADD ;
/* work out which of the old attributes we will be removing */
for ( i = 0 ; i < old_msg - > num_elements ; i + + ) {
const struct dsdb_attribute * sa ;
el = & old_msg - > elements [ i ] ;
sa = dsdb_attribute_by_lDAPDisplayName ( schema , el - > name ) ;
if ( ! sa ) {
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
if ( ldb_attr_cmp ( el - > name , rdn_name ) = = 0 ) {
/* don't remove the rDN */
continue ;
}
2009-12-21 21:28:04 +11:00
if ( sa - > linkID & & sa - > linkID & 1 ) {
2009-12-16 17:24:21 +11:00
ret = replmd_delete_remove_link ( module , schema , old_dn , el , sa ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-12-21 21:28:04 +11:00
continue ;
2009-12-16 17:24:21 +11:00
}
if ( ! sa - > linkID & & ldb_attr_in_list ( preserved_attrs , el - > name ) ) {
continue ;
}
ret = ldb_msg_add_empty ( msg , el - > name , LDB_FLAG_MOD_DELETE , & el ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
ldb_module_oom ( module ) ;
return ret ;
}
}
/* work out what the new rdn value is, for updating the
rDN and name fields */
new_rdn_value = ldb_dn_get_rdn_val ( new_dn ) ;
ret = ldb_msg_add_value ( msg , rdn_name , new_rdn_value , & el ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
el - > flags = LDB_FLAG_MOD_REPLACE ;
el = ldb_msg_find_element ( old_msg , " name " ) ;
if ( el ) {
ret = ldb_msg_add_value ( msg , " name " , new_rdn_value , & el ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
el - > flags = LDB_FLAG_MOD_REPLACE ;
}
2009-12-21 21:26:15 +11:00
ret = dsdb_module_modify ( module , msg , DSDB_FLAG_OWN_MODULE ) ;
if ( ret ! = LDB_SUCCESS ) {
2009-12-16 17:24:21 +11:00
ldb_asprintf_errstring ( ldb , " replmd_delete: Failed to modify object %s in delete - %s " ,
ldb_dn_get_linearized ( old_dn ) , ldb_errstring ( ldb ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-12-17 23:00:16 +11:00
/* now rename onto the new DN */
ret = dsdb_module_rename ( module , old_dn , new_dn , 0 ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to rename object from '%s' to '%s' - %s \n " ,
ldb_dn_get_linearized ( old_dn ) ,
ldb_dn_get_linearized ( new_dn ) ,
ldb_errstring ( ldb ) ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-12-16 17:24:21 +11:00
talloc_free ( tmp_ctx ) ;
return ldb_module_done ( req , NULL , NULL , LDB_SUCCESS ) ;
}
2009-09-14 13:13:12 -07:00
2007-01-11 09:54:10 +00:00
static int replmd_replicated_request_error ( struct replmd_replicated_request * ar , int ret )
{
2008-09-11 18:36:28 -04:00
return ret ;
2007-01-11 09:54:10 +00:00
}
static int replmd_replicated_request_werror ( struct replmd_replicated_request * ar , WERROR status )
{
int ret = LDB_ERR_OTHER ;
/* TODO: do some error mapping */
2008-09-11 18:36:28 -04:00
return ret ;
2007-01-11 09:54:10 +00:00
}
static int replmd_replicated_apply_add ( struct replmd_replicated_request * ar )
{
2009-01-30 16:31:19 -05:00
struct ldb_context * ldb ;
2008-09-11 18:36:28 -04:00
struct ldb_request * change_req ;
2007-11-09 19:24:51 +01:00
enum ndr_err_code ndr_err ;
2007-01-11 09:54:10 +00:00
struct ldb_message * msg ;
struct replPropertyMetaDataBlob * md ;
struct ldb_val md_value ;
uint32_t i ;
int ret ;
2007-01-13 10:53:12 +00:00
/*
* TODO : check if the parent object exist
*/
/*
* TODO : handle the conflict case where an object with the
* same name exist
*/
2009-01-30 16:31:19 -05:00
ldb = ldb_module_get_ctx ( ar - > module ) ;
2007-01-11 09:54:10 +00:00
msg = ar - > objs - > objects [ ar - > index_current ] . msg ;
md = ar - > objs - > objects [ ar - > index_current ] . meta_data ;
2009-10-16 16:20:15 +11:00
ret = ldb_sequence_number ( ldb , LDB_SEQ_NEXT , & ar - > seq_num ) ;
2007-01-11 09:54:10 +00:00
if ( ret ! = LDB_SUCCESS ) {
return replmd_replicated_request_error ( ar , ret ) ;
}
2007-01-13 10:53:12 +00:00
ret = ldb_msg_add_value ( msg , " objectGUID " , & ar - > objs - > objects [ ar - > index_current ] . guid_value , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return replmd_replicated_request_error ( ar , ret ) ;
}
ret = ldb_msg_add_string ( msg , " whenChanged " , ar - > objs - > objects [ ar - > index_current ] . when_changed ) ;
if ( ret ! = LDB_SUCCESS ) {
return replmd_replicated_request_error ( ar , ret ) ;
}
2009-10-16 16:20:15 +11:00
ret = samdb_msg_add_uint64 ( ldb , msg , msg , " uSNCreated " , ar - > seq_num ) ;
2007-01-11 09:54:10 +00:00
if ( ret ! = LDB_SUCCESS ) {
return replmd_replicated_request_error ( ar , ret ) ;
}
2009-10-16 16:20:15 +11:00
ret = samdb_msg_add_uint64 ( ldb , msg , msg , " uSNChanged " , ar - > seq_num ) ;
2009-09-13 14:24:08 +10:00
if ( ret ! = LDB_SUCCESS ) {
return replmd_replicated_request_error ( ar , ret ) ;
}
2009-09-22 20:56:32 -07:00
/* remove any message elements that have zero values */
for ( i = 0 ; i < msg - > num_elements ; i + + ) {
2009-12-19 12:23:22 +11:00
struct ldb_message_element * el = & msg - > elements [ i ] ;
if ( el - > num_values = = 0 ) {
2009-09-22 20:56:32 -07:00
DEBUG ( 4 , ( __location__ " : Removing attribute %s with num_values==0 \n " ,
2009-12-19 12:23:22 +11:00
el - > name ) ) ;
memmove ( el , el + 1 , sizeof ( * el ) * ( msg - > num_elements - ( i + 1 ) ) ) ;
2009-09-22 20:56:32 -07:00
msg - > num_elements - - ;
i - - ;
2009-12-19 12:23:22 +11:00
continue ;
2009-09-22 20:56:32 -07:00
}
}
2007-01-23 10:21:14 +00:00
/*
* the meta data array is already sorted by the caller
*/
2007-01-11 09:54:10 +00:00
for ( i = 0 ; i < md - > ctr . ctr1 . count ; i + + ) {
2009-10-16 16:20:15 +11:00
md - > ctr . ctr1 . array [ i ] . local_usn = ar - > seq_num ;
2007-01-11 09:54:10 +00:00
}
2008-01-01 22:05:05 -06:00
ndr_err = ndr_push_struct_blob ( & md_value , msg ,
2009-01-30 16:31:19 -05:00
lp_iconv_convenience ( ldb_get_opaque ( ldb , " loadparm " ) ) ,
2008-01-01 22:05:05 -06:00
md ,
2007-11-09 19:24:51 +01:00
( ndr_push_flags_fn_t ) ndr_push_replPropertyMetaDataBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
NTSTATUS nt_status = ndr_map_error2ntstatus ( ndr_err ) ;
2007-01-11 09:54:10 +00:00
return replmd_replicated_request_werror ( ar , ntstatus_to_werror ( nt_status ) ) ;
}
ret = ldb_msg_add_value ( msg , " replPropertyMetaData " , & md_value , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return replmd_replicated_request_error ( ar , ret ) ;
}
2007-01-23 10:21:14 +00:00
replmd_ldb_message_sort ( msg , ar - > schema ) ;
2009-09-02 11:20:26 +10:00
if ( DEBUGLVL ( 4 ) ) {
char * s = ldb_ldif_message_string ( ldb , ar , LDB_CHANGETYPE_ADD , msg ) ;
DEBUG ( 4 , ( " DRS replication add message: \n %s \n " , s ) ) ;
talloc_free ( s ) ;
}
2008-09-11 18:36:28 -04:00
ret = ldb_build_add_req ( & change_req ,
2009-01-30 16:31:19 -05:00
ldb ,
2008-09-11 18:36:28 -04:00
ar ,
2007-01-11 09:54:10 +00:00
msg ,
2008-09-27 02:27:54 +02:00
ar - > controls ,
2007-01-11 09:54:10 +00:00
ar ,
2009-10-16 16:20:15 +11:00
replmd_op_callback ,
2008-09-11 18:36:28 -04:00
ar - > req ) ;
2007-01-11 09:54:10 +00:00
if ( ret ! = LDB_SUCCESS ) return replmd_replicated_request_error ( ar , ret ) ;
2008-09-11 18:36:28 -04:00
return ldb_next_request ( ar - > module , change_req ) ;
2007-01-11 09:54:10 +00:00
}
2009-12-18 20:57:21 +11:00
/*
return true if an update is newer than an existing entry
see section 5.11 of MS - ADTS
*/
static bool replmd_update_is_newer ( const struct GUID * current_invocation_id ,
const struct GUID * update_invocation_id ,
uint32_t current_version ,
uint32_t update_version ,
NTTIME current_change_time ,
NTTIME update_change_time )
2007-01-13 11:17:27 +00:00
{
2009-12-18 20:57:21 +11:00
if ( update_version ! = current_version ) {
return update_version > current_version ;
2007-01-13 11:17:27 +00:00
}
2009-12-18 20:57:21 +11:00
if ( update_change_time > current_change_time ) {
return true ;
2007-01-13 11:17:27 +00:00
}
2009-12-18 20:57:21 +11:00
if ( update_change_time = = current_change_time ) {
return GUID_compare ( update_invocation_id , current_invocation_id ) > 0 ;
2007-01-13 11:17:27 +00:00
}
2009-12-18 20:57:21 +11:00
return false ;
}
2007-01-13 11:17:27 +00:00
2009-12-18 20:57:21 +11:00
static bool replmd_replPropertyMetaData1_is_newer ( struct replPropertyMetaData1 * cur_m ,
struct replPropertyMetaData1 * new_m )
{
return replmd_update_is_newer ( & cur_m - > originating_invocation_id ,
& new_m - > originating_invocation_id ,
cur_m - > version ,
new_m - > version ,
cur_m - > originating_change_time ,
new_m - > originating_change_time ) ;
2007-01-13 11:17:27 +00:00
}
2007-01-11 09:54:10 +00:00
static int replmd_replicated_apply_merge ( struct replmd_replicated_request * ar )
{
2009-01-30 16:31:19 -05:00
struct ldb_context * ldb ;
2008-09-11 18:36:28 -04:00
struct ldb_request * change_req ;
2007-11-09 19:24:51 +01:00
enum ndr_err_code ndr_err ;
2007-01-13 11:17:27 +00:00
struct ldb_message * msg ;
struct replPropertyMetaDataBlob * rmd ;
struct replPropertyMetaDataBlob omd ;
const struct ldb_val * omd_value ;
struct replPropertyMetaDataBlob nmd ;
struct ldb_val nmd_value ;
uint32_t i , j , ni = 0 ;
uint32_t removed_attrs = 0 ;
int ret ;
2009-01-30 16:31:19 -05:00
ldb = ldb_module_get_ctx ( ar - > module ) ;
2007-01-13 11:17:27 +00:00
msg = ar - > objs - > objects [ ar - > index_current ] . msg ;
rmd = ar - > objs - > objects [ ar - > index_current ] . meta_data ;
ZERO_STRUCT ( omd ) ;
omd . version = 1 ;
/*
2009-08-19 15:53:19 +10:00
* TODO : check repl data is correct after a rename
2007-01-13 11:17:27 +00:00
*/
2008-09-11 18:36:28 -04:00
if ( ldb_dn_compare ( msg - > dn , ar - > search_msg - > dn ) ! = 0 ) {
2009-08-19 15:53:19 +10:00
ldb_debug ( ldb , LDB_DEBUG_TRACE , " replmd_replicated_request rename %s => %s \n " ,
2008-09-11 18:36:28 -04:00
ldb_dn_get_linearized ( ar - > search_msg - > dn ) ,
2007-01-13 11:17:27 +00:00
ldb_dn_get_linearized ( msg - > dn ) ) ;
2009-12-28 17:20:13 +11:00
if ( dsdb_module_rename ( ar - > module ,
ar - > search_msg - > dn , msg - > dn ,
DSDB_FLAG_OWN_MODULE ) ! = LDB_SUCCESS ) {
2009-08-19 15:53:19 +10:00
ldb_debug ( ldb , LDB_DEBUG_FATAL , " replmd_replicated_request rename %s => %s failed - %s \n " ,
ldb_dn_get_linearized ( ar - > search_msg - > dn ) ,
ldb_dn_get_linearized ( msg - > dn ) ,
ldb_errstring ( ldb ) ) ;
return replmd_replicated_request_werror ( ar , WERR_DS_DRA_DB_ERROR ) ;
}
2007-01-13 11:17:27 +00:00
}
/* find existing meta data */
2008-09-11 18:36:28 -04:00
omd_value = ldb_msg_find_ldb_val ( ar - > search_msg , " replPropertyMetaData " ) ;
2007-01-13 11:17:27 +00:00
if ( omd_value ) {
2008-09-11 18:36:28 -04:00
ndr_err = ndr_pull_struct_blob ( omd_value , ar ,
2009-01-30 16:31:19 -05:00
lp_iconv_convenience ( ldb_get_opaque ( ldb , " loadparm " ) ) , & omd ,
2007-11-09 19:24:51 +01:00
( ndr_pull_flags_fn_t ) ndr_pull_replPropertyMetaDataBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
NTSTATUS nt_status = ndr_map_error2ntstatus ( ndr_err ) ;
2007-01-13 11:17:27 +00:00
return replmd_replicated_request_werror ( ar , ntstatus_to_werror ( nt_status ) ) ;
}
if ( omd . version ! = 1 ) {
return replmd_replicated_request_werror ( ar , WERR_DS_DRA_INTERNAL_ERROR ) ;
}
}
ZERO_STRUCT ( nmd ) ;
nmd . version = 1 ;
nmd . ctr . ctr1 . count = omd . ctr . ctr1 . count + rmd - > ctr . ctr1 . count ;
2008-09-11 18:36:28 -04:00
nmd . ctr . ctr1 . array = talloc_array ( ar ,
2007-01-13 11:17:27 +00:00
struct replPropertyMetaData1 ,
nmd . ctr . ctr1 . count ) ;
if ( ! nmd . ctr . ctr1 . array ) return replmd_replicated_request_werror ( ar , WERR_NOMEM ) ;
/* first copy the old meta data */
for ( i = 0 ; i < omd . ctr . ctr1 . count ; i + + ) {
nmd . ctr . ctr1 . array [ ni ] = omd . ctr . ctr1 . array [ i ] ;
ni + + ;
}
/* now merge in the new meta data */
for ( i = 0 ; i < rmd - > ctr . ctr1 . count ; i + + ) {
bool found = false ;
for ( j = 0 ; j < ni ; j + + ) {
2009-12-18 20:57:21 +11:00
bool cmp ;
2007-01-13 11:17:27 +00:00
if ( rmd - > ctr . ctr1 . array [ i ] . attid ! = nmd . ctr . ctr1 . array [ j ] . attid ) {
continue ;
}
2009-12-18 20:57:21 +11:00
cmp = replmd_replPropertyMetaData1_is_newer ( & nmd . ctr . ctr1 . array [ j ] ,
& rmd - > ctr . ctr1 . array [ i ] ) ;
if ( cmp ) {
2007-01-13 11:17:27 +00:00
/* replace the entry */
nmd . ctr . ctr1 . array [ j ] = rmd - > ctr . ctr1 . array [ i ] ;
found = true ;
break ;
}
2009-12-18 20:57:21 +11:00
DEBUG ( 1 , ( " Discarding older DRS attribute update to %s on %s from %s \n " ,
msg - > elements [ i - removed_attrs ] . name ,
ldb_dn_get_linearized ( msg - > dn ) ,
GUID_string ( ar , & rmd - > ctr . ctr1 . array [ i ] . originating_invocation_id ) ) ) ;
2007-01-13 11:17:27 +00:00
/* we don't want to apply this change so remove the attribute */
ldb_msg_remove_element ( msg , & msg - > elements [ i - removed_attrs ] ) ;
removed_attrs + + ;
found = true ;
break ;
}
if ( found ) continue ;
nmd . ctr . ctr1 . array [ ni ] = rmd - > ctr . ctr1 . array [ i ] ;
ni + + ;
}
/*
* finally correct the size of the meta_data array
*/
nmd . ctr . ctr1 . count = ni ;
/*
* the rdn attribute ( the alias for the name attribute ) ,
* ' cn ' for most objects is the last entry in the meta data array
* we have stored
*
2007-01-23 10:21:14 +00:00
* sort the new meta data array
2007-01-13 11:17:27 +00:00
*/
2009-09-24 16:50:59 -07:00
ret = replmd_replPropertyMetaDataCtr1_sort ( & nmd . ctr . ctr1 , ar - > schema , msg - > dn ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
2007-01-13 11:17:27 +00:00
}
/*
* check if some replicated attributes left , otherwise skip the ldb_modify ( ) call
*/
if ( msg - > num_elements = = 0 ) {
2009-01-30 16:31:19 -05:00
ldb_debug ( ldb , LDB_DEBUG_TRACE , " replmd_replicated_apply_merge[%u]: skip replace \n " ,
2007-01-13 11:17:27 +00:00
ar - > index_current ) ;
2008-09-11 18:36:28 -04:00
ar - > index_current + + ;
return replmd_replicated_apply_next ( ar ) ;
2007-01-13 11:17:27 +00:00
}
2009-01-30 16:31:19 -05:00
ldb_debug ( ldb , LDB_DEBUG_TRACE , " replmd_replicated_apply_merge[%u]: replace %u attributes \n " ,
2007-01-13 11:17:27 +00:00
ar - > index_current , msg - > num_elements ) ;
2009-10-16 16:20:15 +11:00
ret = ldb_sequence_number ( ldb , LDB_SEQ_NEXT , & ar - > seq_num ) ;
2009-09-12 12:07:06 +10:00
if ( ret ! = LDB_SUCCESS ) {
return replmd_replicated_request_error ( ar , ret ) ;
}
for ( i = 0 ; i < ni ; i + + ) {
2009-10-16 16:20:15 +11:00
nmd . ctr . ctr1 . array [ i ] . local_usn = ar - > seq_num ;
2009-09-12 12:07:06 +10:00
}
2009-09-15 11:46:59 -07:00
/* create the meta data value */
ndr_err = ndr_push_struct_blob ( & nmd_value , msg ,
lp_iconv_convenience ( ldb_get_opaque ( ldb , " loadparm " ) ) ,
& nmd ,
( ndr_push_flags_fn_t ) ndr_push_replPropertyMetaDataBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
NTSTATUS nt_status = ndr_map_error2ntstatus ( ndr_err ) ;
return replmd_replicated_request_werror ( ar , ntstatus_to_werror ( nt_status ) ) ;
}
2007-01-13 11:17:27 +00:00
/*
2008-09-11 18:36:28 -04:00
* when we know that we ' ll modify the record , add the whenChanged , uSNChanged
2007-01-13 11:17:27 +00:00
* and replPopertyMetaData attributes
*/
ret = ldb_msg_add_string ( msg , " whenChanged " , ar - > objs - > objects [ ar - > index_current ] . when_changed ) ;
if ( ret ! = LDB_SUCCESS ) {
return replmd_replicated_request_error ( ar , ret ) ;
}
2009-10-16 16:20:15 +11:00
ret = samdb_msg_add_uint64 ( ldb , msg , msg , " uSNChanged " , ar - > seq_num ) ;
2007-01-13 11:17:27 +00:00
if ( ret ! = LDB_SUCCESS ) {
return replmd_replicated_request_error ( ar , ret ) ;
}
ret = ldb_msg_add_value ( msg , " replPropertyMetaData " , & nmd_value , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return replmd_replicated_request_error ( ar , ret ) ;
}
2007-01-23 10:21:14 +00:00
replmd_ldb_message_sort ( msg , ar - > schema ) ;
2007-01-13 11:17:27 +00:00
/* we want to replace the old values */
for ( i = 0 ; i < msg - > num_elements ; i + + ) {
msg - > elements [ i ] . flags = LDB_FLAG_MOD_REPLACE ;
}
2009-09-02 11:20:26 +10:00
if ( DEBUGLVL ( 4 ) ) {
char * s = ldb_ldif_message_string ( ldb , ar , LDB_CHANGETYPE_MODIFY , msg ) ;
DEBUG ( 4 , ( " DRS replication modify message: \n %s \n " , s ) ) ;
talloc_free ( s ) ;
}
2008-09-11 18:36:28 -04:00
ret = ldb_build_mod_req ( & change_req ,
2009-01-30 16:31:19 -05:00
ldb ,
2008-09-11 18:36:28 -04:00
ar ,
2007-01-13 11:17:27 +00:00
msg ,
2008-09-27 02:27:54 +02:00
ar - > controls ,
2007-01-13 11:17:27 +00:00
ar ,
2009-10-16 16:20:15 +11:00
replmd_op_callback ,
2008-09-11 18:36:28 -04:00
ar - > req ) ;
2007-01-13 11:17:27 +00:00
if ( ret ! = LDB_SUCCESS ) return replmd_replicated_request_error ( ar , ret ) ;
2008-09-11 18:36:28 -04:00
return ldb_next_request ( ar - > module , change_req ) ;
2007-01-11 09:54:10 +00:00
}
2008-09-11 18:36:28 -04:00
static int replmd_replicated_apply_search_callback ( struct ldb_request * req ,
2007-01-11 09:54:10 +00:00
struct ldb_reply * ares )
{
2008-09-11 18:36:28 -04:00
struct replmd_replicated_request * ar = talloc_get_type ( req - > context ,
2007-01-11 09:54:10 +00:00
struct replmd_replicated_request ) ;
2008-09-11 18:36:28 -04:00
int ret ;
if ( ! ares ) {
return ldb_module_done ( ar - > req , NULL , NULL ,
LDB_ERR_OPERATIONS_ERROR ) ;
}
if ( ares - > error ! = LDB_SUCCESS & &
ares - > error ! = LDB_ERR_NO_SUCH_OBJECT ) {
return ldb_module_done ( ar - > req , ares - > controls ,
ares - > response , ares - > error ) ;
}
2007-01-11 09:54:10 +00:00
switch ( ares - > type ) {
case LDB_REPLY_ENTRY :
2008-09-11 18:36:28 -04:00
ar - > search_msg = talloc_steal ( ar , ares - > message ) ;
2007-01-11 09:54:10 +00:00
break ;
2008-09-11 18:36:28 -04:00
2007-01-11 09:54:10 +00:00
case LDB_REPLY_REFERRAL :
/* we ignore referrals */
break ;
2008-09-11 18:36:28 -04:00
case LDB_REPLY_DONE :
if ( ar - > search_msg ! = NULL ) {
ret = replmd_replicated_apply_merge ( ar ) ;
} else {
ret = replmd_replicated_apply_add ( ar ) ;
2007-01-11 09:54:10 +00:00
}
2008-09-11 18:36:28 -04:00
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_done ( ar - > req , NULL , NULL , ret ) ;
2007-01-11 09:54:10 +00:00
}
}
2008-09-11 18:36:28 -04:00
talloc_free ( ares ) ;
2007-01-11 09:54:10 +00:00
return LDB_SUCCESS ;
}
2008-09-11 18:36:28 -04:00
static int replmd_replicated_uptodate_vector ( struct replmd_replicated_request * ar ) ;
static int replmd_replicated_apply_next ( struct replmd_replicated_request * ar )
2007-01-11 09:54:10 +00:00
{
2009-01-30 16:31:19 -05:00
struct ldb_context * ldb ;
2007-01-11 09:54:10 +00:00
int ret ;
char * tmp_str ;
char * filter ;
2008-09-11 18:36:28 -04:00
struct ldb_request * search_req ;
2009-10-16 16:20:15 +11:00
struct ldb_search_options_control * options ;
2007-01-11 09:54:10 +00:00
2008-09-11 18:36:28 -04:00
if ( ar - > index_current > = ar - > objs - > num_objects ) {
2009-09-03 12:55:57 +10:00
/* done with it, go to next stage */
2008-09-11 18:36:28 -04:00
return replmd_replicated_uptodate_vector ( ar ) ;
}
2009-01-30 16:31:19 -05:00
ldb = ldb_module_get_ctx ( ar - > module ) ;
2008-09-11 18:36:28 -04:00
ar - > search_msg = NULL ;
tmp_str = ldb_binary_encode ( ar , ar - > objs - > objects [ ar - > index_current ] . guid_value ) ;
2007-01-11 09:54:10 +00:00
if ( ! tmp_str ) return replmd_replicated_request_werror ( ar , WERR_NOMEM ) ;
2008-09-11 18:36:28 -04:00
filter = talloc_asprintf ( ar , " (objectGUID=%s) " , tmp_str ) ;
2007-01-11 09:54:10 +00:00
if ( ! filter ) return replmd_replicated_request_werror ( ar , WERR_NOMEM ) ;
talloc_free ( tmp_str ) ;
2008-09-11 18:36:28 -04:00
ret = ldb_build_search_req ( & search_req ,
2009-01-30 16:31:19 -05:00
ldb ,
2008-09-11 18:36:28 -04:00
ar ,
2009-10-16 16:20:15 +11:00
NULL ,
2007-01-11 09:54:10 +00:00
LDB_SCOPE_SUBTREE ,
filter ,
NULL ,
NULL ,
ar ,
2008-09-11 18:36:28 -04:00
replmd_replicated_apply_search_callback ,
ar - > req ) ;
2009-09-24 16:50:59 -07:00
ret = ldb_request_add_control ( search_req , LDB_CONTROL_SHOW_DELETED_OID , true , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2009-10-16 16:20:15 +11:00
/* we need to cope with cross-partition links, so search for
the GUID over all partitions */
options = talloc ( search_req , struct ldb_search_options_control ) ;
if ( options = = NULL ) {
DEBUG ( 0 , ( __location__ " : out of memory \n " ) ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
options - > search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT ;
ret = ldb_request_add_control ( search_req ,
LDB_CONTROL_SEARCH_OPTIONS_OID ,
true , options ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2009-09-24 16:50:59 -07:00
2007-01-11 09:54:10 +00:00
if ( ret ! = LDB_SUCCESS ) return replmd_replicated_request_error ( ar , ret ) ;
2008-09-11 18:36:28 -04:00
return ldb_next_request ( ar - > module , search_req ) ;
2007-01-11 09:54:10 +00:00
}
2008-09-11 18:36:28 -04:00
static int replmd_replicated_uptodate_modify_callback ( struct ldb_request * req ,
2007-01-12 13:17:25 +00:00
struct ldb_reply * ares )
{
2009-01-30 16:31:19 -05:00
struct ldb_context * ldb ;
2008-09-11 18:36:28 -04:00
struct replmd_replicated_request * ar = talloc_get_type ( req - > context ,
2007-01-12 13:17:25 +00:00
struct replmd_replicated_request ) ;
2009-01-30 16:31:19 -05:00
ldb = ldb_module_get_ctx ( ar - > module ) ;
2007-01-12 13:17:25 +00:00
2008-09-11 18:36:28 -04:00
if ( ! ares ) {
return ldb_module_done ( ar - > req , NULL , NULL ,
LDB_ERR_OPERATIONS_ERROR ) ;
}
if ( ares - > error ! = LDB_SUCCESS ) {
return ldb_module_done ( ar - > req , ares - > controls ,
ares - > response , ares - > error ) ;
2007-01-12 13:17:25 +00:00
}
2008-09-11 18:36:28 -04:00
if ( ares - > type ! = LDB_REPLY_DONE ) {
2009-01-30 16:31:19 -05:00
ldb_set_errstring ( ldb , " Invalid reply type \n ! " ) ;
2008-09-11 18:36:28 -04:00
return ldb_module_done ( ar - > req , NULL , NULL ,
LDB_ERR_OPERATIONS_ERROR ) ;
}
2007-01-12 13:17:25 +00:00
2008-09-11 18:36:28 -04:00
talloc_free ( ares ) ;
return ldb_module_done ( ar - > req , NULL , NULL , LDB_SUCCESS ) ;
2007-01-12 13:17:25 +00:00
}
static int replmd_replicated_uptodate_modify ( struct replmd_replicated_request * ar )
{
2009-01-30 16:31:19 -05:00
struct ldb_context * ldb ;
2008-09-11 18:36:28 -04:00
struct ldb_request * change_req ;
2007-11-09 19:24:51 +01:00
enum ndr_err_code ndr_err ;
2007-01-12 13:17:25 +00:00
struct ldb_message * msg ;
struct replUpToDateVectorBlob ouv ;
const struct ldb_val * ouv_value ;
const struct drsuapi_DsReplicaCursor2CtrEx * ruv ;
struct replUpToDateVectorBlob nuv ;
struct ldb_val nuv_value ;
struct ldb_message_element * nuv_el = NULL ;
2007-01-12 17:02:55 +00:00
const struct GUID * our_invocation_id ;
struct ldb_message_element * orf_el = NULL ;
struct repsFromToBlob nrf ;
struct ldb_val * nrf_value = NULL ;
struct ldb_message_element * nrf_el = NULL ;
2007-01-12 13:17:25 +00:00
uint32_t i , j , ni = 0 ;
bool found = false ;
time_t t = time ( NULL ) ;
NTTIME now ;
int ret ;
2009-01-30 16:31:19 -05:00
ldb = ldb_module_get_ctx ( ar - > module ) ;
2007-01-12 13:17:25 +00:00
ruv = ar - > objs - > uptodateness_vector ;
ZERO_STRUCT ( ouv ) ;
ouv . version = 2 ;
ZERO_STRUCT ( nuv ) ;
nuv . version = 2 ;
unix_to_nt_time ( & now , t ) ;
2007-01-12 16:02:10 +00:00
/*
* first create the new replUpToDateVector
*/
2008-09-11 18:36:28 -04:00
ouv_value = ldb_msg_find_ldb_val ( ar - > search_msg , " replUpToDateVector " ) ;
2007-01-12 13:17:25 +00:00
if ( ouv_value ) {
2008-09-11 18:36:28 -04:00
ndr_err = ndr_pull_struct_blob ( ouv_value , ar ,
2009-01-30 16:31:19 -05:00
lp_iconv_convenience ( ldb_get_opaque ( ldb , " loadparm " ) ) , & ouv ,
2007-11-09 19:24:51 +01:00
( ndr_pull_flags_fn_t ) ndr_pull_replUpToDateVectorBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
NTSTATUS nt_status = ndr_map_error2ntstatus ( ndr_err ) ;
2007-01-12 13:17:25 +00:00
return replmd_replicated_request_werror ( ar , ntstatus_to_werror ( nt_status ) ) ;
}
if ( ouv . version ! = 2 ) {
return replmd_replicated_request_werror ( ar , WERR_DS_DRA_INTERNAL_ERROR ) ;
}
}
/*
* the new uptodateness vector will at least
2007-02-20 14:56:45 +00:00
* contain 1 entry , one for the source_dsa
2007-01-12 13:17:25 +00:00
*
* plus optional values from our old vector and the one from the source_dsa
*/
2007-02-20 14:56:45 +00:00
nuv . ctr . ctr2 . count = 1 + ouv . ctr . ctr2 . count ;
2007-01-12 13:17:25 +00:00
if ( ruv ) nuv . ctr . ctr2 . count + = ruv - > count ;
2008-09-11 18:36:28 -04:00
nuv . ctr . ctr2 . cursors = talloc_array ( ar ,
2007-01-12 13:17:25 +00:00
struct drsuapi_DsReplicaCursor2 ,
nuv . ctr . ctr2 . count ) ;
if ( ! nuv . ctr . ctr2 . cursors ) return replmd_replicated_request_werror ( ar , WERR_NOMEM ) ;
/* first copy the old vector */
for ( i = 0 ; i < ouv . ctr . ctr2 . count ; i + + ) {
nuv . ctr . ctr2 . cursors [ ni ] = ouv . ctr . ctr2 . cursors [ i ] ;
ni + + ;
}
2007-02-20 14:56:45 +00:00
/* get our invocation_id if we have one already attached to the ldb */
2009-01-30 16:31:19 -05:00
our_invocation_id = samdb_ntds_invocation_id ( ldb ) ;
2007-02-20 14:56:45 +00:00
2007-01-12 13:17:25 +00:00
/* merge in the source_dsa vector is available */
for ( i = 0 ; ( ruv & & i < ruv - > count ) ; i + + ) {
found = false ;
2007-02-20 14:56:45 +00:00
if ( our_invocation_id & &
GUID_equal ( & ruv - > cursors [ i ] . source_dsa_invocation_id ,
our_invocation_id ) ) {
continue ;
}
2007-01-12 13:17:25 +00:00
for ( j = 0 ; j < ni ; j + + ) {
if ( ! GUID_equal ( & ruv - > cursors [ i ] . source_dsa_invocation_id ,
& nuv . ctr . ctr2 . cursors [ j ] . source_dsa_invocation_id ) ) {
continue ;
}
found = true ;
/*
* we update only the highest_usn and not the latest_sync_success time ,
* because the last success stands for direct replication
*/
if ( ruv - > cursors [ i ] . highest_usn > nuv . ctr . ctr2 . cursors [ j ] . highest_usn ) {
nuv . ctr . ctr2 . cursors [ j ] . highest_usn = ruv - > cursors [ i ] . highest_usn ;
}
break ;
}
if ( found ) continue ;
/* if it's not there yet, add it */
nuv . ctr . ctr2 . cursors [ ni ] = ruv - > cursors [ i ] ;
ni + + ;
}
/*
* merge in the current highwatermark for the source_dsa
*/
found = false ;
for ( j = 0 ; j < ni ; j + + ) {
2007-01-12 16:02:10 +00:00
if ( ! GUID_equal ( & ar - > objs - > source_dsa - > source_dsa_invocation_id ,
2007-01-12 13:17:25 +00:00
& nuv . ctr . ctr2 . cursors [ j ] . source_dsa_invocation_id ) ) {
continue ;
}
found = true ;
/*
* here we update the highest_usn and last_sync_success time
* because we ' re directly replicating from the source_dsa
*
* and use the tmp_highest_usn because this is what we have just applied
* to our ldb
*/
2007-01-12 16:02:10 +00:00
nuv . ctr . ctr2 . cursors [ j ] . highest_usn = ar - > objs - > source_dsa - > highwatermark . tmp_highest_usn ;
2007-01-12 13:17:25 +00:00
nuv . ctr . ctr2 . cursors [ j ] . last_sync_success = now ;
break ;
}
if ( ! found ) {
/*
* here we update the highest_usn and last_sync_success time
* because we ' re directly replicating from the source_dsa
*
* and use the tmp_highest_usn because this is what we have just applied
* to our ldb
*/
2007-01-12 16:02:10 +00:00
nuv . ctr . ctr2 . cursors [ ni ] . source_dsa_invocation_id = ar - > objs - > source_dsa - > source_dsa_invocation_id ;
nuv . ctr . ctr2 . cursors [ ni ] . highest_usn = ar - > objs - > source_dsa - > highwatermark . tmp_highest_usn ;
2007-01-12 13:17:25 +00:00
nuv . ctr . ctr2 . cursors [ ni ] . last_sync_success = now ;
ni + + ;
}
/*
* finally correct the size of the cursors array
*/
nuv . ctr . ctr2 . count = ni ;
2007-01-12 17:19:48 +00:00
/*
* sort the cursors
*/
qsort ( nuv . ctr . ctr2 . cursors , nuv . ctr . ctr2 . count ,
sizeof ( struct drsuapi_DsReplicaCursor2 ) ,
2009-09-14 11:46:59 -07:00
( comparison_fn_t ) drsuapi_DsReplicaCursor2_compare ) ;
2007-01-12 17:19:48 +00:00
2007-01-12 13:17:25 +00:00
/*
* create the change ldb_message
*/
2008-09-11 18:36:28 -04:00
msg = ldb_msg_new ( ar ) ;
2007-01-12 13:17:25 +00:00
if ( ! msg ) return replmd_replicated_request_werror ( ar , WERR_NOMEM ) ;
2008-09-11 18:36:28 -04:00
msg - > dn = ar - > search_msg - > dn ;
2007-01-12 13:17:25 +00:00
2008-01-01 22:05:05 -06:00
ndr_err = ndr_push_struct_blob ( & nuv_value , msg ,
2009-01-30 16:31:19 -05:00
lp_iconv_convenience ( ldb_get_opaque ( ldb , " loadparm " ) ) ,
2008-01-01 22:05:05 -06:00
& nuv ,
2007-11-09 19:24:51 +01:00
( ndr_push_flags_fn_t ) ndr_push_replUpToDateVectorBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
NTSTATUS nt_status = ndr_map_error2ntstatus ( ndr_err ) ;
2007-01-12 13:17:25 +00:00
return replmd_replicated_request_werror ( ar , ntstatus_to_werror ( nt_status ) ) ;
}
ret = ldb_msg_add_value ( msg , " replUpToDateVector " , & nuv_value , & nuv_el ) ;
if ( ret ! = LDB_SUCCESS ) {
return replmd_replicated_request_error ( ar , ret ) ;
}
nuv_el - > flags = LDB_FLAG_MOD_REPLACE ;
2007-01-12 17:02:55 +00:00
/*
* now create the new repsFrom value from the given repsFromTo1 structure
*/
ZERO_STRUCT ( nrf ) ;
nrf . version = 1 ;
nrf . ctr . ctr1 = * ar - > objs - > source_dsa ;
/* and fix some values... */
nrf . ctr . ctr1 . consecutive_sync_failures = 0 ;
nrf . ctr . ctr1 . last_success = now ;
nrf . ctr . ctr1 . last_attempt = now ;
nrf . ctr . ctr1 . result_last_attempt = WERR_OK ;
nrf . ctr . ctr1 . highwatermark . highest_usn = nrf . ctr . ctr1 . highwatermark . tmp_highest_usn ;
/*
* first see if we already have a repsFrom value for the current source dsa
* if so we ' ll later replace this value
*/
2008-09-11 18:36:28 -04:00
orf_el = ldb_msg_find_element ( ar - > search_msg , " repsFrom " ) ;
2007-01-12 17:02:55 +00:00
if ( orf_el ) {
for ( i = 0 ; i < orf_el - > num_values ; i + + ) {
struct repsFromToBlob * trf ;
2008-09-11 18:36:28 -04:00
trf = talloc ( ar , struct repsFromToBlob ) ;
2007-01-12 17:02:55 +00:00
if ( ! trf ) return replmd_replicated_request_werror ( ar , WERR_NOMEM ) ;
2009-01-30 16:31:19 -05:00
ndr_err = ndr_pull_struct_blob ( & orf_el - > values [ i ] , trf , lp_iconv_convenience ( ldb_get_opaque ( ldb , " loadparm " ) ) , trf ,
2007-11-09 19:24:51 +01:00
( ndr_pull_flags_fn_t ) ndr_pull_repsFromToBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
NTSTATUS nt_status = ndr_map_error2ntstatus ( ndr_err ) ;
2007-01-12 17:02:55 +00:00
return replmd_replicated_request_werror ( ar , ntstatus_to_werror ( nt_status ) ) ;
}
if ( trf - > version ! = 1 ) {
return replmd_replicated_request_werror ( ar , WERR_DS_DRA_INTERNAL_ERROR ) ;
}
/*
* we compare the source dsa objectGUID not the invocation_id
* because we want only one repsFrom value per source dsa
* and when the invocation_id of the source dsa has changed we don ' t need
* the old repsFrom with the old invocation_id
*/
if ( ! GUID_equal ( & trf - > ctr . ctr1 . source_dsa_obj_guid ,
& ar - > objs - > source_dsa - > source_dsa_obj_guid ) ) {
talloc_free ( trf ) ;
continue ;
}
talloc_free ( trf ) ;
nrf_value = & orf_el - > values [ i ] ;
break ;
}
/*
* copy over all old values to the new ldb_message
*/
ret = ldb_msg_add_empty ( msg , " repsFrom " , 0 , & nrf_el ) ;
if ( ret ! = LDB_SUCCESS ) return replmd_replicated_request_error ( ar , ret ) ;
* nrf_el = * orf_el ;
}
/*
* if we haven ' t found an old repsFrom value for the current source dsa
* we ' ll add a new value
*/
if ( ! nrf_value ) {
struct ldb_val zero_value ;
ZERO_STRUCT ( zero_value ) ;
ret = ldb_msg_add_value ( msg , " repsFrom " , & zero_value , & nrf_el ) ;
if ( ret ! = LDB_SUCCESS ) return replmd_replicated_request_error ( ar , ret ) ;
nrf_value = & nrf_el - > values [ nrf_el - > num_values - 1 ] ;
}
/* we now fill the value which is already attached to ldb_message */
2008-01-01 22:05:05 -06:00
ndr_err = ndr_push_struct_blob ( nrf_value , msg ,
2009-01-30 16:31:19 -05:00
lp_iconv_convenience ( ldb_get_opaque ( ldb , " loadparm " ) ) ,
2008-01-01 22:05:05 -06:00
& nrf ,
2007-11-09 19:24:51 +01:00
( ndr_push_flags_fn_t ) ndr_push_repsFromToBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
NTSTATUS nt_status = ndr_map_error2ntstatus ( ndr_err ) ;
2007-01-12 17:02:55 +00:00
return replmd_replicated_request_werror ( ar , ntstatus_to_werror ( nt_status ) ) ;
}
/*
* the ldb_message_element for the attribute , has all the old values and the new one
* so we ' ll replace the whole attribute with all values
*/
nrf_el - > flags = LDB_FLAG_MOD_REPLACE ;
2009-09-02 11:20:26 +10:00
if ( DEBUGLVL ( 4 ) ) {
char * s = ldb_ldif_message_string ( ldb , ar , LDB_CHANGETYPE_MODIFY , msg ) ;
DEBUG ( 4 , ( " DRS replication uptodate modify message: \n %s \n " , s ) ) ;
talloc_free ( s ) ;
}
2007-01-12 17:02:55 +00:00
/* prepare the ldb_modify() request */
2008-09-11 18:36:28 -04:00
ret = ldb_build_mod_req ( & change_req ,
2009-01-30 16:31:19 -05:00
ldb ,
2008-09-11 18:36:28 -04:00
ar ,
2007-01-12 13:17:25 +00:00
msg ,
2008-09-27 02:27:54 +02:00
ar - > controls ,
2007-01-12 13:17:25 +00:00
ar ,
2008-09-11 18:36:28 -04:00
replmd_replicated_uptodate_modify_callback ,
ar - > req ) ;
2007-01-12 13:17:25 +00:00
if ( ret ! = LDB_SUCCESS ) return replmd_replicated_request_error ( ar , ret ) ;
2008-09-11 18:36:28 -04:00
return ldb_next_request ( ar - > module , change_req ) ;
2007-01-12 13:17:25 +00:00
}
2008-09-11 18:36:28 -04:00
static int replmd_replicated_uptodate_search_callback ( struct ldb_request * req ,
2007-01-12 13:17:25 +00:00
struct ldb_reply * ares )
{
2008-09-11 18:36:28 -04:00
struct replmd_replicated_request * ar = talloc_get_type ( req - > context ,
2007-01-12 13:17:25 +00:00
struct replmd_replicated_request ) ;
2008-09-11 18:36:28 -04:00
int ret ;
if ( ! ares ) {
return ldb_module_done ( ar - > req , NULL , NULL ,
LDB_ERR_OPERATIONS_ERROR ) ;
}
if ( ares - > error ! = LDB_SUCCESS & &
ares - > error ! = LDB_ERR_NO_SUCH_OBJECT ) {
return ldb_module_done ( ar - > req , ares - > controls ,
ares - > response , ares - > error ) ;
}
2007-01-12 13:17:25 +00:00
switch ( ares - > type ) {
case LDB_REPLY_ENTRY :
2008-09-11 18:36:28 -04:00
ar - > search_msg = talloc_steal ( ar , ares - > message ) ;
2007-01-12 13:17:25 +00:00
break ;
2008-09-11 18:36:28 -04:00
2007-01-12 13:17:25 +00:00
case LDB_REPLY_REFERRAL :
/* we ignore referrals */
break ;
2008-09-11 18:36:28 -04:00
case LDB_REPLY_DONE :
if ( ar - > search_msg = = NULL ) {
ret = replmd_replicated_request_werror ( ar , WERR_DS_DRA_INTERNAL_ERROR ) ;
} else {
ret = replmd_replicated_uptodate_modify ( ar ) ;
2007-01-12 13:17:25 +00:00
}
2008-09-11 18:36:28 -04:00
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_done ( ar - > req , NULL , NULL , ret ) ;
2007-01-12 13:17:25 +00:00
}
}
2008-09-11 18:36:28 -04:00
talloc_free ( ares ) ;
2007-01-12 13:17:25 +00:00
return LDB_SUCCESS ;
}
2008-09-11 18:36:28 -04:00
static int replmd_replicated_uptodate_vector ( struct replmd_replicated_request * ar )
2007-01-12 13:17:25 +00:00
{
2009-01-30 16:31:19 -05:00
struct ldb_context * ldb ;
2007-01-12 13:17:25 +00:00
int ret ;
2007-12-20 00:02:15 +01:00
static const char * attrs [ ] = {
2007-01-12 13:17:25 +00:00
" replUpToDateVector " ,
2007-01-12 17:02:55 +00:00
" repsFrom " ,
2007-01-12 13:17:25 +00:00
NULL
} ;
2008-09-11 18:36:28 -04:00
struct ldb_request * search_req ;
2009-01-30 16:31:19 -05:00
ldb = ldb_module_get_ctx ( ar - > module ) ;
2008-09-11 18:36:28 -04:00
ar - > search_msg = NULL ;
2007-01-12 13:17:25 +00:00
2008-09-11 18:36:28 -04:00
ret = ldb_build_search_req ( & search_req ,
2009-01-30 16:31:19 -05:00
ldb ,
2008-09-11 18:36:28 -04:00
ar ,
2007-01-12 13:17:25 +00:00
ar - > objs - > partition_dn ,
LDB_SCOPE_BASE ,
" (objectClass=*) " ,
attrs ,
NULL ,
ar ,
2008-09-11 18:36:28 -04:00
replmd_replicated_uptodate_search_callback ,
ar - > req ) ;
2007-01-12 13:17:25 +00:00
if ( ret ! = LDB_SUCCESS ) return replmd_replicated_request_error ( ar , ret ) ;
2008-09-11 18:36:28 -04:00
return ldb_next_request ( ar - > module , search_req ) ;
2007-01-12 13:17:25 +00:00
}
2009-09-03 12:55:57 +10:00
2007-01-06 10:15:02 +00:00
static int replmd_extended_replicated_objects ( struct ldb_module * module , struct ldb_request * req )
{
2009-01-30 16:31:19 -05:00
struct ldb_context * ldb ;
2007-01-11 09:54:10 +00:00
struct dsdb_extended_replicated_objects * objs ;
struct replmd_replicated_request * ar ;
2008-09-27 02:27:54 +02:00
struct ldb_control * * ctrls ;
2009-09-03 12:55:57 +10:00
int ret , i ;
struct replmd_private * replmd_private =
talloc_get_type ( ldb_module_get_private ( module ) , struct replmd_private ) ;
2007-01-11 09:54:10 +00:00
2009-01-30 16:31:19 -05:00
ldb = ldb_module_get_ctx ( module ) ;
ldb_debug ( ldb , LDB_DEBUG_TRACE , " replmd_extended_replicated_objects \n " ) ;
2007-01-11 09:54:10 +00:00
objs = talloc_get_type ( req - > op . extended . data , struct dsdb_extended_replicated_objects ) ;
if ( ! objs ) {
2009-01-30 16:31:19 -05:00
ldb_debug ( ldb , LDB_DEBUG_FATAL , " replmd_extended_replicated_objects: invalid extended data \n " ) ;
2007-01-13 11:37:13 +00:00
return LDB_ERR_PROTOCOL_ERROR ;
}
if ( objs - > version ! = DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION ) {
2009-01-30 16:31:19 -05:00
ldb_debug ( ldb , LDB_DEBUG_FATAL , " replmd_extended_replicated_objects: extended data invalid version [%u != %u] \n " ,
2007-01-13 11:37:13 +00:00
objs - > version , DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION ) ;
2007-01-11 09:54:10 +00:00
return LDB_ERR_PROTOCOL_ERROR ;
}
2008-09-11 18:36:28 -04:00
ar = replmd_ctx_init ( module , req ) ;
if ( ! ar )
2007-01-11 09:54:10 +00:00
return LDB_ERR_OPERATIONS_ERROR ;
2008-09-11 18:36:28 -04:00
2009-10-16 16:20:15 +11:00
/* Set the flags to have the replmd_op_callback run over the full set of objects */
ar - > apply_mode = true ;
2008-09-11 18:36:28 -04:00
ar - > objs = objs ;
2009-01-30 16:31:19 -05:00
ar - > schema = dsdb_get_schema ( ldb ) ;
2008-09-11 18:36:28 -04:00
if ( ! ar - > schema ) {
2009-01-30 16:31:19 -05:00
ldb_debug_set ( ldb , LDB_DEBUG_FATAL , " replmd_ctx_init: no loaded schema found \n " ) ;
2008-09-11 18:36:28 -04:00
talloc_free ( ar ) ;
2009-09-22 14:26:59 -07:00
DEBUG ( 0 , ( __location__ " : %s \n " , ldb_errstring ( ldb ) ) ) ;
2008-09-11 18:36:28 -04:00
return LDB_ERR_CONSTRAINT_VIOLATION ;
2007-01-11 09:54:10 +00:00
}
2008-09-27 02:27:54 +02:00
ctrls = req - > controls ;
if ( req - > controls ) {
req - > controls = talloc_memdup ( ar , req - > controls ,
talloc_get_size ( req - > controls ) ) ;
if ( ! req - > controls ) return replmd_replicated_request_werror ( ar , WERR_NOMEM ) ;
}
ret = ldb_request_add_control ( req , DSDB_CONTROL_REPLICATED_UPDATE_OID , false , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
ar - > controls = req - > controls ;
req - > controls = ctrls ;
2009-09-03 12:55:57 +10:00
DEBUG ( 4 , ( " linked_attributes_count=%u \n " , objs - > linked_attributes_count ) ) ;
/* save away the linked attributes for the end of the
transaction */
for ( i = 0 ; i < ar - > objs - > linked_attributes_count ; i + + ) {
struct la_entry * la_entry ;
2009-09-14 03:44:10 -07:00
if ( replmd_private - > la_ctx = = NULL ) {
replmd_private - > la_ctx = talloc_new ( replmd_private ) ;
2009-09-03 12:55:57 +10:00
}
2009-09-14 03:44:10 -07:00
la_entry = talloc ( replmd_private - > la_ctx , struct la_entry ) ;
2009-09-03 12:55:57 +10:00
if ( la_entry = = NULL ) {
ldb_oom ( ldb ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
la_entry - > la = talloc ( la_entry , struct drsuapi_DsReplicaLinkedAttribute ) ;
if ( la_entry - > la = = NULL ) {
2009-09-13 14:24:08 +10:00
talloc_free ( la_entry ) ;
2009-09-03 12:55:57 +10:00
ldb_oom ( ldb ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
* la_entry - > la = ar - > objs - > linked_attributes [ i ] ;
/* we need to steal the non-scalars so they stay
around until the end of the transaction */
talloc_steal ( la_entry - > la , la_entry - > la - > identifier ) ;
talloc_steal ( la_entry - > la , la_entry - > la - > value . blob ) ;
DLIST_ADD ( replmd_private - > la_list , la_entry ) ;
}
2007-01-11 09:54:10 +00:00
return replmd_replicated_apply_next ( ar ) ;
2007-01-06 10:15:02 +00:00
}
2009-09-03 12:55:57 +10:00
/*
process one linked attribute structure
*/
static int replmd_process_linked_attribute ( struct ldb_module * module ,
struct la_entry * la_entry )
{
struct drsuapi_DsReplicaLinkedAttribute * la = la_entry - > la ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
2009-10-16 15:11:28 +11:00
struct dsdb_schema * schema = dsdb_get_schema ( ldb ) ;
2009-09-03 12:55:57 +10:00
struct ldb_message * msg ;
TALLOC_CTX * tmp_ctx = talloc_new ( la_entry ) ;
int ret ;
const struct dsdb_attribute * attr ;
2009-11-12 15:39:17 +11:00
struct dsdb_dn * dsdb_dn ;
2009-09-25 20:38:20 -07:00
uint64_t seq_num = 0 ;
2009-12-28 17:19:29 +11:00
struct ldb_message_element * old_el ;
2009-11-12 15:39:17 +11:00
WERROR status ;
2009-12-10 23:48:30 +11:00
time_t t = time ( NULL ) ;
2009-12-18 20:57:21 +11:00
struct ldb_result * res ;
const char * attrs [ 2 ] ;
struct parsed_dn * pdn_list , * pdn ;
2009-12-21 21:21:55 +11:00
struct GUID guid = GUID_zero ( ) ;
2009-12-18 20:57:21 +11:00
NTSTATUS ntstatus ;
bool active = ( la - > flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE ) ? true : false ;
2009-12-19 19:57:37 +11:00
const struct GUID * our_invocation_id ;
2009-11-12 15:39:17 +11:00
2009-09-03 12:55:57 +10:00
/*
linked_attributes [ 0 ] :
& objs - > linked_attributes [ i ] : struct drsuapi_DsReplicaLinkedAttribute
identifier : *
identifier : struct drsuapi_DsReplicaObjectIdentifier
__ndr_size : 0x0000003a ( 58 )
__ndr_size_sid : 0x00000000 ( 0 )
guid : 8e95 b6a9 - 13 dd - 4158 - 89 db - 3220 a5be5cc7
sid : S - 0 - 0
__ndr_size_dn : 0x00000000 ( 0 )
dn : ' '
attid : DRSUAPI_ATTRIBUTE_member ( 0x1F )
value : struct drsuapi_DsAttributeValue
__ndr_size : 0x0000007e ( 126 )
blob : *
blob : DATA_BLOB length = 126
flags : 0x00000001 ( 1 )
1 : DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
originating_add_time : Wed Sep 2 22 : 20 : 01 2009 EST
meta_data : struct drsuapi_DsReplicaMetaData
version : 0x00000015 ( 21 )
originating_change_time : Wed Sep 2 23 : 39 : 07 2009 EST
originating_invocation_id : 794640f 3 - 18 cf - 40 ee - a211 - a93992b67a64
originating_usn : 0x000000000001e19c ( 123292 )
2009-11-12 15:39:17 +11:00
( for cases where the link is to a normal DN )
2009-09-03 12:55:57 +10:00
& target : struct drsuapi_DsReplicaObjectIdentifier3
__ndr_size : 0x0000007e ( 126 )
__ndr_size_sid : 0x0000001c ( 28 )
guid : 7639e594 - db75 - 4086 - b0d4 - 67890 ae46031
sid : S - 1 - 5 - 21 - 2848215498 - 2472035911 - 1947525656 - 19924
__ndr_size_dn : 0x00000022 ( 34 )
dn : ' CN = UOne , OU = TestOU , DC = vsofs8 , DC = com '
*/
2009-11-12 15:39:17 +11:00
/* find the attribute being modified */
attr = dsdb_attribute_by_attributeID_id ( schema , la - > attid ) ;
if ( attr = = NULL ) {
DEBUG ( 0 , ( __location__ " : Unable to find attributeID 0x%x \n " , la - > attid ) ) ;
2009-09-03 12:55:57 +10:00
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-11-12 15:39:17 +11:00
2009-12-18 20:57:21 +11:00
attrs [ 0 ] = attr - > lDAPDisplayName ;
attrs [ 1 ] = NULL ;
2009-09-03 12:55:57 +10:00
2009-12-18 20:57:21 +11:00
/* get the existing message from the db for the object with
this GUID , returning attribute being modified . We will then
use this msg as the basis for a modify call */
ret = dsdb_module_search ( module , tmp_ctx , & res , NULL , LDB_SCOPE_SUBTREE , attrs ,
DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
DSDB_SEARCH_SHOW_DELETED |
DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
DSDB_SEARCH_REVEAL_INTERNALS ,
" objectGUID=%s " , GUID_string ( tmp_ctx , & la - > identifier - > guid ) ) ;
2009-09-03 12:55:57 +10:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-12-18 20:57:21 +11:00
if ( res - > count ! = 1 ) {
ldb_asprintf_errstring ( ldb , " DRS linked attribute for GUID %s - DN not found " ,
GUID_string ( tmp_ctx , & la - > identifier - > guid ) ) ;
talloc_free ( tmp_ctx ) ;
return LDB_ERR_NO_SUCH_OBJECT ;
}
msg = res - > msgs [ 0 ] ;
2009-09-03 12:55:57 +10:00
2009-12-18 20:57:21 +11:00
if ( msg - > num_elements = = 0 ) {
ret = ldb_msg_add_empty ( msg , attr - > lDAPDisplayName , LDB_FLAG_MOD_REPLACE , & old_el ) ;
if ( ret ! = LDB_SUCCESS ) {
ldb_module_oom ( module ) ;
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-09-03 12:55:57 +10:00
} else {
2009-12-18 20:57:21 +11:00
old_el = & msg - > elements [ 0 ] ;
old_el - > flags = LDB_FLAG_MOD_REPLACE ;
2009-09-03 12:55:57 +10:00
}
2009-12-18 20:57:21 +11:00
/* parse the existing links */
ret = get_parsed_dns ( module , tmp_ctx , old_el , & pdn_list , attr - > syntax - > ldap_oid ) ;
2009-09-03 12:55:57 +10:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-11-12 15:39:17 +11:00
2009-12-19 19:57:37 +11:00
/* get our invocationId */
our_invocation_id = samdb_ntds_invocation_id ( ldb ) ;
if ( ! our_invocation_id ) {
ldb_debug_set ( ldb , LDB_DEBUG_ERROR , __location__ " : unable to find invocationId \n " ) ;
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
ret = replmd_check_upgrade_links ( pdn_list , old_el - > num_values , our_invocation_id ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-12-28 17:19:29 +11:00
status = dsdb_dn_la_from_blob ( ldb , attr , schema , tmp_ctx , la - > value . blob , & dsdb_dn ) ;
2009-12-18 20:57:21 +11:00
if ( ! W_ERROR_IS_OK ( status ) ) {
2009-12-28 17:19:29 +11:00
ldb_asprintf_errstring ( ldb , " Failed to parsed linked attribute blob for %s on %s - %s \n " ,
old_el - > name , ldb_dn_get_linearized ( msg - > dn ) , win_errstr ( status ) ) ;
2009-09-03 12:55:57 +10:00
return LDB_ERR_OPERATIONS_ERROR ;
2009-11-12 15:39:17 +11:00
}
2009-09-03 12:55:57 +10:00
2009-12-18 20:57:21 +11:00
ntstatus = dsdb_get_extended_dn_guid ( dsdb_dn - > dn , & guid , " GUID " ) ;
2009-12-21 21:21:55 +11:00
if ( ! NT_STATUS_IS_OK ( ntstatus ) & & active ) {
ldb_asprintf_errstring ( ldb , " Failed to find GUID in linked attribute blob for %s on %s from %s " ,
old_el - > name ,
ldb_dn_get_linearized ( dsdb_dn - > dn ) ,
ldb_dn_get_linearized ( msg - > dn ) ) ;
2009-12-18 20:57:21 +11:00
return LDB_ERR_OPERATIONS_ERROR ;
2009-09-25 20:38:20 -07:00
}
2009-12-28 17:22:12 +11:00
/* re-resolve the DN by GUID, as the DRS server may give us an
old DN value */
ret = dsdb_module_dn_by_guid ( module , dsdb_dn , & guid , & dsdb_dn - > dn ) ;
if ( ret ! = LDB_SUCCESS ) {
ldb_asprintf_errstring ( ldb , __location__ " : Failed to re-resolve GUID %s " ,
GUID_string ( tmp_ctx , & guid ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-12-18 20:57:21 +11:00
/* see if this link already exists */
2009-12-21 21:21:55 +11:00
pdn = parsed_dn_find ( pdn_list , old_el - > num_values , & guid , dsdb_dn - > dn ) ;
2009-12-18 20:57:21 +11:00
if ( pdn ! = NULL ) {
/* see if this update is newer than what we have already */
struct GUID invocation_id = GUID_zero ( ) ;
uint32_t version = 0 ;
NTTIME change_time = 0 ;
bool was_active = ldb_dn_get_extended_component ( pdn - > dsdb_dn - > dn , " DELETED " ) = = NULL ;
dsdb_get_extended_dn_guid ( pdn - > dsdb_dn - > dn , & invocation_id , " RMD_INVOCID " ) ;
dsdb_get_extended_dn_uint32 ( pdn - > dsdb_dn - > dn , & version , " RMD_VERSION " ) ;
dsdb_get_extended_dn_nttime ( pdn - > dsdb_dn - > dn , & change_time , " RMD_CHANGETIME " ) ;
if ( ! replmd_update_is_newer ( & invocation_id ,
& la - > meta_data . originating_invocation_id ,
version ,
la - > meta_data . version ,
change_time ,
la - > meta_data . originating_change_time ) ) {
DEBUG ( 1 , ( " Discarding older DRS linked attribute update to %s on %s from %s \n " ,
old_el - > name , ldb_dn_get_linearized ( msg - > dn ) ,
GUID_string ( tmp_ctx , & la - > meta_data . originating_invocation_id ) ) ) ;
2009-09-25 20:38:20 -07:00
talloc_free ( tmp_ctx ) ;
2009-12-18 20:57:21 +11:00
return LDB_SUCCESS ;
2009-09-25 20:38:20 -07:00
}
2009-12-18 20:57:21 +11:00
/* get a seq_num for this change */
ret = ldb_sequence_number ( ldb , LDB_SEQ_NEXT , & seq_num ) ;
if ( ret ! = LDB_SUCCESS ) {
2009-09-25 20:38:20 -07:00
talloc_free ( tmp_ctx ) ;
2009-12-18 20:57:21 +11:00
return ret ;
2009-09-25 20:38:20 -07:00
}
2009-09-03 12:55:57 +10:00
2009-12-18 20:57:21 +11:00
if ( was_active ) {
/* remove the existing backlink */
ret = replmd_add_backlink ( module , schema , & la - > identifier - > guid , & guid , false , attr , false ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
}
2009-09-03 12:55:57 +10:00
2009-12-18 20:57:21 +11:00
ret = replmd_update_la_val ( tmp_ctx , pdn - > v , dsdb_dn , pdn - > dsdb_dn ,
& la - > meta_data . originating_invocation_id ,
la - > meta_data . originating_usn , seq_num ,
la - > meta_data . originating_change_time ,
2009-12-20 00:10:40 +11:00
la - > meta_data . version ,
2009-12-18 20:57:21 +11:00
! active ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-09-03 12:55:57 +10:00
2009-12-18 20:57:21 +11:00
if ( active ) {
/* add the new backlink */
ret = replmd_add_backlink ( module , schema , & la - > identifier - > guid , & guid , true , attr , false ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
}
} else {
/* get a seq_num for this change */
ret = ldb_sequence_number ( ldb , LDB_SEQ_NEXT , & seq_num ) ;
if ( ret ! = LDB_SUCCESS ) {
2009-09-18 14:10:42 -07:00
talloc_free ( tmp_ctx ) ;
2009-12-18 20:57:21 +11:00
return ret ;
}
old_el - > values = talloc_realloc ( msg - > elements , old_el - > values ,
struct ldb_val , old_el - > num_values + 1 ) ;
if ( ! old_el - > values ) {
ldb_module_oom ( module ) ;
2009-09-18 14:10:42 -07:00
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-12-18 20:57:21 +11:00
old_el - > num_values + + ;
ret = replmd_build_la_val ( tmp_ctx , & old_el - > values [ old_el - > num_values - 1 ] , dsdb_dn ,
& la - > meta_data . originating_invocation_id ,
la - > meta_data . originating_usn , seq_num ,
la - > meta_data . originating_change_time ,
2009-12-20 00:10:40 +11:00
la - > meta_data . version ,
2009-12-18 20:57:21 +11:00
( la - > flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE ) ? false : true ) ;
2009-09-18 14:10:42 -07:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-12-18 20:57:21 +11:00
if ( active ) {
ret = replmd_add_backlink ( module , schema , & la - > identifier - > guid , & guid ,
true , attr , false ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-09-18 14:10:42 -07:00
}
}
2009-12-18 20:57:21 +11:00
/* we only change whenChanged and uSNChanged if the seq_num
has changed */
if ( add_time_element ( msg , " whenChanged " , t ) ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
if ( add_uint64_element ( msg , " uSNChanged " , seq_num ) ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-12-19 21:42:40 +11:00
ret = dsdb_check_single_valued_link ( attr , old_el ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
ret = dsdb_module_modify ( module , msg , DSDB_MODIFY_RELAX ) ;
2009-09-03 12:55:57 +10:00
if ( ret ! = LDB_SUCCESS ) {
2009-12-19 21:42:40 +11:00
ldb_debug ( ldb , LDB_DEBUG_WARNING , " Failed to apply linked attribute change '%s' \n %s \n " ,
2009-09-03 12:55:57 +10:00
ldb_errstring ( ldb ) ,
ldb_ldif_message_string ( ldb , tmp_ctx , LDB_CHANGETYPE_MODIFY , msg ) ) ;
2009-12-18 20:57:21 +11:00
talloc_free ( tmp_ctx ) ;
return ret ;
2009-09-03 12:55:57 +10:00
}
talloc_free ( tmp_ctx ) ;
return ret ;
}
2007-01-06 10:15:02 +00:00
static int replmd_extended ( struct ldb_module * module , struct ldb_request * req )
{
if ( strcmp ( req - > op . extended . oid , DSDB_EXTENDED_REPLICATED_OBJECTS_OID ) = = 0 ) {
return replmd_extended_replicated_objects ( module , req ) ;
}
return ldb_next_request ( module , req ) ;
}
2009-09-03 12:55:57 +10:00
/*
we hook into the transaction operations to allow us to
perform the linked attribute updates at the end of the whole
transaction . This allows a forward linked attribute to be created
before the object is created . During a vampire , w2k8 sends us linked
attributes before the objects they are part of .
*/
static int replmd_start_transaction ( struct ldb_module * module )
{
/* create our private structure for this transaction */
struct replmd_private * replmd_private = talloc_get_type ( ldb_module_get_private ( module ) ,
struct replmd_private ) ;
2009-12-16 11:34:33 +11:00
replmd_txn_cleanup ( replmd_private ) ;
2009-09-13 14:24:08 +10:00
2009-11-20 12:09:24 +11:00
/* free any leftover mod_usn records from cancelled
transactions */
while ( replmd_private - > ncs ) {
struct nc_entry * e = replmd_private - > ncs ;
DLIST_REMOVE ( replmd_private - > ncs , e ) ;
talloc_free ( e ) ;
2009-09-13 14:24:08 +10:00
}
2009-09-03 12:55:57 +10:00
return ldb_next_start_trans ( module ) ;
}
/*
2009-09-03 18:33:17 +10:00
on prepare commit we loop over our queued la_context structures and
2009-09-03 12:55:57 +10:00
apply each of them
*/
2009-09-03 18:33:17 +10:00
static int replmd_prepare_commit ( struct ldb_module * module )
2009-09-03 12:55:57 +10:00
{
struct replmd_private * replmd_private =
talloc_get_type ( ldb_module_get_private ( module ) , struct replmd_private ) ;
2009-09-13 14:24:08 +10:00
struct la_entry * la , * prev ;
2009-12-16 11:34:33 +11:00
struct la_backlink * bl ;
2009-09-13 14:24:08 +10:00
int ret ;
2009-09-03 12:55:57 +10:00
/* walk the list backwards, to do the first entry first, as we
* added the entries with DLIST_ADD ( ) which puts them at the
* start of the list */
for ( la = replmd_private - > la_list ; la & & la - > next ; la = la - > next ) ;
2009-09-13 14:24:08 +10:00
for ( ; la ; la = prev ) {
prev = la - > prev ;
DLIST_REMOVE ( replmd_private - > la_list , la ) ;
2009-09-03 12:55:57 +10:00
ret = replmd_process_linked_attribute ( module , la ) ;
if ( ret ! = LDB_SUCCESS ) {
2009-12-16 11:34:33 +11:00
replmd_txn_cleanup ( replmd_private ) ;
2009-09-03 12:55:57 +10:00
return ret ;
}
}
2009-09-03 18:33:17 +10:00
2009-12-16 11:34:33 +11:00
/* process our backlink list, creating and deleting backlinks
as necessary */
for ( bl = replmd_private - > la_backlinks ; bl ; bl = bl - > next ) {
ret = replmd_process_backlink ( module , bl ) ;
if ( ret ! = LDB_SUCCESS ) {
replmd_txn_cleanup ( replmd_private ) ;
return ret ;
}
}
replmd_txn_cleanup ( replmd_private ) ;
2009-09-13 14:24:08 +10:00
/* possibly change @REPLCHANGED */
ret = replmd_notify_store ( module ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2009-09-03 12:55:57 +10:00
2009-09-03 18:33:17 +10:00
return ldb_next_prepare_commit ( module ) ;
2009-09-03 12:55:57 +10:00
}
static int replmd_del_transaction ( struct ldb_module * module )
{
struct replmd_private * replmd_private =
talloc_get_type ( ldb_module_get_private ( module ) , struct replmd_private ) ;
2009-12-16 11:34:33 +11:00
replmd_txn_cleanup ( replmd_private ) ;
2009-09-03 12:55:57 +10:00
return ldb_next_del_trans ( module ) ;
}
2008-02-20 04:33:43 +01:00
_PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
2007-01-04 12:10:55 +00:00
. name = " repl_meta_data " ,
2009-09-13 14:24:08 +10:00
. init_context = replmd_init ,
. add = replmd_add ,
. modify = replmd_modify ,
2009-09-14 13:13:12 -07:00
. rename = replmd_rename ,
2009-12-16 17:24:21 +11:00
. del = replmd_delete ,
2009-09-13 14:24:08 +10:00
. extended = replmd_extended ,
2009-09-03 12:55:57 +10:00
. start_transaction = replmd_start_transaction ,
2009-09-03 18:33:17 +10:00
. prepare_commit = replmd_prepare_commit ,
2009-09-03 12:55:57 +10:00
. del_transaction = replmd_del_transaction ,
2007-01-04 12:10:55 +00:00
} ;